Почему время выполнения программы так сильно различается?

Есть программа на С++, которая читает размеры и сигнатуры файлов, а также считает их хэши. Я решил распараллелить её посредством std::async. Всё вроде нормально, кроме одного момента: на одних и тех же файлах с одними и теми же результатами программа может выполняться почти на минуту быстрее/дольше:

87,98s user 19,80s system 75% cpu 2:23,52 total
...
76,20s user 17,61s system 113% cpu 1:22,71 total
...
85,96s user 18,13s system 73% cpu 2:20,75 total


И так далее. Я раз 30 прогнал программу, обычно она выполняется за ~2:20, но время от времени - за ~1:20.
Сначала я подумал, что наборы файлов по-разному распределяются по потокам, вставил подсчёт размера набора для каждого потока - оказалось что нет, наборы всегда одинаковые. Но вот время выполнения почему-то разное.
Программа выполняется в Linux, количество потоков в программе равно количеству потоков процессора (в моём случае - 8), целевой каталог с файлами лежит на SATA SSD. Системный кэш между прогонами сбрасывается. Во время всех прогонов состояние системы примерно одинаковое: запущены одни и те же программы, в фоне играет плеер, я смотрю в диспетчер задач. Целевой каталог с файлами, повторюсь, один и тот же, он точно не меняется от прогона к прогону. И результаты работы программы одинаковые полностью.
Подскажите хотя бы примерно, куда смотреть. Может ли это быть результатом ситуативной работы планировщика процессов в Linux? Всё-таки такая большая разница...
Или может быть это из-за того, что в программе широко используются std::unordered_map и std::unordered_set? Я слышал, их реализация далека от идеальной.
  • Вопрос задан
  • 452 просмотра
Пригласить эксперта
Ответы на вопрос 3
jcmvbkbc
@jcmvbkbc
"I'm here to consult you" © Dogbert
… 75% cpu 2:23,52 total
… 113% cpu 1:22,71 total
… 73% cpu 2:20,75 total
количество потоков в программе равно количеству потоков процессора (в моём случае - 8…

Похоже, что твоя программа не справляется с загрузкой всех ядер, едва одно ядро она нагружает. Я бы смотрел в то как потоки взаимодействуют друг с другом и искал там явную или скрытую сериализацию.
Ответ написан
Комментировать
wataru
@wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
У вас там работа с диском. Да еще многопоточная. Что там в кеше у SSD окажется, выполняется ли какой-нибудь TRIM в контроллере SSD, индексирует ли что-то какой-нибудь системный процесс, на какое ядро планировщик закинет какие потоки - куча факторов.
Ответ написан
Комментировать
@rPman
Любой вопрос о производительности своего приложения нужно начинать с профилирования.
google: c++ profiler, первая же статья с хабра как пример.

И да отсутствие 100% нагрузки на все ядра уже повод задуматься что что то делаешь не так (или приложение упирается в недостаточно высокую скорость чтения файлов как пример). Кстати напоминаю, современные ядра что у intel что у amd - виртуальные, мало того, есть модели десктопных процессоров, где некоторые ядра не такие же как остальные (читай медленнее) а значит выкачивать 100% эффективности не так просто. Например многопоточные приложения числодробилки я сразу запускаю на 1/2 от количества ядер процессора (иначе можно получить замедление вместо ускорения).

Для начала попробуй зафиксировать для своего однопоточного приложения определенные ядра, например с помощью taskset (google: linux cpu core affinity for specified application). Если делать тупо, то перебирай доступные ядра по одному (может быть по два, так как асинхронные методы могут внутри себя использовать потоки, для реализации асинхронности тех действий для которых они в ОС не реализованы), иначе нужно проанализировать свои ядра по отдельности бенчмарками и принимать решение обосновано.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы