C ++ kullanarak nano saniyede zaman sağlamak için zamanlayıcı işlevi


101

Bir API'nin bir değer döndürmesi için geçen süreyi hesaplamak istiyorum. Böyle bir eylem için harcanan zaman nano saniye alanındadır. API bir C ++ sınıfı / işlevi olduğundan, aynı şeyi hesaplamak için timer.h'yi kullanıyorum:

  #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;
  }

Yukarıdaki kod, zamanı saniye cinsinden verir. Aynı şeyi nano saniyelerde ve daha hassas bir şekilde nasıl elde ederim?


yukarıdaki kod saniyeler içinde hesaplanıyor, cevabı nano saniyede almak istiyorum ...
gagneet

İyi bir cevap almak için platformu soruya (ve tercihen başlığa da) eklemeniz gerekir.
Patrick Johnmeyer

Zamanın elde edilmesine ek olarak, mikro kıyaslama ile ilgili sorunlara bakılması gerekir (ki bu son derece karmaşıktır) - sadece tek bir yürütme yapmak ve zamanı başlangıçta ve sonunda almak yeterli hassasiyet vermeyecektir.
Blaisorblade

@Blaisorblade: Özellikle bazı testlerimde clock()düşündüğüm kadar hızlı olmadığını keşfettiğim için.
Mooing Duck

Yanıtlar:


83

Başkalarının işlevi bir döngüde tekrar tekrar çalıştırma hakkında yazdıkları doğrudur.

Linux (ve BSD) için clock_gettime () kullanmak istiyorsunuz .

#include <sys/time.h>

int main()
{
   timespec ts;
   // clock_gettime(CLOCK_MONOTONIC, &ts); // Works on FreeBSD
   clock_gettime(CLOCK_REALTIME, &ts); // Works on Linux
}

Windows için QueryPerformanceCounter'ı kullanmak istiyorsunuz . Ve işte QPC hakkında daha fazlası

Görünüşe göre bazı yonga setlerinde QPC ile ilgili bilinen bir sorun var, bu yüzden bu yonga setine sahip olmadığınızdan emin olmak isteyebilirsiniz. Ek olarak bazı çift çekirdekli AMD'ler de soruna neden olabilir . Sebbbi'nin söylediği ikinci gönderiye bakın:

QueryPerformanceCounter () ve QueryPerformanceFrequency () biraz daha iyi çözünürlük sunar, ancak farklı sorunları vardır. Örneğin, Windows XP'de, sorunu çözmek için özel olarak AMD çift çekirdekli sürücü paketini kurmadığınız sürece, tüm AMD Athlon X2 çift çekirdekli CPU'lar, çekirdeklerden herhangi birinin PC'sini "rasgele" olarak geri döndürür (PC bazen biraz geriye atlar). Benzer sorunları olan başka bir çift + çekirdekli CPU görmedik (p4 dual, p4 ht, core2 dual, core2 quad, phenom quad).

DÜZENLEME 2013/07/16:

Http://msdn.microsoft.com/en-us/library/windows/desktop/ee417693(v=vs.85).aspx adresinde belirtildiği gibi belirli koşullar altında QPC'nin etkinliği konusunda bazı tartışmalar var gibi görünüyor.

... QueryPerformanceCounter ve QueryPerformanceFrequency tipik olarak birden fazla işlemci için ayarlanırken, BIOS veya sürücülerdeki hatalar, iş parçacığı bir işlemciden diğerine geçerken bu rutinlerin farklı değerler döndürmesine neden olabilir ...

Ancak bu StackOverflow yanıtı https://stackoverflow.com/a/4588605/34329 QPC'nin Win XP servis paketi 2'den sonra herhangi bir MS işletim sisteminde düzgün çalışması gerektiğini belirtir.

