亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用C+提供以納米秒為單位的時間的計時器功能

使用C+提供以納米秒為單位的時間的計時器功能

C++ C
飲歌長嘯 2019-06-25 13:32:08
使用C+提供以納米秒為單位的時間的計時器功能我希望計算API返回值所需的時間。這種行動所需的時間是在納米秒的空間內。由于API是一個C+類/函數,所以我使用timer.h來計算相同的內容:  #include <ctime>   #include <cstdio>   using namespace std;   int main(int argc, char** argv) {       clock_t start;       double diff;       start = clock();       diff = ( std::clock() - start ) / (double)CLOCKS_PER_SEC;       cout<<"printf: "<< diff <<'\n';       return 0;   }以上代碼以秒為單位給出了時間。如何在納米秒內以更高的精度獲得相同的結果?
查看完整描述

3 回答

?
慕尼黑5688855

TA貢獻1848條經驗 獲得超2個贊

這個新的答案使用C+11的。<chrono>設施。雖然還有其他的答案可以說明如何使用<chrono>,它們都沒有顯示如何使用<chrono>帶著RDTSC其他幾個答案中提到的設施。所以我想我應該展示如何使用RDTSC帶著<chrono>..此外,我將演示如何在時鐘上臨時編寫測試代碼,以便您可以在RDTSC和你的系統內置的時鐘設施(這很可能是基于clock()clock_gettime()和/或QueryPerformanceCounter.

注意,RDTSC指令是x86特定的。QueryPerformanceCounter只適用于Windows。和clock_gettime()僅限POSIX。下面我介紹兩個新的時鐘:std::chrono::high_resolution_clockstd::chrono::system_clock,如果您可以假設C+11,則現在是跨平臺的。

首先,下面是如何從Intel中創建一個與C+11兼容的時鐘。rdtsc裝配指令。我就叫它x::clock:

#include <chrono>namespace x{struct clock{
    typedef unsigned long long                 rep;
    typedef std::ratio<1, 2'800'000'000>       period; // My machine is 2.8 GHz
    typedef std::chrono::duration<rep, period> duration;
    typedef std::chrono::time_point<clock>     time_point;
    static const bool is_steady =              true;

    static time_point now() noexcept
    {
        unsigned lo, hi;
        asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
        return time_point(duration(static_cast<rep>(hi) << 32 | lo));
    }
};

}  // x

這個時鐘所做的就是計算CPU周期,并將其存儲在一個無符號64位整數中。您可能需要調整編譯器的匯編語言語法。或者您的編譯器可能提供一個您可以使用的內部特性(例如:now() {return __rdtsc();}).

要構建一個時鐘,您必須給它表示(存儲類型)。您還必須提供時鐘周期,這必須是一個編譯時間常數,即使您的機器可能改變不同的電源模式下的時鐘速度。根據這些基本原理,您可以很容易地定義您的時鐘的“本地”時間持續時間和時間點。

如果你想要做的只是輸出時鐘滴答的數量,那么你給出的時鐘周期是多少并不重要。只有當您想將時鐘滴答的數量轉換為一些實時單位(例如納秒)時,這個常數才會起作用。在這種情況下,你能提供的時鐘速度越精確,轉換到納秒(毫秒,隨便什么)的精度就越高。

下面是示例代碼,演示如何使用x::clock..實際上,我已經對時鐘上的代碼進行了模板化,因為我想向您展示如何用完全相同的語法使用許多不同的時鐘。這個特殊的測試顯示了在循環下運行所需時間時的循環開銷是什么:

#include <iostream>template <class clock>voidtest_empty_loop(){
    // Define real time units
    typedef std::chrono::duration<unsigned long long, std::pico> picoseconds;
    // or:
    // typedef std::chrono::nanoseconds nanoseconds;
    // Define double-based unit of clock tick
    typedef std::chrono::duration<double, typename clock::period> Cycle;
    using std::chrono::duration_cast;
    const int N = 100000000;
    // Do it
    auto t0 = clock::now();
    for (int j = 0; j < N; ++j)
        asm volatile("");
    auto t1 = clock::now();
    // Get the clock ticks per iteration
    auto ticks_per_iter = Cycle(t1-t0)/N;
    std::cout << ticks_per_iter.count() << " clock ticks per iteration\n";
    // Convert to real time units
    std::cout << duration_cast<picoseconds>(ticks_per_iter).count()
              << "ps per iteration\n";}

