最近在改造公司旧系统代码(C++),需要查找某个函数性能底下原因,所以自己写了一个打点计时类用于性能分析,其中最主要的取时间函数getSysTimeMicros由同事(杨成)提供。
头文件 performanceCounter.h
里面时间值单位为微秒,如果计时打点超过20000个,请修改头文件中COUNTER_ARRAY_SIZE。
#pragma once
#include <stdint.h>
#define COUNTER_ARRAY_SIZE 20000
class CPerformanceCounter
{
public:
CPerformanceCounter(const char* pInfo = NULL);
~CPerformanceCounter();
void debugAllElapseInfo();
int64_t getStartTime() const;
int64_t getAllElapseUSec();
int getTickMaxElapseIndex();
int getTickMinElapseIndex();
int getCount() const;
int64_t getTickTime(const int index);
int64_t getTickElapseUSec(const int index);
bool isStartCount(const int index);
void start();
int64_t tick();
void debugEveryTickElapseInfo();
private:
static int64_t getSysTimeMicros();
void debugElapseInfo(const int64_t usedTime, const char* info = NULL);
int64_t getValidTickElapseUSec(const int index);
int64_t m_StartTime;
int64_t m_EndTime;
int m_Count;
int64_t m_CounterTimes[COUNTER_ARRAY_SIZE];
char m_Info[256];
};
实现文件 performanceCounter.cpp
#include "performanceCounter.h"
#include <stdio.h>
#include <sysinfoapi.h>
#include <debugapi.h>
#define EPOCHFILETIME (116444736000000000UL)
CPerformanceCounter::CPerformanceCounter(const char* pInfo)
{
m_StartTime = 0;
m_EndTime = 0;
m_Count = 0;
if (NULL != pInfo) {
strcpy(m_Info, pInfo);
}
else {
m_Info[0] = 0;
}
}
CPerformanceCounter::~CPerformanceCounter()
{
}
void CPerformanceCounter::debugAllElapseInfo()
{
debugElapseInfo(getAllElapseUSec(), "All");
}
void CPerformanceCounter::debugElapseInfo(const int64_t usedTime, const char* info)
{
int64_t temp = usedTime % 1000000;
int second = usedTime / 1000000;
int millise = temp / 1000;
int micros = temp % 1000;
char tick_expr[512] = { 0 };
sprintf(tick_expr, "%s: %s Elpase Time=%ds,%dms,%dus\n", m_Info, NULL == info ? "" : info, second, millise, micros);
OutputDebugStringA(tick_expr);
}
void CPerformanceCounter::start()
{
m_Count = 0;
m_StartTime = getSysTimeMicros();
m_EndTime = getStartTime();
}
int64_t CPerformanceCounter::tick()
{
int64_t tmpTime = m_EndTime;
m_EndTime = getSysTimeMicros();
m_CounterTimes[m_Count++] = m_EndTime;
return m_EndTime - tmpTime;
}
void CPerformanceCounter::debugEveryTickElapseInfo()
{
char info[20];
for (int i = 0; i < m_Count; i++) {
sprintf(info, "Tick %d", i + 1);
debugElapseInfo(getTickElapseUSec(i), info);
}
}
int64_t CPerformanceCounter::getStartTime() const
{
return m_StartTime;
}
int64_t CPerformanceCounter::getAllElapseUSec()
{
return m_EndTime - m_StartTime;
}
int CPerformanceCounter::getTickMaxElapseIndex()
{
int result = -1;
int64_t m_MaxTime = 0;
int64_t tmpTime;
for (int i = 0; i < m_Count; i++) {
tmpTime = getTickElapseUSec(i);
if (tmpTime > m_MaxTime) {
m_MaxTime = tmpTime;
result = i;
}
}
return result;
}
int CPerformanceCounter::getTickMinElapseIndex()
{
int result = -1;
int64_t m_MinTime = 0x7fffffffffffff;
int64_t tmpTime;
for (int i = 0; i < m_Count; i++) {
tmpTime = getTickElapseUSec(i);
if (tmpTime < m_MinTime) {
m_MinTime = tmpTime;
result = i;
}
}
return result;
}
int CPerformanceCounter::getCount() const
{
return m_Count;
}
int64_t CPerformanceCounter::getTickTime(const int index)
{
if (isStartCount(index)) {
return 0;
}
return m_CounterTimes[index];
}
int64_t CPerformanceCounter::getTickElapseUSec(const int index)
{
if (isStartCount(index)) {
return -1;
}
return getValidTickElapseUSec(index);
}
int64_t CPerformanceCounter::getValidTickElapseUSec(const int index)
{
return 0 == index ? m_CounterTimes[index] - m_StartTime : m_CounterTimes[index] - m_CounterTimes[index - 1];
}
bool CPerformanceCounter::isStartCount(const int index)
{
return index < 0 || index > m_Count - 1;
}
int64_t CPerformanceCounter::getSysTimeMicros()
{
// 从1601年1月1日0:0:0:000到1970年1月1日0:0:0:000的时间(单位100ns)
FILETIME ft;
LARGE_INTEGER li;
GetSystemTimeAsFileTime(&ft);
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
// 从1970年1月1日0:0:0:000到现在的微秒数(UTC时间)
return (li.QuadPart - EPOCHFILETIME) / 10;
}
使用范例:
CPerformanceCounter performanceCounter("Refresh Original");
CRefreshRDBYCOriginalImpl refreshRDBYC;
performanceCounter.start();
for (int i = 0; i < PERFORMANCE_TEST_RUN_NUM; i++) {
refreshRDBYC.refresh();
performanceCounter.tick();
}
performanceCounter.debugEveryTickElapseInfo(); // 打印每个打点计时花费时间
performanceCounter.debugAllElapseInfo(); // 打印所有打点计时花费时间
}