Bu makale, Windows 7'nin işlemcilerin değişmeyen bir TSC'ye sahip olup olmadığını belirleyebileceğini ve yoksa harici bir zamanlayıcıya geri döndüğünü göstermektedir. http://performancebydesign.blogspot.com/2012/03/high-resolution-clocks-and-timers-for.html İşlemciler arasında senkronizasyon hala bir sorundur.

Zamanlayıcılarla ilgili diğer ince okumalar:

Daha fazla ayrıntı için yorumlara bakın.


1
TSC saatinin eski bir çift Xeon PC'de çarpık olduğunu gördüm, ancak C1 saat rampası etkinleştirilmiş Athlon X2'deki kadar kötü değil. C1 saat rampası ile, bir HLT talimatının yürütülmesi saati yavaşlatır ve boş çekirdeklerdeki TSC'nin aktif çekirdeklerden daha yavaş artmasına neden olur.
bk1e

6
CLOCK_MONOTONIC, sahip olduğum Linux sürümlerinde çalışıyor.
Bernard

1
@Bernard - Buna en son baktığımdan beri yeni eklenmiş olmalı. Söylediğin için teşekkürler.
grieve

3
Aslında, CLOCK_MONOTONIC_RAWNTP tarafından ayarlanmayan donanım zamanını elde etmek için, varsa, kullanmanız gerekir.

Burada tartışıldığı gibi, QPC'nin doğru uygulanması, en azından güvenilmez olduğu bilinen yerlerde TSC sayacını kullanmaz: stackoverflow.com/q/510462/53974
Blaisorblade

69

Bu yeni cevap C ++ 11'in <chrono>imkanını kullanır . Nasıl kullanılacağını gösteren başka cevaplar olsa da <chrono>, bunların hiçbiri buradaki diğer cevapların birçoğunda bahsedilen tesis <chrono>ile nasıl kullanılacağını göstermiyor RDTSC. Bu yüzden nasıl kullanılacağını göstermek düşündüm RDTSCile <chrono>. Ek olarak, saat üzerindeki test kodunu nasıl şablon haline getirebileceğinizi göstereceğim, böylece RDTSCsisteminizin yerleşik saat tesisleri arasında hızlı bir şekilde geçiş yapabilirsiniz (muhtemelen clock(), clock_gettime()ve / veya QueryPerformanceCounter.

Not o RDTSCtalimat x86 özeldir. QueryPerformanceCounteryalnızca Windows'dur. Ve clock_gettime()sadece POSIX. Aşağıda iki yeni saat tanıtıyorum: std::chrono::high_resolution_clockve std::chrono::system_clock, eğer C ++ 11'i varsayabilirseniz, artık platformlar arası.

İlk olarak, Intel rdtscmontaj talimatından C ++ 11 uyumlu bir saati nasıl oluşturacağınız aşağıda açıklanmıştır . Ben onu arayacağım 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

Bu saatin tek yaptığı CPU döngülerini saymak ve onu işaretsiz 64 bitlik bir tamsayıda saklamaktır. Derleyiciniz için assembly dili sözdizimini ayarlamanız gerekebilir. Veya derleyiciniz bunun yerine kullanabileceğiniz bir intrinsic sunabilir (örn. now() {return __rdtsc();}).

Bir saat inşa etmek için ona gösterimi (depolama türü) vermelisiniz. Ayrıca, makineniz farklı güç modlarında saat hızını değiştirebilse de, derleme zamanı sabiti olması gereken saat periyodunu da sağlamalısınız. Ve bunlardan, saatinizin "yerel" zaman süresini ve zaman noktasını bu temeller açısından kolayca tanımlayabilirsiniz.

Tek yapmak istediğiniz saat tiklerinin sayısını çıkarmaksa, saat periyodu için hangi sayıyı verdiğiniz önemli değildir. Bu sabit, yalnızca saat tiklerinin sayısını nanosaniye gibi gerçek zamanlı birime dönüştürmek istiyorsanız devreye girer. Ve bu durumda, saat hızını ne kadar doğru sağlayabiliyorsanız, nanosaniyeye dönüştürme o kadar doğru olacaktır (milisaniye, her neyse).

