关于 高精度性能计数器的频率 和 cpu 频率 不一致问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*
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
 
高精度性能计数器的频率是不变的,而且比cpu(平均)频率低得多
*/
 
#include <iostream>
#include <windows.h>
using namespace std;
 
#define read_tsc(tsc) \
    long long tsc; \
    _asm rdtsc \
    _asm mov dword ptr[tsc],eax \
    _asm mov dword ptr[tsc+4],edx
 
#define read_hrpc(pc) \
    LARGE_INTEGER pc; \
    QueryPerformanceCounter(&pc);
 
int main()
{
    read_hrpc(pc1);
    read_tsc(tsc1);
 
    cout << "waiting..." << endl;
    Sleep(1000);
 
    read_tsc(tsc2);
    read_hrpc(pc2);
 
    LARGE_INTEGER freq;
    QueryPerformanceFrequency(&freq);
    double elapse = (pc2.QuadPart - pc1.QuadPart) / (double)freq.QuadPart;
    double cpu_freq = (tsc2 - tsc1) / elapse;
 
    cout << "perf freq:\t" << freq.QuadPart / 1000.0 / 1000 << "\tMHz" << endl;
    cout << "cpu freq:\t" << cpu_freq / 1000 / 1000 / 1000 << "\tGHz" << endl;
 
    return 0;
}

  

 

备注:

QueryPerformanceFrequency将获得一个频率Freq,它表示高性能计时器1秒钟的计数次数,也就是说QueryPerformanceCounter获得的时间是一个计数值,其单位是秒。

高性能计时器的精度:在笔者的电脑上,频率Freq为3134267,一个计数的时间是秒,也就是0.319微秒或319纳秒。这也就是高性能计时器的精度。

高性能计时器的归零:QueryPerformanceCounter获得的计数是一个有符号的64位整数。频率Freq为3134267的Windows在连续运行9.3万年后,QueryPerformanceCounter获得的计数才可能归零。

需要注意:并不是所有的电脑都支持QueryPerformanceCounter,返回0不支持。

内联汇编VS 64位 改 32位。

 

posted @   三岁玩童  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
历史上的今天:
2022-02-02 VS编译lua和C调用lua
点击右上角即可分享
微信分享提示