呵呵呵呵呵

萝莉有三好,柔体 轻音 易推倒。女神有三宝,干嘛 呵呵 去洗澡。宅男有三好:Dota 基友 破电脑。


BCB获取CPU的时钟周期数RDTSC的方法

BCB获取CPU的时钟周期数RDTSC的方法

在Windows平台下,常用的计时器有两种,一种是timeGetTime多媒体计时器,它可以提供毫秒级的计时。但这个精度对很多应用场合而 言还是太粗糙了。另一种是QueryPerformanceCount计数器,随系统的不同可以提供微秒级的计数。对于实时图形处理、多媒体数据流处理、 或者实时系统构造的程序员,善用QueryPerformanceCount/QueryPerformanceFrequency是一项基本功。
在Intel Pentium以上级别的CPU中,有一个称为“时间戳(Time Stamp)”的部件,它以64位无符号整型数的格式,记录了 自CPU上电以来所经过的时钟周期数。由于目前的CPU主频都非常高,因此这个部件可以达到纳秒级的计时精度。这个精确性是上述两种方法所无法比拟的。
在Pentium以上的CPU中,提供了一条机器指令RDTSC(Read Time Stamp Counter)来读取这个时间戳的数字,并 将其保存在EDX:EAX寄存器对中。由于EDX:EAX寄存器对恰好是Win32平台下C++语言保存函数返回值的寄存器,所以我们可以把这条指令看成是一个普通的函数调用。像这样:
inline unsigned __int64 GetCycleCount()
{
__asm RDTSC
}

__int64  t1 = GetCycleCount();
Sleep(1000);
__int64 t2 = GetCycleCount();
t2 -= t1;

AnsiString str;
double f = (double)(t2)/(1024*1024*1024);
str.sprintf("%.3f GHz",f);

直接在程序中使用的汇编语言如下:
__int64 t1;
__asm
  {
    rdtsc
    mov    dword ptr [t1],     eax
    mov    dword ptr [t1+4],   edx
  }


计算sqrt所花时间:

void sqrti(void)
{
 __asm
  {
    rdtsc
    mov    dword ptr [t1],     eax
    mov    dword ptr [t1+4],   edx
  }
for(int i=0;i<5;i++)
{
sq=sqrt(5);
}
__asm
  {
    rdtsc
    mov    dword ptr [t2],     eax
    mov    dword ptr [t2+4],   edx
  }
 
  tr = t2-t1;
s1=IntToStr(tr);
 __asm
  {
    rdtsc
    mov    dword ptr [t1],     eax
    mov    dword ptr [t1+4],   edx
  }
for(int i=0;i<5;i++)
{
sq=sqrt(5);
}
__asm
  {
    rdtsc
    mov    dword ptr [t2],     eax
    mov    dword ptr [t2+4],   edx
  }
  tr = t2 - t1 ;
s2=IntToStr(tr);
 
}


如果RDTSC不被C++的内嵌汇编器直接支持,所以我们要用_emit伪指令直接嵌入该指令的机器码形式0X0F、0X31,如下:

inline unsigned __int64 GetCycleCount()
{
__asm _emit 0x0F
__asm _emit 0x31
}
以后在需要计数器的场合,可以像使用普通的Win32 API一样,调用两次GetCycleCount函数 。


VS2015以后还有个__rdtsc函数【https://msdn.microsoft.com/en-us/library/twchhe95.aspx】,如下:

unsigned __int64 __rdtsc();

Header file <intrin.h>
Remarks

This routine is available only as an intrinsic.

The interpretation of the TSC value in this generation of hardware differs from that in earlier versions of x64. See hardware manuals for more information.
Example

// rdtsc.cpp
// processor: x86, x64
#include <stdio.h>
#include <intrin.h>

#pragma intrinsic(__rdtsc)

int main()
{
    unsigned __int64 i;
    i = __rdtsc();
    printf_s("%I64d ticks\n", i);
}

3363423610155519 ticks

需要注意的是:

在多核时代,RDTSC 指令的准确度大大削弱了,原因有三:
1. 不能保证同一块主板上每个核的 CPU 时钟周期数(Time Stamp Counter)是同步的;
2. CPU 的时钟频率可能变化,例如笔记本电脑的节能功能;
3. 乱序执行导致 RDTSC 测得的周期数不准。
    
虽然 RDTSC 废掉了,高精度计时还是有办法的,在 Windows 上用 QueryPerformanceCounter 和 QueryPerformanceFrequency,Linux 上用 POSIX 的 clock_gettime 函数,以 CLOCK_MONOTONIC 参数调用。
    

更多内容:

通过机器指令RDTSC读取TSC时间戳代码
linux中使用getrusage获取系统资源的占用信息
fopen mode中a与a+区别
linux ubuntu下解压缩tar.xz文件
Source Insight最新版3.50.0082下载与注册码

本文链接地址:http://www.hehehehehe.cn/i/817.html