Какой самый надежный инструмент для профилирования gprof или kcachegrind? - PullRequest
2 голосов
/ 13 июня 2011

Профилирование некоторого кода C ++ для обработки чисел с gprof и kcachegrind дает аналогичные результаты для функций, которые больше всего влияют на время выполнения (50-80% в зависимости от ввода), но для функций между 10-30% и эти инструменты дают разные результаты. Значит ли это, что один из них ненадежен? Что бы вы сделали здесь?

Ответы [ 2 ]

7 голосов
/ 16 июня 2011

gprof на самом деле довольно примитивно. Вот что он делает. 1) Сэмплирует программный счетчик с постоянной скоростью и записывает, сколько сэмплов попадает в каждую функцию (исключительное время). 2) Подсчитывает, сколько раз любая функция A вызывает любую функцию B. Исходя из этого, он может узнать, сколько раз каждая функция была вызвана в целом, и каково ее среднее исключительное время. Чтобы получить среднее время включения каждой функции, оно распространяет исключительное время вверх в графе вызовов.

Если вы ожидаете, что это будет иметь какую-то точность, вы должны знать о некоторых проблемах. Во-первых, он учитывает только время ЦП, т. Е. Не учитывает ввод-вывод или другие системные вызовы. Во-вторых, рекурсия смущает это. В-третьих, предпосылка о том, что функции всегда придерживаются среднего времени выполнения, независимо от того, когда они вызваны или кто их вызывает, весьма сомнительна. В-четвертых, представление о том, что функции (и их граф вызовов) - это то, о чем вам нужно знать, а не о строках кода, является просто популярным предположением, не более того. В-пятых, представление о том, что точность измерения даже имеет отношение к нахождению «узких мест», также является популярным предположением, не более того.

Callgrind может работать на уровне линий - это хорошо. К сожалению, он разделяет другие проблемы.

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

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

Итак, в конце у вас есть 1000 образцов стека вызовов. Выберите любую строку кода L, которая появляется на более чем одном из них. Предположим, вы могли бы как-то оптимизировать эту строку, избегая ее, удаляя ее или передавая ее действительно очень быстрому процессору.

Что будет с этими образцами?

Поскольку эта строка кода L теперь не занимает (по существу) совсем никакого времени, ни одна выборка не может поразить ее, поэтому эти выборки просто исчезнут , уменьшая общее количество выборок и, следовательно, общее время. ! Фактически, общее время будет уменьшено на долю времени, которое L находился в стеке, что примерно равно части выборок, которые его содержали.

Я не хочу получать слишком статистические данные, но многие люди думают, что вам нужно много выборок, потому что они считают, что точность измерения важна. Это не так, если причина, по которой вы делаете это, состоит в том, чтобы выяснить, что нужно исправить, чтобы ускориться. Акцент делается на нахождение , что исправить, а не на измерение это. Линия L находится в стеке в некоторой доле F времени, верно? Таким образом, каждый образец имеет вероятность F попадания в него, верно? Так же, как подбрасывание монеты. Существует теория об этом, называемая Правило наследования . Это говорит о том, что (при упрощенных, но общих предположениях), если вы подбрасываете монету N раз и видите «головы» S раз, вы можете оценить справедливость монеты F как (в среднем) (S+1)/(N+2). Итак, если вы берете всего лишь три выборки и видите L на двух из них, знаете ли вы, что такое F? Конечно, нет. Но вы делаете в среднем знаете, что это (2 + 1) / (3 + 2) или 60% . Так вот, сколько времени вы могли бы сэкономить (в среднем), "оптимизируя" строку L. И, конечно же, образцы стеков показали, что точно , где находится линия L ("узкое место" **). Действительно ли имело значение, что вы не измеряли его до двух или трех десятичных знаков?

Кстати, он невосприимчив к всем другим проблемам, упомянутым выше .

** Я продолжаю помещать кавычки вокруг "узкого места", потому что то, что делает большинство программного обеспечения медленным, не имеет ничего общего с горлышком бутылки.Лучшая метафора - это «утечка» - то, что просто напрасно тратит время.

2 голосов
/ 13 июня 2011

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

С другой стороны, KCacheGrind использует valgrind, что фактически интерпретируетвесь код.

Таким образом, KCacheGrind может быть "более точным" (за счет больших накладных расходов) , если ЦП, моделируемый valgrind, близок к реальному ЦП.1014 *

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

Для «лучших» данных gprof выполняйте код дольше (и на максимально широком диапазоне тестовых данных).Чем больше у вас есть, тем лучше будут статистические измерения.

...