這段代碼所做的第一件事就是創建一個“實時”單元來顯示結果。我選擇了皮秒,但是你可以選擇任何你喜歡的單位,無論是積分還是基于浮點。舉個例子,有一個預先制作的std::chrono::nanoseconds我可以用的單位。

作為另一個例子,我希望以浮點數的形式打印出每次迭代的平均時鐘周期數,因此我創建了另一個基于Double的持續時間,它具有與時鐘的刻度相同的單位(稱為Cycle在代碼中)。

循環是通過調用clock::now()兩邊都有。如果要命名此函數返回的類型,則如下所示:

typename clock::time_point t0 = clock::now();

(如x::clock例如,也適用于系統提供的時鐘)。

要獲得以浮點時鐘為單位的持續時間,只需減去兩個時間點,而要獲得每一個迭代值,則將持續時間除以迭代次數。

屬性可以在任何時間內獲取計數。count()成員函數這將返回內部表示。最后我用std::chrono::duration_cast若要轉換持續時間,請執行以下操作Cycle持續時間picoseconds打印出來。

使用此代碼很簡單:

int main(){
    std::cout << "\nUsing rdtsc:\n";
    test_empty_loop<x::clock>();

    std::cout << "\nUsing std::chrono::high_resolution_clock:\n";
    test_empty_loop<std::chrono::high_resolution_clock>();

    std::cout << "\nUsing std::chrono::system_clock:\n";
    test_empty_loop<std::chrono::system_clock>();}

以上我是用我們自制的測試來練習的。x::clock,并將這些結果與使用兩個系統提供的時鐘的結果進行比較:std::chrono::high_resolution_clockstd::chrono::system_clock..對我來說這是打印出來的:

Using rdtsc:
1.72632 clock ticks per iteration
616ps per iteration

Using std::chrono::high_resolution_clock:
0.620105 clock ticks per iteration
620ps per iteration

Using std::chrono::system_clock:
0.00062457 clock ticks per iteration
624ps per iteration

這表明每個時鐘都有一個不同的刻度周期,因為每個時鐘的每一次迭代的滴答數都有很大的不同。然而,當轉換為一個已知的時間單位(例如,皮秒),我得到了大約相同的結果,每個時鐘(您的里程可能有所不同)。

請注意,我的代碼完全沒有“神奇的轉換常量”。實際上,整個示例中只有兩個神奇的數字:

  1. 我的機器的時鐘速度來定義

    x::clock.

  2. 要測試的迭代次數。如果更改這個數目會使結果有很大差異,那么您可能應該提高迭代次數,或者在測試時清空計算機上的競爭進程。


查看完整回答
反對 回復 2019-06-25
?
慕沐林林

TA貢獻2016條經驗 獲得超9個贊

有了這樣的精確度,最好是在cpu滴答中進行推理,而不是在系統調用中進行推理。像鐘()..別忘了,如果執行一條指令需要超過一納秒.擁有納秒精度幾乎是不可能的。

不過,差不多吧是一個開始:

以下是檢索自CPU上次啟動以來傳遞的80x86 CPU時鐘滴答號的實際代碼。它將在奔騰及以上領域開展工作(386/486沒有得到支持)。這段代碼實際上是特定于MSVisualC+的,但是只要它支持內聯程序集,它可能很容易移植到其他任何東西。

inline __int64 GetCpuClocks(){

    // Counter
    struct { int32 low, high; } counter;

    // Use RDTSC instruction to get clocks count
    __asm push EAX
    __asm push EDX
    __asm __emit 0fh __asm __emit 031h // RDTSC
    __asm mov counter.low, EAX
    __asm mov counter.high, EDX
    __asm pop EDX
    __asm pop EAX    // Return result
    return *(__int64 *)(&counter);}

這個函數還具有非??斓膬烖c-它通常不需要超過50個CPU周期來執行。

使用計時圖:
如果您需要將時鐘計數轉換為真正經過的時間,請將結果除以芯片的時鐘速度。記住,“額定”GHz很可能與你的芯片的實際速度略有不同。要檢查芯片的真實速度,可以使用幾個非常好的實用程序或Win 32調用QueryPerformanceFrequy()。


查看完整回答
反對 回復 2019-06-25
  • 3 回答
  • 0 關注
  • 798 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號