C ++ 'da bir Kod Parçacığının Yürütme Süresini Hesaplama


121

Saniyeler içinde bir C ++ kod parçacığının yürütme zamanını hesaplamalıyım. Windows veya Unix makinelerde çalışıyor olmalıdır.

Bunu yapmak için aşağıdaki kodu kullanıyorum. (daha önce içe aktar)

clock_t startTime = clock();
// some code here
// to compute its execution duration in runtime
cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << endl;

Ancak küçük girdiler veya a = a + 1 gibi kısa ifadeler için "0 saniye" sonucu alıyorum. Sanırım 0.0000001 saniye veya bunun gibi bir şey olmalı.

System.nanoTime()Java'nın bu durumda oldukça iyi çalıştığını hatırlıyorum . Ancak clock()C ++ işlevinden aynı işlevselliği elde edemiyorum .

Bir çözümün var mı?


29
İşletim sisteminin baştan sona kadar iş parçacığınızı iyi bir şekilde çalıştırmayabileceği gerçeği nedeniyle herhangi bir zaman farkına dayalı karşılaştırmanın yanlış olabileceğini unutmayın. Onu kesintiye uğratabilir ve sizinkiyle iç içe geçmiş diğer konuları çalıştırabilir, bu da işleminizi tamamlamak için geçen gerçek süre üzerinde önemli bir etkiye sahip olacaktır. Birden çok kez çalıştırabilir ve sonuçların ortalamasını alabilirsiniz; çalışan diğer işlemlerin sayısını en aza indirebilirsiniz. Ancak bunların hiçbiri iplik askıya alma etkisini tamamen ortadan kaldırmaz.
Mordachai

14
Mordachi, neden onu ortadan kaldırmak isteyesin? İpliklerin hiçbir zaman kesintiye uğramadığı büyülü bir dünyada değil, gerçek dünya ortamında işlevinizin nasıl performans gösterdiğini görmek istiyorsunuz. Birkaç kez çalıştırdığınız ve bir ortalama yaptığınız sürece çok doğru olacaktır.
Thomas Bonini

Evet, birkaç kez çalıştırıyorum ve sonuçları ortalama.
AhmetB - Google

14
Andreas, Mordachai'nin yorumu, OP, kodunun performansını farklı bir algoritma ile karşılaştırmak istiyorsa alakalı. Örneğin, bu öğleden sonra birkaç saat testi çalıştırır ve ardından yarın sabah farklı bir algoritma test ederse, kaynakları öğleden sonra sabaha kıyasla çok daha fazla işlemle paylaşıyor olabileceğinden karşılaştırması güvenilir olmayabilir. Ya da belki bir kod seti, işletim sisteminin ona daha az işlem süresi vermesine neden olur. Zamana dayalı bir karşılaştırma yapmak istiyorsa, bu tür performans ölçümünün güvenilmez olmasının birçok nedeni vardır.
weberc2

4
@Mordachai Eski bir yoruma yanıt verdiğimi biliyorum, ancak bunu benim yaptığım gibi tökezleyen herkes için - algoritmaların performansına göre, ortalama değil, minimum birkaç çalıştırma yapmak istersiniz. Bu, işletim sistemi tarafından en az kesintiye uğrayan ve bu yüzden çoğunlukla kodunuzun zamanlaması.
Baruch

Yanıtlar:


115

Yazdığım bu fonksiyonu kullanabilirsiniz. Siz çağırırsınız GetTimeMs64()ve sistem saatini kullanarak unix döneminden bu yana geçen milisaniye sayısını döndürür - tıpkı time(NULL)milisaniye dışında olduğu gibi .

Hem Windows hem de linux üzerinde çalışır; iş parçacığı güvenlidir.

Windows'ta ayrıntı düzeyinin 15 ms olduğunu unutmayın; linux üzerinde uygulamaya bağlıdır, ancak genellikle 15 ms'dir.

#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#include <ctime>
#endif

/* Remove if already defined */
typedef long long int64; typedef unsigned long long uint64;

/* Returns the amount of milliseconds elapsed since the UNIX epoch. Works on both
 * windows and linux. */

