日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

C/C++獲取系統(tǒng)時(shí)間

 junshuai103 2015-01-12

網(wǎng)摘和自己整理的,所以分類為翻譯,請(qǐng)見諒。

不過當(dāng)計(jì)算算法耗時(shí)的時(shí)候,不要忘記second,不能只要用Milliseconds來減,不然后出現(xiàn)負(fù)值,若是算法耗時(shí)太長(zhǎng)就得用minutes啦。再不然,就hours……

//方案— 優(yōu)點(diǎn):僅使用C標(biāo)準(zhǔn)庫;缺點(diǎn):只能精確到秒級(jí)
#include <time.h> 
#include <stdio.h> 
int main( void ) 

    time_t t = time(0); 
    char tmp[64]; 
    strftime( tmp, sizeof(tmp), "%Y/%m/%d %X %A 本年第%j天 %z",localtime(&t) ); 
    puts( tmp ); 
    return 0; 
}
size_t strftime(char *strDest, size_t maxsize, const char *format, const struct tm *timeptr);
根據(jù)格式字符串生成字符串。
struct tm *localtime(const time_t *timer);
取得當(dāng)?shù)貢r(shí)間,localtime獲取的結(jié)果由結(jié)構(gòu)tm返回
返回的字符串可以依下列的格式而定:
%a 星期幾的縮寫。Eg:Tue 
%A 星期幾的全名。 Eg: Tuesday
%b 月份名稱的縮寫。 
%B 月份名稱的全名。 
%c 本地端日期時(shí)間較佳表示字符串。 
%d 用數(shù)字表示本月的第幾天 (范圍為 00 至 31)。日期
%H 用 24 小時(shí)制數(shù)字表示小時(shí)數(shù) (范圍為 00 至 23)。 
%I 用 12 小時(shí)制數(shù)字表示小時(shí)數(shù) (范圍為 01 至 12)。 
%j 以數(shù)字表示當(dāng)年度的第幾天 (范圍為 001 至 366)。 
%m 月份的數(shù)字 (范圍由 1 至 12)。
%M 分鐘。 
%p 以 ''AM'' 或 ''PM'' 表示本地端時(shí)間。 
%S 秒數(shù)。 
%U 數(shù)字表示為本年度的第幾周,第一個(gè)星期由第一個(gè)周日開始。 
%W 數(shù)字表示為本年度的第幾周,第一個(gè)星期由第一個(gè)周一開始。 
%w 用數(shù)字表示本周的第幾天 ( 0 為周日)。 
%x 不含時(shí)間的日期表示法。 
%X 不含日期的時(shí)間表示法。 Eg: 15:26:30
%y 二位數(shù)字表示年份 (范圍由 00 至 99)。 
%Y 完整的年份數(shù)字表示,即四位數(shù)。 Eg:2008
%Z(%z) 時(shí)區(qū)或名稱縮寫。Eg:中國標(biāo)準(zhǔn)時(shí)間 
%% % 字符。

//方案二 優(yōu)點(diǎn):能精確到毫秒級(jí);缺點(diǎn):使用了windows API 
#include <windows.h> 
#include <stdio.h> 
int main( void ) 

SYSTEMTIME sys; 
GetLocalTime( &sys ); 
printf( "%4d/%02d/%02d %02d:%02d:%02d.%03d 星期%1d\n",sys.wYear,sys.wMonth,sys.wDay,sys.wHour,sys.wMinute, sys.wSecond,sys.wMilliseconds,sys.wDayOfWeek); 
return 0;
}
//方案三,優(yōu)點(diǎn):利用系統(tǒng)函數(shù),還能修改系統(tǒng)時(shí)間
//此文件必須是c++文件
#include<stdlib.h>
#include<iostream>
using namespace std;
void main()
{
    system("time");
}
//方案四,將當(dāng)前時(shí)間折算為秒級(jí),再通過相應(yīng)的時(shí)間換算即可
//此文件必須是c++文件
#include<iostream>
#include<ctime>
using namespace std;
int main()
{
time_t now_time;
now_time = time(NULL);
cout<<now_time;
return 0;
}