Aşağıda nasıl kullanılacağını gösteren örnek kod bulunmaktadır x::clock. Aslında, aynı sözdizimiyle birçok farklı saati nasıl kullanabileceğinizi göstermek istediğim için saatin kodunu şablon haline getirdim. Bu özel test, bir döngü altında zamanlamak istediğiniz şeyi çalıştırırken döngü ek yükünün ne olduğunu gösteriyor:

#include <iostream>

template <class clock>
void
test_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";
}

Bu kodun yaptığı ilk şey, sonuçları görüntülemek için "gerçek zamanlı" bir birim oluşturmaktır. Pikosaniyeleri seçtim, ancak integral veya kayan nokta tabanlı istediğiniz herhangi bir birimi seçebilirsiniz. Örnek olarak std::chrono::nanosecondskullanmış olabileceğim önceden yapılmış bir birim var.

Başka bir örnek olarak, yineleme başına ortalama saat döngüsü sayısını bir kayan nokta olarak yazdırmak istiyorum, bu nedenle, saatin onay işaretiyle aynı birimlere sahip ( Cyclekodda çağrılır ) çifte dayalı başka bir süre oluşturuyorum .

Döngü, clock::now()her iki taraftaki çağrılarla zamanlanır . Bu işlevden döndürülen türü adlandırmak isterseniz:

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

( x::clockörnekte açıkça gösterildiği gibi ve sistem tarafından sağlanan saatler için de geçerlidir).

Kayan noktalı saat tikleri cinsinden bir süre elde etmek için, kişi yalnızca iki zaman noktasını çıkarır ve yineleme başına değeri elde etmek için bu süreyi yineleme sayısına bölün.

count()Üye işlevini kullanarak istediğiniz süre içinde sayıyı alabilirsiniz . Bu, dahili gösterimi döndürür. Sonunda kullanmak std::chrono::duration_castsüresini dönüştürmek Cyclesüresine picosecondsve bu out yazdırın.

Bu kodu kullanmak basittir:

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>();
}

Yukarıda, testi ev yapımı makinemizi kullanarak yapıyorum x::clockve bu sonuçları sistem tarafından sağlanan iki saati kullanarak karşılaştırıyorum: std::chrono::high_resolution_clockve std::chrono::system_clock. Benim için bu çıktı:

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

Bu, bu saatlerin her birinin farklı bir tıklama periyoduna sahip olduğunu gösterir, çünkü yineleme başına tik sayısı her saat için büyük ölçüde farklıdır. Ancak bilinen bir zaman birimine dönüştürüldüğünde (örneğin pikosaniye), her saat için yaklaşık olarak aynı sonucu alıyorum (kilometreniz değişebilir).

Kodumun nasıl tamamen "sihirli dönüşüm sabitleri" içermediğine dikkat edin. Aslında, tüm örnekte yalnızca iki sihirli sayı vardır:

  1. Tanımlamak için makinemin saat hızı x::clock.
  2. Üzerinde test edilecek yineleme sayısı. Bu sayıyı değiştirmek sonuçlarınızın büyük ölçüde değişmesine neden oluyorsa, muhtemelen yineleme sayısını artırmanız veya test sırasında bilgisayarınızı rakip süreçlerden boşaltmanız gerekir.

5
"RDTSC yalnızca Intel’dir" derken, gerçekten x86 mimarisine ve türevlerine atıfta bulunuyorsunuz, değil mi? AMD, Cyrix, Transmeta x86 yongalarında talimat var ve Intel RISC ve ARM işlemcileri yok.
Ben Voigt

1
@BenVoigt: +1 Evet, düzeltmeniz oldukça doğru, teşekkür ederim.
Howard Hinnant