uint64 GetTimeMs64()
{
#ifdef _WIN32
 /* Windows */
 FILETIME ft;
 LARGE_INTEGER li;

 /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
  * to a LARGE_INTEGER structure. */
 GetSystemTimeAsFileTime(&ft);
 li.LowPart = ft.dwLowDateTime;
 li.HighPart = ft.dwHighDateTime;

 uint64 ret = li.QuadPart;
 ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
 ret /= 10000; /* From 100 nano seconds (10^-7) to 1 millisecond (10^-3) intervals */

 return ret;
#else
 /* Linux */
 struct timeval tv;

 gettimeofday(&tv, NULL);

 uint64 ret = tv.tv_usec;
 /* Convert from micro seconds (10^-6) to milliseconds (10^-3) */
 ret /= 1000;

 /* Adds the seconds (10^0) after converting them to milliseconds (10^-3) */
 ret += (tv.tv_sec * 1000);

 return ret;
#endif
}

1
İleride referans olması için: Sadece bir başlık dosyasına atıyorum ve kullanıyorum. Sahip olduğuma sevindim.
Daniel Handojo

1
gettimeofdaySistem saati değiştirilirse yöntemin istenmeyen bir sonuç verebileceğine inanıyorum . Bu sizin için bir sorun olacaksa, clock_gettimeonun yerine bakmak isteyebilirsiniz .
Azmisov

Windows için bu yöntemin herhangi bir avantajı var GetTickCountmı?
MicroVirus

Kullanarak derlenmezgcc -std=c99
Assimilater

@MicroVirus: evet, GetTickCountsistem başlatıldığından beri geçen süredir , işlevim UNIX döneminden beri geçen zamanı döndürüyor, bu da onu tarihler ve saatler için kullanabileceğiniz anlamına geliyor. Eğer sadece iki olay arasında geçen zamanla ilgileniyorsanız benimki hala daha iyi bir seçim çünkü bu bir int64; GetTickCount bir int32'dir ve 50 günde bir taşar, yani kaydettiğiniz iki olay taşma arasında ise garip sonuçlar alabilirsiniz.
Thomas Bonini

43

Mikrosaniyeler (UNIX, POSIX, vb.) Kullanan başka bir çalışma örneğim var.

    #include <sys/time.h>
    typedef unsigned long long timestamp_t;

    static timestamp_t
    get_timestamp ()
    {
      struct timeval now;
      gettimeofday (&now, NULL);
      return  now.tv_usec + (timestamp_t)now.tv_sec * 1000000;
    }

    ...
    timestamp_t t0 = get_timestamp();
    // Process
    timestamp_t t1 = get_timestamp();

    double secs = (t1 - t0) / 1000000.0L;

İşte bunu kodladığımız dosya:

https://github.com/arhuaco/junkcode/blob/master/emqbit-bench/bench.c


5
#include <sys/time.h>Örneğinizin başına eklemelisiniz .
niekas

40

İşte size tatmin edici bir çözünürlük sağlayan C ++ 11'de basit bir çözüm.

#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

#include <iostream>
#include <ctime>

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

İşte örnek kullanım:

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


Bu hatayı c ++ 11 çözümünüzle alıyorum:/usr/lib/x86_64-linux-gnu/libstdc++.so.6: version GLIBCXX_3.4.19 not found (required by ../cpu_2d/g500)
user9869932

@julianromera hangi platformu kullanıyorsunuz? libstdc ++ kitaplığını ve g ++ 'yı kurdunuz mu?
gongzhitaao

Bu, Linux ubuntu 12'nin bir Slurm ızgarasıdır. Bunu henüz düzelttim. Bağlayıcının sonuna -static-libstdc ++ ekledim. @
Gongzhitaao'ya

18
#include <boost/progress.hpp>

using namespace boost;

int main (int argc, const char * argv[])
{
  progress_timer timer;

  // do stuff, preferably in a 100x loop to make it take longer.

  return 0;
}

Ne zaman progress_timerkapsam dışına gider onun yaratılış beri geçen zaman dışarı yazdırılır.

