读《Efficient C++》疑惑[1]

[入库:2005年8月18日] [更新:2007年3月24日]

本文简介:选择自 hustli 的 blog

    当我们进行软件开发时,如果代码比较少,我们可以很容易的掌握、了解程序的执行情况,但是当代码超过数千行,特别是达到上万行的时候,我们就很难准确掌握程序的流程,在这种情况下,进行代码跟踪是很重要的一件事情。
    代码跟踪技术,对于大多数程序员来讲,就是定义一个比较简单的trace类,将程序的信息进行输出,一般是在程序的入口写一条信息,在程序的出口写一条信息,虽然这是以时间性能为代价,但是它有助于我们在不使用调试器的情况下找到问题所在。
    最极端的情况就是通过#ifdef开关,彻底消除性能开销,但是要像打开/关闭跟踪,必须重新编译,显然程序的最终用户无法这么做。所以只有通过动态的与程序通信来进行跟踪控制。
    首先,为了能够获得程序执行时间,我们先自己定义一个简单的测试性能的类,名字就叫做timer,实现如下:
    class timer
    {
    public:
       timer():start(clock()) {}
       ~timer() { cout<<"the time is :"<<clock()-start<<endl; }
    private:
       clock_t start;
    };
    接下来,我们就要定义一个简单的跟踪类trace,初步实现如下:
    class trace
    {
    public:
       trace(const string& name);
       ~trace();
       static bool trace_active;
    private:
       string thename;
    };

    bool trace::trace_active=false;

    inline trace::trace(const string& name):thename(name)
    {
      if(trace_active)
        cout<<"enter the function:"<<name<<endl;
    }

    inline trace::trace(const char* name):thename(name)
    {
      if(trace_active)
         cout<<"enter the function:"<<*name<<"ms"<<endl;
    }

   inline trace::~trace()
   {
     if(trace_active)
        cout<<"exit the function:"<<thename<<endl;
   }
   接下来我们进行测试,先定义一个简单的函数:int f(int x) { return x+1; }
   先测试不跟踪的时间开销:
   int main()
   {
       timer* time=new timer;
       trace::trace_active=false;
       for(int i=0; i<1000000; ++i)    f(i);
       delete time;
     
       return 0;
    }
    输出时间是30ms。
    接下来,我们打开跟踪功能: int f(int x) { trace trace("f"); return x+1; } trace::trace_active=false;
    同时把i/o关闭,再次测试,结果如下:1892ms 
    这里我们看到了时间提升了62倍,主要的性能来源就是(1)在构造函数中"f"要转换成string类型,(2)thename的构造和析构。似乎各自影响了1/3的效率,是不是这样呢?
    下面,我们取消"f"要转换成string类型的开销:增加一个构造函数:
    trace(const char* name):thename(name)
    {
      if(trace_active)
         cout<<"enter the function:"<<name<<"ms"<<endl;
    }
    再次进行测试,结果如下(关闭i/o):1690ms 
    性能的提高似乎并不像我们预期的那样高,为什么呢?难大是if(trace_active)影响了测试结果?我们再把这条判断语句关闭,再次进行测试,结果如下:1646ms。
    还是差了一些,并不是1/3的数据,是不是参数传递的影响?这次我们把thename也拿掉,看看类本身到底占用了多少时间,再次测试,结果如下:153ms。
    分析以上数据:类本身的参数传递等占用了153ms,if判断语句占用了44ms,thename的构造和析构占用了1493ms,"f"转换成string占用了202ms,所以我们的主要目标应该集中在thename上面,下面我们用组合取代聚合,看看性能的变化:
    class trace
    {
    public:
       trace(const string& name);
       ~trace();
       static bool trace_active;
    private:
       string* thename;
    };

    bool trace::trace_active=false;

    inline trace::trace(const string& name)
    {
      if(trace_active)
      {
        cout<<"enter the function:"<<name<<endl;
        thename=new string(name);
      }
    }

    inline trace::trace(const char* name)
    {
      if(trace_active)
      {
         cout<<"enter the function:"<<*name<<"ms"<<endl;
         thename=new string(name);

本文关键:跟踪
  相关方案
Google
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top