Низкая производительность из-за гиперпоточности с OpenMP: как привязать потоки к ядрам
Я разрабатываю большой код умножения плотной матрицы. Когда я профилирую код, он иногда получает около 75% пиковых провалов в моей четырехъядерной системе, а иногда - около 36%. Эффективность не меняется между выполнениями кода. Он либо начинается с 75% и продолжается с этой эффективностью, либо начинается с 36% и продолжается с этой эффективностью.
Я проследил проблему до гиперпоточности и того факта, что я установил число потоков равным четырем вместо восьми по умолчанию.Когда я отключаю гиперпоточность в BIOS, я получаю примерно 75% эффективности (или, по крайней мере, я никогда не вижу резкого падения до 36%).
Прежде чем я вызову любой параллельный код, я делаюomp_set_num_threads(4)
, Я также пыталсяexport OMP_NUM_THREADS=4
прежде чем я запускаю свой код, но он кажется эквивалентным.
Я не хочу отключать гиперпоточность в BIOS. Я думаю, что мне нужно привязать четыре потока к четырем ядрам. Я проверил несколько разных случаевGOMP_CPU_AFFINITY
но до сих пор у меня есть проблема, что эффективность иногда составляет 36%.Что такое отображение с гиперпоточностью и ядрами? Например. соответствуют ли нить 0 и нить одному и тому же ядру, а нить 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
Редактировать:Эти варианты также хорошо работают (gemm это имя моего исполняемого файла)
numactl -C 0,1,2,3 ./gemm
а также
taskset -c 0,1,2,3 ./gemm