Профилирование C ++ при наличии агрессивного встраивания?

Я пытаюсь выяснить, на что моя программа на C ++ тратит свое время, используя gprof. Вот моя дилемма: если я компилирую с теми же настройками оптимизации, которые использую для моей сборки релиза, почти все будет встроено, а gprof бесполезно сообщает мне, что 90% моего времени тратится на базовую процедуру, где все было встроено. С другой стороны, если я компилирую с отключенным встраиванием, программа будет работать на порядок медленнее.

Я хочу узнать, сколько времени занимают процедуры, вызываемые из моей основной процедуры, когда моя программа скомпилирована с включенным встраиванием.

Я использую 64-разрядную версию Ubuntu 9.04 на четырехъядерном компьютере Intel. Я заглянул в google-perftools, но, похоже, это не работает на x86_64. Запуск на 32-битной машине не вариант.

Есть ли у кого-нибудь предложения относительно того, как я могу более эффективно профилировать свое приложение, когда встраивание включено?

Изменить: Вот некоторые пояснения моей проблемы. Прошу прощения, если изначально было непонятно.

Я хочу узнать, где проводилось время в моем приложении. Профилирование моей оптимизированной сборки привело к тому, что gprof сказал мне, что ~ 90% времени тратится на main, где все было встроено. Я уже знал это до профилирования!

Я хочу узнать, сколько времени занимают встроенные функции, желательно без отключения оптимизации или встраивания в мои параметры сборки. Приложение работает примерно на порядок медленнее при профилировании с отключенным встраиванием. Эта разница во времени выполнения является проблемой удобства, но также я не уверен, что профиль производительности программы, созданной с отключенным встраиванием, будет строго соответствовать профилю производительности программы, созданной с включенным встраиванием.

Вкратце: есть ли способ получить полезную информацию о профилировании программы на C ++ без отключения оптимизации или встраивания?


person Brad Larsen    schedule 18.01.2010    source источник
comment
stackoverflow.com/questions/375913/. В этой ветке много информации   -  person Hassan Syed    schedule 18.01.2010


Ответы (6)


Я предполагаю, что вы хотите выяснить, какие строки кода обходятся вам достаточно дорого, чтобы их можно было оптимизировать. Это сильно отличается от функций времени. Вы можете добиться большего, чем gprof.

Вот довольно полное объяснение того, как сделай это.

Вы можете сделать это вручную или использовать один из профилировщиков, который может предоставить ту же информацию, например oprofile и RotateRight / Zoom.

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

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