1
CPU daraltma bunu nasıl etkileyecek? İşlemci yüküne göre saat hızı değişmiyor mu?
Tejas Kale

@TejasKale: Bu, "Bir saat inşa etmek için ..." ile başlayan ardışık iki paragrafın cevabında açıklanmaktadır. Tipik olarak zamanlama kodu, bir iş parçacığını engelleyen işi ölçmez (ama yapabilir). Ve bu nedenle tipik olarak CPU'nuz yavaşlamaz. Ancak uyku, muteks kilidi, koşul_değişken bekleme, vb. İçeren kodu ölçüyorsanız, rdtscsaatin diğer birimlere yanlış dönüşümleri olması muhtemeldir. Saatleri kolayca değiştirip karşılaştırabilmeniz için ölçümlerinizi ayarlamak iyi bir fikirdir (bu cevapta gösterildiği gibi).
Howard Hinnant

28

Bu doğruluk seviyesi ile, clock () gibi sistem çağrısı yerine CPU tick ile mantık yürütmek daha iyi olacaktır . Ve unutmayın ki bir komutu yürütmek bir nanosaniyeden fazla sürerse ... nanosaniye doğruluğuna sahip olmak neredeyse imkansızdır.

Yine de böyle bir şey bir başlangıç:

İşte CPU'nun son başlatılmasından bu yana geçen 80x86 CPU saat işaretlerinin sayısını almak için gerçek kod. Pentium ve üzerinde çalışacaktır (386/486 desteklenmez). Bu kod aslında MS Visual C ++ 'ya özgüdür, ancak satır içi derlemeyi desteklediği sürece başka herhangi bir şeye muhtemelen çok kolay taşınabilir.

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);

}

Bu işlev aynı zamanda son derece hızlı olma avantajına da sahiptir - çalıştırmak için genellikle en fazla 50 cpu döngüsü gerekir.

Zamanlama Şekillerini Kullanma :
Saat sayılarını gerçek geçen zamana çevirmeniz gerekiyorsa, sonuçları çipinizin saat hızına bölün. Unutmayın ki "derecelendirilmiş" GHz çipinizin gerçek hızından muhtemelen biraz farklı olacaktır. Çipinizin gerçek hızını kontrol etmek için, çok iyi birkaç yardımcı program veya Win32 çağrısı, QueryPerformanceFrequency () kullanabilirsiniz.


bilgi için teşekkürler, bu yararlıdır. zamanı hesaplamak için cpu döngülerini düşünmemiştim, bunun akılda tutulması gereken çok iyi bir nokta olduğunu düşünüyorum :-)
gagneet

4
TSC sayılarını geçen süreye dönüştürmek için QueryPerformanceFrequency () kullanmak işe yaramayabilir. QueryPerformanceCounter (), mevcut olduğunda Vista'da HPET'i (Yüksek Hassasiyetli Olay Zamanlayıcısı) kullanır. Kullanıcı boot.ini dosyasına / USEPMTIMER eklerse ACPI güç yönetimi zamanlayıcısını kullanır.
bk1e

23

Bunu doğru bir şekilde yapmak için iki yoldan birini kullanabilirsiniz, birlikte RDTSCveya ile clock_gettime(). İkincisi yaklaşık 2 kat daha hızlıdır ve doğru mutlak zamanı verme avantajına sahiptir. Not Bunun için RDTSC(bu sayfadaki Diğer yorumlar hatalar var ve bazı işlemciler üzerinde yanlış zamanlama değerleri verebilir) şeklinde belirtilen işin doğru bunu kullanmak gerekir

inline uint64_t rdtsc()
{
    uint32_t lo, hi;
    __asm__ __volatile__ (
      "xorl %%eax, %%eax\n"
      "cpuid\n"
      "rdtsc\n"
      : "=a" (lo), "=d" (hi)
      :
      : "%ebx", "%ecx" );
    return (uint64_t)hi << 32 | lo;
}