//方案五,貌似這個(gè)也是兼容C/C++的

int64_t ts = systemTime(); 

打印時(shí)候使用%ld


====================================================================================================

C語言中如何獲取時(shí)間?精度如何?

1 使用time_t time( time_t * timer ) 精確到秒

2 使用clock_t clock() 得到的是CPU時(shí)間精確到1/CLOCKS_PER_SEC秒

3 計(jì)算時(shí)間差使用double difftime( time_t timer1, time_t timer0 )

4 使用DWORD GetTickCount() 精確到毫秒

5 如果使用MFC的CTime類,可以用CTime::GetCurrentTime() 精確到秒

6 要獲取高精度時(shí)間,可以使用

BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency)

獲取系統(tǒng)的計(jì)數(shù)器的頻率

BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount)

獲取計(jì)數(shù)器的值

然后用兩次計(jì)數(shù)器的差除以Frequency就得到時(shí)間。

7 Multimedia Timer Functions

The following functions are used with multimedia timers.

timeBeginPeriod/timeEndPeriod/timeGetDevCaps/timeGetSystemTime

//*********************************************************************

//用標(biāo)準(zhǔn)C實(shí)現(xiàn)獲取當(dāng)前系統(tǒng)時(shí)間的函數(shù)

 

一.time()函數(shù)

 

     time(&rawtime)函數(shù)獲取當(dāng)前時(shí)間距1970年1月1日的秒數(shù),以秒計(jì)數(shù)單位,存于rawtime 中。

#include "time.h"

void main ()

{

time_t rawtime;

struct tm * timeinfo;

time ( &rawtime );

timeinfo = localtime ( &rawtime );

printf ( "\007The current date/time is: %s", asctime (timeinfo) );

exit(0);

}

=================

#include -- 必須的時(shí)間函數(shù)頭文件

time_t -- 時(shí)間類型(time.h 定義是typedef long time_t; 追根溯源,time_t是long)

struct tm -- 時(shí)間結(jié)構(gòu),time.h 定義如下:

int tm_sec;

int tm_min;

int tm_hour;

int tm_mday;

int tm_mon;

int tm_year;

int tm_wday;

int tm_yday;

int tm_isdst;

time ( &rawtime ); -- 獲取時(shí)間,以秒計(jì),從1970年1月一日起算,存于rawtime

localtime ( &rawtime ); -- 轉(zhuǎn)為當(dāng)?shù)貢r(shí)間,tm 時(shí)間結(jié)構(gòu)

asctime ()-- 轉(zhuǎn)為標(biāo)準(zhǔn)ASCII時(shí)間格式:

星期 月 日 時(shí):分:秒 年

 

-----------------------------------------------------------------------------

二.clock()函數(shù),用clock()函數(shù),得到系統(tǒng)啟動(dòng)以后的毫秒級(jí)時(shí)間,然后除以CLOCKS_PER_SEC,就可以換成“秒”,標(biāo)準(zhǔn)c函數(shù)。

clock_t clock ( void );

#include

clock_t t = clock();

long sec = t / CLOCKS_PER_SEC;

他是記錄時(shí)鐘周期的,實(shí)現(xiàn)看來不會(huì)很精確,需要試驗(yàn)驗(yàn)證;

---------------------------------------------------------------------------

三.gettime(&t); 據(jù)說tc2.0的time結(jié)構(gòu)含有毫秒信息

#include

#include

int main(void)

{

struct time t;

gettime(&t);

printf("The current time is: -:d:d.d\n",

t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund);

return 0;

}

time 是一個(gè)結(jié)構(gòu)體,, 其中成員函數(shù) ti_hund 是毫秒。。。

 

--------------------------------------------------------------------------------

四.GetTickCount(),這個(gè)是windows里面常用來計(jì)算程序運(yùn)行時(shí)間的函數(shù);

DWORD dwStart = GetTickCount();

//這里運(yùn)行你的程序代碼

DWORD dwEnd = GetTickCount();

則(dwEnd-dwStart)就是你的程序運(yùn)行時(shí)間, 以毫秒為單位