GÜNCELLEME : İşte Boost olmadan çalışan bir sürüm (macOS / iOS'ta test edilmiştir):

#include <chrono>
#include <string>
#include <iostream>
#include <math.h>
#include <unistd.h>

class NLTimerScoped {
private:
    const std::chrono::steady_clock::time_point start;
    const std::string name;

public:
    NLTimerScoped( const std::string & name ) : name( name ), start( std::chrono::steady_clock::now() ) {
    }


    ~NLTimerScoped() {
        const auto end(std::chrono::steady_clock::now());
        const auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>( end - start ).count();

        std::cout << name << " duration: " << duration_ms << "ms" << std::endl;
    }

};

int main(int argc, const char * argv[]) {

    {
        NLTimerScoped timer( "sin sum" );

        float a = 0.0f;

        for ( int i=0; i < 1000000; i++ ) {
            a += sin( (float) i / 100 );
        }

        std::cout << "sin sum = " << a << std::endl;
    }



    {
        NLTimerScoped timer( "sleep( 4 )" );

        sleep( 4 );
    }



    return 0;
}

2
Bu işe yarar, ancak progress_timer'ın kullanımdan kaldırıldığını unutmayın (yükseltme 1.50'den bir süre önce) - auto_cpu_timer daha uygun olabilir.
Davida

3
@meowsqueak hmm, auto_cpu_timer, Boost sistem kitaplığının bağlanmasını gerektiriyor gibi görünüyor, bu nedenle artık yalnızca başlık içeren bir çözüm değil. Çok kötü ... diğer seçenekleri birden bire daha çekici hale getiriyor.
Tomas Andrle

1
evet, bu iyi bir nokta, eğer Boost'u henüz bağlamadıysanız, o zaman değerinden daha fazla sorun demektir. Ama zaten yaparsan, oldukça iyi çalışıyor.
Davida

@meowsqueak Evet, veya bazı hızlı kıyaslama testleri için Boost'un eski sürümünü edinin.
Tomas Andrle

@TomasAndrle Bağlantı artık mevcut değil.
Zheng Qu

5

Windows, QueryPerformanceCounter () işlevi sağlar ve Unix, gettimeofday () işlevine sahiptir. Her iki işlev de en az 1 mikro saniye farkı ölçebilir.


Ancak windows.h'yi kullanmak kısıtlanmıştır. Aynı derlenmiş kaynak hem Windows hem de Unix üzerinde çalışmalıdır. Bu problem nasıl çözülür?
AhmetB - Google

2
Sonra bazı sarıcı kitaplıklarını arayın stackoverflow.com/questions/1487695/…
Captain Comic

4
aynı derlenmiş kaynak , her iki sistemde de aynı ikiliyi çalıştırmak istiyormuşsunuz gibi geliyor, bu durum böyle görünmüyor. Eğer anlamına gelse aynı kaynağı daha sonra bir #ifdefok olmalıdır (ve bunu kabul etmiş yanıt bakarsak edilir), sonra sorun görmüyorum: #ifdef WIN32 #include <windows.h> ... #else ... #endif.
just somebody

3

Yazdığım bazı programlarda RDTS'yi bu amaçla kullandım. RDTSC zamanla ilgili değil, işlemcinin başlamasından sonraki döngü sayısıyla ilgilidir. Saniyede bir sonuç almak için bunu sisteminizde kalibre etmeniz gerekir, ancak performansı değerlendirmek istediğinizde gerçekten kullanışlıdır, döngü sayısını saniyelerle değiştirmeye çalışmadan doğrudan kullanmak daha da iyidir.

(yukarıdaki bağlantı bir fransız wikipedia sayfasıdır, ancak C ++ kod örnekleri vardır, İngilizce sürümü burada )


2

Sistemden zaman bilgisi almak için standart kütüphane işlevlerini kullanmanızı öneririm.

Daha iyi çözünürlük istiyorsanız, daha fazla yürütme yinelemesi gerçekleştirin. Programı bir kez çalıştırmak ve numune almak yerine 1000 veya daha fazla kez çalıştırın.


2

İç döngüyü birkaç kez, performans zamanlamasıyla yalnızca bir kez ve ortalama olarak iç döngü tekrarlarını bölerek çalıştırmak, her şeyi (döngü + performans zamanlaması) birkaç kez ve ortalama olarak çalıştırmaktan daha iyidir. Bu, performans zamanlama kodunun ek yükünü gerçek profilli bölümünüze göre azaltacaktır.

