Низкая производительность из-за гиперпоточности с OpenMP: как привязать потоки к ядрам

Я разрабатываю большой код умножения плотной матрицы. Когда я профилирую код, он иногда получает около 75% пиковых провалов в моей четырехъядерной системе, а иногда - около 36%. Эффективность не меняется между выполнениями кода. Он либо начинается с 75% и продолжается с этой эффективностью, либо начинается с 36% и продолжается с этой эффективностью.

Я проследил проблему до гиперпоточности и того факта, что я установил число потоков равным четырем вместо восьми по умолчанию. Когда я отключаю гиперпоточность в BIOS, я получаю примерно 75% эффективности (или, по крайней мере, я никогда не вижу резкого падения до 36%).

Прежде чем я вызову любой параллельный код, я делаю omp_set_num_threads(4), Я также пытался export OMP_NUM_THREADS=4 прежде чем запустить мой код, но он кажется эквивалентным.

Я не хочу отключать гиперпоточность в BIOS. Я думаю, что мне нужно привязать четыре потока к четырем ядрам. Я проверил несколько разных случаев GOMP_CPU_AFFINITY но до сих пор у меня есть проблема, что иногда эффективность составляет 36%. Что такое отображение с гиперпоточностью и ядрами? Например, поток 0 и поток 1 соответствуют одному и тому же ядру, а поток 2 и поток 3 - другому ядру?

Как я могу привязать потоки к каждому ядру без миграции потоков, чтобы мне не пришлось отключать гиперпоточность в BIOS? Может быть, мне нужно изучить использование sched_setaffinity?

Некоторые детали моей нынешней системы: ядро ​​Linux 3.13, GCC 4.8,Intel Xeon E5-1620 (четыре физических ядра, восемь гиперпотоков).

Редактировать: кажется, работает хорошо

export GOMP_CPU_AFFINITY="0 1 2 3 4 5 6 7"

или же

export GOMP_CPU_AFFINITY="0-7"

Редактировать: это, кажется, также работает хорошо

export OMP_PROC_BIND=true

Изменить: эти параметры также работают хорошо (гемм это имя моего исполняемого файла)

numactl -C 0,1,2,3 ./gemm

а также

taskset -c 0,1,2,3 ./gemm

1 ответ

Это не прямой ответ на ваш вопрос, но, возможно, стоит обратить на это внимание: очевидно, гиперпоточность может привести к сбою вашего кэша. Вы пытались проверить valgrind, чтобы увидеть, какая проблема вызывает вашу проблему? Может потребоваться быстрое решение проблемы с выделением некоторого количества мусора в верхней части стека каждого потока, чтобы ваши потоки не вышибали строки кэша друг друга.

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

Для быстрого теста - если вы измените свои входные матрицы на нечто, не кратное размеру вашего кэша (чтобы они больше не были выровнены по границе), и ваши проблемы исчезнут, то есть хороший шанс, что вы имеете дело с конфликт отсутствует.

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