這個(gè)函數(shù)只精確到55ms,1個(gè)tick就是55ms。

--------------------------------------------------------------------------------

五.timeGetTime()t,imeGetTime()基本等于GetTickCount(),但是精度更高

DWORD dwStart = timeGetTime();

//這里運(yùn)行你的程序代碼

DWORD dwEnd = timeGetTime();

則(dwEnd-dwStart)就是你的程序運(yùn)行時(shí)間, 以毫秒為單位

雖然返回的值單位應(yīng)該是ms,但傳說精度只有10ms。

=========================================

//*****************************************************************Unix

##unix時(shí)間相關(guān),也是標(biāo)準(zhǔn)庫的

//*********************************************************************

1.timegm函數(shù)只是將struct tm結(jié)構(gòu)轉(zhuǎn)成time_t結(jié)構(gòu),不使用時(shí)區(qū)信息;

time_t timegm(struct tm *tm);

2.mktime使用時(shí)區(qū)信息

time_t mktime(struct tm *tm);

timelocal 函數(shù)是GNU擴(kuò)展的與posix函數(shù)mktime相當(dāng)

time_t timelocal (struct tm *tm);

3.gmtime函數(shù)只是將time_t結(jié)構(gòu)轉(zhuǎn)成struct tm結(jié)構(gòu),不使用時(shí)區(qū)信息;

struct tm * gmtime(const time_t *clock);

4.localtime使用時(shí)區(qū)信息

struct tm * localtime(const time_t *clock);

1.time獲取時(shí)間,stime設(shè)置時(shí)間

time_t t;

t = time(&t);

2.stime其參數(shù)應(yīng)該是GMT時(shí)間,根據(jù)本地時(shí)區(qū)設(shè)置為本地時(shí)間;

int stime(time_t *tp)

3.UTC=true 表示采用夏時(shí)制;

4.文件的修改時(shí)間等信息全部采用GMT時(shí)間存放,不同的系統(tǒng)在得到修改時(shí)間后通過localtime轉(zhuǎn)換成本地時(shí)間;

5.設(shè)置時(shí)區(qū)推薦使用setup來設(shè)置;

6.設(shè)置時(shí)區(qū)也可以先更變/etc/sysconfig/clock中的設(shè)置再將ln -fs /usr/share/zoneinfo/xxxx/xxx /etc/localtime 才能重效

time_t只能表示68年的范圍,即mktime只能返回1970-2038這一段范圍的time_t

看看你的系統(tǒng)是否有time_t64,它能表示更大的時(shí)間范圍

//***************************************************************windows

##Window里面的一些不一樣的

//*********************************************************************

 

一.CTime () 類

VC編程一般使用CTime類 獲得當(dāng)前日期和時(shí)間

 

CTime t = GetCurrentTime();

SYSTEMTIME 結(jié)構(gòu)包含毫秒信息

typedef struct _SYSTEMTIME {

WORD wYear;

WORD wMonth;

WORD wDayOfWeek;

WORD wDay;

WORD wHour;

WORD wMinute;

WORD wSecond;

WORD wMilliseconds;

} SYSTEMTIME, *PSYSTEMTIME;

SYSTEMTIME t1;

GetSystemTime(&t1)

CTime curTime(t1);

WORD ms = t1.wMilliseconds;

SYSTEMTIME sysTm;

::GetLocalTime(&sysTm);

在time.h中的_strtime() //只能在windows中用

char t[11];

_strtime(t);

puts(t);

 

//*****************************

獲得當(dāng)前日期和時(shí)間

CTime tm=CTime::GetCurrentTime();

CString str=tm.Format("%Y-%m-%d");

在VC中,我們可以借助CTime時(shí)間類,獲取系統(tǒng)當(dāng)前日期,具體使用方法如下:

CTime t = CTime::GetCurrentTime(); //獲取系統(tǒng)日期,存儲(chǔ)在t里面

int d=t.GetDay(); //獲得當(dāng)前日期

int y=t.GetYear(); //獲取當(dāng)前年份

int m=t.GetMonth(); //獲取當(dāng)前月份

int h=t.GetHour(); //獲取當(dāng)前為幾時(shí)