person Mike Dunlavey    schedule 18.01.2010
comment
(+1) хорошая информация, особенно ссылка на снимок стека (в которой говорится, что ключ захватывает, а не выборку), хотя все инструменты, похоже, скорее измеряют, чем захватывают - снимок стека тоже. - person Hassan Syed; 18.01.2010
comment
@ Хасан: Ага. Я считаю это делом акцента на точности определения местоположения, а не на точности измерения. Oprofile и Zoom берут образцы стека в настенное время, и они могут дать вам, для каждого оператора,% образцов, содержащих этот оператор. Если они дают это из большого количества образцов, это нормально, но на самом деле не обязательно. Лично я делаю это вручную, потому что тогда я также могу видеть больше информации о состоянии, такой как данные, над которыми я работаю. Часто это важная информация. - person Mike Dunlavey; 18.01.2010
comment
Да, я согласен, я тоже делаю это вручную - и консенсус в отношении профилирования игровых движков / встроенной работы / процедур ОС и вещей RTOS также в значительной степени использует этот подход. - person Hassan Syed; 18.01.2010
comment
@ Хасан: Без шуток? Боже, они ужасно тихи на ТАК. Я уверен, что в высокопроизводительной графике на счету каждый цикл. Я использую этот метод с тех пор, как занимался ассемблером на мини в 78-м году. Даже тогда разработчики аппаратного обеспечения хотели предоставить мне таймеры для настройки производительности. Я сказал, спасибо, но нет, спасибо. Кнопка паузы и пошаговое действие - не только самые простые инструменты, но и самые эффективные. - person Mike Dunlavey; 18.01.2010
comment
Сборка профиля, которую я пытался выполнить, была построена с теми же параметрами, что и моя сборка выпуска, за исключением добавления -fno-inlining и -pg. Я не встраивал ни одну из своих функций явно; Я оставил это компилятору, исходя из предположения, что он может лучше, чем я, решить, что подходит для встраивания. Из-за того, что компилятор выполнял встраивание, мне не удалось выяснить, какие функции занимали время - все они были встроены. Профилирование с явно отключенным встраиванием, позвольте мне получить эту информацию. Также было бы полезно узнать, какие линии дороги. - person Brad Larsen; 19.01.2010
comment
@Bradford: Я бы в любом случае просто сделал стеки-шоты. Они могут точно сказать, что происходит. Может быть, проблема во встраивании, но, честно говоря, меня это действительно удивит. Скорее всего, я бы никогда не смог догадаться об этом. Не думайте об этом слишком усердно - просто сделайте это - и посмотрите, что он вам скажет. Это просто. Я бы начал с медленной версии. Что-то стоит 90% времени, поэтому вы точно увидите, что это такое, как только вы приостановите его, с 90% уверенностью. Если поставить на паузу еще несколько раз, сомнений не останется. - person Mike Dunlavey; 20.01.2010
comment
... Мне будет интересно услышать, что вы узнаете. - person Mike Dunlavey; 20.01.2010
comment
@Mike: Моя проблема не была сформулирована так четко, как могла бы быть изначально. Моя проблема заключается в том, что попытка профилирования с теми же настройками оптимизации, что и моя сборка релиза, приводит к тому, что gprof не сообщает мне ничего полезного: почти весь код моего внутреннего цикла встроен в тело, а gprof просто говорит мне: `` Ну и дела, ты тратишь все ваше время в основном цикле ''. Дополнительную информацию см. в моем отредактированном вопросе. - person Brad Larsen; 20.01.2010
comment
@Mike: Когда у меня будет больше времени (срок подачи документов через 2 дня), я попробую, чтобы stackshot'' method you suggest. In the meantime, I compiled with profiling support and with inlining explicitly disabled, but other build options the same as in my release build. When running this build, my application ran many times slower, but gprof was able to give me more useful information than 90% времени проводилось в основном цикле, который составляет всю программу ''. Оказывается, серьезным виновником является код, который очищает хеш-таблицу, занимая около 25% от общего времени выполнения. Остальная часть профиля была довольно плоской. - person Brad Larsen; 20.01.2010
comment
@Bradford: Я рад, что gprof дал вам некоторое представление. Stackshots должны дать больше. Я только что получил комментарий к этому ответу (stackoverflow.com/questions/375913/), где пользователь заявляет о 60-кратном ускорении. - person Mike Dunlavey; 20.01.2010


Разработайте несколько макросов, используя высокопроизводительный механизм синхронизации вашего процессора (например, x86) - подпрограммы, которые не полагаются на системные вызовы и связывают один поток, выполняющий ваш основной цикл, с конкретным процессором (установить привязку). Вам нужно будет реализовать следующий макрос.

PROF_INIT //allocate any variables -- probably a const char
PROF_START("name") // start a timer
PROF_STOP() // end a timer and calculate the difference -- 
            // which you write out using a async fd

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

Примечание.

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

-- редактировать --

Возможно, вас заинтересует ссылка из этого ответа на один из моих вопросов.

person Hassan Syed    schedule 18.01.2010

Будет ли valgrind более полезным?

В сочетании с графическим интерфейсом пользователя KCachegrind он предлагает бесплатный и простой способ просмотра аннотированного кода, подходящего для встроенного код. Вот довольно простая инструкция: http://web.stanford.edu/class/cs107/guide_callgrind.html

person Dmitry    schedule 18.01.2010

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

