1. 这个是windows里面常用来计算程序运行时间的函数:
1: DWORD dwStart = GetTickCount();
2: Test(); // Your program.
3: DWORD dwEnd = GetTickCount();
4: DWORD dwTimes = dwEnd - dwStart;
则(dwEnd-dwStart)就是你的程序运行时间, 以毫秒为单位这个函数只精确到55ms,1个tick就是55ms。
2. timeGetTime()基本等于GetTickCount(),但是精度更高:
1: DWORD dwStart = timeGetTime();
2: Test(); // Your program
3: DWORD dwEnd = timeGetTime();
4: DWORD dwTimes = dwEnd - dwStart;
则(dwEnd-dwStart)就是你的程序运行时间, 以毫秒为单位虽然返回的值单位应该是ms,但传说精度只有10ms。
3. 用clock()函数,得到系统启动以后的毫秒级时间,然后除以CLOCKS_PER_SEC,就可以换成“秒”,标准c函数。
clock_t clock ( void );
1: #include <time.h>
2: clock_t t = clock();
3: long sec = t / CLOCKS_PER_SEC;
他是记录时钟周期的,实现看来不会很精确,需要试验验证。
1: #include <iostream>
2: #include <ctime>
3: using namespace std;
4: int main()
5: {
6: time_t begin,end;
7: begin = clock();
8: //这里加上你的代码
9: end = clock();
10: cout << "runtime: " << double(end - begin) / CLOCKS_PER_SEC << endl;
11: return 0;
12: }
4. unix时间相关,也是标准库的
这些在<time.h>
1). timegm函数只是将struct tm结构转成time_t结构,不使用时区信息;
1: time_t timegm(struct tm *tm);
2).mktime使用时区信息
1: time_t mktime(struct tm *tm);
timelocal 函数是GNU扩展的与posix函数mktime相当
1: time_t timelocal (struct tm *tm);
3). gmtime函数只是将time_t结构转成struct tm结构,不使用时区信息;
1: struct tm * gmtime(const time_t *clock);
1: struct tm * localtime(const time_t *clock);
1: time_t t;
2: t = time(&t);
1: int stime(time_t *tp)
。
5. Window里面的一些不一样的
CTime MFC类,好像就是把time.h封了个类,没扩展
1: CTime t = GetCurrentTime();
SYSTEMTIME 结构包含毫秒信息
1: typedef struct _SYSTEMTIME {
2: WORD wYear;
3: WORD wMonth;
4: WORD wDayOfWeek;
5: WORD wDay;
6: WORD wHour;
7: WORD wMinute;
8: WORD wSecond;
9: WORD wMilliseconds;
10: } SYSTEMTIME, *PSYSTEMTIME;
11:
12: SYSTEMTIME t1;
13: GetSystemTime(&t1)
14: CTime curTime(t1);
15: WORD ms = t1.wMilliseconds;
16:
17: SYSTEMTIME sysTm;
18: ::GetLocalTime(&sysTm);
在time.h中的_strtime() //只能在windows中用
1: char t[11];
2: _strtime(t);
3: puts(t);
6. 下面是转的一个用汇编的精确计时方法
---------------------------------------------------------------------------------------
如何获得程序或者一段代码运行的时间?你可能说有专门的程序测试工具,确实,不过你也可以在程序中嵌入汇编代码来实现。
在Pentium的指令系统中有一条指令可以获得CPU内部64位计数器的值,我们可以通过代码两次获取该计数器的值而获得程序或代码运行的时钟周期数,进而通过你的cpu的频率算出一个时钟周期的时间,从而算出程序运行的确切时间。
我们通过指令TDSIC来获得cpu内部计数器的值,指令TDSIC返回值放在EDX:EAX中,其中EDX中存放64位寄存器中高32位的值,EAX存放第32位的值。下面看看实现的代码:
1: //用汇编实现获取一段代码运行的时间
2: #include<iostream>
3: using namespace std;
4:
5: void GetClockNumber (long high, long low);
6: void GetRunTime();
7:
8: int main()
9: {
10: long HighStart,LowStart,HighEnd,LowEnd;
11: long numhigh,numlow;
12: //获取代码运行开始时cpu内部计数器的值
13: __asm
14: {
15: RDTSC
16: mov HighStart, edx
17: mov LowStart, eax
18: }
19: for(int i= 0; i<100000; i++ )
20: {
21: for(int i= 0; i<100000; i++ )
22: {
23: }
24: }
25: //获取代码结束时cpu内部计数器的值,并减去初值
26: __asm
27: {
28: RDTSC
29: mov HighEnd, edx
30: Mov LowEnd, eax
31: //获取两次计数器值得差
32: sub eax, LowStart
33: cmp eax, 0 ; 如果低32的差为负则求返,因为第二次取得永远比第一次的大
34: jg L1
35: neg eax
36: jmp L2
37: L1: mov numlow, eax
38: L2: sbb edx, HighStart
39: mov numhigh, edx
40: }
41: //把两个计数器值之差放在一个64位的整形变量中
42: //先把高32位左移32位放在64的整形变量中,然后再加上低32位
43: __int64 timer =(numhigh<<32) + numlow;
44: //输出代码段运行的时钟周期数
45: //以频率1.1Gcpu为例,如果换计算机把其中的1.1改乘其它即可,因为相信大家的cpu都应该在1G以上 ^_^
46: cout<< (double) (timer /1.1/1000000000) << endl;
47: return 0;
48: }
这样通过一条简单的汇编指令就可以获得程序或一段代码的大概时间,不过并不能得到运行的确切时间,因为即使去掉中间的循环,程序也会有个运行时间,
因为在第一次取得计数器的值后,有两条汇编指令mov HighStart, edx mov LowStart, eax这两条指令当然也有运行时间 ,当然你可以减去这两条指令的运行时间(在1.1G的机子上是3e-8s),这样会更精确一点。
如果你要确切知道程序的运行时间,专业的测试软件肯定会更好一点,不过好像一般没有必要获取除非专门的要求的程序。
不过能DIY一个也是不错的,不管有没有,最起码你可以学到在VC++中如何嵌入汇编代码以及如何使用32位的寄存器,其实和16位的寄存器一样使用,将来64的也应该一样,只不过位数不同罢了 。
1: //C++高精度实现计算程序运行时间
2: #include <iostream>
3: #include <windows.h>
4: using namespace std;
5:
6: void Test()//测试程序
7: {
8: for(int i=0; i<1000; i++)
9: {
10: for(int j=0; j<100; j++)
11: {
12: printf("%d,%d/n",i,j);
13: }
14: }
15: }
16:
17: int main(void)
18: {
19: LARGE_INTEGER BegainTime ;
20: LARGE_INTEGER EndTime ;
21: LARGE_INTEGER Frequency ;
22: QueryPerformanceFrequency(&Frequency);
23: QueryPerformanceCounter(&BegainTime) ;
24:
25: //要测试的代码放在这里
26: Test();
27:
28: QueryPerformanceCounter(&EndTime);
29:
30: //输出运行时间(单位:s)
31: cout << "运行时间(单位:s):" <<(double)( EndTime.QuadPart - BegainTime.QuadPart )/ Frequency.QuadPart <<endl;
32:
33: system("pause") ;
34: return 0 ;
35: }
附 vc计算高精度时间差
面线框里的代码便可实现计算精度达到微秒级的时间差:
------------------------------------------------------------------------------------
1: LARGE_INTEGER litmp;
2: LONGLONG QPart1,Qpart2;
3: double dfMinus,dfFreq,dfTime;
4:
5: //获得计时器的时钟频率
6: QueryPerformanceFrequency(&litmp);
7: dfFreq = (double)litmp.QuadPart;
8: QueryPerformanceCounter(&litmp);
9: Qpart1 = litmp.QuadPart; //开始计时
10:
11: Block1(); //工作模块 函数等,根据自己需要添加。
12:
13: QueryPerformanceCounter(&litmp);
14: Qpart2 = litmp.QuadPart; //终止计时
15: dfMinus = (double)(QPart2 - QPart1);//计算计数器值
16: dfTime = dfMinus / dfFreq;//获得对应时间,单位为秒 你可以乘1000000精确到毫秒级(us)
--------------------------------------------------------------------------------------
在一些计算机硬件系统中,包含有高精度运行计数器(high-resolution performance
counter),利用它可以获得高精度定时间隔,其精度与CPU的时钟频率有关。
1、首先调用QueryPerformanceFrequency函数取得高精度运行计数器的频率f。单位是每秒多少次(n/s),此数
一般很大。
2、在需要定时的代码的两端分别调用QueryPerformanceCounter以取得高精度运行计数器的数值n1,n2。两次数
值的差值通过f换算成时间间隔,t=(n2-n1)/f。
下面举一个例子来演示这种方法的使用及它的精确度。
在VC 6.0 下用MFC建立一个对话框工程,取名为HightTimer.在对话框面板中控件的布局如下图:
其中包含两个静态文本框,两个编辑框和两个按纽。上面和下面位置的编辑框的ID分别为IDC_E_TEST和IDC_E_ACT
UAL,通过MFC ClassWizard添加的成员变量也分别对应为DWORD m_dwTest和DWORD m_dwAct.
“退出”按钮的ID为IDOK,“开始测试”按按钮ID为IDC_B_TEST,用MFC
ClassWizard添加此按纽的单击消息处理函数如下:
1: void CHightTimerDlg::OnBTest()
2: {
3: // TODO: Add your control notification handler code here
4: UpdateData(TRUE); //取输入的测试时间值到与编辑框相关联的成员变量m_dwTest中
5: LARGE_INTEGER frequence;//LARGE_INTEGER是一个联合,其中LOWPART为低32位,HIGHPART为高32位,
6: //两者构成一个结构,而QuadPart是其中的64位符号整数,为LongLong类型
7: if(!QueryPerformanceFrequency( &frequence)) //取高精度运行计数器的频率,若硬件不支持则返回FALSE
8: MessageBox("Your computer hardware doesn't support the high-resolution performance counter",
9: "Not Support", MB_ICONEXCLAMATION | MB_OK);
10: LARGE_INTEGER test, ret;
11: test.QuadPart = frequence.QuadPart * m_dwTest / 1000000;
12: //通过频率换算微秒数到对应的数量(与CPU时钟有关),1秒=1000000微秒
13: //test 中存储着m_dwTest毫秒所需的次数
14: ret = MySleep( test ); //调用此函数开始延时,返回实际花销的数量
15: m_dwAct = (DWORD)(1000000 * ret.QuadPart / frequence.QuadPart ); //换算到微秒数
16: UpdateData(FALSE); //显示到对话框面板
17: }
1: LARGE_INTEGER CHightTimerDlg::MySleep(LARGE_INTEGER Interval)
2: ///////////////////////////////////////////////////////////////////////////////////////////////////
3: //////////
4: // 功能:执行实际的延时功能
5: // 参数:Interval 参数为需要执行的延时与时间有关的数量
6: // 返回值:返回此函数执行后实际所用的时间有关的数量
7: ///////////////////////////////////////////////////////////////////////////////////////////////////
8: ////////
9: {
10: LARGE_INTEGER privious, current, Elapse;
11: QueryPerformanceCounter( &privious );
12: current = privious;
13: while( current.QuadPart - privious.QuadPart < Interval.QuadPart )
14: QueryPerformanceCounter( &t );
15: Elapse.QuadPart = current.QuadPart - privious.QuadPart;
16: return Elapse;
17: }
注:别忘了在头文件中为此函数添加函数声明。
至此,可以编译和执行此工程了,当测试时间超过3微秒时,准确度已经非常高了,此时机器执行本身延时函数代码的时间对需要延时的时间影响很小了。
上面的函数由于演示测试的需要,没有在函数级封装,下面给出的函数基本上可以以全局函数的形式照搬到别的程序中。
1: BOOL MySleep(DWORD dwInterval)
2: ///////////////////////////////////////////////////////////////////////////////////////////////////
3: //////////
4: // 功能:执行微秒级的延时功能
5: // 参数:Interval 参数为需要的延时数(单位:微秒)
6: // 返回值:若计算机硬件不支持此功能,返回FALSE,若函数执行成功,返回TRUE
7: ///////////////////////////////////////////////////////////////////////////////////////////////////
8: ////////
9: {
10: BOOL bNormal = TRUE;
11: LARGE_INTEGER frequence, privious, current, interval;
12: if(!QueryPerformanceFrequency( &frequence))
13: {
14: ::MessageBox(NULL, "Your computer hardware doesn't support the high-resolution performance
15: counter", "Not Support", MB_ICONEXCLAMATION | MB_OK); //或其它的提示信息
16: return FALSE;
17: }
18: interval.QuadPart = frequence.QuadPart * dwInterval / 1000000;
19: bNormal = bNormal && QueryPerformanceCounter( &privious );
20: current = privious;
21: while( current.QuadPart - privious.QuadPart < interval.QuadPart )
22: bNormal = bNormal && QueryPerformanceCounter( &t );
23: return bNormal;
24: }
需要指出的是,由于在此函数中的代码很多,机器在执行这些代码所花费的时间也很长,所以在需要几个微秒的
延时时,会影响精度。实际上,读者在熟悉这种方法后,只要使用QueryPerformanceFrequency和QueryPerforman
ceCounter这两个函数就能按实际需要写出自己的延时代码了。
一个计算时间的类:
1: // Elapsed.h: interface for the CElapsed class.
2: //
3: //////////////////////////////////////////////////////////////////////
4:
5: #if !defined(AFX_ELAPSED_H__4A992E21_8B47_11D6_B1B2_FFFCE130B010__INCLUDED_)
6: #define AFX_ELAPSED_H__4A992E21_8B47_11D6_B1B2_FFFCE130B010__INCLUDED_
7:
8: #if _MSC_VER > 1000
9: #pragma once
10: #endif // _MSC_VER > 1000
11:
12: class CElapsed
13: {
14: private:
15: int Initialized;
16: __int64 Frequency;
17: __int64 BeginTime;
18:
19: public:
20: BOOL Avaliable();
21: double End();
22: BOOL Begin();
23: CElapsed();
24: virtual ~CElapsed();
25: };
26:
27: #endif // !defined(AFX_ELAPSED_H__4A992E21_8B47_11D6_B1B2_FFFCE130B010__INCLUDED_)
28:
29:
30:
31: // Elapsed.cpp: implementation of the CElapsed class.
32: //
33: //////////////////////////////////////////////////////////////////////
34:
35: #include "stdafx.h"
36: //#include "myimage.h"
37: #include "Elapsed.h"
38:
39: #ifdef _DEBUG
40: #undef THIS_FILE
41: static char THIS_FILE[]=__FILE__;
42: #define new DEBUG_NEW
43: #endif
44:
45: //////////////////////////////////////////////////////////////////////
46: // Construction/Destruction
47: //////////////////////////////////////////////////////////////////////
48:
49: CElapsed::CElapsed()
50: {
51: Initialized=QueryPerformanceFrequency((LARGE_INTEGER *)&Frequency);
52: }
53:
54: CElapsed::~CElapsed()
55: {
56:
57: }
58:
59: BOOL CElapsed::Begin()
60: {
61: if(!Initialized)
62: return 0;
63: return QueryPerformanceCounter((LARGE_INTEGER *)&BeginTime);
64: }
65:
66: double CElapsed::End()
67: {
68: if(!Initialized)
69: return 0;
70: __int64 endtime;
71: QueryPerformanceCounter((LARGE_INTEGER *)&endtime);
72:
73: __int64 elapsed=endtime-BeginTime;
74:
75: return (double)elapsed/(double)Frequency;
76: }
77: BOOL CElapsed::Avaliable()
78: {
79: return Initialized;
80: }