int mm=t.GetMinute(); //獲取當(dāng)前分鐘

int s=t.GetSecond(); //獲取當(dāng)前秒

int w=t.GetDayOfWeek(); //獲取星期幾,注意1為星期天,7為星期六

 

二.CTimeSpan類

如果想計(jì)算兩段時(shí)間的差值,可以使用CTimeSpan類,具體使用方法如下:

CTime t1( 1999, 3, 19, 22, 15, 0 );

CTime t = CTime::GetCurrentTime();

CTimeSpan span=t-t1; //計(jì)算當(dāng)前系統(tǒng)時(shí)間與時(shí)間t1的間隔

int iDay=span.GetDays(); //獲取這段時(shí)間間隔共有多少天

int iHour=span.GetTotalHours(); //獲取總共有多少小時(shí)

int iMin=span.GetTotalMinutes();//獲取總共有多少分鐘

int iSec=span.GetTotalSeconds();//獲取總共有多少秒

 

 

------------------------------------------------------------------------------

 

三._timeb()函數(shù)

_timeb定義在SYS\TIMEB.H,有四個(gè)fields

dstflag

millitm

time

timezone

void _ftime( struct _timeb *timeptr );

struct _timeb timebuffer;

_ftime( &timebuffer );

取當(dāng)前時(shí)間:文檔講可以到ms,有人測(cè)試,好象只能到16ms!

 

 

四.設(shè)置計(jì)時(shí)器

定義TIMER ID

#define TIMERID_JISUANFANGSHI 2

在適當(dāng)?shù)牡胤皆O(shè)置時(shí)鐘,需要開始其作用的地方;

SetTimer(TIMERID_JISUANFANGSHI,200,NULL);

在不需要定時(shí)器的時(shí)候的時(shí)候銷毀掉時(shí)鐘

KillTimer(TIMERID_JISUANFANGSHI);

對(duì)應(yīng)VC程序的消息映射

void CJisuan::OnTimer(UINT nIDEvent)

{switch(nIDEvent)}

---------------------------------------------------------------------------------------

##如何設(shè)定當(dāng)前系統(tǒng)時(shí)間---------------------------------------windows

SYSTEMTIME m_myLocalTime,*lpSystemTime;

m_myLocalTime.wYear=2003;

m_myLocalTime.wM;

m_myLocalTime.wDay=1;

m_myLocalTime.wHour=0;

m_myLocalTime.wMinute=0;

m_myLocalTime.wSec;

m_myLocalTime.wMillisec;

lpSystemTime=&m_myLocalTime;

if( SetLocalTime(lpSystemTime) ) //此處換成 SetSystemTime( )也不行

MessageBox("OK !");

else

MessageBox("Error !");

SYSTEMTIME m_myLocalTime,*lpSystemTime;

m_myLocalTime.wYear=2003;

m_myLocalTime.wM;

m_myLocalTime.wDay=1;

lpSystemTime=&m_myLocalTime;

if( SetDate(lpSystemTime) ) //此處換成 SetSystemTime( )也不行

MessageBox("OK !");

else

MessageBox("Error !");

 

本文來自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/khuang2008/archive/2008/12/09/3483274.aspx

 

一種制作微秒級(jí)精度定時(shí)器的方法

當(dāng)使用定時(shí)器時(shí),在很多情況下只用到毫秒級(jí)的時(shí)間間隔,所以只需用到下面的兩種常用方式就滿足要求了。一是用SetTimer函數(shù)建立一個(gè)定時(shí)器后,在程序中通過處理由定時(shí)器發(fā)送到線程消息隊(duì)列中的WM_TIMER消息,而得到定時(shí)的效果(退出程序時(shí)別忘了調(diào)用和SetTimer配對(duì)使用的KillTimer函數(shù))。二是利用GetTickCount函數(shù)可以返回自計(jì)算機(jī)啟動(dòng)后的時(shí)間,通過兩次調(diào)用GetTickCount函數(shù),然后控制它們的差值來取得定時(shí)效果,此方式跟第一種方式一樣,精度也是毫秒級(jí)的。

