测量程序运行时间的几个函数

摘要:本文详细的讨论了在windows平台中,测量程序运行时间的几个函数,GetTickCount, QueryPerformanceCounter和RDTSC,并给出示例代码。
  算法的好坏有好多评价指标,其中一个重要的指标是时间复杂度。如果两个程序完成一个同样的任务,即功能相同,处理的数据相同,那么运行时间较短者为优。操作系统和库函数一般都提供了对时间测量的函数,这么函数一般都会返回一个代表当前时间的数值,通过在运行某个程序或某段代码之前调用一次时间函数来得到一个数值,在程序或者代码段运行之后再调用一次时间函数来得到另一个数值,将后者减去前者即为程序的运行时间。
 在windwos平台(指windwow95及以后的版本,下同),常用的用于测量时间的函数或方法有三种:1.API函数GetTickCount或C函数clock, 2.API函数QueryPerformanceCounter, 3:汇编指令RDSTC
1.API函数GetTickCount:
函数原形:DWORD GetTickCount(VOID);
该函数取回从电脑开机至现在的毫秒数,即每个时间单位为1毫秒。他的分辨率比较低,常用在测量用时较长程序,如果你的程序用时为100毫秒以上,可以使用这个函数.另一个和GetTickCount类似的函数是clock,该函数的回的时间的单位的是CLOCKS_PER_SEC,在windows95/2000操作系统,该值是1000,也就是说,在windows平台,这两个函数的功能几乎完全相同。
2.API函数QueryPerformanceCounter:
函数原形:BOOL QueryPerformanceCounter( LARGE_INTEGER *lpPerformanceCount);该函数取回当前的高分辨值performance计数器,用一个64bit数来表示。如果你的硬件不支持高分辨performance计数器,系统可能返加零。不像GetTickCount,每个计数器单位表示一个固定的时间1毫秒,为了知道程序确切的执行时间,你需要调用函数QueryPerformanceFrequency来得到每秒performance计数器的次数,即频率。
3.汇编指令RDTSC:
RDTSC 指令读取CPU内部的“时间戳(TimeStamp)",它是一个64位无符号数计数器,这条指令执行完毕后,存储在EDX:EAX寄存中。该指令从intel奔腾CPU开始引入,一些老式的CPU不支持该指令,奔腾后期的CPU包括AMD的CPU均支持这条指令。和QueryPerformanceCounter类似,要想知道程序的确实的执行时间,必须知道CPU的频率,即平常所说的CPU的主频。不幸的是没有现成的函数可以得到CPU的频率。一种办法可行的办法延时一段指定时间,时间的测量可以用QueryPerformanceCounter来做,在这段时间的开始和结束调用RDTSC,得到其时钟数的差值,然后除以这段时间的的秒数就可以了。
 
下面的代码给出使用3个函数封装和测试代码,用RDTSC指令来计时的代码参考了一个Ticktest的源代码,作者不详。
getTime1,使用GetTickCount返回一个表示当前时间的值,单位秒。
getTime2,和getTime1类似,精度更高。
getTime3,返回一个64bit的一个计数器,欲转换为秒,需除以CPU频率。示例代码见函数test3.

