Приложения работают медленнее с несколькими потоками
У меня 40-ядерный сервер под управлением Ubuntu 14.04 LTS. Я использую приложение с возможностью многопоточности. Я обнаружил, что запуск приложения с увеличением числа потоков улучшает время выполнения, пока я не переберу определенное число, и в этот момент время выполнения снова начнет увеличиваться. Этот номер потока намного ниже количества ядер, которые у меня есть. Вот несколько примеров (это "настоящие" времена):
8 threads: 1m45.992s
16 threads: 1m7.494s
24 threads: 1m45.174s
32 threads: 3m10.819s
40 threads: 6m12.194s
80 threads: 25m22.937s
У меня не хватает памяти (используется только 4 ГБ из 128 ГБ) и не используется подкачка. Во время этих тестов другие процессы со значительной загрузкой ЦП не выполняются.
Интересно, что когда я запускаю версию того же приложения, скомпилированного из того же источника в OS X, с теми же данными на моем PowerMac с 8 ядрами, я получаю стабильное улучшение времени выполнения до 16 потоков с незначительным (несколько секунд) замедлением при 32 и 64 потоков, так что я не верю, что это проблема с прикладным программным обеспечением. Действительно, когда я использую другое приложение с поддержкой многопоточности с функцией, аналогичной первой, на сервере Ubuntu, я вижу похожие, хотя и не столь впечатляющие результаты:
16 threads: 4m4.795s
40 threads: 2m31.430s
60 threads: 3m7.007s
80 threads: 5m6.946s
Мне обычно приходится проводить этот анализ последовательно на сотнях наборов данных, поэтому любое повышение эффективности может иметь большое значение. Мой вопрос заключается в том, может ли это быть связано с проблемой конфигурации системного программного обеспечения по сравнению с проблемой с моим оборудованием. Будем весьма благодарны за любые мысли о том, с чего начать искать решение этой проблемы и получить полную выгоду от всех моих процессоров.
Спасибо.
1 ответ
Вероятно, вы сталкиваетесь с конфликтными точками в коде, такими как блокировка (с помощью фьютексов и т. П.), Где происходит сериализация кода и, следовательно, останавливается масштабирование производительности.
Кроме того, процессор x86 может иметь N ядер, каждое из которых имеет, скажем, 2 потока каждое, но это не дает вам 2 x N производительности, поскольку гиперпоток выполняется, когда доступны определенные блоки выполнения. Я полагаю, что для одного процессора x86 с сокетами можно получить до 30% дополнительной производительности с помощью гиперпотока.
Кроме того, вы можете столкнуться с конфликтом в памяти, будь то в кеше (L1, L2 или L3) или даже в самой памяти. Таким образом, вы можете столкнуться с ограничениями пропускной способности, сбоев кэша или TLB.
При N process > N CPU вы получите больше процессов, чем может быть запущено, поэтому планировщик должен выполнять больше работы по упреждению запускаемых процессов, и это еще одно ограничение, которое сказывается на производительности.
Вы можете получить низкоуровневые показатели производительности с помощью таких инструментов, как perf. Установите его с помощью:
sudo apt-get install linux-tools
И запустите ваше приложение с perf, чтобы получить некоторые показатели производительности:
perf stat your-program
Вы можете сделать более глубокий анализ, используя отчет и отчет, например:
sudo perf record your-program
sudo perf report
В качестве альтернативы, запустите вашу программу и во время ее работы используйте perf top, чтобы получить интерактивное представление активности системы в режиме реального времени:
sudo perf top
Надеюсь, это даст вам некоторое представление о том, где происходит горлышко бутылки.