用這兩種方式取得的定時(shí)效果雖然在許多場(chǎng)合已經(jīng)滿足實(shí)際的要求,但由于它們的精度只有毫秒級(jí)的,而且在要求定時(shí)時(shí)間間隔小時(shí),實(shí)際定時(shí)誤差大。下面介紹一種能取得高精度定時(shí)的方法。

在一些計(jì)算機(jī)硬件系統(tǒng)中,包含有高精度運(yùn)行計(jì)數(shù)器(high-resolution   performance   counter),利用它可以獲得高精度定時(shí)間隔,其精度與CPU的時(shí)鐘頻率有關(guān)。采用這種方法的步驟如下:

1、首先調(diào)用QueryPerformanceFrequency函數(shù)取得高精度運(yùn)行計(jì)數(shù)器的頻率f。單位是每秒多少次(n/s),此數(shù)一般很大。

2、在需要定時(shí)的代碼的兩端分別調(diào)用QueryPerformanceCounter以取得高精度運(yùn)行計(jì)數(shù)器的數(shù)值n1,n2。兩次數(shù)值的差值通過f換算成時(shí)間間隔,t=(n2-n1)/f。

下面舉一個(gè)例子來演示這種方法的使用及它的精確度。

在VC   6.0   下用MFC建立一個(gè)對(duì)話框工程,取名為HightTimer.在對(duì)話框面板中控件的布局如下圖:

其中包含兩個(gè)靜態(tài)文本框,兩個(gè)編輯框和兩個(gè)按紐。上面和下面位置的編輯框的ID分別為IDC_E_TEST和IDC_E_ACTUAL,通過MFC  ClassWizard添加的成員變量也分別對(duì)應(yīng)為DWORD   m_dwTest和DWORD   m_dwAct.   “退出”按紐的ID為IDOK,“開始測(cè)試”按紐ID為IDC_B_TEST,用MFC   ClassWizard添加此按紐的單擊消息處理函數(shù)如下:

void   CHightTimerDlg::OnBTest()

{

//   TODO:   Add   your   control   notification   handler   code   here

UpdateData(TRUE);   //取輸入的測(cè)試時(shí)間值到與編輯框相關(guān)聯(lián)的成員變量m_dwTest中

  

LARGE_INTEGER   frequence;

if(!QueryPerformanceFrequency(   &frequence))   //取高精度運(yùn)行計(jì)數(shù)器的頻率,若硬件不支持則返回FALSE

MessageBox("Your   computer   hardware   doesn't   support   the   high-resolution   performance   counter",

"Not   Support",   MB_ICONEXCLAMATION   |   MB_OK);

 

LARGE_INTEGER   test,   ret;

test.QuadPart   =   frequence.QuadPart   *   m_dwTest   /   1000000;   //通過頻率換算微秒數(shù)到對(duì)應(yīng)的數(shù)量(與CPU時(shí)鐘有關(guān)),1秒=1000000微秒

ret   =   MySleep(   test   );   //調(diào)用此函數(shù)開始延時(shí),返回實(shí)際花銷的數(shù)量

 

m_dwAct   =   (DWORD)(1000000   *   ret.QuadPart   /   frequence.QuadPart   );   //換算到微秒數(shù)

 

UpdateData(FALSE);   //顯示到對(duì)話框面板

}

   其中上面調(diào)用的MySleep函數(shù)如下:

 

LARGE_INTEGER   CHightTimerDlg::MySleep(LARGE_INTEGER   Interval)

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

//   功能:執(zhí)行實(shí)際的延時(shí)功能     
//   參數(shù):Interval   參數(shù)為需要執(zhí)行的延時(shí)與時(shí)間有關(guān)的數(shù)量     
//   返回值:返回此函數(shù)執(zhí)行后實(shí)際所用的時(shí)間有關(guān)的數(shù)量     
///////////////////////////////////////////////////////////////////////////////////////////////////////////

  

LARGE_INTEGER   privious,   current,   Elapse;

 

QueryPerformanceCounter(   &privious   );

current   =   privious;

 

