Низкая производительность из-за гиперпоточности с 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 потоков вы можете получить действительно неудачно выровненный доступ. Если ваши матрицы выровнены по кратному размеру вашего кеша, и если у вас есть пары потоков, обращающихся к областям, кратным кешу, любого случайного чтения третьим потоком будет достаточно, чтобы начать вызывать пропуски конфликтов.
Для быстрого теста - если вы измените свои входные матрицы на нечто, не кратное размеру вашего кэша (чтобы они больше не были выровнены по границе), и ваши проблемы исчезнут, то есть хороший шанс, что вы имеете дело с конфликт отсутствует.