RDTSC 获取时间

一、了解RDTSC指令

rdtsc指令, 该指令返回CPU自启动以来的时钟周期数;该时钟周期数,即处理器的时间戳

在CPU通电启动后,首先会重置EDX和EAX,在每个时钟周期上升或下降沿到来时,会自动累计周期数,并被记录到EDX和EAX寄存器中,EDX是高位,EAX是低位。

rdtsc指令就是从该寄存器中进行获取的。

周期和频率的关系公式:T(周期)=1/f(频率)

如CPU频率f为1GHz,则其时钟周期T=1/1GHz秒,意味着每隔T秒,CPU完成一个最基本的动作,并在寄存器中,对周期数加1。

故,假设当前时钟周期数为m,则可计算出CPU自启动后,累计运行时间X=m*T,整理下:

X=m/f

时钟周期与时钟频率互为倒数, 我们可以找出以下关系:

时钟频率时钟周期
1Hz1s
1KHz1ms
1MHz1μs
1GHz1ns

注意计算时,单位要搭配好,比如:

  • f为Hz时,计算得到的X为秒;
  • f为GHz时,计算得到的X为纳秒。

在 Windows 用 QueryPerformanceCounter 和 QueryPerformanceFrequency,Linux 下用 POSIX 的 clock_gettime 函数,RDTS 耗时最少。

小结

CPU累计运行时间=时钟周期数/CPU频率

二、RDTSC指令在win和linux上的实现

我们已经知道RDTSC可以获取CPU运行时间,另外win平台上也已经有了一个类似的函数:

DWORD GetTickCount();

该函数返回值是系统启动后经过的毫秒数,最长为49.7天。

其微软帮助为:

GetTickCount function (sysinfoapi.h) - Win32 apps | Microsoft Docs

三、win和linux下RDTSC的实现

#include <stdint.h>

//  rdtsc
#if _WIN32

#include <intrin.h>
uint64_t rdtsc()  // win
{
    return __rdtsc();
}

#else

uint64_t rdtsc() // linux
{
    unsigned int lo, hi;
    __asm__ volatile ("rdtsc" : "=a" (lo), "=d" (hi));
    return ((uint64_t)hi << 32) | lo;
}

#endif

四、利用chrono统计毫秒,微妙,纳秒运行时间

void CalRunTime() {
    auto t1=std::chrono::steady_clock::now();
    //run code
    auto t2=std::chrono::steady_clock::now();
    
    //秒
    double dr_s=std::chrono::duration<double>(t2-t1).count();
    //毫秒级
    double dr_ms=std::chrono::duration<double,std::milli>(t2-t1).count();
    //微妙级
    double dr_us=std::chrono::duration<double,std::micro>(t2-t1).count();
    //纳秒级
    double dr_ns=std::chrono::duration<double,std::nano>(t2-t1).count(); 
}

chrono中有三种时钟:system_clock,steady_clock和high_resolution_clock。每一个clock类中都有确定的time_point, duration, Rep, Period类型。

system_clock是不稳定的。因为时钟是可调的,即这种是完全自动适应本地账户的调节。这种调节可能造成的是,首次调用now()返回的时间要早于上次调用now()所返回的时间,这就违反了节拍频率的均匀分布。稳定闹钟对于超时的计算很重要,所以C++标准库提供一个稳定时钟 std::chrono::steady_clock。std::chrono::high_resolution_clock 是标准库中提供的具有最小节拍周期(因此具有最高的精度的时钟)。

上文所说time_since_epoch(),以及将要介绍的now()函数的返回值都依赖于时钟的精度,测试时钟的精度的一种方法就是:

#include <iostream>

#include <chrono>

using namespace std;

int main()

{

    cout << "system clock : ";

    cout << chrono::system_clock::period::num << "/" << 
            chrono::system_clock::period::den << "s" << endl;

    cout << "steady clock : ";

    cout << chrono::steady_clock::period::num << "/" 
         << chrono::steady_clock::period::den << "s" << endl;

    cout << "high resolution clock : ";

    cout << chrono::high_resolution_clock::period::num << "/" 
         << chrono::high_resolution_clock::period::den << "s" << endl;

    system("pause");

    return 0;

}

windows系统的测试结果是system_clock的精度是100纳秒,而high_resolution的精度是1纳秒,对于程序来说,一般毫秒级就够了,所以说chrono提供的时钟精度绰绰有余。

 

win下,__rdtsc()函数的微软帮助为:

__rdtsc | Microsoft Docs

linux下,则需要内联汇编来实现。

RDTSC指令结合CPU频率,也可以用来计算代码段的执行时间。

参考链接:

《RDTSC指令的使用以及相关问题》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值