posts - 71,  comments - 41,  trackbacks - 0

System Clock级高精度计时器,支持Window/Linux平台。输入参数CPU主频,该值可从注册表(Windows)或/proc/cpuinfo(Linux)中获得。
大道至简——精度高,抖动大

//  *****************************************************************************
//   IA32Timer   version:  1.0    date: 04/26/2006
//   ----------------------------------------------------------------------------
//   This class is a wrapper of IA32 RDTSC 
//   (ReaD Time Stamp Counter) instruction.
//   It will help you get the interval time with
//   different level.
//   ----------------------------------------------------------------------------
//   Copyright (C) 2006 - Charles Zu
//  *****************************************************************************
//      Note: All the classes the author designed are leading with "Z"
//   which is contradistinguished form the leading with "C" of MFC
//  *****************************************************************************

class  ZIA32Timer
{
public :
    ZIA32Timer(
double  ghz)
    :m_startcycle(
0 ), m_ghz(ghz)
    
{
#ifndef _WIN32
        m_high 
=   0 ;
        m_low 
=   0 ;
#endif
    }


    
void  Start()
    
{
#ifdef _WIN32
        m_startcycle 
=  RTSC();
#else
        RTSC();
        m_startcycle 
=  (unsigned  long   long ) m_high  *  ( 1   <<   30 *   4   +  m_low;
#endif
    }


#ifdef _WIN32
    unsigned __int64 Stop(
int  unit);
#else
    unsigned 
long   long  Stop( int  unit);
#endif

    
static   enum  Unit {CYCLE, NS, US, MS, S} s_unit;

private :
#ifdef _WIN32
    unsigned __int64  m_startcycle;
#else
    unsigned 
long   long  m_startcycle;
    unsigned 
int  m_high;
    unsigned 
int  m_low;
#endif

#ifdef _WIN32
    unsigned __int64 RTSC();
#else
   
void  RTSC();
#endif

double  m_ghz;

}
;

#ifdef _WIN32
    inline unsigned __int64 ZIA32Timer::RTSC()
    
{
        _asm    _emit 
0x0F
        _asm    _emit 
0x31
    }

#else
    inline 
void  ZIA32Timer::RTSC()
    
{
        asm(
" rdtsc; movl %%edx,%0; movl %%eax,%1 "     //  Read cycle counter
            :  " =r "  (m_high),  " =r "  (m_low)                                    
            : 
/*  No input  */                              
            : 
" %edx " " %eax " );
    }

#endif

#ifdef _WIN32
    inline unsigned __int64 ZIA32Timer::Stop(
int  unit)
    
{
        
switch (unit)
        
{
        
case  CYCLE:
            
return  (unsigned __int64)(RTSC()  -  m_startcycle);
        
break ;

        
case  NS:
            
return  (unsigned __int64)((RTSC()  -  m_startcycle)  /  m_ghz);
        
break ;

        
case  US:
            
return  (unsigned __int64)((RTSC()  -  m_startcycle)  /  m_ghz  /   1000 );
        
break ;

        
case  MS:
            
return  (unsigned __int64)((RTSC()  -  m_startcycle)  /  m_ghz  /   1000000 );
        
break ;

        
case  S:
            
return  (unsigned __int64)((RTSC()  -  m_startcycle)  /  m_ghz  /   1000000000 );
        
break ;

        
default :
            
break ;
        }

        
return   0 ;
    }

#else
    inline unsigned 
long   long  ZIA32Timer::Stop( int  unit)
    
{
        unsigned 
long   long  stoppiont;
        RTSC();
        stoppiont 
=  (((unsigned  long   long )m_high)  <<   32 +  m_low;
        
        
switch (unit)
        
{
        
case  CYCLE:
            
return  (unsigned  long   long )(stoppiont  -  m_startcycle);
            
break ;

        
case  NS:
            
return  (unsigned  long   long )((stoppiont  -  m_startcycle)  /  m_ghz);
            
break ;

        
case  US:
            
return  (unsigned  long   long )((stoppiont  -  m_startcycle)  /  m_ghz  /   1000 );
            
break ;

        
case  MS:
            
return  (unsigned  long   long )((stoppiont  -  m_startcycle)  /  m_ghz  /   1000000 );
            
break ;

        
case  S:
            
return  (unsigned  long   long )((stoppiont  -  m_startcycle)  /  m_ghz  /   1000000000 );
            
break ;

        
default :
            
break ;
        }

        
return   0 ;
    }

#endif

下边给个测试程序,由于我的CPU主频为3GHZ,所以写了hard code
#include <stdio.h>
#ifdef _WIN32
#include 
<windows.h>
#else
#include 
<unistd.h>
#endif

#include 
"IA32Timer.h"

void MySleep()
{
#ifdef _WIN32
//     Sleep(1);
     Sleep(10);
//     Sleep(100);
//     Sleep(1000);
#else
    usleep(
100 * 1000);
#endif
}


int main(int argc, char** argv)
{
    ZIA32Timer ztimer(
3); //the arg is the GHZ of your CPU

#ifdef _WIN32
unsigned __int64 interval;
#else
unsigned 
long long interval;
#endif

    ztimer.Start();
    MySleep();
    interval 
= ztimer.Stop(ZIA32Timer::CYCLE);
    fprintf(stdout, 
"interval = %u (cycle)\n", interval);

    ztimer.Start();
    MySleep();
    interval 
= ztimer.Stop(ZIA32Timer::NS);
    fprintf(stdout, 
"interval = %u (ns)\n", interval);

    ztimer.Start();
    MySleep();
    interval 
= ztimer.Stop(ZIA32Timer::US);
    fprintf(stdout, 
"interval = %u (us)\n", interval);

    ztimer.Start();
    MySleep();
    interval 
= ztimer.Stop(ZIA32Timer::MS);
    fprintf(stdout, 
"interval = %u (ms)\n", interval);

    ztimer.Start();
    MySleep();
    interval 
= ztimer.Stop(ZIA32Timer::S);
    fprintf(stdout, 
"interval = %u (s)\n", interval);

    
return 0;
}

参考了高人的汇编实现,自己整理,贴出来,希望对你有启示
posted on 2006-11-28 14:49 Charles 阅读(1654) 评论(4)  编辑 收藏 引用 所属分类: Helper Utility

FeedBack:
# re: IA32/Windows&Linux高精度计时器
2006-11-28 18:55 | erran
看的不是很明白, 不过
win32下有精确计时的API:
QueryPerformanceFrequency
QueryPerformanceCounter
也是Cpu级的, 用起来很方便.
linux应该也有这样的系统API..
  回复  更多评论
  
# re: IA32/Windows&Linux高精度计时器
2006-11-28 19:48 | Charles
IA32's RDTSC(ReaD Time Stamp Counter) instruction returns the number of clock cycles passed since the booting of the CPU in 64-bit unsigned integer, through the EDX and EAX 32-bit general register pair. So it is more precision than any other method:)  回复  更多评论
  
# re: IA32/Windows&Linux高精度计时器
2007-12-17 19:15 | input
如果是双核cpu会对测试结果产生什么影响?  回复  更多评论
  
# re: IA32/Windows&Linux高精度计时器
2008-01-08 11:52 | 小林子
在采用讯驰技术的笔记本芯片上,使用 RTDSC 指令不可信,因为CPU 是变频的  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2006年11月>
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

决定开始写工作日记,记录一下自己的轨迹...

常用链接

留言簿(4)

随笔分类(70)

随笔档案(71)

charles推荐访问

搜索

  •  

积分与排名

  • 积分 - 45470
  • 排名 - 462

最新评论

阅读排行榜

评论排行榜