Windows使用CPU时间戳进行高精度计时

VC++中的计时器及多媒体高精度计时器 Windows计时器是一个非常有用的编程元素,而且计时器的使用非常简单,我们只需要一个时间间隔参数来调用SetTimer函数设置和启动计时器,通过WM_TIMER消息的响应函数进行计时器控制,调用KillTimer函数停止计时器。 但是由于Windows是一个非实时操作系统,所以如果我们定义的时间间隔小于100ms的时候,计时器可能不会很准确。所以,对于有些时间要求比较高的情况,我们需要使用多媒 阅读详情
对关注性能的程序开发人员而言,一个好的计时部件既是益友,也是良师。计时器既可以作为程序组件帮助程序员精确的控制程序进程,又是一件有力的调试武器,在有经验的程序员手里可以尽快的确定程序的性能瓶颈,或者对不同的算法作出有说服力的性能比较。
    在Windows平台下,常用的计时器有两种,一种是timeGetTime多媒体计时器,它可以提供毫秒级的计时。但这个精度对很多应用场合而言还是太粗糙了。另一种是QueryPerformanceCount计数器,随系统的不同可以提供微秒级的计数。对于实时图形处理、多媒体数据流处理、或者实时系统构造的程序员,善用QueryPerformanceCount/QueryPerformanceFrequency是一项基本功。
    本文要介绍的,是另一种直接利用Pentium CPU内部时间戳进行计时的高精度计时手段。以下讨论主要得益于《Windows图形编程》一书,第15页-17页,有兴趣的读者可以直接参考该书。关于RDTSC指令的详细讨论,可以参考Intel产品手册。本文仅仅作抛砖之用。
    在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
    }
    但是不行,因为RDTSC不被C++的内嵌汇编器直接支持,所以我们要用_emit伪指令直接嵌入该指令的机器码形式0X0F、0X31,如下:
    inline unsigned __int64 GetCycleCount()
    {
     __asm _emit 0x0F
     __asm _emit 0x31
    }
    以后在需要计数器的场合,可以像使用普通的Win32 API一样,调用两次GetCycleCount函数,比较两个返回值的差,像这样:
    unsigned long t;
    t = (unsigned long)GetCycleCount();
    //Do Something time-intensive ...
    t -= (unsigned long)GetCycleCount();
    《Windows图形编程》第15页编写了一个类,把这个计数器封装起来。有兴趣的读者可以去参考那个类的代码。作者为了更精确的定时,做了一点小小的改进,把执行RDTSC指令的时间,通过连续两次调用GetCycleCount函数计算出来并保存了起来,以后每次计时结束后,都从实际得到的计数中减掉这一小段时间,以得到更准确的计时数字。但我个人觉得这一点点改进意义不大。在我的机器上实测,这条指令大概花掉了几十到100多个周期,在Celeron 800MHz的机器上,这不过是十分之一微秒的时间。对大多数应用来说,这点时间完全可以忽略不计;而对那些确实要精确到纳秒数量级的应用来说,这个补偿也过于粗糙了。
    这个方法的优点是:
    1.高精度。可以直接达到纳秒级的计时精度(在1GHz的CPU上每个时钟周期就是一纳秒),这是其他计时方法所难以企及的。
    2.成本低。timeGetTime 函数需要链接多媒体库winmm.lib,QueryPerformance* 函数根据MSDN的说明,需要硬件的支持(虽然我还没有见过不支持的机器)和KERNEL库的支持,所以二者都只能在Windows平台下使用(关于DOS平台下的高精度计时问题,可以参考《图形程序开发人员指南》,里面有关于控制定时器8253的详细说明)。但RDTSC指令是一条CPU指令,凡是i386平台下Pentium以上的机器均支持,甚至没有平台的限制(我相信i386版本UNIX和Linux下这个方法同样适用,但没有条件试验),而且函数调用的开销是最小的。
    3.具有和CPU主频直接对应的速率关系。一个计数相当于1/(CPU主频Hz数)秒,这样只要知道了CPU的主频,可以直接计算出时间。这和QueryPerformanceCount不同,后者需要通过QueryPerformanceFrequency获取当前计数器每秒的计数次数才能换算成时间。
    这个方法的缺点是:
    1.现有的C/C++编译器多数不直接支持使用RDTSC指令,需要用直接嵌入机器码的方式编程,比较麻烦。
    2.数据抖动比较厉害。其实对任何计量手段而言,精度和稳定性永远是一对矛盾。如果用低精度的timeGetTime来计时,基本上每次计时的结果都是相同的;而RDTSC指令每次结果都不一样,经常有几百甚至上千的差距。这是这种方法高精度本身固有的矛盾。
    关于这个方法计时的最大长度,我们可以简单的用下列公式计算:
    自CPU上电以来的秒数 = RDTSC读出的周期数 / CPU主频速率(Hz)
    64位无符号整数所能表达的最大数字是1.8×10^19,在我的Celeron 800上可以计时大约700年(书中说可以在200MHz的Pentium上计时117年,这个数字不知道是怎么得出来的,与我的计算有出入)。无论如何,我们大可不必关心溢出的问题。
    下面是几个小例子,简要比较了三种计时方法的用法与精度
    //Timer1.cpp 使用了RDTSC指令的Timer类//KTimer类的定义可以参见《Windows图形编程》P15
    //编译行:CL Timer1.cpp /link USER32.lib
    #include <stdio.h>
    #include "KTimer.h"
    main()
    {
     unsigned t;
     KTimer timer;
     timer.Start();
     Sleep(1000);
     t = timer.Stop();
     printf("Lasting Time: %d\n",t);
    }
    //Timer2.cpp 使用了timeGetTime函数
    //需包含<mmsys.h>,但由于Windows头文件错综复杂的关系
    //简单包含<windows.h>比较偷懒:)
    //编译行:CL timer2.cpp /link winmm.lib
    #include <windows.h>
    #include <stdio.h>
    main()
    {
     DWORD t1, t2;
     t1 = timeGetTime();
     Sleep(1000);
     t2 = timeGetTime();
     printf("Begin Time: %u\n", t1);
     printf("End Time: %u\n", t2);
     printf("Lasting Time: %u\n",(t2-t1));
    }
    //Timer3.cpp 使用了QueryPerformanceCounter函数
    //编译行:CL timer3.cpp /link KERNEl32.lib
    #include <windows.h>
    #include <stdio.h>
    main()
    {
     LARGE_INTEGER t1, t2, tc;
     QueryPerformanceFrequency(&tc);
     printf("Frequency: %u\n", tc.QuadPart);
     QueryPerformanceCounter(&t1);
     Sleep(1000);
     QueryPerformanceCounter(&t2);
     printf("Begin Time: %u\n", t1.QuadPart);
     printf("End Time: %u\n", t2.QuadPart);
     printf("Lasting Time: %u\n",( t2.QuadPart- t1.QuadPart));
    }
    ////////////////////////////////////////////////
    //以上三个示例程序都是测试1秒钟休眠所耗费的时间
    file://测试环境:Celeron 800MHz / 256M SDRAM
    //          Windows 2000 Professional SP2
    //          Microsoft Visual C++ 6.0 SP5
    ////////////////////////////////////////////////
    以下是Timer1的运行结果,使用的是高精度的RDTSC指令
    Lasting Time: 804586872
    以下是Timer2的运行结果,使用的是最粗糙的timeGetTime API
    Begin Time: 20254254
    End Time: 20255255
    Lasting Time: 1001
    以下是Timer3的运行结果,使用的是QueryPerformanceCount API
    Frequency: 3579545
    Begin Time: 3804729124
    End Time: 3808298836
    Lasting Time: 3569712
    古人说,触类旁通。从一本介绍图形编程的书上得到一个如此有用的实时处理知识,我感到非常高兴。有美不敢自专,希望大家和我一样喜欢这个轻便有效的计时器。