ve clock_gettime için: (rastgele mikrosaniye çözünürlüğü seçtim)

#include <time.h>
#include <sys/timeb.h>
// needs -lrt (real-time lib)
// 1970-01-01 epoch UTC time, 1 mcs resolution (divide by 1M to get time_t)
uint64_t ClockGetTime()
{
    timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    return (uint64_t)ts.tv_sec * 1000000LL + (uint64_t)ts.tv_nsec / 1000LL;
}

üretilen zamanlama ve değerler:

Absolute values:
rdtsc           = 4571567254267600
clock_gettime   = 1278605535506855

Processing time: (10000000 runs)
rdtsc           = 2292547353
clock_gettime   = 1031119636

22

İstenilen sonuçları elde etmek için aşağıdakileri kullanıyorum:

#include <time.h>
#include <iostream>
using namespace std;

int main (int argc, char** argv)
{
    // reset the clock
    timespec tS;
    tS.tv_sec = 0;
    tS.tv_nsec = 0;
    clock_settime(CLOCK_PROCESS_CPUTIME_ID, &tS);
    ...
    ... <code to check for the time to be put here>
    ...
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tS);
    cout << "Time taken is: " << tS.tv_sec << " " << tS.tv_nsec << endl;

    return 0;
}

2
Olumsuz oy verdim çünkü bu kodu uygulamaya çalışırken ilk önce neden zaman belirtiminin tanımlanmadığını Google'a bildirmek zorunda kaldım. Sonra POSIX ne olduğunu google'da aradım ... ve anladığım kadarıyla, bu kod standart kitaplığa neyin bağlı kalacağı Windows kullanıcıları için geçerli değil.
Daniel Katz

8

İçin C ++ 11 , burada basit bir sarıcı:

#include <iostream>
#include <chrono>

class Timer
{
public:
    Timer() : beg_(clock_::now()) {}
    void reset() { beg_ = clock_::now(); }
    double elapsed() const {
        return std::chrono::duration_cast<second_>
            (clock_::now() - beg_).count(); }

private:
    typedef std::chrono::high_resolution_clock clock_;
    typedef std::chrono::duration<double, std::ratio<1> > second_;
    std::chrono::time_point<clock_> beg_;
};

Veya * nix üzerinde C ++ 03 için,

class Timer
{
public:
    Timer() { clock_gettime(CLOCK_REALTIME, &beg_); }

    double elapsed() {
        clock_gettime(CLOCK_REALTIME, &end_);
        return end_.tv_sec - beg_.tv_sec +
            (end_.tv_nsec - beg_.tv_nsec) / 1000000000.;
    }

    void reset() { clock_gettime(CLOCK_REALTIME, &beg_); }

private:
    timespec beg_, end_;
};

Kullanım örneği:

int main()
{
    Timer tmr;
    double t = tmr.elapsed();
    std::cout << t << std::endl;

    tmr.reset();
    t = tmr.elapsed();
    std::cout << t << std::endl;
    return 0;
}

Gönderen https://gist.github.com/gongzhitaao/7062087


5

Genel olarak, bir işlevi çağırmanın ne kadar sürdüğünü zamanlamak için, bunu birden çok kez yapmak istersiniz. Fonksiyonunuzu yalnızca bir kez çağırırsanız ve çalışması çok kısa bir süre alırsa, hala zamanlayıcı fonksiyonlarını çağırmanın ek yüküne sahipsiniz ve bunun ne kadar sürdüğünü bilmiyorsunuz.

Örneğin, işlevinizin çalışmasının 800 ns alacağını tahmin ediyorsanız, onu bir döngüde on milyon kez çağırın (bu, yaklaşık 8 saniye sürecektir). Arama başına süreyi öğrenmek için toplam süreyi on milyona bölün.