while(   current.QuadPart   -   privious.QuadPart   <   Interval.QuadPart   )

QueryPerformanceCounter(   ¤t   );

 

Elapse.QuadPart   =   current.QuadPart   -   privious.QuadPart;

 

return   Elapse;

}

注:別忘了在頭文件中為此函數(shù)添加函數(shù)聲明。

 

至此,可以編譯和執(zhí)行此工程了,結(jié)果如上圖所示。在本人所用的機(jī)上(奔騰366,   64M內(nèi)存)測(cè)試,當(dāng)測(cè)試時(shí)間超過3微秒時(shí),準(zhǔn)確度已經(jīng)非常高了,此時(shí)機(jī)器執(zhí)行本身延時(shí)函數(shù)代碼的時(shí)間對(duì)需要延時(shí)的時(shí)間影響很小了。

 

上面的函數(shù)由于演示測(cè)試的需要,沒有在函數(shù)級(jí)封裝,下面給出的函數(shù)基本上可以以全局函數(shù)的形式照搬到別的程序中。

 

BOOL   MySleep(DWORD   dwInterval)

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

//   功能:執(zhí)行微秒級(jí)的延時(shí)功能     
//   參數(shù):Interval   參數(shù)為需要的延時(shí)數(shù)(單位:微秒)     
//   返回值:若計(jì)算機(jī)硬件不支持此功能,返回FALSE,若函數(shù)執(zhí)行成功,返回TRUE     
///////////////////////////////////////////////////////////////////////////////////////////////////////////  

{

BOOL   bNormal   =   TRUE;

LARGE_INTEGER   frequence,   privious,   current,   interval;

 

if(!QueryPerformanceFrequency(   &frequence))

{

::MessageBox(NULL,   "Your   computer   hardware   doesn't   support   the   high-resolution   performance  counter",

"Not   Support",   MB_ICONEXCLAMATION   |   MB_OK);   //或其它的提示信息

return   FALSE;

}

 

interval.QuadPart   =   frequence.QuadPart   *   dwInterval   /   1000000;

 

bNormal   =   bNormal   &&   QueryPerformanceCounter(   &privious   );

current   =   privious;

 

while(   current.QuadPart   -   privious.QuadPart   <   interval.QuadPart   )

bNormal   =   bNormal   &&   QueryPerformanceCounter(   ¤t   );

 

return   bNormal;

}

 

需要指出的是,由于在此函數(shù)中的代碼很多,機(jī)器在執(zhí)行這些代碼所花費(fèi)的時(shí)間也很長(zhǎng),所以在需要幾個(gè)微秒的延時(shí)時(shí),會(huì)影響精度。實(shí)際上,讀者在熟悉這種方法后,只要使用QueryPerformanceFrequency和QueryPerformanceCounter這兩個(gè)函數(shù)就能按實(shí)際需要寫出自己的延時(shí)代碼了。

 

使用CPU時(shí)間戳進(jìn)行高精度計(jì)時(shí)

對(duì)關(guān)注性能的程序開發(fā)人員而言,一個(gè)好的計(jì)時(shí)部件既是益友,也是良師。計(jì)時(shí)器既可以作為程序組件幫助程序員精確的控制程序進(jìn)程,又是一件有力的調(diào)試武器,在有經(jīng)驗(yàn)的程序員手里可以盡快的確定程序的性能瓶頸,或者對(duì)不同的算法作出有說服力的性能比較。

 

在Windows平臺(tái)下,常用的計(jì)時(shí)器有兩種,一種是timeGetTime多媒體計(jì)時(shí)器,它可以提供毫秒級(jí)的計(jì)時(shí)。但這個(gè)精度對(duì)很多應(yīng)用場(chǎng)合而言還是太粗糙了。另一種是QueryPerformanceCount計(jì)數(shù)器,隨系統(tǒng)的不同可以提供微秒級(jí)的計(jì)數(shù)。對(duì)于實(shí)時(shí)圖形處理、多媒體數(shù)據(jù)流處理、或者實(shí)時(shí)系統(tǒng)構(gòu)造的程序員,善用QueryPerformanceCount/QueryPerformanceFrequency是一項(xiàng)基本功。

 

