纳秒与微秒级时间

纳秒与微秒级时间

转自:AlbertZ316的专栏  http://blog.csdn.net/albertz316/article/details/7193579

1秒 = 1000毫秒 = 1000 000微秒 = 1000 000 000 纳秒

大家都知道windows下的时间计数器提供的是毫秒级的时间计数。那么怎么提供一个精度更高的计数器呢。在Intel   Pentium以上级别的CPU中,有一个称为“时间戳(Time   Stamp)”的部件,它以64位无符号整型数的格式,记录了自CPU上电以来所经过的时钟周期数。对于一个主频为1GHz的CPU,则其一个时钟周期就是一纳秒。由于目前的CPU主频都非常高,因此这个部件可以达到 纳秒级的计时精度。在Pentium以上的CPU中,提供了一条机器指令RDTSC(Read   Time   Stamp   Counter)来读取这个时间戳的数字,并将其保存在EDX:EAX寄存器对中。由于EDX:EAX寄存器对恰好是Win32平台下C++语言保存函数 返回值的寄存器,所以我们可以把这条指令看成是一个普通的函数调用。像这样:     
    
  inline   unsigned   __int64   GetCPUCycleCount()     
  {     
  __asm   RDTSC     
  }  

如果RDTSC不被C++的内嵌汇编器直接支持,我们还可以要用_emit伪指令直接嵌入该指令的机器码形式0X0F、0X31,如下:     
    
  inline   unsigned   __int64   GetCPUCycleCount()     
  {     
  __asm   _emit   0x0F     
  __asm   _emit   0x31     
  }     
    
  以后在需要计数器的场合,可以像使用普通的Win32   API一样,调用两次GetCPUCycleCount函数,比较两个返回值的差,然后利用CPU的时钟周期的差数就可以计算出一个纳秒级的计时。公式如下  

时间   =   CPU时钟周期数差数   /   CPU主频速率(Hz)

vc中的实现代码如下:

// 纳秒 微秒 时间精度的实现

#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>                   // 使用timeGetTime() 需要包含此头文件
#pragma comment(lib,"winmm.lib")        // 使用timeGetTime() 需要包含此lib

// 微秒级
class MicrosecondTimer
{
public:
    inline MicrosecondTimer()
    {
        QueryPerformanceFrequency(&freq);
    }
    inline void Start()
    {
        QueryPerformanceCounter(&startCount);
    }
    // 返回微秒 
    inline UINT64 Stop()          
    {
        QueryPerformanceCounter(&endCount);
        UINT64 decrease = endCount.QuadPart - startCount.QuadPart;
        double elapsed  decrease / (double)freq.QuadPart;
        return UINT64(elapsed*1000000);
    }
private:
    LARGE_INTEGER freq;
    LARGE_INTEGER startCount;
    LARGE_INTEGER endCount;
};


// 纳秒级
// 连续调用start和stop所需的时间大概是62ns
class NanosecondTimer
{

public:
    inline NanosecondTimer()
    {  
        startT = 0;
        frequency = CalCPUFrequency();
    }
    //得到计算机启动到现在的时钟周期
    static inline  UINT64 GetCPUCycleCount(void)
    {
        //      __asm   _emit   0x0F
        //      __asm   _emit   0x31
        __asm RDTSC
    }

    // 得到CPU的频率
    static inline double CalCPUFrequency()
    {
        LARGE_INTEGER liFreq,liStart,liEnd;
        QueryPerformanceFrequency(&liFreq);      
        QueryPerformanceCounter(&liStart);
        UINT64 startCounts = GetCPUCycleCount();
        Sleep(1000);
        QueryPerformanceCounter(&liEnd);
        UINT64 endCounts = GetCPUCycleCount() - startCounts;
        double elapsed =  (liEnd.QuadPart - liStart.QuadPart) / (double)(liFreq.QuadPart);     // 微秒级精度
        double freq = endCounts / (elapsed*1000000);
        return freq;
    }
    inline void Start()
    {
        startT = GetCPUCycleCount();
    }
    inline UINT64 Stop()
    {
        UINT64 endT = GetCPUCycleCount() - startT;
        return UINT64( endT * 1000 / frequency );
    }
    inline double Frequency()
    {
        return frequency;
    }

private:
    UINT64 startT;
    double frequency;   // MHz/s
};


int main(int argc, CHAR* argv[])
{

    NanosecondTimer NT;
    MicrosecondTimer MT;
    DWORD t1 = 0, t2 = 0;
    UINT64 ns = 0 ;
    UINT64 ms =  0;

    for (int i = 0; i < 10 ; i++ )
    {
        NT.Start();
        MT.Start();
        Sleep(1);
        ms = MT.Stop();
        ns = NT.Stop();
        printf("CPU:%f; %f \n %I64d; %I64d; \r\n",NT.CalCPUFrequency(),cpuc.GetCpuFrequency() , ns, ms);
    }
    getchar();
    return 0;
}

事实上在windows中每次调用代码指令的时间都不稳定,所以这是很难真正的精确到纳秒级的。windows下最多只能提供微秒级的精确度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值