Aslında, belirli bir arama için API'nin performansını almaya çalışıyorum. her çalıştırma için farklı bir süre verebilir, bu performans iyileştirmesi için yaptığım grafiği etkileyebilir ... dolayısıyla süre nano saniye cinsinden. ama evet, bu harika bir fikir, dikkate alacağım.
gagneet

5

X86 işlemcileri altında çalışan gcc ile aşağıdaki işlevi kullanabilirsiniz:

unsigned long long rdtsc()
{
  #define rdtsc(low, high) \
         __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))

  unsigned int low, high;
  rdtsc(low, high);
  return ((ulonglong)high << 32) | low;
}

Digital Mars C ++ ile:

unsigned long long rdtsc()
{
   _asm
   {
        rdtsc
   }
}

çip üzerindeki yüksek performanslı zamanlayıcıyı okur. Profil oluştururken bunu kullanıyorum.


2
bu yararlı, işlemcinin x86 olup olmadığını kontrol edeceğim, çünkü deney için bir apple mac kullanıyorum ... teşekkürler :-)
gagneet

1
Kullanıcının yüksek ve düşük için hangi değerleri vermesi gerekiyor? Neden bir fonksiyonun gövdesi içinde bir makro tanımlıyorsunuz? Ayrıca, muhtemelen işaretsiz uzun uzun yazılan çok uzun, standart bir tür değildir. Bunu kullanmak isterdim ama nasıl olduğundan emin değilim;)
Joseph Garvin

1
unsigned long, linux altında kullanılacak doğru şey değildir. Hem uzun hem de uzun, 64 bit Linux'ta 64 bit olduğu için bunun yerine int kullanmayı düşünebilirsiniz.
Marius

3
TSC sayacı günümüzde genellikle güvenilmezdir: frekans değiştirildiğinde birçok işlemcide hızını değiştirir ve farklı çekirdekler arasında tutarsızdır, bu nedenle TSC her zaman büyümez.
Blaisorblade

1
@Marius: Yorumunuzu unsigned intdahili tür olarak kullanarak uyguladım .
Blaisorblade

3

Bir saniyenin altında hassasiyete ihtiyacınız varsa, sisteme özgü uzantıları kullanmanız gerekir ve işletim sisteminin belgelerine bakmanız gerekir. POSIX, gettimeofday ile mikrosaniyeye kadar destekler , ancak bilgisayarların 1GHz'in üzerinde frekansları olmadığı için daha kesin bir şey yoktur.

Boost kullanıyorsanız, boost :: posix_time öğesini kontrol edebilirsiniz .


kodu taşınabilir tutmak istiyorum, destek kitaplığını görecek ve bunu kodla paketleyip paketleyemeyeceğimi kontrol edecek. teşekkürler :-)
gagneet

3

Burada Borland kodunu kullanıyorum ti_hund bana bazen negatif bir sayı veriyor ama zamanlama oldukça iyi.

#include <dos.h>

void main() 
{
struct  time t;
int Hour,Min,Sec,Hun;
gettime(&t);
Hour=t.ti_hour;
Min=t.ti_min;
Sec=t.ti_sec;
Hun=t.ti_hund;
printf("Start time is: %2d:%02d:%02d.%02d\n",
   t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund);
....
your code to time
...

// read the time here remove Hours and min if the time is in sec

gettime(&t);
printf("\nTid Hour:%d Min:%d Sec:%d  Hundreds:%d\n",t.ti_hour-Hour,
                             t.ti_min-Min,t.ti_sec-Sec,t.ti_hund-Hun);
printf("\n\nAlt Ferdig Press a Key\n\n");
getch();
} // end main

3

Brock Adams'ın yöntemini basit bir sınıfla kullanarak:

int get_cpu_ticks()
{
    LARGE_INTEGER ticks;
    QueryPerformanceFrequency(&ticks);
    return ticks.LowPart;
}

