Cara Menghitung Waktu Eksekusi Cuplikan Kode di C ++


121

Saya harus menghitung waktu eksekusi potongan kode C ++ dalam hitungan detik. Ini harus berfungsi baik di mesin Windows atau Unix.

Saya menggunakan kode kode berikut untuk melakukan ini. (impor sebelumnya)

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

Namun untuk input kecil atau pernyataan pendek seperti a = a + 1, saya mendapatkan hasil "0 detik". Saya pikir itu pasti sekitar 0,0000001 detik atau sesuatu seperti itu.

Saya ingat bahwa System.nanoTime()di Java berfungsi cukup baik dalam kasus ini. Namun saya tidak bisa mendapatkan fungsionalitas yang sama persis dari clock()fungsi C ++.

Apakah Anda punya solusi?


29
Perlu diingat bahwa setiap perbandingan berbasis perbedaan waktu mungkin tidak akurat karena fakta bahwa OS mungkin tidak menjalankan utas Anda dari awal hingga akhir. Ini dapat menghentikannya dan menjalankan utas lain yang terkait dengan utas Anda, yang akan berdampak signifikan pada waktu yang sebenarnya dibutuhkan untuk menyelesaikan operasi Anda. Anda dapat menjalankan beberapa kali, dan menghitung rata-rata hasilnya; Anda dapat meminimalkan jumlah proses lain yang berjalan. Tapi tidak satupun dari ini akan menghilangkan efek suspensi benang sepenuhnya.
Mordachai

14
Mordachi, mengapa Anda ingin menghilangkannya? Anda ingin melihat bagaimana fungsi Anda bekerja di lingkungan dunia nyata, bukan di dunia magis di mana utas tidak pernah terputus. Selama Anda menjalankannya beberapa kali dan membuat rata-rata, itu akan sangat akurat.
Thomas Bonini

Ya, saya menjalankannya beberapa kali dan rata-rata hasilnya.
AhmetB - Google

14
Andreas, komentar Mordachai relevan jika OP ingin membandingkan kinerja kodenya dengan algoritme yang berbeda. Misalnya, jika dia menjalankan beberapa pengujian jam siang ini dan kemudian menguji algoritme yang berbeda besok pagi, perbandingannya mungkin tidak dapat diandalkan karena dia mungkin berbagi sumber daya dengan lebih banyak proses di sore hari daripada di pagi hari. Atau mungkin satu set kode akan menyebabkan OS memberikan waktu pemrosesan yang lebih sedikit. Ada banyak alasan mengapa jenis pengukuran kinerja ini tidak dapat diandalkan jika dia ingin melakukan perbandingan berbasis waktu.
weberc2

4
@Mordachai Saya tahu saya membalas komentar lama, tetapi untuk siapa pun yang tersandung pada hal ini seperti yang saya lakukan - untuk mengatur waktu kinerja algoritme Anda ingin mengambil minimum beberapa langkah, bukan rata-rata. Ini adalah salah satu yang memiliki gangguan paling sedikit oleh OS dan begitu juga waktu sebagian besar kode Anda.
Baruch

Jawaban:


115

Anda dapat menggunakan fungsi yang saya tulis ini. Anda memanggil GetTimeMs64(), dan itu mengembalikan jumlah milidetik yang telah berlalu sejak zaman unix menggunakan jam sistem - seperti halnya time(NULL), kecuali dalam milidetik.

Ia bekerja pada windows dan linux; ini aman untuk benang.

Perhatikan bahwa granularitas adalah 15 md di windows; di linux bergantung pada implementasi, tetapi biasanya juga 15 ms.

#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
Untuk referensi di masa mendatang: Saya hanya membuangnya ke file header dan menggunakannya. Senang memilikinya.
Daniel Handojo

1
Saya yakin metode ini gettimeofdaydapat memberikan hasil yang tidak diinginkan jika jam sistem diubah. Jika ini menjadi masalah bagi Anda, Anda mungkin ingin melihatnya clock_gettime.
Azmisov

Apakah metode untuk Windows ini memiliki kelebihan GetTickCount?
MicroVirus

Tidak dikompilasi menggunakangcc -std=c99
Assimilater

@MicroVirus: ya, GetTickCountadalah waktu yang telah berlalu sejak sistem dimulai, sementara fungsi saya mengembalikan waktu sejak zaman UNIX yang berarti Anda dapat menggunakannya untuk tanggal dan waktu. Jika Anda hanya tertarik pada waktu berlalu antara dua peristiwa, saya masih merupakan pilihan yang lebih baik karena ini adalah int64; GetTickCount adalah int32 dan meluap setiap 50 hari yang berarti Anda bisa mendapatkan hasil yang aneh jika dua peristiwa yang Anda daftarkan berada di antara luapan.
Thomas Bonini

