Встраивание поддержки профилирования в код - PullRequest
1 голос
/ 27 ноября 2009

Я хочу (я не знаю, возможно ли это) встроить поддержку профилирования в мой код вместо использования какого-либо внешнего профилировщика Я слышал, что есть некоторые API-профилировщики, которые используются большинством авторов профилировщиков. Можно ли использовать этот API для профилирования из исполняемого кода? Есть ли другие соображения?

Ответы [ 5 ]

2 голосов
/ 28 ноября 2009

EQATEC Profiler создает инструментированную версию вашего приложения, которая будет сама по себе запускать и собирать статистику профилирования - вам не нужно подключать профилировщик. По умолчанию ваше приложение будет просто выгружать статистику в текстовые xml-файлы.

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

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

2 голосов
/ 27 ноября 2009

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

Вы можете найти эту запись в блоге полезной для начала: http://geekswithblogs.net/.NETonMyMind/archive/2006/08/20/88549.aspx

1 голос
/ 27 ноября 2009

Что я сделал, когда не могу использовать свою любимую технику , так это. Это неуклюже и дает информацию с низким разрешением, но это работает. Во-первых, есть глобальный стек строк. Это в C, но вы можете адаптировать его к C #:

int nStack = 0;
char* stack[10000];

Затем при входе и выходе из каждой подпрограммы, для которой у вас есть исходный код, нажмите / вытолкните название подпрограммы:

void EveryFunction(){
    int iStack = nStack++; stack[iStack] = "EveryFunction";

    ... code inside function

    nStack = iStack; stack[iStack] = NULL;
}

Так что теперь стек [0..nStack] поддерживает текущий стек вызовов (за вычетом номеров строк, из которых вызываются функции), поэтому он не так хорош, как реальный стек вызовов, но лучше, чем ничего.

Теперь вам нужен способ сделать его снимки в случайное или псевдослучайное время. Иметь еще одну глобальную переменную и процедуру для просмотра:

time_t timeToSnap;
void CheckForSnap(){
    time_t now = time(NULL);
    if (now >= timeToSnap){
        if (now - timeToSnap > 10000) timeToSnap = now; // don't take snaps since 1970
        timeToSnap += 1; // setup time for next snapshot
        // print stack to snapshot file
    }
}

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

Как я уже сказал, это лучше, чем ничего. У него есть недостатки:

  • Он не захватывает номера строк, откуда поступают вызовы, поэтому, если вы обнаружите функцию с подозрительно большим временем, вам нужно порыться в ней, чтобы найти трудоемкий код.
  • Он добавляет значительные накладные расходы, а именно все вызовы к time(NULL), поэтому, когда вы удалите все свои большие проблемы, будет труднее найти маленькие.
  • Если ваша программа тратит значительное время на ожидание ввода-вывода или пользовательского ввода, вы увидите кучу сэмплов, накопленных после этого ввода-вывода. Если это файловый ввод-вывод, это полезная информация, но если это пользовательский ввод, вам придется отказаться от этих семплов, потому что все, что они говорят, это то, что вы тратите время.

Важно понимать несколько вещей:

  • Вопреки общепринятому мнению, точность измерения времени (и, следовательно, большого количества образцов) не важна. Важно то, что выборки происходят в то время, когда вы ожидаете, пока программа выполнит свою работу.
  • Также вопреки принятой мудрости, вы не ищете граф вызовов, вам не нужно заботиться о рекурсии, вам не нужно заботиться о том, сколько миллисекунд занимает любая подпрограмма или сколько раз она вызывается, и вам не нужно заботиться о разнице между включенным и исключительным временем или о разнице между процессором и временем настенных часов. нужно заботиться о том, какой процент времени он находится в стеке, потому что это количество времени, за которое он отвечает, в том смысле, что если бы вы могли как-то это сделать рутина не занимает много времени, поэтому ваше общее время уменьшится.
1 голос
/ 27 ноября 2009

Есть статья GameDev, в которой обсуждается, как построить инфраструктуру профилирования в программе на C ++. Возможно, вы сможете адаптировать этот подход для работы с C #, если объекты, созданные в стеке, освобождаются при выходе, а не оставляются для сборщика мусора

http://www.gamedev.net/reference/programming/features/enginuity3/

Даже если вы не можете использовать всю технику, могут быть полезные идеи.

1 голос
/ 27 ноября 2009

API профилировщика платформы .NET - это COM-объект, который перехватывает вызовы до того, как .NET их обрабатывает. Насколько я понимаю, он не может быть размещен в управляемом (C #) коде.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...