C++的profile辅助模板类

profile 参见
http://www.csdn.net/Develop/Read_Article.asp?Id=18504
应该翻译成什么?望告知
(类似的还有 Rational Quantify
现被包含在新的 Rational PurifyPlus 中
http://www-900.ibm.com/cn/software/rational/products/purifyplus/index.shtml )

我们公司开发的软件对程序的运行速度要求很高
所以 profile 非常必要
但是 VC6 的 profile 和 Rational Quantify 用起来都很烦

如果是默认方式下用
我的程序原来计算10分钟 用它们来运行的话 要1个多小时
当然 我是可以利用这段时间来和同事喝茶聊天的
不过 1个小时之后 喝完茶了 聊完天了 继续 profile 的心情也没有了

如果是自定义要分析的代码
查相关资料 设定参数
My God! 烦死!

Rational Quantify 有个要求: Debug版
886 Rational Quantify

我碰到过 VC6 的 profile 不准的时候
用相同参数进行计算
有时A函数占的时间最长 B函数占时间0???
有时B函数占的时间最长 A函数占时间0???
还有 在GUI的程序里 profile 出来的结果总是奇奇怪怪的
也许是我不会用?

不过 没关系 我自己DIY了一个
例:
  PROCEDURE_TIME(1, Sleep(200));
  for (char i = 0; i != 5; ++i)
  {
    TOTAL_COUNT(2);
    TOTAL_TIME(3);
    rt = FUNC_TIME(4, MySleep(200));
  }
运行完后结果:
4: 5 times, 1.00 seconds.
3: 5 times, 1.00 seconds.
2: 5 times.
1: 1 times, 0.20 seconds.
很方便吧?

结果会在控制台上显示出来
如果你的程序不是控制台程序
没关系 我推荐一个好东东
DebugView
http://www.sysinternals.com/ntw2k/freeware/debugview.shtml
结果也会在那上面显示出来的

我觉得这个玩艺儿尚有两点不足
1. 不能用字符串做标志
TOTAL_TIME(3);
里面的 (3) 不能用 ("MySleep")
想到过一个方法
用类似 MAKE_MASK('M','y','S','l','e','e','p') 把它转换成一个 __int64
最后出结果的时候 再把这个 __int64 的值 转换为字符串
不过 每次都要写类似MAKE_MASK('M','y','S','l','e','e','p')的东东的话...
饶了我吧~~~
2. 它总是有额外开销的
这个好像没有办法解决
还好 如果是 Release 版的话 误差很小
不过一般它也是用在比较耗费时间的代码上的 这点误差应该可以忽略不计了

使用时要注意的地方:
0. 标志只能为整数 范围:0 <= X <= INT_MAX
   用相同的数做标志 计时/计数结果叠加(TOTAL_COUNT只与TOTAL_COUNT叠加)
  例:TOTAL_TIME(0); PROCEDURE_TIME(0, Sleep(200)); TOTAL_COUNT(0); TOTAL_COUNT(0);
      TOTAL_TIME 和 PROCEDURE_TIME 的结果就叠加了
      前后两次 TOTAL_COUNT 的结果也叠加了

1. 如果函数返回引用(&)或常量引用(const &) 用 REF_FUNC_TIME
虽然有时用 FUNC_TIME 也可以编译运行
但终归改变了程序原来的运行方式

2. 调用函数的时候 如果不需要返回值 用 PROCEDURE_TIME
这样可以去掉传回返回值的额外开销

3. 如果函数没有返回值 只允许使用 PROCEDURE_TIME

4. TOTAL_COUNT
有时你只想计数
要把开销减到最小 就用这个

5. mmm...
没了吧...

什么?linux的?
没关系
把 GetTickCount 改为 clock
把 OutputDebugString 改为 ...
(这个改成什么我也不知道 应该有差不多的吧?大不了输出成文件嘛!)

祝大家用得愉快!


以下代码用 VC6 GCC 编译运行通过

//filename: ShowRunTime.h
#ifndef SHOWTIME_H
#define SHOWTIME_H
#include <stdio.h>
#include <windows.h>
#include <time.h>

template <int I>
class CShowRunTimesAss
{
public:
  unsigned int total_times;
  CShowRunTimesAss()
  {
    total_times = 0;
  }
  ~CShowRunTimesAss()
  {
    char tmp[256];
    sprintf(tmp, "/n%d: %u times./n", I, total_times);
    printf(tmp);
    OutputDebugString(tmp);
  }
  static void AddShowRunTimes()
  {
    static CShowRunTimesAss<I> tt;
    ++tt.total_times;
  }
};

template <int I>
class CShowRunTimeAss
{
public:
  unsigned int total_time;
  unsigned int total_times;
  CShowRunTimeAss()
  {
    total_time = total_times = 0;
  }
  ~CShowRunTimeAss()
  {
    char tmp[256];
    sprintf(tmp, "/n%d: %u times, %4.2f seconds./n", I, total_times, (double)total_time / CLOCKS_PER_SEC);
    printf(tmp);
    OutputDebugString(tmp);
  }
};

template <int I>
class CShowRunTime
{
public:
  CShowRunTime()
  {
    ShowRunTimeBegin();
  }
  ~CShowRunTime()
  {
    ShowRunTimeEnd(0);
  }
  static CShowRunTimeAss<I>& Gettt()
  {
    static CShowRunTimeAss<I> tt;
    return tt;
  }
  static bool ShowRunTimeBegin()
  {
    //Gettt().total_time -= clock();      // more slowly
    Gettt().total_time -= GetTickCount();
    return true;
  }
  template <typename T>
  static T ShowRunTimeEnd(T t)
  {
    //Gettt().total_time += clock();
    Gettt().total_time += GetTickCount();
    ++Gettt().total_times;
    return t;
  }
};
//

#define TOTAL_COUNT(I)          do { CShowRunTimesAss<I>::AddShowRunTimes(); } while (0)
#define TOTAL_TIME(I)           CShowRunTime<I> _ShowRunTime_##I
#define PROCEDURE_TIME(I, X)    do { CShowRunTime<I> _ShowRunTime_; X; } while (0)
#define TOTAL_TIME_BEGIN(I)     CShowRunTime<I>::ShowRunTimeBegin()
#define TOTAL_TIME_END(I, X)    CShowRunTime<I>::ShowRunTimeEnd(X)
#define FUNC_TIME(I, X)         (TOTAL_TIME_BEGIN(I) ? TOTAL_TIME_END(I, X) : TOTAL_TIME_END(I, X))
#define REF_FUNC_TIME(I, X)     (TOTAL_TIME_BEGIN(I) ? *TOTAL_TIME_END(I, &(X)) : *TOTAL_TIME_END(I, &(X)))

#endif // #ifndef SHOWTIME_H
//filename: main.cpp
#include <iostream>
#include "ShowRunTime.h"
using namespace std;

class ctest1
{
public:
  ctest1(const ctest1& rhs) { cout << "ctest1() copy/n"; }
  ctest1() { cout << "ctest1()/n"; }
  ~ctest1() { cout << "~ctest1()/n"; }
};

ctest1 ftest1()
{
  cout << "ftest1()/n";
  return ctest1();
}

int testval()
{
  cout << "testval()/n";
  return 0;
}

int& testref()
{
  static int i;
  cout << "testref() " << i << endl;
  return i;
}

const int& testconstref()
{
  static int i;
  cout << "testconstref() " << i << endl;
  return i;
}

int MySleep(DWORD dwMilliseconds)
{
  Sleep(dwMilliseconds);
  return 0;
}

int main()
{
  TOTAL_TIME(0);
  ctest1 t;
  int rt;
  
  cout << "call ftest1 direct/n";
  ftest1();
  cout << "/call ftest1 direct/n";
  cout << "call ftest1 indirect/n";
  FUNC_TIME(1, ftest1());
  cout << "/call ftest1 indirect/n";
  cout << endl;

  testref() = 1;
//  testconstref() = 2;
//  testval() = 3;
  REF_FUNC_TIME(11, testref()) = 4;
//  REF_FUNC_TIME(11, testconstref()) = 5;  // VC6 Error! Should not be OK. assignment of read-only location!
//  REF_FUNC_TIME(11, testval()) = 6;
  cout << "call testref direct/n";
  cout << "result address is: " << (int)&testref() << endl;
  cout << "/call testref direct/n";
  cout << "call testref indirect/n";
  cout << "result address is: " << (int)&REF_FUNC_TIME(11, testref()) << endl;
  cout << "/call address indirect/n";
  cout << endl;

  PROCEDURE_TIME(11, Sleep(200));
  for (char i = 0; i != 5; ++i)
  {
    TOTAL_COUNT(2);
    TOTAL_TIME(3);
    rt = FUNC_TIME(4, MySleep(200));
  }
  
  cout << "call ftest1 indirect once again/n";
  FUNC_TIME(1, ftest1());
  cout << "/call ftest1 indirect once again/n";
  cout << "call ftest1 indirect once again, and use another counter/n";
  FUNC_TIME(5, ftest1());
  cout << "/call ftest1 indirect once again, and use another counter/n";

//  system("PAUSE");
  return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coolcch

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值