【C/C++/CUDA C/Python】CPU/GPU 程序块运行时间多种计算方法全解析 1.CPU程序块运行时间计算 2.GPU程序块运行时间计算 2.1 cuda计时事件 cudaEvent_t 阅读详情

相关推荐

C++:精确计时的实现

在C++编程中,我们经常需要对代码的执行时间进行精确计时。本文将介绍如何在C++中实现精确计时,并提供相应的源代码示例。库提供的计时功能,我们可以在C++中实现精确计时。表示一个时间段,可以通过它来获取时间差的不同单位,例如秒、毫秒、微秒和纳秒等。库提供了高精度的时间测量工具,可以在纳秒级别进行计时。下面是一个简单的示例代码,演示了如何使用。的函数,它代表了一个需要计时的耗时操作。函数,并使用精确计时来测量其执行时间。在上面的示例中,我们定义了一个名为。在上面的示例中,我们使用。在C++中,可以使用。

ByteWhizX的博客 366

C++中精确计时的方法

对关注性能的程序开发人员而言,一个好的计时部件既是益友,也是良师。计时器既可以作为程序组件帮助程序员精确的控制程序进程,又是一件有力的调试武器,在有经验的程序员手里可以尽快的确定程序的性能瓶颈,或者对不同的算法作出有说服力的性能比较。 在Windows平台下,常用的计时器有两种,一种是timeGetTime多媒体计时器,它可以提供毫秒级的计时。但这个精度对很多应用场合而言还是太粗糙了。另一种是Qu