__int64 get_cpu_clocks()
{
    struct { int32 low, high; } counter;

    __asm cpuid
    __asm push EDX
    __asm rdtsc
    __asm mov counter.low, EAX
    __asm mov counter.high, EDX
    __asm pop EDX
    __asm pop EAX

    return *(__int64 *)(&counter);
}

class cbench
{
public:
    cbench(const char *desc_in) 
         : desc(strdup(desc_in)), start(get_cpu_clocks()) { }
    ~cbench()
    {
        printf("%s took: %.4f ms\n", desc, (float)(get_cpu_clocks()-start)/get_cpu_ticks());
        if(desc) free(desc);
    }
private:
    char *desc;
    __int64 start;
};

Kullanım Örneği:

int main()
{
    {
        cbench c("test");
        ... code ...
    }
    return 0;
}

Sonuç:

test yapıldı: 0.0002 ms

Bazı işlev çağrısı ek yükü var, ancak yine de yeterince hızlı olmalı :)


3

Sen kullanabilirsiniz Profiler Gömülü (a işlemci döngüsü sayısında) multiplatform zamanlayıcı bir arayüze sahiptir (Windows ve Linux için ücretsiz) ve size saniyede devri sayısını verebilir:

EProfilerTimer timer;
timer.Start();

... // Your code here

const uint64_t number_of_elapsed_cycles = timer.Stop();
const uint64_t nano_seconds_elapsed =
    mumber_of_elapsed_cycles / (double) timer.GetCyclesPerSecond() * 1000000000;

Döngü sayısının zamana göre yeniden hesaplanması, muhtemelen CPU frekansının dinamik olarak değiştirilebildiği modern işlemcilerde tehlikeli bir işlemdir. Bu nedenle, dönüştürülen sürelerin doğru olduğundan emin olmak için profil oluşturmadan önce işlemci frekansının düzeltilmesi gerekir.


2

Bu Linux içinse, Epoch'tan beri saniye ve mikrosaniye veren bir yapı döndüren "gettimeofday" işlevini kullanıyorum. Daha sonra zaman farkını elde etmek için ikisini çıkarmak ve istediğiniz zaman hassasiyetine dönüştürmek için timersub'ı kullanabilirsiniz. Bununla birlikte, nanosaniye belirtirsiniz ve aradığınız şey clock_gettime () işlevi gibi görünür . Zamanı, içine girdiğiniz yapıya saniye ve nanosaniye cinsinden yerleştirir.


clock_gettime () şimdilik hile yapmalı. benim amacım için aynısını kullanmayı deneyeceğim ...
gagneet

2

Bunun hakkında ne düşünüyorsun:

    int iceu_system_GetTimeNow(long long int *res)
    {
      static struct timespec buffer;
      // 
    #ifdef __CYGWIN__
      if (clock_gettime(CLOCK_REALTIME, &buffer))
        return 1;
    #else
      if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &buffer))
        return 1;
    #endif
      *res=(long long int)buffer.tv_sec * 1000000000LL + (long long int)buffer.tv_nsec;
      return 0;
    }

2

İşte iyi çalışan güzel bir Boost zamanlayıcısı:

//Stopwatch.hpp

#ifndef STOPWATCH_HPP
#define STOPWATCH_HPP

//Boost
#include <boost/chrono.hpp>
//Std
#include <cstdint>

class Stopwatch
{
public:
    Stopwatch();
    virtual         ~Stopwatch();
    void            Restart();
    std::uint64_t   Get_elapsed_ns();
    std::uint64_t   Get_elapsed_us();
    std::uint64_t   Get_elapsed_ms();
    std::uint64_t   Get_elapsed_s();
private:
    boost::chrono::high_resolution_clock::time_point _start_time;
};

#endif // STOPWATCH_HPP


//Stopwatch.cpp

#include "Stopwatch.hpp"

Stopwatch::Stopwatch():
    _start_time(boost::chrono::high_resolution_clock::now()) {}

Stopwatch::~Stopwatch() {}

