Russian Qt Forum

Qt => Кладовая готовых решений => Тема начата: SASA от Октябрь 15, 2010, 13:30



Название: Сбор метрик функций.
Отправлено: SASA от Октябрь 15, 2010, 13:30
Недавно, я чуть-чуть поменял алгоритм работы программы. И, на глазок, приложение стало работать чуть дольше. Мне захотелось сравнить время работы старой и новой функции. Написав нехитрый код, я замерил время работы и количество вызовов. Но эта функция вызывает десяток других. У меня возник вопрос: "Какую из ни следует оптимизировать". Копи-паст и вот я получил необходимые данные. Чем дольше я разбирался, тем больше меня бесил копи-паст. А потом это все вычищать :'(
Можно, конечно, воспользоваться профиляторм, но:
1. Многие из них стоят денег (под Винду).
2. Надо перекомпилировать весь проект.
3. Много избыточной информации.
4. Сложность использования.

Поэтому я решил написать что-то, чтоб одной строкой вставлять в функцию все необходимое для её анализа.
Порядок работы:
1. Подключаем gaudge.h.
2. В начале функции вставляем макрос MEASUREIT.
Код:
CClass::Method()
{
MEASUREIT;
// делаем много-много действий
}
3. Компилируем программу, запускаем, работаем, закрываем.
4. В консоли получаем строку вида
Код:
"CClass::Method" Time:  23. Count: 12 . 
, где
Time - общее время выполнения функции
Count - количество вызовов.

Ну собственно код.
gaudge.h
Код:
/*!	\file	gaudge.h
* \brief Файл со свем необходимым для измерения времени работы функций.
* \author SASA.
* \date 2010/10/14
*/
#ifndef MED_GAUDGE_H
#define MED_GAUDGE_H

#include <QString>
#include <QTime>

/// Напишите этот макрос в самом начале функции, и по концу программы будет выдана статистика: сколько раз вызвали, сколько времени потратили.
#define MEASUREIT static CGaudge gaudge_339b8a83_553b_4adc_955c_718943a1462f(__FUNCTION__); \
CGaudgeHelpper gaudgehelper_9357359e_3a55_40e2_aca8_0be960a81c78(&gaudge_339b8a83_553b_4adc_955c_718943a1462f);

/*! \brief Класс измеритель времени работы метода и количества вызовов.
* \author SASA
* \date 2010/10/14
*/
class CGaudge
{
public:
/*! \brief Создать измеряльщик.
* \param[in] _name (\c const QString) - Имя измерямого объекта.
*/
CGaudge(const QString _name);
~CGaudge(void);
void incrementCount() { m_callCount++; }
void startTimeMeasuring();
void stopTimeMeasuring();
protected:
int m_callTime; ///< Время вызова.
int m_callCount; ///< Количество вызовов.
QString m_name; ///< Имя измерямого объекта.
QTime m_stopwatch;  ///< Часики для засечки времени.
};

/*! \brief Класс автоматом начинает и заканчивает измерение.
* \author SASA
* \date 2010/10/14
*/
class CGaudgeHelpper
{
public:
CGaudgeHelpper(CGaudge * _guadge);
~CGaudgeHelpper();
protected:
CGaudge * m_guadge; ///< Измеритель, с которым работаем
};

#endif // MED_GAUDGE_H

gaudge.cpp
Код:
#include "gaudge.h"
#include <QtCore>

CGaudge::CGaudge( const QString _name )
{
m_callTime = 0;
m_callCount = 0;
m_name = _name;
}
CGaudge::~CGaudge(void)
{
qDebug() << m_name << "Time: " << m_callTime << ". Count: " << m_callCount << ".";
}

void CGaudge::startTimeMeasuring()
{
m_stopwatch.restart();
}

void CGaudge::stopTimeMeasuring()
{
m_callTime += m_stopwatch.elapsed();
}

CGaudgeHelpper::CGaudgeHelpper(CGaudge * _guadge)
{
m_guadge = _guadge;
if(m_guadge)
{
m_guadge->incrementCount();
m_guadge->startTimeMeasuring();
}
}

CGaudgeHelpper::~CGaudgeHelpper()
{
if(m_guadge)
{
m_guadge->stopTimeMeasuring();
}
}

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


Название: Re: Сбор метрик функций.
Отправлено: navrocky от Октябрь 15, 2010, 22:06
Да, простенько и со вкусом :)

Интересно какая погрешность QTime? Маленькие функции оно видимо адекватно не засчитает...

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

Попридираюсь для приличия :)
Цитировать
CGaudge(const QString _name) -> CGaudge(const QString& _name)

Можно еще тело объекта в pimpl запхнуть чтобы не инклюдить кутэшные хедеры...


Название: Re: Сбор метрик функций.
Отправлено: SASA от Октябрь 15, 2010, 22:49
Попридираюсь для приличия
Цитировать
CGaudge(const QString _name) -> CGaudge(const QString& _name)

Это описка  ;)


Название: Re: Сбор метрик функций.
Отправлено: daimon от Июнь 15, 2011, 03:25
мне бы вариант для прогресс бара подсчёт времени до овончания работы фунций


Название: Re: Сбор метрик функций.
Отправлено: kambala от Июнь 15, 2011, 12:52
если в функции используется цикл с заранее известным количеством итераций, то это делается элементарно и написано прямо в ассистенте (QProgressDialog)


Название: Re: Сбор метрик функций.
Отправлено: SASA от Июнь 16, 2011, 09:31
мне бы вариант для прогресс бара подсчёт времени до овончания работы фунций

Данное готовое решение имеет мало общего с Вашим вопросом. Лучше откройте новую тему.

По теме. С помощью этой штуки можно отлавливать некоторые течи. Например, вы подозреваете, что какой-то объект не удаляется. Ставим макрос MEASUREIT в конструктор и диструктор соответствующего. А потом сравниваем количество вызовов.


Название: Re: Сбор метрик функций.
Отправлено: Denjs от Июнь 16, 2011, 09:53
гм... а фиксить время входа и выхода каждого раза - можно?
что бы потом построить график с линеечками где каждая дина каждой полоски пропорциональна времени работы каждой функции ...

PS: я все ношусь с идеей построить трейс фактически случившихся вызовов функций с разверткой по времени...
это помогает выделить лишние вызовы одних и тех-же функций на втором-третьем уровне вложенности и оптимизировать код...

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

или кто знает как это сделать иначе? с помощью каких-либо инструментов трейсинга gcc-шного компилятора?


Название: Re: Сбор метрик функций.
Отправлено: Igors от Июнь 16, 2011, 16:17
гм... а фиксить время входа и выхода каждого раза - можно?
Так делали старые профайлеры, компилятор создавал специальный код для них. Принцип тот же что и у SASA. Это работало, но типичной проблемой был жуткий overhead когда время выполнения ф-ции мало или соразмеримо с затратами на замер.

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

Делать аналогичное самому - ну это "мячты/прожекты"  :)  На такой проект надо работать


Название: Re: Сбор метрик функций.
Отправлено: panAlexey от Сентябрь 21, 2011, 16:54

А так да профайлеров под винду я бесплатных не нашел, под линупсом есть один, но как тут правильно замечено столько выдает инфы, что с наскоку не разобрать.
gprof (http://www.opennet.ru/docs/RUS/gprof/)