#include "stdafx.h"
#include "windows.h"
#include "tchar.h"
double getTime1()
{
       DWORD t=GetTickCount();
       return (double)t/1000.00;
}
double getTime2() //使用高精度计时器
{      
       static LARGE_INTEGER s_freq;
       LARGE_INTEGER performanceCount;
       double t;
       if (s_freq.QuadPart==0)
       {
              if ( !QueryPerformanceFrequency( &s_freq))
                     return 0;
       }
       
       QueryPerformanceCounter( &performanceCount );
       t=(double)performanceCount.QuadPart / (double)s_freq.QuadPart;
       return t;
}
void test1()
{
       double t1,t2;
       t1=getTime1();
       Sleep(1000);
       t2=getTime1()-t1;
       printf("It take %.8f second\n",t2);//你们把/n贴代码里表示很高级么
}
void test2()
{
       double t1,t2;
       t1=getTime2();
       Sleep(1000);
       t2=getTime2()-t1;
       printf("It take %.8f second\n",t2);
}
inline BOOL isNTOS() //检测是否运行在NT操作系统
{
       typedef BOOL (WINAPI *lpfnGetVersionEx) (LPOSVERSIONINFO);
       static int bIsNT=-1;
       if (bIsNT!=1)
              return (BOOL)bIsNT;
       // Get Kernel handle
       HMODULE hKernel32 = GetModuleHandle(_T("KERNEL32.DLL"));
       if (hKernel32 == NULL)
              return FALSE;
 #ifdef _UNICODE
    lpfnGetVersionEx lpGetVersionEx = (lpfnGetVersionEx) GetProcAddress(hKernel32, _T("GetVersionExW"));
 #else
    lpfnGetVersionEx lpGetVersionEx = (lpfnGetVersionEx) GetProcAddress(hKernel32, _T("GetVersionExA"));
 #endif
 
       if (lpGetVersionEx)
       {
              OSVERSIONINFO osvi;
              memset(&osvi, 0, sizeof(OSVERSIONINFO));
              osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
              if (!lpGetVersionEx(&osvi))
                     bIsNT=FALSE;
              else
                     bIsNT=(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT);
       }
       else
       {
              //Since GetVersionEx is not available we known that 
              //we are running on NT 3.1 as all modern versions of NT and
              //any version of Windows 95/98 support GetVersionEx
              bIsNT=TRUE;
       }
       return bIsNT;
}
inline static BOOL checkRDSTC() //检测CPU是否支持RDSTC指令
{
       static int bHasRDSTC= -1;
       SYSTEM_INFO sys_info;
       
       if ( bHasRDSTC !=-1 )
              return (BOOL)bHasRDSTC;
       GetSystemInfo(&sys_info);
       if (sys_info.dwProcessorType==PROCESSOR_INTEL_PENTIUM)
       {
              try
              {
                     _asm
                     {
                     _emit 0x0f                           ; rdtsc     
                     _emit 0x31
                     }
              }
              catch (...)       // Check to see if the opcode is defined.
              {
                     bHasRDSTC=FALSE; return FALSE;
              }
              // Check to see if the instruction ticks accesses something that changes.
              volatile ULARGE_INTEGER ts1,ts2;
              _asm
              {
                     xor eax,eax
                     _emit 0x0f                                  ; cpuid
                     _emit 0xa2
                     _emit 0x0f                                  ; rdtsc
                     _emit 0x31
                     mov ts1.HighPart,edx
                     mov ts1.LowPart,eax
                     xor eax,eax
                     _emit 0x0f                                  ; cpuid
                     _emit 0xa2
                     _emit 0x0f                                  ; rdtsc
                     _emit 0x31
                     mov ts2.HighPart,edx
                     mov ts2.LowPart,eax
              }
              // If we return true then there's a very good chance it's a real RDTSC instruction!
              if (ts2.HighPart>ts1.HighPart)
                  bHasRDSTC=TRUE;
              else if (ts2.HighPart==ts1.HighPart && ts2.LowPart>ts1.LowPart)
                     bHasRDSTC=TRUE;
              else
              { 
                     printf("RDTSC instruction NOT present./n");
                     bHasRDSTC=FALSE;
              }
       }
       else
              bHasRDSTC=FALSE;
       return bHasRDSTC;
}
//***********************************************
void getTime3( LARGE_INTEGER *pTime) //返加当前CPU的内部计数器
{
       if (checkRDSTC())
       {
              volatile ULARGE_INTEGER ts;
       //on NT don't bother disabling interrupts as doing
       //so will generate a priviledge instruction exception
              if (!isNTOS())
                     _asm cli
           //----------------      
        _asm
              {
                     xor eax,eax
            //-------------save rigister
                     push ebx
                     push ecx
                     
                     _emit 0x0f                                  ; cpuid - serialise the processor
                     _emit 0xa2
                     
                     //------------
                     _emit 0x0f                                  ; rdtsc
                     _emit 0x31
                     
                     mov ts.HighPart,edx
                     mov ts.LowPart,eax
                     
                     pop ecx
                     pop ebx
              }
        //-----------------
              if (!isNTOS())
                     _asm      sti
              //---------        
        pTime->QuadPart=ts.QuadPart;
       }
       else
           pTime->QuadPart=0;
}
// maxDetermainTime:最大测定时间,单位毫秒,在首次调用该函数时,
// 将花费maxDetermineTime的时间来测定CPU频率,以后的调用将直接返加静态变量的值
double GetCPUFrequency(DWORD maxDetermineTime )
{
       static double CPU_freq;
       LARGE_INTEGER period,t1,t2;
       register LARGE_INTEGER goal,current;
       
       if (CPU_freq>1000)      //this value have been initilization
              return CPU_freq;
       if (!QueryPerformanceFrequency(&period) || !checkRDSTC())
       {
              CPU_freq=-1.00;
              return CPU_freq;
       }
       QueryPerformanceCounter(&goal);
       goal.QuadPart += period.QuadPart * maxDetermineTime/1000;
       getTime3( &t1);  //开始计时
       do    //延时maxDetermineTime毫秒
       {
              QueryPerformanceCounter(¤t);
       } while(current.QuadPart<goal.QuadPart);
       getTime3(&t2);      //结束计时
       
       CPU_freq=double((t2.QuadPart-t1.QuadPart)*1000/maxDetermineTime);
       
       char buff[100];
       sprintf(buff,"Estimated the processor clock frequency =%gHz/n",CPU_freq);
    ::MessageBox(NULL,buff,"",MB_OK);
       return CPU_freq;
}
void test3()
{
       LARGE_INTEGER t,t1,t2;
       double f1,f2;
       
       GetCPUFrequency(100); //花费0.1秒时间计算CPU频率
       f1=getTime2();
       getTime3(&t1);
       Sleep(1000);
       getTime3(&t2);
       f2=getTime2();
       t.QuadPart=t2.QuadPart-t1.QuadPart;
       printf("It take %.8f second by getTime3\n",(double)t.QuadPart/GetCPUFrequency(100));
       printf("It take %.8f second by getTime2\n",f2-f1);
}
int main(int argc, char* argv[])
{
       test1();
       test2();
       test3();
       return 0;
}


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wzdworld001/archive/2007/06/08/1644111.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本目录下提供的是《手把手教你学51单片机(C语言版)》教材中所有例程与作业习题的源代码。 请将整个目录复制到电脑硬盘上使用,如直接在光盘路径下打开工程可能会导致软件报错。 运行目录下的Clean.bat可以清理程序编译过程中产生的中间文件和临时文件。 lesson2 (第2章): 点亮一个LED示例,所在章节2.4 lesson3 (第3章): LED闪烁示例,所在章节3.5 lesson4 (第4章): 4_1:用P0口控制LED的示例,所在章节4.8 4_2:用P0口控制实现流水灯效果,所在章节4.8 4_t4:作业题4,逐次右移的流水灯效果,所在章节4.9 4_t5:作业题5,左右往复移动的流水灯效果,所在章节4.9 lesson5 (第5章): 5_1:基于定时器查询模式的LED闪烁,所在章节5.2.3 5_2:静态点亮数码管的某几段,所在章节5.3.2 5_3:数码管静态显示一位字符,所在章节5.3.3 5_t3:作业题3,定时器查询模式实现左右移动的流水灯,所在章节5.4 5_t5:作业题5,变更lesson5_3的正计数为倒计数,所在章节5.4 lesson6 (第6章): 6_1:数码管动态显示原理示例(if...else if...语句示例),所在章节6.4 6_2:数码管动态显示原理示例(switch...case...语句示例),所在章节6.4 6_3:基于中断带消隐的数码管动态显示示例,所在章节6.5 6_t4:作业题4,在lesson6_3多位数字显示的基础上不显示高位的0,所在章节6.6 6_t5:作业题5,变更lesson6_3的正计数为倒计数,所在章节6.6 lesson7 (第7章): 7_1:基于数码管计时程序的静态变量演示,所在章节7.2 7_2:点亮LED点阵上的一个点,所在章节7.3 7_3:点亮LED点阵上的一行,所在章节7.3 7_4:点亮LED点阵上的全部点,所在章节7.3 7_5:LED点阵显示静态图形,所在章节7.4 7_6:LED点阵显示纵向移动的动画,所在章节7.5.1 7_6_h:LED点阵显示横向移动的动画(掉转板子方向的取巧方式),所在章节7.5.2 7_7:LED点阵显示横向移动的动画,所在章节7.5.2 7_t3:作业题3,lesson7_6的向上移动改为向下移动,所在章节7.6 7_t4:作业题4,lesson7_7的向左移动改为向右移动,所在章节7.6 7_t5:作业题5,基于LED点阵的9~0倒计数,所在章节7.6 7_t6:作业题6,独立LED、数码管、点阵LED同时全亮,所在章节7.6 lesson8 (第8章): 8_1:基于数码管计时程序的函数调用演示,所在章节8.2 8_2:按键基本原理演示例程,所在章节8.4.3 8_3:独立按键扫描原理演示例程,所在章节8.4.3 8_4:独立按键消抖原理演示例程,所在章节8.4.4 8_5:独立按键扫描并消抖的演示例程,所在章节8.4.4 8_6:矩阵按键扫描并消抖的演示例程,所在章节8.4.5 8_7:基于矩阵按键和数码管实现的简易加法计算器,所在章节8.5 8_t4:作业题4,变更lesson8_5的递增计数为递减计数,所在章节8.6 8_t5:作业题5,在lesson8_7基础上实现简易加减计算器,所在章节8.6 lesson9 (第9章): 9_1:步进电机驱动的基础示例,所在章节9.3.3 9_2:步进电机转动任意角度的示例,所在章节9.3.4 9_3:实用的步进电机驱动示例,所在章节9.3.5 9_4:按键控制步进电机转动的示例,所在章节9.3.6 9_5:蜂鸣器驱动的基础示例,所在章节9.4 9_6:蜂鸣器演奏简单乐谱——“两只老虎”,所在章节9.4 lesson10 (第10章): 10_1:基于数码管显示的数字秒表,所在章节10.1 10_2:基于PWM方式控制LED的亮度,所在章节10.2 10_3:基于PWM方式控制LED实现呼吸灯效果,所在章节10.2 10_4:交通信号灯示例,所在章节10.3 10_5:长短按键/连续按键功能实现示例,所在章节10.5 10_t3:作业题3,数码管计时与流水灯同时运行的示例,所在章节10.6 lesson11 (第11章): 11_1:普通IO口模拟实现串口通信的示例,所在章节11.4 11_2:单片机硬件UART查询方式实现串口通信的示例,所在章节11.5.3 11_3:单片机硬件UART中断方式实现串口通信的示例,所在章节11.5.3 11_4:UART串口通信及控制数码管显示的示例,所在章节11.6 11_t5:作业题5,UART串口控制流水灯流动和停止,所在章节11.7 11_t6:作业题6,UART串口控制蜂鸣器的开关,所在章节11.7 lesson12 (第12章): 12_1:指针作为函数参数的示例,所在章节12.1 12_2:指向变量的指针与变量关系的示例,所在章节12.2 12_3:指针、字符串、字符数组、ASCII码演示示例,所在章节12.3 12_4:1602液晶基本操作演示示例,所在章节12.4 lesson13 (第13章): 13_1:1602液晶显示两行字符串,并实现整屏的重复左移,所在章节13.2 13_2:多c文件示例,1602液晶显示两行字符串,并实现整屏的重复左移,所在章节13.3 13_3:整型数为操作数的简易+-*/计算器,所在章节13.4 13_4:基于帧模式的实用串口程序示例,所在章节13.5 13_t2:作业题2,1602液晶显示两行字符串,并实现整屏的重复右移,所在章节13.6 lesson14 (第14章): 14_1:寻址I2C总线上存在的和不存在的地址,将应答状态显示到液晶上,所在章节14.2 14_2:用单字节读写模式访问EEPROM,每次+1后写回,所在章节14.3.1 14_3:用多字节读写模式访问EEPROM,依次+1,+2,+3...后写回,所在章节14.3.2 14_4:用连续读与分页写模式访问EEPROM,依次+1,+2,+3...后写回,所在章节14.3.3 14_5:读取EEPROM中的数据显示到液晶,并可通过UART修改EEPROM中的数据,所在章节14.4 14_t3:作业题3,以lesson10_4为基础实现可通过UART设定时间的交通灯示例,所在章节14.5 14_t4:作业题4,基于液晶、按键、EEPROM的密码锁示例,所在章节14.5 lesson15 (第15章): 15_1:用单次读写模式访问DS1302,并将日期时间显示在液晶上,所在章节15.3.4 15_2:用突发读写模式访问DS1302,并将日期时间显示在液晶上,所在章节15.3.5 15_3:DS1302实现简易电子钟,通过按键校时,所在章节15.5 lesson16 (第16章): 16_1:接收NEC协议的红外编码并将用户码和键码显示到数码管上,所在章节16.3 16_2:控制DS18B20测量温度并将温度值显示到液晶上,所在章节16.4 16_t2:作业题2,用遥控器控制步进电机正反转,所在章节16.5 16_t4:作业题4,带温度显示的电子钟,所在章节16.5 lesson17 (第17章): 17_1:将模拟输入通道0、1、3的电压值显示到液晶上,所在章节17.4 17_2:由按键控制DA输出可调电压值,所在章节17.6 17_3:由按键控制DA输出可变化的波形,所在章节17.7 17_t3:作业题3,可调频率的信号发生器,所在章节17.8 lesson18 (第18章): 18_1:RS485基本示例,接收任意数据帧并添加回车换行后送回,所在章节18.1 18_2:基于RS485的Modbus通信示例,支持寄存器读写操作,所在章节18.3 18_t3:作业题3,基于Modbus协议实现电子钟校时,所在章节18.4 lesson19 (第19章): 19_1:多功能电子钟例程,所在章节19.4
### 回答1: adams运行时间函数是一个用于估算一个物体或多个物体的运动轨迹和所需时间的数学函数。它基于牛顿的运动定律和微积分原理,通过将运动过程离散化,将连续的运动方程转化为递推的差分方程来模拟和计算物体的运动状态。 具体而言,adams运行时间函数将物体的位置、速度和加速度等信息作为输入,然后根据给定的运动方程和初始条件,迭代计算出物体在特定时间点的位置和速度。在每个时间步长上,它使用差分方程将当前状态转化为下一个时间点的状态,并重复这个过程,直到达到所需的时间。 adams运行时间函数的优势在于其可以处理复杂的力学系统,并对多个物体的相互作用进行建模和计算。通过将不同物体的运动方程相互关联,可以得到它们之间的相对运动和相互影响。这使得它在模拟和预测复杂动态系统中的物体运动和相互作用时非常有用。 总之,adams运行时间函数是一个用于估算物体运动轨迹和所需时间的数学函数,基于牛顿的运动定律和微积分原理,通过离散化运动方程和差分方程来模拟和计算物体的运动状态。它的应用范围广泛,适用于模拟和预测复杂力学系统中的物体运动和相互作用。 ### 回答2: adams运行时间函数是一个用于计算程序执行时间的函数。通常我们希望知道一个程序或者某个特定代码块的运行时间,这可以用来评估程序的效率,进而优化代码。 adams运行时间函数可以通过记录程序的开始时间和结束时间来计算程序的执行时间。具体来说,它会使用系统提供的时钟函数来获取当前时间,在程序的不同位置分别记录开始时间和结束时间,然后计算差值得到程序的执行时间。 为了使用adams运行时间函数,我们需要在程序中设定一个开始时间点,通常在代码的开头。我们可以使用系统提供的时间函数,如clock函数或者时间戳函数来获取当前时间,并将其保存在一个变量中。然后在代码的结束位置,我们再次获取当前时间,保存在另一个变量中。 最后,我们可以通过将结束时间减去开始时间得到程序的运行时间。使用适当的单位(如秒、毫秒等)来表示时间。 adams运行时间函数在性能分析、程序优化等方面非常有用。通过测量不同代码段的执行时间,我们可以确定哪些部分需要改进或者优化,从而提高程序的性能。 总之,adams运行时间函数是一个用于计算程序执行时间的函数,通过记录开始时间和结束时间,以及计算时间差值,来提供程序的运行时间信息,从而帮助我们优化代码。 ### 回答3: adams是一个用于多步法求解常微分方程的数值计算方法。在计算过程中,adams方法需要对每一步的函数值进行估计并确定下一个时间步长的函数值。因此,adams方法的运行时间函数可以表示为以下几个方面。 首先,adams方法的运行时间与问题规模相关。问题规模可以通过求解的方程维数、时间步长等参数来衡量。一般来说,问题规模越大,求解所需的运算量也越多,运行时间也相应增加。 其次,adams方法的运行时间与计算机硬件性能有关。较快的计算机硬件可以加快求解过程中的矩阵运算、函数估计等计算步骤,从而减少运行时间。 此外,adams方法的运行时间还与收敛条件有关。对于某些情况下,adams方法可能需要进行多次迭代才能达到所需的精度要求。因此,收敛条件的松紧程度也会影响到adams方法的运行时间。 最后,adams方法的运行时间还与算法实现的优化程度有关。在实际应用中,对于adams方法的算法实现可以进行各种优化,例如使用矩阵计算技巧、并行计算等方法,以减少运行时间。 总的来说,adams方法的运行时间函数受问题规模、计算机硬件性能、收敛条件和算法优化等多个因素的影响。在实际使用中,可以通过调整这些因素来优化adams方法的运行时间

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值