Я пытаюсь оптимизировать производительность программы на C ++ и сократить время ее выполнения. Тем не менее, у меня возникают проблемы с выяснением, где находится узкое место.
Команда time показывает, что запуск самой программы занимает около 5 минут, а около 5 минут пользовательское процессорное время занимает 4,5 минуты.
Профилировщик ЦП (как gcc profiler, так и google perftool) показывает, что вызовы функций занимают всего 60 секунд всего процессорного времени. Я также попытался использовать профилировщик для выборки в реальном времени вместо процессорного времени, и это дает мне похожие результаты.
Профилировщик ввода / вывода (я использовал ioapps) также показывает, что ввод / вывод занимает всего около 30 секунд времени выполнения программы.
Таким образом, в основном у меня не учтено 3,5 минуты (наибольшая часть времени выполнения программы), и я считаю, что именно в этом и заключается узкое место.
Что я пропустил и как мне узнать, куда уходит это время?
Как предложил Öö Tiib, просто разбейте программу в отладчике. То, как я это делаю, это запускаю программу, переключаюсь в окно вывода, набираю Ctrl-C, чтобы прервать программу, переключаюсь обратно в окно GDB, набираю «thread 1», чтобы быть в контексте основной программы, и введите «bt», чтобы увидеть трассировку стека.
Теперь посмотрите на трассировку стека и поймите ее, потому что, хотя инструкция на счетчике программы отвечает за этот конкретный цикл, так же каждый вызов в стеке.
Если вы сделаете это несколько раз, вы увидите, какая именно линия отвечает за узкое место.
Как только вы видите это на двух (2) образцах, вы прибиваете это.
Затем исправьте это и сделайте все снова, найдя следующее узкое место, и так далее.
Вы можете легко обнаружить, что таким образом вы получаете огромное ускорение.
< пламя>
Некоторые люди говорят, что это именно то, что делают профилировщики, только они делают это лучше.
Это то, что вы слышите в лекционных залах и в блогах, но вот сделка:
Есть способы ускорить ваш код, которые, например, не проявляют себя как «медленные функции» или «горячие пути» — реорганизация структуры данных.
Каждая функция выглядит более или менее невинной, даже если она имеет высокий процент времени включения.
Они раскрываются, если вы на самом деле посмотрите на образцы стека.
Так что проблема с хорошими профилировщиками не в сборе образцов, это в представлении результатов. Статистика и измерения не могут сказать вам, о чем говорит небольшой выбор образцов, тщательно изученный.
А как насчет вопроса малого или большого количества образцов? Не лучше ли?
Хорошо, предположим, у вас есть бесконечный цикл, или, если не бесконечный, он просто работает намного дольше, чем вы знаете, что должен? Будет ли 1000 образцов стека найти это лучше, чем один образец? (Нет.) Если вы посмотрите на это в отладчике, вы поймете, что находитесь в цикле, потому что это занимает в основном 100% времени. Это где-то в стеке — просто сканируйте стек, пока не найдете его.
Даже если цикл занимает только 50% или 20% времени, это вероятность того, что каждый образец увидит его.
Итак, если вы видите что-то, от чего вы можете избавиться всего за два образца, стоит сделать это.
Итак, что покупают 1000 образцов?
Может быть, кто-то думает: «А что, если мы пропустим одну или две проблемы? Может, это достаточно хорошо». Ну так что?
Предположим, что в коде есть три проблемы: P занимает 50% времени, Q — 25% и R — 12,5%. Хороший материал называется А.
Это показывает ускорение, которое вы получите, если вы исправите один из них, два или все три.
PRPQPQPAPQPAPRPQ original time with avoidable code P, Q, and R all mixed together
RQQAQARQ fix P - 2 x speedup
PRPPPAPPAPRP fix Q - 1.3 x "PPQPQPAPQPAPPQ fix R - 1.14 x "RAAR fix P and Q - 4 x "QQAQAQ fix P and R - 2.7 x "PPPPAPPAPP fix Q and R - 1.6 x "AA fix P, Q, and R - 8 x speedup
Это дает понять, почему те, которые «уходят», действительно причиняют боль?
Лучший Вы можете сделать, если вы пропустите любой из них в два раза медленнее.
Их легко найти, если изучить образцы. Примерно на половине образцов.
Если вы исправите P и сделаете это снова, Q будет на половине выборок. Как только вы исправите Q, R будет на половине выборок.
Исправьте R, и вы получите 8-кратное ускорение.
Вам не нужно останавливаться на достигнутом. Вы можете продолжать идти, пока действительно не сможете найти что-то, что можно исправить.
Чем больше проблем, тем выше потенциальное ускорение,
но вы не можете позволить себе пропустить ни одного.
Проблема с профилировщиками (даже хорошими) состоит в том, что, лишая вас возможности видеть и изучать отдельные образцы, они скрывают проблемы, которые вам нужно найти.
Подробнее обо всем этом.
Для статистически склонных, вот как это работает.
Есть хорошие профилировщики.
Лучше всего использовать стенные сэмплеры со стенным временем, которые сообщают процент включения по отдельным линиям, позволяя включать и выключать сэмплирование с помощью горячей клавиши.
Увеличить (вики) это такой профилировщик.
Но даже те делают ошибку, предполагая, что вам нужно много образцов.
Вы этого не делаете, и цена, которую вы платите за них, вы на самом деле не видите, поэтому не видите Зачем время тратится, поэтому вы не можете легко сказать, если это необходимо,
и вы не можете избавиться от чего-то, если не знаете, что вам это не нужно.
В результате вы пропускаете узкие места, и они в конечном итоге тормозят ваше ускорение.
< / Пламя>
Других решений пока нет …