43

Saya memiliki contoh kerja lain yang menggunakan mikrodetik (UNIX, POSIX, dll).

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

Inilah file tempat kami mengkodekan ini:

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


5
Anda harus menambahkan #include <sys/time.h>di awal contoh Anda.
niekas

40

Berikut adalah solusi sederhana di C ++ 11 yang memberi Anda resolusi yang memuaskan.

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

Atau di * nix, untuk c ++ 03

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

Berikut contoh pemakaiannya:

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

Dari https://gist.github.com/gongzhitaao/7062087


Saya mendapatkan kesalahan ini dengan solusi c ++ 11 Anda:/usr/lib/x86_64-linux-gnu/libstdc++.so.6: version GLIBCXX_3.4.19 not found (required by ../cpu_2d/g500)
user9869932

@julianromera platform apa yang Anda gunakan? apakah Anda menginstal pustaka libstdc ++ dan g ++?
gongzhitaao

Ini adalah grid Slurm dari Linux ubuntu 12. Saya baru saja memperbaikinya. Saya menambahkan -static-libstdc ++ di akhir linker. Terima kasih telah bertanya @gongzhitaao
pengguna9869932

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

Ketika progress_timerkeluar dari ruang lingkup itu akan mencetak waktu yang telah berlalu sejak pembuatannya.

PEMBARUAN : Berikut adalah versi yang berfungsi tanpa Boost (diuji di macOS / iOS):

#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
Ini berfungsi, tetapi perhatikan bahwa progress_timer tidak digunakan lagi (kadang sebelum boost 1,50) - auto_cpu_timer mungkin lebih sesuai.
davidA

3
@meowsqueak hmm, auto_cpu_timer tampaknya memerlukan pustaka sistem Boost untuk ditautkan, jadi ini bukan lagi solusi hanya-header. Sayang sekali ... tiba-tiba membuat opsi lain lebih menarik.
Tomas Andrle

1
ya, itu poin yang bagus, jika Anda belum menautkan Boost maka itu lebih merepotkan daripada nilainya. Tetapi jika Anda sudah melakukannya, itu bekerja dengan cukup baik.
davidA

@meowsqueak Ya, atau untuk beberapa pengujian benchmark cepat, dapatkan saja Boost versi lama.
Tomas Andrle

@TomasAndrle Tautan tidak ada lagi.
Zheng Qu

5

Windows menyediakan fungsi QueryPerformanceCounter (), dan Unix memiliki gettimeofday () Kedua fungsi tersebut dapat mengukur setidaknya perbedaan 1 mikro-detik.


Tetapi menggunakan windows.h dibatasi. Sumber terkompilasi yang sama harus berjalan di Windows dan Unix. Bagaimana menangani masalah ini?
AhmetB - Google

2
Kemudian cari beberapa perpustakaan pembungkus stackoverflow.com/questions/1487695/…
Captain Comic

4
sumber terkompilasi yang sama terdengar seperti Anda ingin menjalankan biner yang sama pada kedua sistem, yang tampaknya tidak demikian. jika Anda berarti sumber yang sama maka #ifdefharus ok (dan itu menilai dari jawaban yang telah Anda diterima), dan kemudian saya tidak melihat masalah: #ifdef WIN32 #include <windows.h> ... #else ... #endif.
hanya seseorang

3

Dalam beberapa program yang saya tulis, saya menggunakan RDTS untuk tujuan tersebut. RDTSC bukan tentang waktu tetapi tentang jumlah siklus dari mulai prosesor. Anda harus mengkalibrasi di sistem Anda untuk mendapatkan hasil dalam hitungan detik, tetapi sangat berguna ketika Anda ingin mengevaluasi kinerja, bahkan lebih baik menggunakan jumlah siklus secara langsung tanpa mencoba mengubahnya kembali ke detik.

(tautan di atas adalah ke halaman wikipedia perancis, tetapi memiliki contoh kode C ++, versi bahasa Inggris ada di sini )


2

Saya menyarankan menggunakan fungsi perpustakaan standar untuk memperoleh informasi waktu dari sistem.

Jika Anda ingin resolusi yang lebih baik, lakukan lebih banyak iterasi eksekusi. Alih-alih menjalankan program sekali dan mendapatkan sampel, jalankan 1000 kali atau lebih.


2

