green_fr: (Default)
[personal profile] green_fr
Пытаюсь закрутить нашу программу чуть побыстрее. Взяли потестировать PCT, который, теоретически, с минимальными исправлениями кода позволяет раскидывать расчёты на разные процессоры, а то и компы. Например, говорят, если у вас есть цикл for, все итерации которого совершено независимы, то вы можете просто заменить ключевое слово for на parfor, и PCT сам разберётся, какую итерацию на какой процессор посылать, как собрать потом результаты и т.п.

Начал тестировать. Вот есть у меня некая процедура doSomeWork(), которая читает какой-то файл с диска, что-то там считает и пишет результат на диск же. Время её работы засёк — 664 секунды. Написал цикл из одной итерации:
for i = 1 : 1
doSomeWork();
end
Проверил, всё ещё 664 секунды.
Запустил PCT, поменял for на parfor — 734 секунды.

Ненормально. Попытался понять, что происходит. MatLab при запуске PCT создаёт дополнительные процессы MatLab, то есть в моём случае крутилось два процесса: один — тот, что исполнял скрипт до parfor, а потом работал диспетчером, и второй — который отрабатывал единственную итерацию моего цикла. Теоретически, есть какая-то потеря времени для передачи данных от одного потока к другому. Но у меня нарочно сделано так, чтобы не было видно вообще ни одной лишней переменной. Теоретически, нужно скопировать код (я не знаю, могут ли разные процессы делить один код, не думаю), но всё равно ведь не на 70 секунд работы!

Поменял цикл до 2, запустил снова. Вижу, как у меня крутится 3 MatLab'а — 2 сожрали по куче памяти (каждый процесс кушает где-то 3GB) и по одному ядру процессора, а третий почти ничего памяти и на нуле процессор, он ждёт.

Время работы — 931 секунда. Оппаньки! Опять же, я понимаю, что у меня есть какой-то код, который не параллелится (чтение данных с диска, запись результатов), но его там с гулькин нос, на пару секунд работы (я проверял). А кроме чтения диска я не вижу ничего — ни сеть не используется, ни ещё какие другие внешние устройства. Куда время потерялось?

С тремя итерациями время ускакало вообще до 1223 секунд, смысл распараллеливать постепенно пропадает.

Проверил, что у меня хватает памяти (не начало ещё свопить) — только сегодня поставили 16GB, а даже с тремя считающими MatLab’ами используется до 11GB. Проверил, что параллельно на этом компе ничего ресурсоёмкого нет (только ЖЖ).

Какие ещё есть варианты? Куда смотреть? А то официальный support откровенно косит под тупых (проблемы только у вас, а у нас вот только что один крупный клиент заказал ферму на 700 ядер, и всё работает!), не сложились у меня как-то с ними отношения...

Date: 2014-02-28 04:23 pm (UTC)
From: [identity profile] birdwatcher.livejournal.com
Недостаточно информации. Если много читает с диска и потом на него пишет, но мало считает, то может насыщать диск. Тогда надо параллелить не процессы, а диски.

Date: 2014-02-28 04:30 pm (UTC)
From: [identity profile] green-fr.livejournal.com
Читает очень мало (пару секунд в начале), пишет чуть больше (секунд 5 в конце). На фоне 664 секунд всего процесса это ведь копейки? Более того, в первом примере только один поток и читал, и писал, причём строго в тех же объёмах, что и без PCT. А всё равно 70 секунд куда-то накинулись.

Date: 2014-02-28 04:38 pm (UTC)
From: [identity profile] birdwatcher.livejournal.com
Да, это копейки. Сделай функцию, которая вообще ничего не делает, и распараллель так же. Будет ли тратиться 70 секунд? Может, у матлаба столько занимает поднять процесс. В R над mpi, которым я пользусь, кластер создается (и все процессы поднимаются) заранее и никуда не девается, а процессы потом весь день только разговариват друг с другом.

Date: 2014-02-28 04:43 pm (UTC)
From: [identity profile] green-fr.livejournal.com
У них уже есть какие-то тупые примеры, которые показывают практически линейный рост производительности с увеличением ядер. Тупо считают случайные числа, или там раскладывают на множители.

