Ортогональная рекурсивная бисекция в часовне (алгоритм Барнса-Хата)
Я реализую распределенную версию симуляции тела Барнса-Хата в часовне. Я уже реализовал последовательную и разделяемую версии памяти, которые доступны на моем GitHub.
Я следую алгоритму, изложенному здесь (глава 7):
- Выполните ортогональную рекурсивную бисекцию и распределите тела так, чтобы каждый процесс выполнялся одинаково
- Построить локально существенное дерево на каждом процессе
- Вычислить силы и выдвинуть тела
У меня есть довольно хорошая идея о том, как реализовать алгоритм в C/MPI, используя MPI_Allreduce
для деления пополам и простой передачи сообщений для связи между процессами (для передачи тела). А также MPI_Comm_split
это очень удобная функция, которая позволяет мне разделять процессы на каждом этапе ORB.
У меня возникли проблемы с выполнением ORB с использованием параллельных / распределенных конструкций, которые предоставляет Chapel. Мне нужен какой-то способ суммирования (сокращения) работы между процессами (локали в часовне), разделения процессов на группы и межпроцессного взаимодействия для передачи тел.
Буду благодарен за любые советы о том, как реализовать это в часовне. Если бы другой подход был лучше для Часовни, это тоже было бы здорово.
0 ответов
После множества тупиков и сбоев мне удалось реализовать алгоритм в Chapel. Его можно найти здесь: https://github.com/novoselrok/parallel-algorithms/tree/75312981c4514b964d5efc59a45e5eb1b8bc41a6/nbody-bh/dm-chapel
Я не смог использовать большую часть модного параллельного оборудования, которое предоставляет Часовня. Я полагался только на блочные распределенные массивы с sync
элементы. Я также воспроизвел модель SPMD.
В main.chpl
Я настроил все необходимые массивы, которые будут использоваться для передачи данных. Каждый массив имеет соответствующий sync
массив используется для синхронизации. Затем каждый работник начинается со своей доли тел и ранее упомянутых массивов. Worker.chpl
содержит основную часть алгоритма
Я заменил MPI_Comm_split
функциональность с пользовательской функцией determineGroupPartners
где я делаю то же самое вручную. Для MPI_Allreduce
Я нашел хороший маленький образец, который я мог использовать везде:
var localeSpace = {0..#numLocales};
var localeDomain = localeSpace dmapped Block(boundingBox=localeSpace);
var arr: [localeDomain] SomeType;
var arr$: [localeDomain] sync int; // stores the ranks of inteded receivers
var rank = here.id;
for i in 0..#numLocales-1 {
var intendedReceiver = (rank + i + 1) % numLocales;
var partner = ((rank - (i + 1)) + numLocales) % numLocales;
// Wait until the previous value is read
if (arr$[rank].isFull) {
arr$[rank];
}
// Store my value
arr[rank] = valueIWantToSend;
arr$[rank] = intendedReceiver;
// Am I the intended receiver?
while (arr$[partner].readFF() != rank) {}
// Read partner value
var partnerValue = arr[partner];
// Do something with partner value
arr$[partner]; // empty
// Reset write, which blocks until arr$[rank] is empty
arr$[rank] = -1;
}
Это довольно сложный способ реализации каналов FIFO (см. Julia RemoteChannel, где я получил вдохновение для этого "шаблона"). Обзор:
Сначала каждая локаль вычисляет своего предполагаемого получателя и своего партнера (откуда локаль будет читать значение)
Локаль проверяет, было ли прочитано предыдущее значение
Locales хранит новое значение и "блокирует" значение, устанавливая
arr$[rank]
с предполагаемым приемникомЛокаль ждет, пока его партнер установит значение и установит соответствующий предполагаемый получатель
Когда локаль является предполагаемым получателем, она считывает значение партнера и выполняет с ним некоторые операции.
Затем локаль очищает / разблокирует значение, читая
arr$[partner]
Наконец он сбрасывает его
arr$[rank]
написав-1
, Таким образом, мы также гарантируем, что значение, установленное локалью, было прочитано предполагаемым получателем
Я понимаю, что это может быть слишком сложным решением этой проблемы. Вероятно, существует лучший алгоритм, который бы соответствовал глобальному представлению Chapels о параллельных вычислениях. Алгоритм, который я реализовал, подходит для модели вычислений SPMD.
При этом, я думаю, что Часовня все еще делает хорошую работу с точки зрения производительности. Вот показатели производительности по сравнению с Юлией и C/MPI. По мере роста числа процессов производительность значительно возрастает. У меня не было возможности запустить тест на кластере с>4 узлами, но я думаю, что Chapel получит респектабельные тесты.