Подтвердить что ты не робот

Разделяемая память, MPI и системы очередей

Мое приложение unix/windows С++ уже распараллеливается с использованием MPI: задание разбивается на N cpus, и каждый кусок выполняется параллельно, довольно эффективный, очень хороший масштабирование скорости, работа выполняется правильно.

Но некоторые данные повторяются в каждом процессе, и по техническим причинам эти данные не могут быть легко разделены на MPI (...). Например:

  • 5 Gb статических данных, то же самое загружено для каждого процесса
  • 4 Гб данных, которые могут быть распределены в MPI, чем больше процессоров используется, тем меньше это ОЗУ на процессор.

В четырехзадачном задании ЦП это означало бы, по крайней мере, нагрузку на 20 ГБ, большая часть памяти "впустую", это ужасно.

Я собираюсь использовать общую память для уменьшения общей нагрузки, "статический" кусок будет загружен только один раз на компьютер.

Итак, главный вопрос:

  • Есть ли какой-либо стандартный способ MPI для обмена памятью на node? Какой-нибудь доступный + бесплатный библиотека?

    • Если нет, я бы использовал boost.interprocess и использовал вызовы MPI для распространения локальных идентификаторов разделяемой памяти.
    • Общая память будет считываться "локальным мастером" для каждого node и доступна только для чтения. Нет необходимости в каких-либо семафорах/синхронизации, потому что это не изменится.
  • Любые проблемы с производительностью или особые проблемы, о которых нужно опасаться?

    • (Там не будет никаких "строк" ​​или слишком странных структур данных, все может быть сведено к массивам и указателям структуры).
  • Задача будет выполнена в системе очередности PBS (или SGE), в случае нечистого выхода процесса, я задаюсь вопросом, очистят ли они эту специальную разделяемую память node.

4b9b3361

Ответ 1

Один из наиболее распространенных подходов в высокопроизводительных вычислениях (HPC) - это гибридные программы MPI/OpenMP. То есть у вас есть N процессов MPI, и каждый процесс MPI имеет M потоков. Этот подход хорошо подходит для кластеров, состоящих из многопроцессорных узлов общей памяти.

Переход на такую ​​иерархическую схему распараллеливания, очевидно, требует более или менее инвазивных изменений, OTOH, если это сделано правильно, может увеличить производительность и масштабируемость кода в дополнение к уменьшению потребления памяти для реплицированных данных.

В зависимости от реализации MPI вы можете или не можете выполнять вызовы MPI из всех потоков. Это определяется аргументами required и provided для функции MPI_Init_Thread(), которую вы должны вызывать вместо MPI_Init(). Возможные значения:

{ MPI_THREAD_SINGLE}
    Only one thread will execute. 
{ MPI_THREAD_FUNNELED}
    The process may be multi-threaded, but only the main thread will make MPI calls (all MPI calls are ``funneled'' to the main thread). 
{ MPI_THREAD_SERIALIZED}
    The process may be multi-threaded, and multiple threads may make MPI calls, but only one at a time: MPI calls are not made concurrently from two distinct threads (all MPI calls are ``serialized''). 
{ MPI_THREAD_MULTIPLE}
    Multiple threads may call MPI, with no restrictions. 

По моему опыту, современные MPI-реализации, такие как Open MPI, поддерживают самый гибкий MPI_THREAD_MULTIPLE. Если вы используете старые библиотеки MPI или некоторую специализированную архитектуру, вам может быть хуже.

Конечно, вам не нужно делать свои потоки с помощью OpenMP, это самый популярный вариант в HPC. Вы можете использовать, например. библиотеку Boost threads, библиотеку Intel TBB или прямые потоки pthreads или windows.

Ответ 2

Я не работал с MPI, но если он похож на другие библиотеки IPC, я видел, что скрывают, являются ли другие потоки/процессы/все на одном и том же или разных машинах, тогда он не сможет гарантировать общую память, Да, он может обрабатывать разделяемую память между двумя узлами на одной машине, если на этой машине была предоставлена ​​общая память. Но попытка обмена памятью между узлами на разных машинах в лучшем случае была бы очень сложной, из-за возникающих сложных проблем согласованности. Я ожидаю, что это просто не реализовано.