Есть, конечно, время на подъём процессов, но специально запускаю ручками с консоли, чтобы это время не входило в подсчитанное. А разговаривать им там не о чем, я специально сделал так, чтобы никакого общения не было, всё только с диска и на диск (ну, я преувеличиваю, я передаю из master thread в каждый worker thread номер папки, из которой нужно читать данные, и в которую писать ответ, но это пара байт в одну сторону, и по получении я вывожу на консоль «папка прочитана» — эти сообщения вылетают явно не через 70 секунд).

Date: 2014-02-28 04:50 pm (UTC)
From: [identity profile] birdwatcher.livejournal.com
Так ты уже запускал эти примеры и убедился, что ускорение линейное? Если да, начинай комментировать куски своей функции, пока линейность тоже не появится.

Date: 2014-02-28 04:25 pm (UTC)
From: [identity profile] muh2.livejournal.com
Память не параллелится. В смысле если ее потоки большие - то наверное будут друг-другу мешать. Но оно ж и так не сильно плохо - ну 70 секунд на запуск процессов - это мнговато, конечно, но потом все-таки 2/3 времени экономится?

Date: 2014-02-28 04:33 pm (UTC)
From: [identity profile] green-fr.livejournal.com
Не 2/3, а 1/3 (в лучшем примере было 3 * 664 = 1992, стало 1223), так что пока что обидно.
А память не параллелится, точно? Потому что у меня как раз основные операции в этих 664 секундах — это тупые операции + и *, но на огромных матрицах. Насколько я понимаю, время доступа к памяти соизмеримо со временем этих операций. А есть варианты распараллелить? Одна плашка памяти или две — это на что-то влияет (по аналогии с винтами)? Существуют ли варианты с несколькими процессорами, у каждого из которых своя память? Несколько материнок?

Date: 2014-02-28 04:48 pm (UTC)
From: [identity profile] birdwatcher.livejournal.com
В предельном случае может получиться, что одна матрица как раз помещается в кэш процессора и поэтому обрабатывается мгновенно, а при попытке обрабатывать две сразу они все время выталкивают друг друга, увеличивая время на порядок. Чтобы это исключить, нужна вторая машина.

Date: 2014-02-28 04:51 pm (UTC)
From: [identity profile] green-fr.livejournal.com
Не, там матрицы по 300MB, и их много на каждом потоке :-) На такие кеши у нас денег не хватит.

Date: 2014-02-28 04:55 pm (UTC)
From: [identity profile] birdwatcher.livejournal.com
Ну у тебя и результат не такой ужасный, как в этом примере.

Date: 2014-02-28 05:08 pm (UTC)
From: [identity profile] muh2.livejournal.com
Ну там надо еще 70 секунд одноразового оверхеда вычесть.

А не специалист совершенно, но да, две плашки должны помочь. Несколько материнок - тоже. возможно архитектура допускает несколько шин памяти, но, опять же возможно, только дорогие материнки это используют. Не знаю толком. Подозреваю, что много дешевых материнок - оптимально.

Date: 2014-02-28 05:34 pm (UTC)
From: [identity profile] bobehobi.livejournal.com
A вы уверены, что каждая итерация не зависит от другой итерации? Может написать простой код, где это гарантировано? Например, вставить в главный цикл блок кода со строго локальными переменными.

Date: 2014-03-01 04:55 pm (UTC)
From: [identity profile] green-fr.livejournal.com
Уверен, потому что там всё так и есть - вызов функции со строго локальными переменными. Там нет никаких общих / глобальных переменных, всё создаётся внутри вызываемой функции, и даже данные разные. На самом деле я немного упростил, я вызываю функцию и передаю ей i, а этот же номер является именем папки со всеми необходимыми данными.

Date: 2014-03-02 12:43 am (UTC)
From: [identity profile] bobehobi.livejournal.com
ОК. Тогда существует ли вообще в природе некий пример успешной паралеллизации в Матлабе? Наверное существует. Почему бы не начать с него и постепенно привести его к желаемому коду?

Profile

green_fr: (Default)
green_fr

June 2025

S M T W T F S
123 4 567
89 1011 12 1314
15 16 17 18 19 2021
22 2324 25262728
2930     

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jun. 27th, 2025 01:25 am
Powered by Dreamwidth Studios