Параллельное приложение имеет случайное поведение

Я пишу программу C, используя pthreads, чтобы выполнить вычисление шаблона волнового фронта на двумерной матрице. Для достижения хорошей производительности я распределяю несколько строк на каждый stream чередующимся образом, например:

stream 0 ——————

thread 1 ——————

stream 2 ——————

Тема 3 ——————

stream 0 ——————

thread 1 ——————

stream 2 ——————

Тема 3 ——————

и т.п.

В этом вычислении я считаю, что это единственный жизнеспособный раскол, поскольку каждый stream нуждается в новых значениях, вычисленных на каждой строке, и не может двигаться дальше, пока они не будут доступны. Теперь уловкой здесь является то, что для streamа 1 нужны значения, вычисленные streamом 0 на его строке, поэтому он должен отслеживать за нитью 0 и не идти вперед. Для этого я разбиваю каждую строку на куски и защищаю каждый кусок критическим разделом. Вычисление выглядит следующим образом:

нить 0 ———–

нить 1 ——

нить 2 —

так что всегда строка i должна отслеживаться за строкой i – 1. Надеюсь, вы поняли эту идею. Я реализовал эту идею, и я тестирую ее на машине, которая представляет собой двойную четырехъядерную систему. Я испытываю странное поведение. Результаты вычисляются правильно, но время работы варьируется от 8x меньше, чем последовательное время и до более чем последовательного времени. Практически, последовательное время для матрицы 12000 x 12000 составляет 16 секунд, а параллельное время работы составляет от 2 до 17 секунд и часто отличается на два последовательных прогона.

Моя первоначальная идея заключалась в том, что эта проблема очень чувствительна к местоположению, поэтому, конечно, я могу получить плохую производительность, если скажем, что streamи 0 и stream 1 запланированы на разных физических процессорах. Оглядываясь в / proc / cpuinfo, я понял, что ядра отображаются таким образом, что 0, 2, 4, 6 находятся на процессоре 0 и 1, 3, 5, 7 находятся на процессоре 1. Затем, после создания streamа, у меня есть использовал pthread_setaffinity_np, чтобы установить сродство к streamам на правильных ядрах. Однако ничего не меняется. Я также попытался использовать pthread_attr_setaffinity_np, а также sched_setaffinity, но я получаю такое же случайное время работы.

Либо kernel ​​игнорирует мои привязки, либо это не проблема. Я действительно надеюсь, что кто-то может мне помочь, поскольку у меня кончаются идеи. Спасибо.

Ядро не игнорирует ваши собеседования, это просто не проблема.

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

Попробуйте сделать куски данных размером одной строки (64 байта). Попробуйте сделать stream 0 пройденным через 64 ​​байта и только после того, как этот stream 1 будет читаться с одного места – и так далее.