本文要介紹的,是另一種直接利用Pentium   CPU內(nèi)部時(shí)間戳進(jìn)行計(jì)時(shí)的高精度計(jì)時(shí)手段。以下討論主要得益于《Windows圖形編程》一書,第15頁-17頁,有興趣的讀者可以直接參考該書。關(guān)于RDTSC指令的詳細(xì)討論,可以參考Intel產(chǎn)品手冊(cè)。本文僅僅作拋磚之用。

 

在Intel   Pentium以上級(jí)別的CPU中,有一個(gè)稱為“時(shí)間戳(Time   Stamp)”的部件,它以64位無符號(hào)整型數(shù)的格式,記錄了自CPU上電以來所經(jīng)過的時(shí)鐘周期數(shù)。由于目前的CPU主頻都非常高,因此這個(gè)部件可以達(dá)到納秒級(jí)的計(jì)時(shí)精度。這個(gè)精確性是上述兩種方法所無法比擬的。

 

在Pentium以上的CPU中,提供了一條機(jī)器指令RDTSC(Read   Time   Stamp   Counter)來讀取這個(gè)時(shí)間戳的數(shù)字,并將其保存在EDX:EAX寄存器對(duì)中。由于EDX:EAX寄存器對(duì)恰好是Win32平臺(tái)下C++語言保存函數(shù)返回值的寄存器,所以我們可以把這條指令看成是一個(gè)普通的函數(shù)調(diào)用。像這樣:

 

inline   unsigned   __int64   GetCycleCount()

 

__asm   RDTSC  

 

 

但是不行,因?yàn)镽DTSC不被C++的內(nèi)嵌匯編器直接支持,所以我們要用_emit偽指令直接嵌入該指令的機(jī)器碼形式0X0F、0X31,如下:

 

inline   unsigned   __int64   GetCycleCount()   
  
    __asm   _emit   0x0F   
    __asm   _emit   0x31   
  
    
以后在需要計(jì)數(shù)器的場(chǎng)合,可以像使用普通的Win32   API一樣,調(diào)用兩次GetCycleCount函數(shù),比較兩個(gè)返回值的差,像這樣:   
    
unsigned   long   t;   
  =   (unsigned   long)GetCycleCount();   
//Do   Something   time-intensive   ...   
  -=   (unsigned   long)GetCycleCount();   
    
  《Windows圖形編程》第15頁編寫了一個(gè)類,把這個(gè)計(jì)數(shù)器封裝起來。有興趣的讀者可以去參考那個(gè)類的代碼。作者為了更精確的定時(shí),做了一點(diǎn)小小的改進(jìn),把執(zhí)行RDTSC指令的時(shí)間,通過連續(xù)兩次調(diào)用GetCycleCount函數(shù)計(jì)算出來并保存了起來,以后每次計(jì)時(shí)結(jié)束后,都從實(shí)際得到的計(jì)數(shù)中減掉這一小段時(shí)間,以得到更準(zhǔn)確的計(jì)時(shí)數(shù)字。但我個(gè)人覺得這一點(diǎn)點(diǎn)改進(jìn)意義不大。在我的機(jī)器上實(shí)測(cè),這條指令大概花掉了幾十到100多個(gè)周期,在Celeron   800MHz的機(jī)器上,這不過是十分之一微秒的時(shí)間。對(duì)大多數(shù)應(yīng)用來說,這點(diǎn)時(shí)間完全可以忽略不計(jì);而對(duì)那些確實(shí)要精確到納秒數(shù)量級(jí)的應(yīng)用來說,這個(gè)補(bǔ)償也過于粗糙了。   
    
這個(gè)方法的優(yōu)點(diǎn)是:   
    
1.高精度??梢灾苯舆_(dá)到納秒級(jí)的計(jì)時(shí)精度(在1GHz的CPU上每個(gè)時(shí)鐘周期就是一納秒),這是其他計(jì)時(shí)方法所難以企及的。   
    