Zamanlayıcı aramalarınızı uygun sistem için tamamlayın. Windows için, QueryPerformanceCounter oldukça hızlıdır ve kullanımı "güvenlidir".

"Rdtsc" yi herhangi bir modern X86 bilgisayarda da kullanabilirsiniz, ancak bazı çok çekirdekli makinelerde sorunlar olabilir (çekirdek atlama, zamanlayıcıyı değiştirebilir) veya bir tür hız adımınız açıksa.


2

(Windows'a özel çözüm) Windows altında doğru zamanlamaları elde etmenin mevcut (yaklaşık 2017) yolu "QueryPerformanceCounter" kullanmaktır. Bu yaklaşım, çok doğru sonuçlar verme avantajına sahiptir ve MS tarafından tavsiye edilmektedir. Çalışan bir örnek almak için kod blobunu yeni bir konsol uygulamasına yerleştirmeniz yeterlidir. Burada uzun bir tartışma var: Yüksek çözünürlüklü zaman damgaları edinme

#include <iostream>
#include <tchar.h>
#include <windows.h>

int main()
{
constexpr int MAX_ITER{ 10000 };
constexpr __int64 us_per_hour{ 3600000000ull }; // 3.6e+09
constexpr __int64 us_per_min{ 60000000ull };
constexpr __int64 us_per_sec{ 1000000ull };
constexpr __int64 us_per_ms{ 1000ull };

// easy to work with
__int64 startTick, endTick, ticksPerSecond, totalTicks = 0ull;

QueryPerformanceFrequency((LARGE_INTEGER *)&ticksPerSecond);

for (int iter = 0; iter < MAX_ITER; ++iter) {// start looping
    QueryPerformanceCounter((LARGE_INTEGER *)&startTick); // Get start tick
    // code to be timed
    std::cout << "cur_tick = " << iter << "\n";
    QueryPerformanceCounter((LARGE_INTEGER *)&endTick); // Get end tick
    totalTicks += endTick - startTick; // accumulate time taken
}

// convert to elapsed microseconds
__int64 totalMicroSeconds =  (totalTicks * 1000000ull)/ ticksPerSecond;

__int64 hours = totalMicroSeconds / us_per_hour;
totalMicroSeconds %= us_per_hour;
__int64 minutes = totalMicroSeconds / us_per_min;
totalMicroSeconds %= us_per_min;
__int64 seconds = totalMicroSeconds / us_per_sec;
totalMicroSeconds %= us_per_sec;
__int64 milliseconds = totalMicroSeconds / us_per_ms;
totalMicroSeconds %= us_per_ms;


std::cout << "Total time: " << hours << "h ";
std::cout << minutes << "m " << seconds << "s " << milliseconds << "ms ";
std::cout << totalMicroSeconds << "us\n";

return 0;
}

2

Her test için tam olarak aynı süreleri vermesi gereken iş parçacığı planlamasına yönelik eksiksiz bir çözüm, programınızı işletim sisteminden bağımsız olacak şekilde derlemek ve programı işletim sistemi içermeyen bir ortamda çalıştırmak için bilgisayarınızı başlatmaktır. Yine de, bu büyük ölçüde pratik değildir ve en iyi ihtimalle zor olacaktır.

İşletim sisteminden kurtulmanın iyi bir alternatifi, mevcut iş parçacığının yakınlığını 1 çekirdeğe ve önceliği en yüksek değere ayarlamaktır. Bu alternatif, yeterince tutarlı sonuçlar sağlamalıdır.

Ayrıca, g ++ veya gcc için test edilen kodun optimize edilmesini önlemek için komut satırına ekleme-Og anlamına gelen hata ayıklamayı engelleyecek optimizasyonları da kapatmalısınız . -O0Böylelikle kod zamanlanmış hızını skewing zamanlama sonuçlarına dahil olacağını ekstra gereksiz yükü tanıtır çünkü bayrak kullanılmamalıdır.

Aksine, hem son üretim yapısında kullandığınızı -Ofast(veya en azından -O3) varsaymak hem de "ölü" kod eleme konusunu görmezden gelmek, aşağıdakilere -Ogkıyasla çok az optimizasyon gerçekleştirir -Ofast; bu nedenle -Ognihai üründe kodun gerçek hızını yanlış gösterebilir.

Ayrıca, tüm hız testleri (bir dereceye kadar) şerefine: ile derlenen nihai üretim ürününde -Ofast, kodun her bir pasajı / bölümü / işlevi izole edilmemiştir; daha ziyade, her kod parçacığı sürekli olarak bir sonrakine akar, böylece derleyicinin potansiyel olarak her yerden kod parçalarını birleştirmesine, birleştirmesine ve bir araya getirmesine izin verir.

Aynı zamanda, yoğun şekilde kullanılan bir kod parçacığını karşılaştırıyorsanız realloc(), yeterince yüksek bellek parçalanması olan bir üretim ürününde kod parçacığı daha yavaş çalışabilir. Bu nedenle, "bütün, parçalarının toplamından daha fazlasıdır" ifadesi bu duruma uygulanır, çünkü nihai üretim yapısındaki kod, hız testi yaptığınız tekil parçacığa göre fark edilir derecede daha hızlı veya daha yavaş çalışabilir.

Uyuşmazlığı azaltabilecek kısmi bir çözüm, ölü kod / döngü eliminasyonunu önlemek için teste dahil olan değişkenlere -Ofastek olarak hız testi için kullanmaktır asm volatile("" :: "r"(var)).

İşte bir Windows bilgisayarda karekök işlevlerinin nasıl karşılaştırılacağına dair bir örnek.

// set USE_ASM_TO_PREVENT_ELIMINATION  to 0 to prevent `asm volatile("" :: "r"(var))`
// set USE_ASM_TO_PREVENT_ELIMINATION  to 1 to enforce `asm volatile("" :: "r"(var))`
#define USE_ASM_TO_PREVENT_ELIMINATION 1

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <chrono>
#include <cmath>
#include <windows.h>
#include <intrin.h>
#pragma intrinsic(__rdtsc)
#include <cstdint>

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

unsigned int guess_sqrt32(register unsigned int n) {
    register unsigned int g = 0x8000;
    if(g*g > n) {
        g ^= 0x8000;
    }
    g |= 0x4000;
    if(g*g > n) {
        g ^= 0x4000;
    }
    g |= 0x2000;
    if(g*g > n) {
        g ^= 0x2000;
    }
    g |= 0x1000;
    if(g*g > n) {
        g ^= 0x1000;
    }
    g |= 0x0800;
    if(g*g > n) {
        g ^= 0x0800;
    }
    g |= 0x0400;
    if(g*g > n) {
        g ^= 0x0400;
    }
    g |= 0x0200;
    if(g*g > n) {
        g ^= 0x0200;
    }
    g |= 0x0100;
    if(g*g > n) {
        g ^= 0x0100;
    }
    g |= 0x0080;
    if(g*g > n) {
        g ^= 0x0080;
    }
    g |= 0x0040;
    if(g*g > n) {
        g ^= 0x0040;
    }
    g |= 0x0020;
    if(g*g > n) {
        g ^= 0x0020;
    }
    g |= 0x0010;
    if(g*g > n) {
        g ^= 0x0010;
    }
    g |= 0x0008;
    if(g*g > n) {
        g ^= 0x0008;
    }
    g |= 0x0004;
    if(g*g > n) {
        g ^= 0x0004;
    }
    g |= 0x0002;
    if(g*g > n) {
        g ^= 0x0002;
    }
    g |= 0x0001;
    if(g*g > n) {
        g ^= 0x0001;
    }
    return g;
}

unsigned int empty_function( unsigned int _input ) {
    return _input;
}

unsigned long long empty_ticks=0;
double empty_seconds=0;
Timer my_time;

template<unsigned int benchmark_repetitions>
void benchmark( char* function_name, auto (*function_to_do)( auto ) ) {
    register unsigned int i=benchmark_repetitions;
    register unsigned long long start=0;
    my_time.reset();
    start=__rdtsc();
    while ( i-- ) {
        auto result = (*function_to_do)( i << 7 );
        #if USE_ASM_TO_PREVENT_ELIMINATION == 1
            asm volatile("" :: "r"(
                // There is no data type in C++ that is smaller than a char, so it will
                //  not throw a segmentation fault error to reinterpret any arbitrary
                //  data type as a char. Although, the compiler might not like it.
                result
            ));
        #endif
    }
    if ( function_name == nullptr ) {
        empty_ticks = (__rdtsc()-start);
        empty_seconds = my_time.elapsed();
        std::cout<< "Empty:\n" << empty_ticks
              << " ticks\n" << benchmark_repetitions << " repetitions\n"
               << std::setprecision(15) << empty_seconds
                << " seconds\n\n";
    } else {
        std::cout<< function_name<<":\n" << (__rdtsc()-start-empty_ticks)
              << " ticks\n" << benchmark_repetitions << " repetitions\n"
               << std::setprecision(15) << (my_time.elapsed()-empty_seconds)
                << " seconds\n\n";
    }
}


int main( void ) {
    void* Cur_Thread=   GetCurrentThread();
    void* Cur_Process=  GetCurrentProcess();
    unsigned long long  Current_Affinity;
    unsigned long long  System_Affinity;
    unsigned long long furthest_affinity;
    unsigned long long nearest_affinity;

    if( ! SetThreadPriority(Cur_Thread,THREAD_PRIORITY_TIME_CRITICAL) ) {
        SetThreadPriority( Cur_Thread, THREAD_PRIORITY_HIGHEST );
    }
    if( ! SetPriorityClass(Cur_Process,REALTIME_PRIORITY_CLASS) ) {
        SetPriorityClass( Cur_Process, HIGH_PRIORITY_CLASS );
    }
    GetProcessAffinityMask( Cur_Process, &Current_Affinity, &System_Affinity );
    furthest_affinity = 0x8000000000000000ULL>>__builtin_clzll(Current_Affinity);
    nearest_affinity  = 0x0000000000000001ULL<<__builtin_ctzll(Current_Affinity);
    SetProcessAffinityMask( Cur_Process, furthest_affinity );
    SetThreadAffinityMask( Cur_Thread, furthest_affinity );

    const int repetitions=524288;

    benchmark<repetitions>( nullptr, empty_function );
    benchmark<repetitions>( "Standard Square Root", standard_sqrt );
    benchmark<repetitions>( "Original Guess Square Root", original_guess_sqrt32 );
    benchmark<repetitions>( "New Guess Square Root", new_guess_sqrt32 );


    SetThreadPriority( Cur_Thread, THREAD_PRIORITY_IDLE );
    SetPriorityClass( Cur_Process, IDLE_PRIORITY_CLASS );
    SetProcessAffinityMask( Cur_Process, nearest_affinity );
    SetThreadAffinityMask( Cur_Thread, nearest_affinity );
    for (;;) { getchar(); }

    return 0;
}

Ayrıca, Timer'ı için Mike Jarvis'e teşekkür edin.

Lütfen (bu çok önemlidir) daha büyük kod parçacıkları çalıştıracaksanız, bilgisayarınızın donmasını önlemek için yineleme sayısını gerçekten azaltmanız gerektiğini unutmayın.


2
Optimizasyonu devre dışı bırakmak dışında iyi yanıt. Karşılaştırma -O0kodu zamanın büyük bir kaybıdır nedeniyle havai -O0 yerine normal -O2veya -O3 -march=nativedeğişir çılgınca kodu ve iş yüküne bağlı olarak değişir. örneğin ekstra adlandırılmış tmp değişkenler için zaman maliyeti -O0. volatileSatır içi olmayan işlevler veya boş satır içi asm ifadeleri ile şeyleri optimize ediciden gizlemek gibi şeyleri optimize etmekten kaçınmanın başka yolları da vardır . -O0kullanılabilirliğe yakın bile değil çünkü kodda farklı darboğazlar var -O0, aynı değil ama daha kötü.
Peter Cordes

1
Ugh, -Ogkoda bağlı olarak hala çok gerçekçi değil. En azından -O2tercihen -O3daha gerçekçidir. asm volatile("" ::: "+r"(var))Derleyicinin bir kayıttaki bir değeri somutlaştırması ve onun içindeki sürekli yayılmayı yenmesi için veya başka bir şey kullanın .
Peter Cordes

@PeterCordes Görüşleriniz için tekrar teşekkür ederiz. İçeriği -O3ve kod parçacığını ile güncelledim asm volatile("" ::: "+r"(var)).
Jack Giffin

1
asm volatile("" ::: "+r"( i ));gereksiz görünüyor. Optimize edilmiş kodda, derleyiciyi döngünün içinde iolduğu kadar somutlaştırmaya zorlamak için hiçbir neden yoktur i<<7. tmp -= 128Her seferinde geçiş yapmak yerine onu optimize etmekten alıkoyuyorsunuz. Bir işlev çağrısının sonucunu kullanmak, eğer değilse, iyidir void. Beğen int result = (*function_to_do)( i << 7 );. Bu asmsonuç için bir ifade kullanabilirsiniz .
Peter Cordes

@PeterCordes Tekrar çok teşekkür ederim ya da görüşleriniz için. Benim sonrası artık dönüş değeri için düzeltme bulunan function_to_doböylece function_to_doortadan olmadan satır içine yerleştirilmiş olabilir. Başka öneriniz varsa lütfen bize bildirin.
Jack Giffin

1

Her çalıştırıldığında aynı kod uzantısını zamanlamak istediğiniz durumlar için (örneğin, bir darboğaz olabileceğini düşündüğünüz kodun profilini çıkarmak için), Andreas Bonini'nin yararlı bulduğum işlevinin etrafına bir sarmalayıcı (küçük bir değişiklik):

#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#endif

/*
 *  A simple timer class to see how long a piece of code takes. 
 *  Usage:
 *
 *  {
 *      static Timer timer("name");
 *
 *      ...
 *
 *      timer.start()
 *      [ The code you want timed ]
 *      timer.stop()
 *
 *      ...
 *  }
 *
 *  At the end of execution, you will get output:
 *
 *  Time for name: XXX seconds
 */
class Timer
{
public:
    Timer(std::string name, bool start_running=false) : 
        _name(name), _accum(0), _running(false)
    {
        if (start_running) start();
    }

    ~Timer() { stop(); report(); }

    void start() {
        if (!_running) {
            _start_time = GetTimeMicroseconds();
            _running = true;
        }
    }
    void stop() {
        if (_running) {
            unsigned long long stop_time = GetTimeMicroseconds();
            _accum += stop_time - _start_time;
            _running = false;
        }
    }
    void report() { 
        std::cout<<"Time for "<<_name<<": " << _accum / 1.e6 << " seconds\n"; 
    }
private:
    // cf. http://stackoverflow.com/questions/1861294/how-to-calculate-execution-time-of-a-code-snippet-in-c
    unsigned long long GetTimeMicroseconds()
    {
#ifdef _WIN32
        /* Windows */
        FILETIME ft;
        LARGE_INTEGER li;

        /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
         *   * to a LARGE_INTEGER structure. */
        GetSystemTimeAsFileTime(&ft);
        li.LowPart = ft.dwLowDateTime;
        li.HighPart = ft.dwHighDateTime;

        unsigned long long ret = li.QuadPart;
        ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
        ret /= 10; /* From 100 nano seconds (10^-7) to 1 microsecond (10^-6) intervals */
#else
        /* Linux */
        struct timeval tv;

        gettimeofday(&tv, NULL);

        unsigned long long ret = tv.tv_usec;
        /* Adds the seconds (10^0) after converting them to microseconds (10^-6) */
        ret += (tv.tv_sec * 1000000);
#endif
        return ret;
    }
    std::string _name;
    long long _accum;
    unsigned long long _start_time;
    bool _running;
};

1

kod bloğunu karşılaştıran basit bir sınıf:

using namespace std::chrono;

class benchmark {
  public:
  time_point<high_resolution_clock>  t0, t1;
  unsigned int *d;
  benchmark(unsigned int *res) : d(res) { 
                 t0 = high_resolution_clock::now();
  }
  ~benchmark() { t1 = high_resolution_clock::now();
                  milliseconds dur = duration_cast<milliseconds>(t1 - t0);
                  *d = dur.count();
  }
};
// simple usage 
// unsigned int t;
// { // put the code in a block
//  benchmark bench(&t);
//  // ...
//  // code to benchmark
// }
// HERE the t contains time in milliseconds

// one way to use it can be :
#define BENCH(TITLE,CODEBLOCK) \
  unsigned int __time__##__LINE__ = 0;  \
  { benchmark bench(&__time__##__LINE__); \
      CODEBLOCK \
  } \
  printf("%s took %d ms\n",(TITLE),__time__##__LINE__);


int main(void) {
  BENCH("TITLE",{
    for(int n = 0; n < testcount; n++ )
      int a = n % 3;
  });
  return 0;
}

0

boost :: timer muhtemelen size ihtiyacınız olan doğruluğu verecektir. Size ne kadar süreceğini söyleyecek kadar doğru bir yer yok a = a+1;, ama birkaç nanosaniye süren bir şeyi zamanlamak için hangi nedeniniz olmalı?


clock()C ++ standart başlığındaki işleve dayanır .
Petter

0

N kez işlev çağrısı yapan ve size ortalamayı döndüren bir lambda oluşturdum.

double c = BENCHMARK_CNT(25, fillVectorDeque(variable));

C ++ 11 başlığını burada bulabilirsiniz .


0

Chrono kitaplığının high_resolution_clock: https://github.com/nfergu/codetimer 'i kullanarak kod bloklarının performansını ölçmek için basit bir yardımcı program yarattım .

Zamanlamalar farklı tuşlara göre kaydedilebilir ve her tuş için zamanlamaların toplu bir görünümü görüntülenebilir.

Kullanım şekli aşağıdaki gibidir:

#include <chrono>
#include <iostream>
#include "codetimer.h"

int main () {
    auto start = std::chrono::high_resolution_clock::now();
    // some code here
    CodeTimer::record("mykey", start);
    CodeTimer::printStats();
    return 0;
}

0

[cxx-rtimers][1]Yerel bir değişken oluşturabileceğiniz herhangi bir kod bloğunun çalışma zamanıyla ilgili istatistikleri toplamak için yalnızca başlık içeren bazı rutinler sağlayan GitHub'a da bakabilirsiniz . Bu zamanlayıcıların C ++ 11'de std :: chrono kullanan sürümleri veya Boost kitaplığındaki zamanlayıcılar veya standart POSIX zamanlayıcı işlevleri vardır. Bu zamanlayıcılar, bir işlev içinde harcanan ortalama, maksimum ve minimum süreyi ve bunun yanı sıra çağrılma sayısını bildirir. Basitçe şu şekilde kullanılabilirler:

#include <rtimers/cxx11.hpp>

void expensiveFunction() {
    static rtimers::cxx11::DefaultTimer timer("expensive");
    auto scopedStartStop = timer.scopedStart();
    // Do something costly...
}

0

Ben böyle yapıyorum, çok fazla kod yok, anlaşılması kolay, ihtiyaçlarıma uyuyor:

void bench(std::function<void()> fnBench, std::string name, size_t iterations)
{
    if (iterations == 0)
        return;
    if (fnBench == nullptr)
        return;
    std::chrono::high_resolution_clock::time_point start, end;
    if (iterations == 1)
    {
        start = std::chrono::high_resolution_clock::now();
        fnBench();
        end = std::chrono::high_resolution_clock::now();
    }
    else
    {
        start = std::chrono::high_resolution_clock::now();
        for (size_t i = 0; i < iterations; ++i)
            fnBench();
        end = std::chrono::high_resolution_clock::now();
    }
    printf
    (
        "bench(*, \"%s\", %u) = %4.6lfs\r\n",
        name.c_str(),
        iterations,
        std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count()
    );
}

Kullanımı:

bench
(
    []() -> void // function
    {
        // Put your code here
    },
    "the name of this", // name
    1000000 // iterations
);

0
#include <omp.h>

double start = omp_get_wtime();

// code 

double finish = omp_get_wtime();

double total_time = finish - start;

2
Bu kod soruyu çözebilirken, sorunun nasıl ve neden çözüldüğüne dair bir açıklama da dahil olmak üzere , gönderinizin kalitesini artırmaya gerçekten yardımcı olur ve muhtemelen daha fazla oy almanıza neden olur. Sadece şimdi soran kişi için değil, gelecekte okuyucular için soruyu cevapladığınızı unutmayın. Açıklamalar eklemek ve hangi sınırlamaların ve varsayımların geçerli olduğuna dair bir gösterge vermek için lütfen yanıtınızı düzenleyin .
dharman
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.