Lebih baik menjalankan loop dalam beberapa kali dengan waktu kinerja hanya sekali dan rata-rata dengan membagi pengulangan loop dalam daripada menjalankan semuanya (loop + waktu kinerja) beberapa kali dan rata-rata. Ini akan mengurangi overhead kode waktu kinerja vs bagian profil Anda yang sebenarnya.

Selesaikan panggilan pengatur waktu Anda untuk sistem yang sesuai. Untuk Windows, QueryPerformanceCounter cukup cepat dan "aman" untuk digunakan.

Anda juga dapat menggunakan "rdtsc" pada PC X86 modern, tetapi mungkin ada masalah pada beberapa mesin multicore (core hopping dapat mengubah timer) atau jika Anda mengaktifkan semacam langkah kecepatan.


2

(solusi khusus windows) Cara saat ini (sekitar 2017) untuk mendapatkan pengaturan waktu yang akurat di bawah jendela adalah dengan menggunakan "QueryPerformanceCounter". Pendekatan ini memiliki keuntungan memberikan hasil yang sangat akurat dan direkomendasikan oleh MS. Cukup masukkan blob kode ke dalam aplikasi konsol baru untuk mendapatkan sampel yang berfungsi. Ada diskusi panjang di sini: Memperoleh stempel waktu resolusi tinggi

#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

Solusi lengkap yang tidak pernah gagal untuk penjadwalan utas, yang harus menghasilkan waktu yang persis sama untuk setiap pengujian, adalah dengan mengkompilasi program Anda menjadi OS independen dan mem-boot komputer Anda untuk menjalankan program dalam lingkungan bebas OS. Namun, ini sebagian besar tidak praktis dan paling-paling sulit.

Pengganti yang baik untuk bebas OS adalah dengan mengatur afinitas utas saat ini ke 1 inti dan prioritas ke yang tertinggi. Alternatif ini harus memberikan hasil yang cukup konsisten.

Anda juga harus menonaktifkan pengoptimalan yang akan mengganggu proses debug, yang untuk g ++ atau gcc berarti menambahkan -Ogke baris perintah , untuk mencegah kode yang sedang diuji dioptimalkan. The -O0bendera tidak boleh digunakan karena memperkenalkan overhead tambahan tidak dibutuhkan yang akan dimasukkan dalam hasil waktu, sehingga skewing kecepatan waktunya kode.

Sebaliknya, keduanya mengasumsikan bahwa Anda menggunakan -Ofast(atau, paling tidak, -O3) pada pembuatan produksi akhir dan mengabaikan masalah penghapusan kode "mati", -Ogmelakukan pengoptimalan yang sangat sedikit dibandingkan dengan -Ofast; jadi-Og dapat salah menggambarkan kecepatan sebenarnya dari kode dalam produk akhir.

Selanjutnya, semua uji kecepatan (sampai batas tertentu) sumpah palsu: dalam produk produksi akhir yang dikompilasi dengan -Ofast, setiap potongan / bagian / fungsi kode tidak diisolasi; sebaliknya, setiap potongan kode terus mengalir ke yang berikutnya, sehingga memungkinkan kompiler untuk berpotensi bergabung, menggabungkan, dan mengoptimalkan bersama potongan kode dari semua tempat.

Pada saat yang sama, jika Anda membuat tolok ukur potongan kode yang sangat sering digunakan realloc() , cuplikan kode tersebut mungkin berjalan lebih lambat dalam produk produksi dengan fragmentasi memori yang cukup tinggi. Oleh karena itu, ekspresi "keseluruhan lebih dari jumlah bagiannya" berlaku untuk situasi ini karena kode dalam pembuatan produksi akhir mungkin berjalan jauh lebih cepat atau lebih lambat daripada cuplikan individu yang Anda uji kecepatannya.

Sebuah solusi parsial yang dapat mengurangi ketidaksesuaian digunakan -Ofastuntuk pengujian kecepatan DENGAN penambahan asm volatile("" :: "r"(var))variabel yang terlibat dalam pengujian untuk mencegah penghapusan kode / loop mati.

Berikut adalah contoh cara mengukur fungsi akar kuadrat di komputer Windows.

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

Juga, penghargaan untuk Mike Jarvis atas Timernya.

Harap dicatat (ini sangat penting) bahwa jika Anda akan menjalankan cuplikan kode yang lebih besar, maka Anda benar-benar harus menolak jumlah iterasi untuk mencegah komputer Anda membeku.


