Симуляция n-тел с общей памятью в Chapel

Я пытаюсь повторно реализовать реализацию с общей памятью для симуляции n тел, представленную в главе 6.1.6 в книге Питера Пачеко «Введение в параллельное программирование». В этой главе он был реализован с использованием OpenMP.

Вот моя параллельная реализация с использованием OpenMP. А вот последовательная реализация с использованием Chapel . У меня возникли проблемы с реализацией параллельной реализации с общей памятью с использованием Chapel. Поскольку невозможно получить ранг потока в цикле forall, я не могу использовать тот же подход, что и в реализации OpenMP. Мне пришлось бы использовать цикл coforall, создавать задачи и распределять итерации вручную. Это не кажется практичным и предполагает, что в Chapel есть более элегантный способ решить эту проблему.

Я ищу руководство и предложения о том, как лучше решить эту проблему с помощью инструментов, предоставляемых Chapel.


person Rok Novosel    schedule 06.10.2018    source источник
comment
Не могли бы вы сделать образец файла входных данных доступным? Мне не повезло создать его с помощью вашего скрипта gen.py (возможно, из-за личных недостатков).   -  person Brad    schedule 08.10.2018
comment
Конечно, я добавил сюда несколько примеров файлов: github.com/novoselrok/parallel -алгоритмы/дерево/мастер/nbody/. Я также обновил скрипт gen.py с инструкцией по его запуску.   -  person Rok Novosel    schedule 09.10.2018
comment
Большое спасибо! Еще одна запоздалая мысль: поскольку ваши ссылки выше указывают на основную ветку репозитория GitHub, вы можете либо встроить снимок кода в этот вопрос, чтобы сделать его вечным по мере развития репозитория GitHub; или указать на конкретную ветвь/SHA в репозитории GitHub, чтобы он продолжал ссылаться на одну и ту же версию кода (при условии, что весь репозиторий не исчезнет).   -  person Brad    schedule 09.10.2018
comment
Хорошая точка зрения! Я отредактировал исходный пост со ссылками на коммит, но не могу отредактировать предыдущий комментарий, поэтому добавляю ссылку на данные сюда: github.com/novoselrok/parallel-algorithms/tree/   -  person Rok Novosel    schedule 10.10.2018


Ответы (1)


Я бы предложил использовать (+) уменьшить намерение для forces в вашем forall-loop, который даст каждой задаче свою собственную частную копию forces, а затем (суммирует) сведет их отдельные копии обратно в исходную переменную forces по мере выполнения задач. Это можно сделать, присоединив к циклу forall следующее предложение with:

  forall q in 0..#n_bodies with (+ reduce forces) {

Находясь здесь, я искал другие способы сделать код немного более элегантным и предложил бы перейти от 2D-массива к массиву массивов для этой проблемы, чтобы свернуть кучу трио похожих операторов кода для x, y , z компонентов до одного оператора. Я также использовал вашу переменную pDomain и создал псевдоним типа для [0..#3] real, чтобы удалить некоторую избыточность в коде. О, и я удалил use из модулей Math и IO, потому что они автоматически используются в программах Chapel.

Вот где это оставило меня:

config const filename = "input.txt";
config const iterations = 100;
config const out_filename = "out.txt";
const X = 0;
const Y = 1;
const Z = 2;
const G = 6.67e-11;
config const dt = 0.1;

// Read input file, initialize bodies                                       
var f = open(filename, iomode.r);
var reader = f.reader();

var n_bodies = reader.read(int);
const pDomain = {0..#n_bodies};

type vec3 = [0..#3] real;

var forces: [pDomain] vec3;
var velocities: [pDomain] vec3;
var positions: [pDomain] vec3;
var masses: [pDomain] real;

for i in pDomain {
  positions[i] = reader.read(vec3);

  velocities[i] = reader.read(vec3);

  masses[i] = reader.read(real);
}

f.close();
reader.close();

for i in 0..#iterations {
  // Reset forces                                                           
  forces = [0.0, 0.0, 0.0];

  forall q in pDomain with (+ reduce forces) {
    for k in pDomain {
      if k <= q {
        continue;
      }
      var diff = positions[q] - positions[k];
      var dist = sqrt(diff[X]**2 + diff[Y]**2 + diff[Z]**2);
      var dist_cubed = dist**3;

      var tmp = -G * masses[q] * masses[k] / dist_cubed;
      var force_qk = tmp * diff;

      forces[q] += force_qk;
      forces[k] -= force_qk;
    }
  }


  forall q in pDomain {
    positions[q] += dt * velocities[q];
    velocities[q] += dt / masses[q] * forces[q];
  }
}

var outf = open(out_filename, iomode.cw);
var writer = outf.writer();

for q in pDomain {
  writer.writeln("%er %er %er %er %er %er".format(positions[q][X], positions[q][Y], positions[q][Z], velocities[q][X], velocities[q][Y], velocities[q][Z]));
}

writer.close();
outf.close();

Еще одно изменение, которое вы могли бы рассмотреть, — заменить цикл forall, который обновляет позиции и скорости, следующими операторами всего массива:

    positions += dt * velocities;                                           
    velocities += dt / masses * forces;                                     

где основной компромисс будет заключаться в том, что forall будет реализовывать операторы объединенным образом, используя один параллельный цикл, а операторы всего массива - нет (по крайней мере, в текущей версии компилятора версии 1.18).

person Brad    schedule 09.10.2018