Профилировщик для кода C++, очень сонный

Я новичок с профилированием. Я хотел бы оптимизировать мой код для удовлетворения временных ограничений. Я использую Visual C++ 08 Express и, следовательно, мне пришлось скачать профилировщик, для меня это очень сонно. Я провел поиск, но не нашел приличного учебника по Sleepy, и вот мой вопрос: как правильно его использовать? Я понял общую идею профилирования, поэтому отсортировал по%exclusive, чтобы найти свои узкие места. Во-первых, в верхней части этого списка у меня есть ZwWaitForSingleObject, RtlEnterCriticalSection, оператор new, RtlLeaveCriticalSection, printf, некоторые итераторы... и после того, как они занимают около 60%, появляется моя первая функция, первая позиция с дочерними вызовами. Может кто-нибудь объяснить мне, почему вышеперечисленное выходит, что они означают и как я могу оптимизировать свой код, если у меня нет доступа к этим критическим 60%? (для "исходного файла": неизвестно...). Кроме того, для моей функции я думаю, что у меня есть время для каждой строки, но это не так, например, арифметика или некоторые функции не имеют времени (не вложены в неиспользуемые предложения "если"). И последнее: как узнать, что какая-то строка может выполняться сверхбыстро, но вызывается тысячи раз, являясь фактическим узким местом?

И наконец, хорош ли Сонный? Или какая-то бесплатная альтернатива для моей платформы?

Помощь очень ценится! ура!

        • ОБНОВИТЬ - - - - -

Я нашел другую версию профилировщика, названную простой Sleepy. Он показывает, сколько раз был вызван какой-то фрагмент, плюс номер строки (я думаю, это указывает на критический). Так что в моем случае.. KiFastSystemCallRet занимает 50%! Это означает, что он ждет каких-то данных, верно? Как улучшить этот вопрос, может быть, есть достойный подход, чтобы отследить, что вызывает эти множественные вызовы и в конечном итоге удалить / изменить его?

2 ответа

Решение

Я хотел бы оптимизировать мой код для удовлетворения временных ограничений

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

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

Если у вас есть "узкое место" (а у вас, вероятно, несколько), это займет некоторую долю времени, например, 30%.
Просто относитесь к этому как к ошибке, которую можно найти.

Случайно остановите программу с помощью кнопки паузы и внимательно посмотрите, что делает программа и почему она это делает. Спросите, можно ли от этого избавиться. Сделайте это 10 раз. В среднем вы увидите проблему на 3 из пауз. Любая активность, которую вы видите более одного раза, если она не является действительно необходимой, является ошибкой скорости. Это не говорит вам точно, сколько стоит проблема, но точно говорит вам, в чем проблема, и что ее стоит исправить. Таким образом, вы увидите вещи, которые ни один профилировщик не сможет найти, потому что профилировщики - это всего лишь программы, и они не могут иметь широкого представления о том, что представляет собой возможность.

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

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

Есть много литературы о профилировании, но очень мало, что на самом деле говорит о том, насколько быстро это достигается на практике. Вот конкретный пример ускорения почти на 3 порядка.

Я использовал GlowCode (коммерческий продукт, похожий на Sleepy) для профилирования нативного кода C++. Вы запускаете процесс инструментирования, затем выполняете свою программу, затем смотрите на данные, полученные инструментом. Шаг инструментирования вводит небольшую функцию трассировки в каждую точку входа и выхода каждого метода и просто измеряет, сколько времени требуется для выполнения каждой функции до завершения.

Используя инструмент профилирования графа вызовов, я перечислил методы, отсортированные от "наибольшее количество использованного времени" к "наименьшее использованное время", и инструмент также отображает количество вызовов. Простое сверление с самым высоким процентным показателем показало мне, какие методы использовались чаще всего. Я мог видеть, что некоторые методы были очень медленными, но углубляясь в них, я обнаружил, что они ожидают ввода данных от пользователя или ответа службы. А некоторым потребовалось много времени, потому что они вызывали некоторые внутренние процедуры тысячи раз при каждом вызове. Мы обнаружили, что кто-то допустил ошибку в кодировании и неоднократно просматривал большой связанный список для каждого элемента в списке, когда ему действительно нужно было пройти его один раз.

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

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

Я хотел бы предупредить вас об одном: ограничить ваши изменения теми, которые будут влиять на восприятие пользователей или пропускную способность системы. Бритье одной миллисекунды от щелчка мышью не будет иметь никакого значения для среднего пользователя, потому что время реакции человека просто не так быстро. У гонщиков есть время реакции в диапазоне 8 миллисекунд, некоторые элитные геймеры даже быстрее, но у обычных пользователей, таких как кассиры банка, будет время реакции в диапазоне 20-30 миллисекунд. Преимущества будут незначительными.

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

Точно так же сокращение одной услуги на одну миллисекунду от службы, которая обрабатывает 100 пользователей в секунду, даст улучшение на 10%, а это означает, что вы могли бы улучшить службу для обработки 110 пользователей в секунду.

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

Другие вопросы по тегам