Заполнение массива с помощью Forall в часовне

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

var x: [1..N] real;

forall i in [1..N] {
  x[i] = reallyHeavyMatrixComputation(i);
}

Есть ли советы, как сохранить это в здравом уме? Должен ли я использовать dmapped для области x или что-то?

1 ответ

Решение

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

Более подробно, ключевые политики параллельного цикла, такие как "Сколько задач следует использовать?" и "Где эти задачи должны выполняться?" контролируются итерацией цикла. Например, в следующем цикле:

var x: [1..N] real;                        // declare a local array

forall i in 1..N do                        // iterate over its indices in parallel
  x[i] = reallyHeavyMatrixComputation(i);

Итеран цикла и диапазон 1..N, По умолчанию итератор диапазона создает число локальных задач, равное количеству процессорных единиц / ядер в текущей локали. В результате вышеприведенный цикл не будет работать быстрее, так как будет использовано больше локалей, если только reallyHeavyMatrixComputation() сама содержала предложения, которые интеллектуально распределяли вычисления по локалям. Если бы он вообще не содержал никаких предложений on, вычисления никогда не покинули бы локаль #0 и были бы только с разделяемой памятью.

Напротив, если для выполнения итерации по распределенному домену или массиву используется цикл Форалла, политика по умолчанию обычно состоит в том, чтобы запускать количество задач в каждой целевой локали, равное количеству процессорных ядер в этой локали, в режиме "владелец вычисляет", То есть каждая локаль будет выполнять подмножество итераций, которыми она владеет, как определено распределением. Например, учитывая цикл:

use CyclicDist;                            // make use of the cyclic distribution module

var D = {1..N} dmapped Cyclic(startIdx=1); // declare a cyclically distributed domain
var x: [D] real;                           // declare an array over that domain

forall i in D do                           // iterate over the domain in parallel
  x[i] = reallyHeavyMatrixComputation();

Индексы D будут циклически распределяться по локалям, поэтому параллельный цикл будет создавать задачи в каждой локали, которые делятся и будут выполнять индексы локали. В результате этот цикл должен масштабироваться по нескольким локалям, даже если reallyHeavyMatrixComputation() это полностью локальное вычисление.

Другой способ написания масштабируемых параллельных циклов в Chapel - это вызов явного параллельного итератора, который будет распределять работу по самим локалям. Например, в Chapel версии 1.16 добавлен распределенный модуль пакета итераторов, который предоставляет итераторы, которые будут распределять работу за вас. Возвращаясь к первому примеру, если он был переписан как:

use DistributedIters;                  // make use of the distributed iterator module                                                                          

var x: [1..N] real;                    // declare a local array

forall i in distributedDynamic(1..N) do    // distribute iterations across locales
  x[i] = reallyHeavyMatrixComputation(i);

затем вызов distributedDynamic итератор станет итерацией цикла вместо диапазона 1..N и контролировать создание задач. Этот итератор динамически распределяет итерации для локалей, используя заданный размер фрагмента (по умолчанию 1), и поэтому его можно использовать для масштабируемого использования нескольких локалей. Смотрите документацию для получения более подробной информации.

Другие вопросы по тегам