2.成本低。timeGetTime   函數(shù)需要鏈接多媒體庫winmm.lib,QueryPerformance*   函數(shù)根據(jù)MSDN的說明,需要硬件的支持(雖然我還沒有見過不支持的機(jī)器)和KERNEL庫的支持,所以二者都只能在Windows平臺(tái)下使用(關(guān)于DOS平臺(tái)下的高精度計(jì)時(shí)問題,可以參考《圖形程序開發(fā)人員指南》,里面有關(guān)于控制定時(shí)器8253的詳細(xì)說明)。但RDTSC指令是一條CPU指令,凡是i386平臺(tái)下Pentium以上的機(jī)器均支持,甚至沒有平臺(tái)的限制(我相信i386版本UNIX和Linux下這個(gè)方法同樣適用,但沒有條件試驗(yàn)),而且函數(shù)調(diào)用的開銷是最小的。   
    
3.具有和CPU主頻直接對(duì)應(yīng)的速率關(guān)系。一個(gè)計(jì)數(shù)相當(dāng)于1/(CPU主頻Hz數(shù))秒,這樣只要知道了CPU的主頻,可以直接計(jì)算出時(shí)間。這和QueryPerformanceCount不同,后者需要通過QueryPerformanceFrequency獲取當(dāng)前計(jì)數(shù)器每秒的計(jì)數(shù)次數(shù)才能換算成時(shí)間。   
    
這個(gè)方法的缺點(diǎn)是:   
    
1.現(xiàn)有的C/C++編譯器多數(shù)不直接支持使用RDTSC指令,需要用直接嵌入機(jī)器碼的方式編程,比較麻煩。   
    
2.數(shù)據(jù)抖動(dòng)比較厲害。其實(shí)對(duì)任何計(jì)量手段而言,精度和穩(wěn)定性永遠(yuǎn)是一對(duì)矛盾。如果用低精度的timeGetTime來計(jì)時(shí),基本上每次計(jì)時(shí)的結(jié)果都是相同的;而RDTSC指令每次結(jié)果都不一樣,經(jīng)常有幾百甚至上千的差距。這是這種方法高精度本身固有的矛盾。   
    
關(guān)于這個(gè)方法計(jì)時(shí)的最大長(zhǎng)度,我們可以簡(jiǎn)單的用下列公式計(jì)算:   
    
自CPU上電以來的秒數(shù)   =   RDTSC讀出的周期數(shù)   /   CPU主頻速率(Hz)   
    
64位無符號(hào)整數(shù)所能表達(dá)的最大數(shù)字是1.8×10^19,在我的Celeron   800上可以計(jì)時(shí)大約700年(書中說可以在200MHz的Pentium上計(jì)時(shí)117年,這個(gè)數(shù)字不知道是怎么得出來的,與我的計(jì)算有出入)。無論如何,我們大可不必關(guān)心溢出的問題。   
    
下面是幾個(gè)小例子,簡(jiǎn)要比較了三種計(jì)時(shí)方法的用法與精度   
    
//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函數(shù)   
//需包含<mmsys.h>,但由于Windows頭文件錯(cuò)綜復(fù)雜的關(guān)系   
//簡(jiǎn)單包含<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函數(shù)   
//編譯行: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));   
  
    
////////////////////////////////////////////////   
//以上三個(gè)示例程序都是測(cè)試1秒鐘休眠所耗費(fèi)的時(shí)間   
file://測(cè)/試環(huán)境:Celeron   800MHz   /   256M   SDRAM       
//                     Windows   2000   Professional   SP2   
//                     Microsoft   Visual   C++   6.0   SP5   
////////////////////////////////////////////////   
    
以下是Timer1的運(yùn)行結(jié)果,使用的是高精度的RDTSC指令   
Lasting   Time:   804586872   
    
以下是Timer2的運(yùn)行結(jié)果,使用的是最粗糙的timeGetTime   API   
Begin   Time:   20254254   
End   Time:   20255255   
Lasting   Time:   1001   
    
以下是Timer3的運(yùn)行結(jié)果,使用的是QueryPerformanceCount   API   
Frequency:   3579545   
Begin   Time:   3804729124   
End   Time:   3808298836   
Lasting   Time:   3569712  


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多