Я написал один раз, главным образом как попытку сделать «глубокую выборку» более удобной для пользователя. Когда вы делаете метод вручную, это объясняется здесь . Он основан на выборке, но вместо того, чтобы брать большое количество маленьких выборок, вы берете небольшое количество больших выборок.
Например, он может сказать, что инструкция I
(обычно это вызов функции) стоит вам более или менее процентов X общего времени выполнения, поскольку она появляется в стеке на X% выборок.
Подумайте об этом, потому что это ключевой момент . Стек вызовов существует до тех пор, пока программа работает. Если конкретная инструкция вызова I
находится в стеке X% времени, то если эта инструкция может исчезнуть, то X% времени исчезнет. Это не зависит от того, сколько раз I
выполняется или сколько времени занимает вызов функции. Таким образом, таймеры и счетчики упускают суть. И в некотором смысле все инструкции являются инструкциями вызова, даже если они вызывают только микрокод.
Сэмплер основан на предпосылке, что лучше знать адрес инструкции I
с точностью (, потому что это то, что вы ищете ), чем знать число X% с точностью , Если вы знаете, что могли бы сэкономить примерно 30% времени путем перекодирования чего-либо, действительно ли вас волнует, что вы можете потерять 5%? Вы все еще хотите исправить это. Количество времени, которое оно фактически экономит, не будет больше или меньше уменьшено вашим знанием X.
Таким образом, есть возможность извлекать сэмплы из таймера, но, честно говоря, я обнаружил, что столь же полезно инициировать прерывание, когда пользователь нажимает обе клавиши Shift одновременно. Поскольку 20 сэмплов, как правило, достаточно, и таким образом вы можете быть уверены, что берут сэмплы в соответствующее время (т. Е. Не ожидая ввода данных пользователем), оно было вполне адекватным. Другой способ - делать выборки только по таймеру, пока пользователь удерживает обе клавиши Shift (или что-то в этом роде).
Меня не беспокоило, что взятие образцов может замедлить программу, потому что цель состояла не в том, чтобы измерить скорость, а в том, чтобы найти самые дорогостоящие инструкции. После исправления чего-либо общее ускорение легко измерить.
Главное, что предоставил профилировщик, это пользовательский интерфейс, позволяющий безболезненно просматривать результаты. То, что выходит из фазы выборки, представляет собой набор выборок стека вызовов, где каждая выборка представляет собой список адресов инструкций, где каждая инструкция, кроме последней, является инструкцией вызова. Пользовательский интерфейс был в основном так называемым «представлением бабочки».
У него есть текущий «фокус», который является конкретной инструкцией. Слева отображается инструкция вызова непосредственно над этой инструкцией, взятая из образцов стека. Если инструкция фокусировки является инструкцией вызова, то приведенные ниже инструкции отображаются справа, как показано на примерах. На инструкции фокусировки отображается процент, который является процентом стеков, содержащих эту инструкцию. Точно так же для каждой инструкции слева или справа процент делится на частоту каждой такой инструкции. Конечно, инструкция была представлена файлом, номером строки и названием функции, в которой она находилась. Пользователь мог легко изучить данные, щелкнув любую из инструкций, чтобы сделать их новым фокусом.
Вариант этого пользовательского интерфейса рассматривал бабочку как двудольный, состоящий из чередующихся слоев инструкций вызова функций и содержащих их функций. Это может дать немного больше ясности времени, потраченного на каждую функцию.
Возможно, это неочевидно, поэтому стоит упомянуть некоторые свойства этой техники.
Рекурсия не является проблемой, потому что, если инструкция появляется более одного раза в любой заданной выборке стека, она все равно считается только одной выборкой, содержащей ее. Все еще остается верным, что расчетное время, которое будет сэкономлено при его удалении, представляет собой процент стеков, на которых он работает.
Обратите внимание, что это не то же самое, что дерево вызовов. Это дает вам стоимость инструкции независимо от того, сколько разных ветвей дерева вызовов она находится.
Производительность интерфейса не является проблемой, поскольку количество выборок не должно быть очень большим. Если конкретная инструкция I находится в центре внимания, то довольно просто определить, как ее могут содержать сэмплы, и для каждой смежной инструкции, сколько сэмплов, содержащих I, также содержит соседнюю инструкцию рядом с ней.
Как упоминалось ранее, скорость выборки не является проблемой, потому что мы не измеряем производительность, мы диагностируем. Выборка не влияет на результаты, потому что выборка не влияет на то, что делает программа в целом. Алгоритм, для выполнения которого требуется N инструкций, по-прежнему требует N инструкций, даже если его останавливали любое количество раз.
Меня часто спрашивают, как сэмплировать программу, которая завершается за миллисекунды. Простой ответ - обернуть его во внешний цикл, чтобы он занял достаточно много времени для выборки. Вы можете узнать, что занимает X% времени, удалить его, получить ускорение X%, а затем удалить внешний цикл.
Этот маленький профилировщик, который я назвал YAPA (еще один анализатор производительности), был основан на DOS и сделал небольшую демонстрацию, но когда у меня была серьезная работа, я прибегал к ручному методу. Основная причина этого заключается в том, что одного стека вызовов часто не хватает информации о состоянии, чтобы сказать вам, почему проводится определенный цикл. Вам также может понадобиться узнать другую информацию о состоянии, чтобы у вас было более полное представление о том, что делала программа в то время. Поскольку я нашел ручной метод довольно удовлетворительным, я положил на полку инструмент.
При обсуждении профилирования часто упускают из виду то, что вы можете сделать это несколько раз, чтобы найти несколько проблем. Например, предположим, что инструкция I1
находится в стеке 5% времени, а I2
находится в стеке 50% времени. Двадцать образцов легко найдут I2
, но, возможно, не I1
. Итак, вы исправите I2
. Затем вы делаете все это снова, но теперь I1
занимает 10% времени, поэтому, вероятно, его увидят 20 образцов. Этот эффект увеличения позволяет многократно применять профилирование для достижения больших сложных коэффициентов ускорения.