2
Jawaban bagus kecuali untuk menonaktifkan pengoptimalan. -O0Kode pembandingan adalah membuang-buang waktu karena overhead -O0 bukannya normal -O2atau sangat-O3 -march=native bervariasi tergantung pada kode dan beban kerja. mis. nama tambahan tmp vars membutuhkan waktu . Ada cara lain untuk menghindari hal-hal dioptimalkan, seperti menyembunyikan sesuatu dari pengoptimal dengan , fungsi non-inline, atau pernyataan asm inline kosong. bahkan tidak dapat digunakan karena kode memiliki kemacetan yang berbeda , tidak sama tetapi lebih buruk. -O0volatile-O0-O0
Peter Cordes

1
Ugh, -Ogmasih belum terlalu realistis, tergantung kodenya. Setidaknya -O2, lebih disukai -O3lebih realistis. Gunakan asm volatile("" ::: "+r"(var))atau sesuatu untuk membuat compiler mewujudkan nilai dalam register, dan kalahkan propagasi konstan melaluinya.
Peter Cordes

@PeterCordes Sekali lagi terima kasih atas wawasan Anda. Saya telah memperbarui konten dengan -O3dan cuplikan kode dengan asm volatile("" ::: "+r"(var)).
Jack Giffin

1
asm volatile("" ::: "+r"( i ));sepertinya tidak perlu. Dalam kode yang dioptimalkan, tidak ada alasan untuk memaksa kompiler terwujud isebaik i<<7di dalam loop. Anda menghentikannya dari pengoptimalan menjadi tmp -= 128alih-alih bergeser setiap saat. Menggunakan hasil dari pemanggilan fungsi itu bagus, jika bukan- void. Suka int result = (*function_to_do)( i << 7 );. Anda bisa menggunakan asmpernyataan tentang hasil itu.
Peter Cordes

@PeterCordes Terima kasih banyak lagi atau wawasan Anda. Posting saya sekarang berisi koreksi untuk nilai kembali dari function_to_dosehingga function_to_dodapat menjadi inline tanpa dihilangkan. Beri tahu saya jika Anda memiliki saran lebih lanjut.
Jack Giffin

1

Untuk kasus di mana Anda ingin mengatur waktu bentangan kode yang sama setiap kali dijalankan (misalnya untuk kode profil yang menurut Anda mungkin menjadi hambatan), berikut adalah pembungkusnya (sedikit modifikasi) fungsi Andreas Bonini yang menurut saya berguna:

#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

hanya kelas sederhana yang mengukur blok kode:

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 mungkin akan memberi Anda akurasi sebanyak yang Anda butuhkan. Tidak ada yang cukup akurat untuk memberi tahu Anda berapa lama a = a+1;waktu yang dibutuhkan, tetapi saya alasan apa Anda harus mengatur waktu sesuatu yang membutuhkan beberapa nanodetik?


Ini bergantung pada clock()fungsi dari header standar C ++.
Petter

0

Saya membuat lambda yang memanggil Anda pemanggilan fungsi N kali dan mengembalikan Anda rata-rata.

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

Anda dapat menemukan header c ++ 11 di sini .


0

Saya membuat utilitas sederhana untuk mengukur kinerja blok kode, menggunakan high_resolution_clock perpustakaan chrono: https://github.com/nfergu/codetimer .

Pengaturan waktu dapat direkam pada kunci yang berbeda, dan tampilan agregat waktu untuk setiap kunci dapat ditampilkan.

Penggunaannya adalah sebagai berikut:

#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

Anda juga dapat melihat di [cxx-rtimers][1]GitHub, yang menyediakan beberapa rutinitas khusus header untuk mengumpulkan statistik pada waktu proses blok kode mana pun tempat Anda dapat membuat variabel lokal. Pengatur waktu tersebut memiliki versi yang menggunakan std :: chrono pada C ++ 11, atau pengatur waktu dari pustaka Boost, atau fungsi pengatur waktu POSIX standar. Pengatur waktu ini akan melaporkan durasi rata-rata, maksimum & minimum yang dihabiskan dalam suatu fungsi, serta berapa kali fungsi itu dipanggil. Mereka dapat digunakan sesederhana berikut:

#include <rtimers/cxx11.hpp>

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

0

Begitulah cara saya melakukannya, tidak banyak kode, mudah dimengerti, sesuai dengan kebutuhan saya:

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

Pemakaian:

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
Meskipun kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan tentang bagaimana dan mengapa ini menyelesaikan masalah akan sangat membantu meningkatkan kualitas posting Anda, dan mungkin menghasilkan lebih banyak suara. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, bukan hanya orang yang bertanya sekarang. Harap edit jawaban Anda untuk menambahkan penjelasan dan memberikan indikasi batasan dan asumsi apa yang berlaku.
Dharman
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.