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