void Stopwatch::Restart()
{
    _start_time = boost::chrono::high_resolution_clock::now();
}

std::uint64_t Stopwatch::Get_elapsed_ns()
{
    boost::chrono::nanoseconds nano_s = boost::chrono::duration_cast<boost::chrono::nanoseconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(nano_s.count());
}

std::uint64_t Stopwatch::Get_elapsed_us()
{
    boost::chrono::microseconds micro_s = boost::chrono::duration_cast<boost::chrono::microseconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(micro_s.count());
}

std::uint64_t Stopwatch::Get_elapsed_ms()
{
    boost::chrono::milliseconds milli_s = boost::chrono::duration_cast<boost::chrono::milliseconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(milli_s.count());
}

std::uint64_t Stopwatch::Get_elapsed_s()
{
    boost::chrono::seconds sec = boost::chrono::duration_cast<boost::chrono::seconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(sec.count());
}

2

Minimalist kopyala ve yapıştır yap + tembel kullanım

Fikir, hızlı testler için kullanabileceğiniz minimalist bir yapıya sahip olmaksa, o zaman C ++ dosyanızda 's' den hemen sonra herhangi bir yere kopyalayıp yapıştırmanızı öneririm #include. Bu, Allman tarzı biçimlendirmeyi feda ettiğim tek örnek.

Yapının ilk satırında hassasiyeti kolayca ayarlayabilirsiniz. Olası değerler şunlardır: nanoseconds, microseconds, milliseconds, seconds, minutes, veya hours.

#include <chrono>
struct MeasureTime
{
    using precision = std::chrono::microseconds;
    std::vector<std::chrono::steady_clock::time_point> times;
    std::chrono::steady_clock::time_point oneLast;
    void p() {
        std::cout << "Mark " 
                << times.size()/2
                << ": " 
                << std::chrono::duration_cast<precision>(times.back() - oneLast).count() 
                << std::endl;
    }
    void m() {
        oneLast = times.back();
        times.push_back(std::chrono::steady_clock::now());
    }
    void t() {
        m();
        p();
        m();
    }
    MeasureTime() {
        times.push_back(std::chrono::steady_clock::now());
    }
};

Kullanım

MeasureTime m; // first time is already in memory
doFnc1();
m.t(); // Mark 1: next time, and print difference with previous mark
doFnc2();
m.t(); // Mark 2: next time, and print difference with previous mark
doStuff = doMoreStuff();
andDoItAgain = doStuff.aoeuaoeu();
m.t(); // prints 'Mark 3: 123123' etc...

Standart çıktı sonucu

Mark 1: 123
Mark 2: 32
Mark 3: 433234

Yürütmeden sonra özet istiyorsanız

Daha sonra raporu isterseniz, örneğin aradaki kodunuz da standart çıktıya yazar. Ardından yapıya aşağıdaki işlevi ekleyin (MeasureTime () 'dan hemen önce):

void s() { // summary
    int i = 0;
    std::chrono::steady_clock::time_point tprev;
    for(auto tcur : times)
    {
        if(i > 0)
        {
            std::cout << "Mark " << i << ": "
                    << std::chrono::duration_cast<precision>(tprev - tcur).count()
                    << std::endl;
        }
        tprev = tcur;
        ++i;
    }
}

O zaman şunları kullanabilirsiniz:

MeasureTime m;
doFnc1();
m.m();
doFnc2();
m.m();
doStuff = doMoreStuff();
andDoItAgain = doStuff.aoeuaoeu();
m.m();
m.s();

Önceki gibi, ancak diğer kod çalıştırıldıktan sonra tüm işaretleri listeleyecektir. Her iki kullanmaması gerektiğini unutmayın m.s()ve m.t().


Ubuntu 16.04'te OpenMP ile mükemmel çalışır. Çok teşekkürler, bu en iyi cevap IMO olmalı!
Íhor Mé
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.