逐日者 3821

时间计量(毫秒)

在Windows平台下,常用的计时器有两种,一种是timeGetTime多媒体计时器,它可以提供毫秒级的计时。但这个精度对很多应用场合而言还是太粗糙了。另一种是QueryPerformanceCount计数器,随系统的不同可以提供微秒级的计数。对于实时图形处理、多媒体数据流处理、或者实时系统构造的程序员,善用QueryPerformanceCount/QueryPerformanceFrequen

xjbclz的专栏 1002

VC获取系统时间、程序运行时间(精确到秒,毫秒)的五种方法

1.使用CTime类(获取系统当前时间,精确到秒) CString str; //获取系统时间 CTime tm; tm=CTime::GetCurrentTime();//获取系统日期 str=tm.Format("现在时间是%Y年%m月%d日 %X"); MessageBox(str,NULL,MB_OK); a,从CTimet中提取年月日时分秒  CTime t = CTime::Ge

天上的猩猩的专栏 2万+

【Flow3D实战】从零构建水利冲淤模型:关键步骤与参数详解

本文详细介绍了使用Flow3D构建水利冲淤模型的关键步骤与参数设置技巧。从基础认知到前处理、计算设置和后处理,全面解析如何高效模拟水流与泥沙的相互作用,特别适用于桥墩冲刷、水库泄洪等工程场景。通过实战案例分享,帮助读者掌握Flow3D在水利工程中的精准应用,提升模型精度与计算效率。

weixin_42549723的博客 493

UVM对象实例化及覆盖的几种方法

UVM对象实例化的方法有多种,以下以object为例: 1)第一种:直接利用new函数进行实例化 trans t1; t1 = new("t1");//利用new函数进行实例化 2)第二种:uvm_component_registry中提供的方法type_id::create,此种方法也是最常使用的方法 trans t2; t2 = trans::type_id::create("t2",this); 3)第三种:uvm_factory中提供的方法creat_object_by_type trans t

沧月九流的博客 3374

获取系统时间几种方法和使用CPU时间戳进行高精度计时

获取系统时间几种方法 和 使用CPU时间戳进行高精度计时收藏 2009-01-22 11:182883人阅读评论(0)收藏举报 1 使用time_t time( time_t * timer ) 精确到秒   计算时间差使用double difftime( time_t timer1, time_t timer0 ) 2 使用clock_t clock() 得到的是CPU时间 精

