IA32/Windows&Linux高精度计时器
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
// 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;
}
#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;
}
参考了高人的汇编实现,自己整理,贴出来,希望对你有启示