person Community    schedule 18.01.2010
comment
еще 10 голосов за то, что заявили об очевидном и не добавили никакой ценности - уэ: P - person Hassan Syed; 18.01.2010
comment
Может быть - но опять же, вполне возможно, что это не так. Если вы рассматриваете вызовы функций как дерево, считается само собой разумеющимся, что все поддеревья одинаково выигрывают от встраивания. На самом деле это почти всегда будет ложью. В одних случаях разница будет незначительной, в других - достаточно значительной. - person Jerry Coffin; 18.01.2010
comment
это и большинство профилировщиков управляются аппаратными прерываниями - и включают другие помехи. - person Hassan Syed; 18.01.2010
comment
Если встраивание позволяет лучше оптимизировать базовую функцию (что очень возможно), то профилирование без встраивания будет вводить в заблуждение. - person Phil Miller; 18.01.2010
comment
Я не понимаю, почему этот голос отклоняется. То, что сказал Нил, правда. Если у вас есть узкое место и вы отключите встраивание, это узкое место будет очевидно в профилировщике. Вы по-прежнему будете работать как минимум так же медленно, как и ваша самая медленная функция. Если ваше самое большое замедление - это накладные расходы на звонки, вам, вероятно, следует похлопать себя по плечу и прекратить работу. Если действительно нет очевидного места, где код работает медленно, тогда вы должны судить, стоит ли его оптимизировать для улучшения на 2–3%. - person Steve; 18.01.2010
comment
Конечно, любое профилирование - это лишь приблизительный показатель того, что произойдет в реальном оптимизированном коде. Однако доля времени, затраченного на каждую функцию, вероятно, будет достаточно репрезентативной для того, что происходит в реальном коде, и дает хорошее первое приближение того, какие функции выиграют от ручной оптимизации, что, безусловно, является целью упражнения. - person ; 18.01.2010
comment
@Hassan Syed: Большинство профилировщиков действительно включают некоторый шум, но он не (даже близко) уникален для ситуации, когда все функции генерируются встроенными, т.е. это правда в целом, а не только ситуация в рука. - person Jerry Coffin; 18.01.2010
comment
Я не уверен, что программа, скомпилированная с отключенным встраиванием, будет эквивалентна по модулю общего времени выполнения программе, в которой компилятор имеет встроенные функции, как сумасшедшие: встраивание может обеспечить дальнейшую оптимизацию, такую ​​как постоянное распространение, подъем цикла, слияние циклов , и т.д. - person Brad Larsen; 19.01.2010
comment
Хорошие программисты используют профилировщик, чтобы получить ответы. Действительно хорошие программисты используют профилировщик для понимания. - person MSalters; 19.01.2010
comment
@MSalters: Не мне говорить, в порядке ли я (или на самом деле), но я проделал тонну настройки производительности и заставил себя отомстить, рассказывая о стекшотах, которые в моем (и других) опыте запускают кольца вокруг профилировщиков. . @Neil: Профилирование грубое, но это не ошибка. Чтобы найти расточителей времени, не требуется точного отсчета времени. @Bradford: Те оптимизации компилятора, о которых так много говорят профессионалы - они помогают только в настройке конечной игры, после того, как вы выполнили тяжелую работу по макросу - оптимизацию, которая они, как правило, не имеют большого опыта, хотя и имеют хорошие намерения. - person Mike Dunlavey; 21.01.2010
comment
... Извините за болтовню, но у меня проблема со словарным запасом, который мы используем для обсуждения производительности. Я бы предпочел, чтобы мы говорили не о функциях и о том, насколько они медленны, а о строках кода и о том, доля времени они несут ответственность за (или для краткости стоимость). По моему опыту, все проблемы с производительностью имеют очень точное местоположение и требуют значительного количества времени, которое экономится, когда они исправляются, удаляя их, вызывая их реже или иным образом находя лучший способ достижения той же цели. - person Mike Dunlavey; 21.01.2010
comment
... и узкое место - подразумевает некоторый ограничивающий ресурс, который ограничивает объем нашего законного бизнеса, который может выполняться за раз. Реальные проблемы с производительностью похожи на те фрактальные кривые (en.wikipedia.org/wiki/Koch_snowflake), где в середине каждой прямой линии вы совершаете небольшой обходной путь, а в середине каждой линии - другую, и так далее. Каждое побочное путешествие (вызов функции) кажется невинным, но в совокупности они умножают длину пути на большой коэффициент, что необязательно. Каждый звонок подобен покупке по кредитной карте, и вы можете подумать, что он стоит недорого. - person Mike Dunlavey; 21.01.2010
comment
... и многие из них этого не делают - они хорошие вещи - но некоторые убийцы, и они не рекламируют себя в исходном коде. Невозможно достоверно угадать, где они. Стекшоты ловят их на месте. (stackoverflow.com/questions / 406760 /). Повторите: это не имеет ничего отношения к встраиванию - стоимость входа / выхода вызовов функций может быть абсолютно бесплатной и идеально оптимизированной. Это все, связанное с дополнительной семантической работой, о которой вы даже не подозреваете. - person Mike Dunlavey; 21.01.2010

Вы можете использовать gcov, чтобы узнать количество выполнений построчно. Это должно хотя бы сказать вам, какие встроенные функции являются узким местом.

person ergosys    schedule 18.01.2010
comment
Я немного поигрался с gcov по вашему предложению. Он подсчитывает количество звонков, чего недостаточно, чтобы сказать мне, что отнимает много времени. - person Brad Larsen; 19.01.2010