电脑翻译官的专栏 1289

别再到处找资源了!WinCC 7.5 SP2官方下载与Windows 10保姆级安装避坑指南

本文提供了WinCC 7.5 SP2在Windows 10上的官方下载与安装全流程指南,重点解决了资源获取难、系统兼容性问题及分卷压缩处理等常见痛点。通过详细的步骤和实用技巧,帮助用户顺利完成安装并优化配置,适用于工控领域的学习者和从业者。

weixin_32924297的博客 470

获取系统时间几种方法 和 使用CPU时间戳进行高精度计时

获取系统时间几种方法 和 使用CPU时间戳进行高精度计时  1 使用time_t time( time_t * timer )    精确到秒  计算时间差使用double difftime( time_t timer1, time_t timer0 ) 2 使用clock_t clock() 得到的是CPU时间    精确到1/CLOCKS_PER_SEC秒3

KZM2008的专栏 1523

告别效率低谷:用ADS仿真手把手教你设计高回退Doherty功放(附1:2非对称案例)

本文详细解析了如何使用ADS仿真设计高回退Doherty功放,特别针对1:2非对称架构进行深入探讨。通过优化功率分配比、峰值管开启阈值等关键参数,显著提升功放在9dB回退点的效率至75%以上,适用于LTE等高PAPR信号场景。文章还提供了ADS仿真环境搭建、参数优化及工程化设计的实用技巧。

weixin_33743248的博客 453

016、自动标注方案实战:用大模型(SAM/Grounding DINO)生成 YOLO 格式伪标签

本文介绍了一种利用大模型自动生成YOLO格式伪标签的实战方案。针对传统人工标注效率低、易出错的问题,作者提出结合Grounding DINO(零样本检测)和SAM(精细分割)的优势:前者快速生成候选框,后者优化边界精度。文章详细阐述了技术选型理由(平衡速度与精度)、环境搭建避坑指南(关键依赖版本)、核心三步流程(检测-分割-格式转换)以及后处理技巧(置信度分级过滤)。实验表明,该方案相比纯人工标注可节省80%时间,且经过SAM优化的边界框精度提升10-15%。特别强调了工程细节:文本描述格式、阈值设定、小目

zzfmlxs的博客 538

超精确计时

一,首先看一下时间换算单位,澄清一下概念:1秒=1000毫秒(ms)                            1毫秒=1/1,000秒(s) 1秒=1,000,000 微秒(μs)                    1微秒=1/1,000,000秒(s) 1秒=1,000,000,000 纳秒(ns)             1纳秒=1/1,000,000,000秒(s) 1

李逸波(PMP) 1472

Python爬虫实战教程:如何高效爬取税务局通知通告

税务局发布的通知通告包含政策法规、办税指南、公告信息等,是纳税人、企业合规经营的重要参考。官网发布频率高,手动查看不便,自动爬取并保存,方便信息及时掌握及历史数据归档。本文以合法合规的方式示范,建议实际应用前确认目标网站允许爬取的范围和方式。建议使用pandas进行数据清洗,如去重、空值处理等。对于研究税务政策、进行大数据分析、搭建行业信息平台,爬取税务局通知通告信息尤为关键。公告列表以分页形式展现,包含标题、发布时间和详情页链接。进行政策趋势图、发布频率统计等可视化。爬取公开数据时,务必遵守网站的。

2201_76125261的博客 1780

C#中精确计时的一点收获

以下所有代码运行环境:Windows 2003, Intel(R) Core(TM) 2 Duo CPU E8400@ 3.00GHz 2.99GHz,2.96GB内存 根据综合网上的一些文章,精确计时主要有以下几种方式 1 调用WIN API中的GetTickCount [DllImport("kernel32")]static extern uint GetTickCount()...

weixin_34025151的博客 560

ShardingJDBC支持批量插入数据