При всей практичности, если вам нужно обмениваться памятью между узлами, лучше всего сделать это за пределами MPI. я не думаю, что вам нужно использовать разделяемую память boost.interprocess -style, так как вы не описываете ситуацию, когда разные узлы делают мелкозернистые изменения в общей памяти; он либо доступен только для чтения, либо разбит на разделы.

John и deus отвечают на вопрос, как отображать в файле, что, безусловно, вы хотите сделать для статических данных 5 Gb (gigabit?). Данные для каждого процессора похожи на одно и то же, и вам просто нужно отправить сообщение каждому node, чтобы сообщить, какую часть файла он должен захватить. ОС должна заботиться о сопоставлении виртуальной памяти с физической памятью с файлами.

Что касается очистки... Я бы предположил, что он не выполняет очистку разделяемой памяти, но mmap ed файлы должны быть очищены, так как файлы закрыты (что должно отпускать их отображения памяти), когда процесс очищается вверх. Я понятия не имею, какие оговорки CreateFileMapping и т.д. Имеют.

Фактическая "общая память" (т.е. boost.interprocess) не очищается, когда процесс умирает. Если возможно, я рекомендую попробовать убить процесс и посмотреть, что осталось.

Ответ 3

С MPI-2 у вас есть RMA (доступ к удаленной памяти) через такие функции, как MPI_Put и MPI_Get. Используя эти функции, если ваша поддержка MPI их поддерживает, это наверняка поможет вам сократить общее потребление памяти вашей программой. В стоимость добавлена ​​сложность кодирования, но эта часть удовольствия от параллельного программирования. Опять же, он удерживает вас в области MPI.

Ответ 4

Я не знаю много о unix, и я не знаю, что такое MPI. Но в Windows то, что вы описываете, является точным соответствием для объекта сопоставления файлов.

Если эти данные вложены в ваш .EXE или .DLL, который он загружает, тогда он будет автоматически разделяться между всеми процессами. Срыв вашего процесса, даже в результате сбоя, не приведет к утечкам или невыпущенным блокировкам ваших данных. однако 9Gb.dll звучит немного некорректно. Так что это, вероятно, не сработает для вас.

Однако вы можете поместить свои данные в файл, а затем CreateFileMapping и MapViewOfFile. Отображение может быть только для чтения, и вы можете отобразить все или часть файла в памяти. Все процессы будут обмениваться страницами, которые сопоставлены с тем же базовым объектом CreateFileMapping. это хорошая практика, чтобы закрыть unmap-представления и закрыть дескрипторы, но если вы не будете делать это для вас в режиме разговора.

Обратите внимание, что если вы не используете x64, вы не сможете сопоставить 5Gb файл в одном представлении (или даже файл 2Gb, 1Gb может работать). Но, учитывая, что вы говорите о том, что это уже работает, я предполагаю, что вы уже только x64.

Ответ 5

Если вы сохраняете свои статические данные в файле, вы можете использовать mmap для unix для получения произвольного доступа к данным. Данные будут обрабатываться по мере необходимости, когда вам нужен доступ к определенному биту данных. Все, что вам нужно сделать, это наложить любые двоичные структуры на данные файла. Это эквивалент Unix для CreateFileMapping и MapViewOfFile, упомянутых выше.

Кстати, glibc использует mmap, когда вы вызываете malloc для запроса более чем страницы данных.

Ответ 6

У меня были некоторые проекты с MPI в SHUT.

Как я знаю, существует множество способов распространения проблемы с использованием MPI, возможно, вы можете найти другое решение, для которого не требуется общая память, мой проект решал уравнение 7 000 000 и 7 000 000 переменных

если вы можете объяснить свою проблему, я постараюсь вам помочь.

Ответ 7

Я столкнулся с этой проблемой в маленьком, когда я использовал MPI несколько лет назад.

Я не уверен, что SGE понимает файлы с отображением памяти. Если вы распространяете данные против кластера Beowulf, я подозреваю, что у вас будут проблемы согласованности. Не могли бы вы немного рассказать о своей многопроцессорной архитектуре?

Мой проект проекта заключался бы в создании архитектуры, в которой каждая часть данных принадлежит определенному процессору. Было бы два потока: один поток был двунаправленным MPI MPI и одним потоком для вычисления результата. Обратите внимание, что MPI и потоки не всегда хорошо сочетаются.