1. 程式人生 > >C和C++中的計時器

C和C++中的計時器

ons 計數 函數返回 void 結構 命令 msdn ear trie

  在我們調試代碼的時候,很多時候需要用代碼的運行時間來衡量代碼的效率,看了網上已經有了很多關於計時的文章,自己學習的時候再進行一些整理吧。

1. time()函數 

  在頭文件time.h中,time()獲取當前的系統時間,只能精確到秒,返回的結果是一個time_t類型,其使用方法如下:

#include <time.h>   
#include <stdio.h>   

int main() {  
     time_t first, second;  
     first=time(NULL);  
     delay(2000);  
     second
=time(NULL); printf("The difference is: %f seconds",difftime(second,first)); //調用difftime求出時間差 return 0; }

2. clock()函數

  在頭文件time.h中,clock()函數返回從“開啟這個程序進程”到“程序中調用clock()函數”時之間的CPU時鐘計時單元(clock tick)數,在MSDN中稱之為掛鐘時間(wal-clock),常量CLOCKS_PER_SEC,它用來表示一秒鐘會有多少個時鐘計時單元,精確到毫秒,其使用方法如下:

#include<time.h>
#include
<stdio.h> int main() { double dur; clock_t start,end; start = clock(); foo();//dosomething end = clock(); dur = (double)(end - start); printf("Use Time:%f\n",(dur/CLOCKS_PER_SEC)); }

3.timeGetTime()函數(Windows API

  以毫秒計的系統時間,該時間為從系統開啟算起所經過的時間。在使用timeGetTime之前應先包含頭文件#include <Mmsystem.h>或#include <Windows.h>並在project->settings->link->Object/library modules中添加winmm.lib。也可以在文件頭部添加 #pragma comment( lib,"winmm.lib" )。

備註:命令行:#pragma comment( lib,"xxx.lib" )時預編譯處理指令,讓vc將winmm.lib添加到工程中去進行編譯。

#include<stdio.h>
#include<windows.h>

#pragma comment( lib,"winmm.lib" )

int main()
{
    DWORD t1, t2;
    t1 = timeGetTime();
    foo();//do something
    t2 = timeGetTime();
    printf("Use Time:%f\n", (t2 - t1)*1.0 / 1000);
    return 0;
}

   該函數的時間精度是五毫秒或更大一些,這取決於機器的性能。可用timeBeginPeriod和timeEndPeriod函數提高timeGetTime函數的精度。如果使用了,連續調用timeGetTime函數,一系列返回值的差異由timeBeginPeriod和timeEndPeriod決定。也可以用timeGetTime實現延時功能Delay

void Delay(DWORD delayTime)
{
  DWORD delayTimeBegin;
  DWORD delayTimeEnd;
  delayTimeBegin=timeGetTime();
  do
  {
    delayTimeEnd
=timeGetTime();
  }
while((delayTimeEnd-delayTimeBegin)<delayTime) }

4.QueryPerformanceCounter()函數和QueryPerformanceFrequency()函數(Windows API)

  QueryPerformanceFrequency()函數返回高精確度性能計數器的值,它可以以微妙為單位計時,但是QueryPerformanceCounter()確切的精確計時的最小單位是與系統有關的,所以,必須要查詢系統以得到QueryPerformanceCounter()返回的嘀噠聲的頻率。QueryPerformanceFrequency()提供了這個頻率值,返回每秒嘀噠聲的個數。

#include<stdio.h>
#include<windows.h>
#pragma comment( lib,"winmm.lib" )

int main()
{
    LARGE_INTEGER t1, t2, tc;
    QueryPerformanceFrequency(&tc);
    QueryPerformanceCounter(&t1);
    foo();//do something
    QueryPerformanceCounter(&t2);
    printf("Use Time:%f\n", (t2.QuadPart - t1.QuadPart)*1.0 / tc.QuadPart);
    return 0;
}

5.GetTickCount()函數(Windows API)

  GetTickCount返回(retrieve)從操作系統啟動所經過(elapsed)的毫秒數,它的返回值是DWORD。

#include<stdio.h>
#include<windows.h>
#pragma comment( lib,"winmm.lib" )

int main()
{
    DWORD t1, t2;
    t1 = GetTickCount();
    foo;//do something
    t2 = GetTickCount();
    printf("Use Time:%f\n", (t2 - t1)*1.0 / 1000);
    return 0;
}

6.RDTSC指令(Windows)

  在Intel Pentium以上級別的CPU中,有一個稱為“時間戳(Time Stamp)”的部件,它以64位無符號整型數的格式,記錄了自CPU上電以來所經過的時鐘周期數。由於目前的CPU主頻都非常高,因此這個部件可以達到納秒級的計時精度。這個精確性是上述幾種方法所無法比擬的.在Pentium以上的CPU中,提供了一條機器指令RDTSC(Read Time Stamp Counter)來讀取這個時間戳的數字,並將其保存在EDX:EAX寄存器對中。由於EDX:EAX寄存器對恰好是Win32平臺下C++語言保存函數返回值的寄存器,所以我們可以把這條指令看成是一個普通的函數調用,因為RDTSC不被C++的內嵌匯編器直接支持,所以我們要用_emit偽指令直接嵌入該指令的機器碼形式0X0F、0X31。

inline unsigned __int64 GetCycleCount()
{
    __asm
    {
        _emit 0x0F;
        _emit 0x31;
    }
}

void test6()
{
    unsigned long t1,t2;
    t1 = (unsigned long)GetCycleCount();
    foo();//dosomething
    t2 = (unsigned long)GetCycleCount();
    printf("Use Time:%f\n",(t2 - t1)*1.0/FREQUENCY);   //FREQUENCY指CPU的頻率
}

獲取CPU頻率參考:http://blog.csdn.net/kofandlizi/article/details/6253801

7.gettimeofday() (Linux)

//timeval結構定義為:
struct timeval
{   
long tv_sec; /**/   long tv_usec; /*微秒*/ };
//timezone 結構定義為: struct timezone
{   
int tz_minuteswest; /*和Greenwich 時間差了多少分鐘*/   int tz_dsttime; /*日光節約時間的狀態*/ };
void test() { struct timeval t1,t2; double timeuse; gettimeofday(&t1,NULL); foo(); gettimeofday(&t2,NULL); timeuse = t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec)/1000000.0; printf("Use Time:%f\n",timeuse); }

8.RDTSC指令計時(Linux)

#if defined (__i386__)
static __inline__ unsigned long long GetCycleCount(void)
{
        unsigned long long int x;
        __asm__ volatile("rdtsc":"=A"(x));
        return x;
}
#elif defined (__x86_64__)
static __inline__ unsigned long long GetCycleCount(void)
{
        unsigned hi,lo;
        __asm__ volatile("rdtsc":"=a"(lo),"=d"(hi));
        return ((unsigned long long)lo)|(((unsigned long long)hi)<<32);
}
#endif

void test8()
{
        unsigned long t1,t2;
        t1 = (unsigned long)GetCycleCount();
        foo();//dosomething
        t2 = (unsigned long)GetCycleCount();
        printf("Use Time:%f\n",(t2 - t1)*1.0/FREQUENCY); //FREQUENCY  CPU的頻率
}

9.GetSystemTime / GetLocalTime(Windows)

  Windows SDK 中有兩個精確到毫秒的獲取當前時間的函數:

    GetSystemTime:獲取 UTC 時間。

    GetLocalTime:獲取當地時間。

  這兩個函數的返回都是:SYSTEMTIME ,結構體占用了 16 個字節,它的定義如下:

typedef struct _SYSTEMTIME {
  WORD wYear;
  WORD wMonth;
  WORD wDayOfWeek;
  WORD wDay;
  WORD wHour;
  WORD wMinute;
  WORD wSecond;
  WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME;
// GetSystemTime.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <Windows.h>

int _tmain(void)
{
    SYSTEMTIME utc_time = { 0 };
    SYSTEMTIME local_time = { 0 };

    GetSystemTime(&utc_time);
    GetLocalTime(&local_time);
    _tprintf(_T("The UTC time is \t: %02d:%02d:%02d.%03d\n"), utc_time.wHour, utc_time.wMinute, utc_time.wSecond, utc_time.wMilliseconds);
    _tprintf(_T("The local time is\t: %02d:%02d:%02d.%03d\n"), local_time.wHour, local_time.wMinute, local_time.wSecond, local_time.wMilliseconds);
    return 0;
}


10.GetSystemTimeAsFileTime

  究竟能不能達到 100 納秒的精確度呢?在 Windows SDK 中有一個結構體:FILETIME,它可以記錄精度達到 100ns 的時間。用哪個函數得到這個值呢?可以用 GetSystemTimeAsFileTime。但是,不要高興得太早,雖

然 FILETIME 能夠達到如此高的精度,但是這個函數我連試都懶得試。為什麽呢?因為 Windows 系統並不是一個實時操作系統(Windows Embedded Compact 2013 是一個實時系統),其時鐘精度一般認為是 15 ~ 16 毫秒。

Windows Sysinternals 給我們提供了一個查看你使用的 Windows 系統的時鐘分辨率的小工具:ClockRes v2.0。把它下載下來在控制臺中執行,結果如下:

技術分享

看到了吧。死心了吧。所以說,用 GetSystemTime / GetLocalTime 就已經很好了。如果要獲得真正毫秒級甚至更高精度的當前系統時間,必須跟 CPU 打交道,別無它法。先貼出代碼吧:

#ifdef _WIN32
#include <windows.h>
#else
#include <time.h>
#endif  // _WIND32


// 定義64位整形
#if defined(_WIN32) && !defined(CYGWIN)
typedef __int64 int64_t;
#else
typedef long long int64t;
#endif  // _WIN32

// 獲取系統的當前時間,單位微秒(us)
int64_t GetSysTimeMicros()
{
#ifdef _WIN32
// 從1601年1月1日0:0:0:000到1970年1月1日0:0:0:000的時間(單位100ns)
#define EPOCHFILETIME   (116444736000000000UL)
    FILETIME ft;
    LARGE_INTEGER li;
    int64_t tt = 0;
    GetSystemTimeAsFileTime(&ft);
    li.LowPart = ft.dwLowDateTime;
    li.HighPart = ft.dwHighDateTime;
    // 從1970年1月1日0:0:0:000到現在的微秒數(UTC時間)
    tt = (li.QuadPart - EPOCHFILETIME) /10;
    return tt;
#else
    timeval tv;
    gettimeofday(&tv, 0);
    return (int64_t)tv.tv_sec * 1000000 + (int64_t)tv.tv_usec;
#endif // _WIN32
    return 0;
}

參考資料:http://blog.csdn.net/luoweifu/article/details/51325432

http://blog.csdn.net/yapingxin/article/details/49466223

http://www.cnblogs.com/leven20061001/archive/2012/11/08/2760126.html

C和C++中的計時器