最近在进行分库分表,但是有张表,里面有一些批量的插入。 也就是: insert xxx values(...),(...),(...) 这样的语句。 开始我的依赖是: <dependency> <groupId>io.shardingjdbc</groupId> <artifactId>sharding-jdbc-core</artifactId> <v

谙忆-陈浩翔 9762

可食用野生植物检测实战:基于YOLOv11的智能识别系统全流程指南

本文介绍了一种基于YOLOv11的可食用野生植物智能识别系统。该系统通过深度学习技术,能在0.2秒内精准识别植物是否可食用,准确率高达92%。文章详细阐述了从数据采集、标注到模型训练、验证的全流程,并开发了用户友好的Tkinter交互界面。该系统解决了户外探险和植物研究中植物识别的痛点,具有高精度、实时性和强泛化能力的特点,为户外安全提供了智能化解决方案。

FJN110的博客 163

windows下实现微秒级的延时

windows下实现微秒级的延时 2010年11月17日   1.微秒级的延时肯定不能基于消息(SetTimer函数),因为一出现消息堵塞等就会影响精   度,而且setTimer单位才是毫秒.实际响应时间可能要到55毫秒左右.   2.微秒级的延时也不能不能基于中断,VxD最快的时钟服务程序Set_Global_Time_Out函数   才能保证1毫秒的精度.其他挂接int...

ejhmm20u 176

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

VC 计算 时间

Q:如何获取时间?精度如何?  A:1 使用time_t time( time_t timer ) 精确到秒 2 使用clock_t clock() 得到的是CPU时间 精确到1/CLOCKS_PER_SEC秒 3 计算时间差使用double difftime( time_t timer1, time_t timer0 ) 4 使用DWORD GetTickCount()

brucetiancai的专栏 2499

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

VC中如何得到一个线程的效率

//定义开始时间  LARGE_INTEGER fre,star_,end_;  QueryPerformanceFrequency(&fre);  QueryPerformanceCounter(&star_);// 处理....  pro( mb);  //得到结束的时间  QueryPerformanceCounter(&end_);  ACE_DEBUG((LM_INFO,ACE_

阿彪的Blog 2361

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

获取系统时间几种方法 和 使用CPU时间戳进行高精度计时收藏

 1 使用time_t time( time_t * timer )    精确到秒  计算时间差使用double difftime( time_t timer1, time_t timer0 ) 2 使用clock_t clock() 得到的是CPU时间    精确到1/CLOCKS_PER_SEC秒3 使用DWORD GetTickCount() 得到的是系统运行的时间 精确到毫秒

rabbit729的专栏 1万+

c纳秒级计时器_C++中获得CPU高精度时间戳( 纳秒级 )

关注性能的程序开发人员而言,一个好的计时部件既是益友,也是良师。计时器既可以作为程序组件帮助程序员精确的控制程序进程,又是一件有力的调试武器,在有经验的程序员手里可以尽快的确定程序的性能瓶颈,或者对不同的算法作出有说服力的性能比较。在Windows平台下,常用的计时器有两种,一种是timeGetTime多媒体计时器,它可以提供毫秒级的计时。但这个精度对很多应用场合而言还是太粗糙了。另一种是Quer...

weixin_39634067的博客 664

Windows高精度计时必看:MFC环境下5种时间戳方案横向评测

本文针对Windows MFC开发中对时间精度有严苛要求的场景,深入评测了GetTickCount、QueryPerformanceCounter、CTime、C++11 Chrono库以及SYSTEMTIME/FILETIME这五种主流时间戳方案。文章从理论精度、实际抖动、CPU开销、多核稳定性及代码易用性等多个维度进行横向对比,并提供了工业控制与游戏开发等场景下的实战代码模板与异常处理指南,帮助开发者根据应用需求选择最合适的微秒级高精度计时方案。

spark7igniter的博客 657
上一篇: Mac系统关于文件夹显示
下一篇: 解决windbg不能正常分析win2008任务管理器导出的dmp文件
cppbegginer
博客等级 码龄18年 26粉丝 75原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值