Russian Qt Forum
Ноябрь 05, 2024, 11:04 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Сбор метрик функций.  (Прочитано 8041 раз)
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();
}
}

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

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #1 : Октябрь 15, 2010, 22:06 »

Да, простенько и со вкусом Улыбающийся

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

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

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

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

Гугль в помощь
SASA
Гость
« Ответ #2 : Октябрь 15, 2010, 22:49 »

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

Это описка  Подмигивающий
Записан
daimon
Гость
« Ответ #3 : Июнь 15, 2011, 03:25 »

мне бы вариант для прогресс бара подсчёт времени до овончания работы фунций
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4746



Просмотр профиля WWW
« Ответ #4 : Июнь 15, 2011, 12:52 »

если в функции используется цикл с заранее известным количеством итераций, то это делается элементарно и написано прямо в ассистенте (QProgressDialog)
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
SASA
Гость
« Ответ #5 : Июнь 16, 2011, 09:31 »

мне бы вариант для прогресс бара подсчёт времени до овончания работы фунций

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

По теме. С помощью этой штуки можно отлавливать некоторые течи. Например, вы подозреваете, что какой-то объект не удаляется. Ставим макрос MEASUREIT в конструктор и диструктор соответствующего. А потом сравниваем количество вызовов.
« Последнее редактирование: Июнь 16, 2011, 09:36 от SASA » Записан
Denjs
Гость
« Ответ #6 : Июнь 16, 2011, 09:53 »

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

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

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

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

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Июнь 16, 2011, 16:17 »

гм... а фиксить время входа и выхода каждого раза - можно?
Так делали старые профайлеры, компилятор создавал специальный код для них. Принцип тот же что и у SASA. Это работало, но типичной проблемой был жуткий overhead когда время выполнения ф-ции мало или соразмеримо с затратами на замер.

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

Делать аналогичное самому - ну это "мячты/прожекты"  Улыбающийся  На такой проект надо работать
Записан
panAlexey
Гипер активный житель
*****
Offline Offline

Сообщений: 864

Акцио ЗАРПЛАТА!!!!! :(


Просмотр профиля
« Ответ #8 : Сентябрь 21, 2011, 16:54 »


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

Win Xp SP-2, Qt4.3.4/MinGW. http://trdm.1gb.ru/
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.051 секунд. Запросов: 23.