компиляции gcc (иногда) приводят к недогрузке процессора

У меня есть большая программа на C ++, которая начинается с чтения тысяч небольших текстовых файлов в память и хранения данных в контейнерах stl. Это займет около минуты. Периодически компиляция будет демонстрировать поведение, при котором начальная часть программы будет работать при нагрузке на процессор около 22-23%. Когда этот шаг закончен, он возвращается к ~ 100% процессору. Скорее всего, это происходит при включенном флаге O2, но не всегда. Это происходит еще реже с флагом -p, что делает практически невозможным профилирование. Я захватил его один раз, но вывод gprof оказался бесполезным — все работает с одинаковой относительной скоростью только при низкой загрузке процессора.

Я совершенно уверен, что это не имеет ничего общего с несколькими ядрами. У меня есть четырехъядерный процессор, и большая часть кода является многопоточным, но я проверил эту проблему, запустив один поток. Кроме того, когда я запускаю проблемный шаг в нескольких потоках, каждый поток работает только на ~ 20% ЦП.

Я заранее прошу прощения за неопределенность вопроса, но у меня закончились идеи о том, как его устранить, поэтому любые советы могут быть полезны.

ОБНОВЛЕНИЕ: просто чтобы убедиться, что проблемная часть кода иногда (~ 30-40% компиляций) работает на 100% CPU, поэтому трудно купить (в противном случае разумный) аргумент, что ввод / вывод является горлышко бутылки

2

Решение

Это буферный кеш


Я предполагаю, что вы видите результаты Linux буферный кеш в операции.

Эти тысячи файлов будут долго считываться с диска, а ЦП будет в основном ожидать вращения и искать задержки. Сообщаемое используемое время ЦП будет низким, выраженным в процентах. (Но, вероятно, больше в целом.)

Но после прочтения эти небольшие файлы полностью кэшируются в памяти, и доступ к каждому файлу (при последующих запусках) становится чисто связанным с процессором действием.

То, останутся ли блоки в кэше, зависит от промежуточной активности, такой как перекомпиляция. Когда запускаются новые программы и читаются другие файлы, программы и файлы будут кэшироваться, а старые блоки будут удаляться, и, очевидно, нагрузка, интенсивно использующая память, также очистит буферный кеш.

4

Другие решения

Так как вы читаете кучу маленьких файлов, ваша программа блокируется, ожидая дискового ввода-вывода большую часть времени. Поскольку процессор не занят, пока он ожидает, пока диск отправит на него данные, нагрузка значительно меньше 100%. Как только это закончится, теперь вы привязаны к процессору, и ваша программа будет использовать все доступное время процессора.

Факт, что это работает быстрее, иногда потому что (как Джаррид & Упоминание DigitalRoss) как только вы прочитаете их в системную память, они будут в кеше ОС, поэтому последующие загрузки будут на порядок быстрее, если только они не были выселены другими дисковыми операциями ввода-вывода. Так что если вы запустите программу вплотную, второй запуск, вероятно, будет намного быстрее. Если вы подождете некоторое время (а тем временем будете заниматься другими делами), возможно, было достаточно других дисковых операций ввода-вывода, чтобы извлечь эти файлы из кэша, и в этом случае потребуется много времени для их повторного чтения.

3

В дополнение к другим ответам, в которых упоминается буферный кеш, если вы хотите понять, что происходит во время компиляции, вы можете передать некоторые из следующих флаги в GCC (т.е. в g++вероятно, как CXXFLAGS установка в вашем Makefile):

  • -v спросить g++ показать вовлеченные подпроцессы (например, cc1plus для правильного компилятора C ++)
  • -time спросить g++ сообщить время каждого подпроцесса
  • -ftime-report спросить g++ (на самом деле cc1plus) сообщать время внутренних фаз или проходов внутри компилятора.
3
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector