Cách tính thời gian thực thi của đoạn mã trong C ++


121

Tôi phải tính toán thời gian thực thi của một đoạn mã C ++ trong vài giây. Nó phải hoạt động trên máy Windows hoặc Unix.

Tôi sử dụng mã mã sau đây để làm điều này. (nhập trước)

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

Tuy nhiên đối với các đầu vào nhỏ hoặc các câu lệnh ngắn như a = a + 1, tôi nhận được kết quả "0 giây". Tôi nghĩ nó phải là một cái gì đó giống như 0,0000001 giây hoặc một cái gì đó tương tự.

Tôi nhớ rằng System.nanoTime()trong Java hoạt động khá tốt trong trường hợp này. Tuy nhiên, tôi không thể nhận được cùng một chức năng chính xác từ clock()chức năng của C ++.

Bạn đã có một giải pháp?


29
Hãy nhớ rằng bất kỳ so sánh dựa trên chênh lệch thời gian nào cũng có thể không chính xác do hệ điều hành có thể không chạy chuỗi của bạn từ đầu đến cuối. Nó có thể làm gián đoạn nó và chạy các chuỗi khác xen kẽ với của bạn, điều này sẽ ảnh hưởng đáng kể đến thời gian thực tế cần thiết để hoàn thành hoạt động của bạn. Bạn có thể chạy nhiều lần và tính trung bình kết quả; bạn có thể giảm thiểu số lượng các quy trình khác đang chạy. Nhưng không có cách nào trong số này sẽ loại bỏ hoàn toàn hiệu ứng treo chỉ.
Mordachai

14
Mordachi, tại sao bạn lại muốn loại bỏ nó? Bạn muốn xem chức năng của mình hoạt động như thế nào trong môi trường thế giới thực, không phải trong một lĩnh vực ma thuật nơi các luồng không bị gián đoạn. Chỉ cần bạn chạy nó vài lần và làm trung bình là nó sẽ rất chính xác.
Thomas Bonini

Có, tôi chạy nó một vài lần và kết quả trung bình.
AhmetB - Google

14
Andreas, bình luận của Mordachai có liên quan nếu OP muốn so sánh hiệu suất của mã của anh ấy với một thuật toán khác. Ví dụ: nếu anh ta chạy một số bài kiểm tra đồng hồ vào chiều nay và sau đó kiểm tra một thuật toán khác vào sáng mai, thì so sánh của anh ta có thể không đáng tin cậy vì anh ta có thể đang chia sẻ tài nguyên với nhiều quy trình hơn vào buổi chiều so với buổi sáng. Hoặc có thể một bộ mã sẽ khiến hệ điều hành cung cấp cho nó ít thời gian xử lý hơn. Có rất nhiều lý do khiến kiểu đo lường hiệu suất này không đáng tin cậy nếu anh ta muốn thực hiện phép so sánh dựa trên thời gian.
weberc2

4
@Mordachai Tôi biết tôi đang trả lời một nhận xét cũ, nhưng đối với bất kỳ ai vấp phải điều này như tôi đã làm - hiệu suất theo thời gian của các thuật toán bạn muốn lấy tối thiểu một vài lần chạy, không phải mức trung bình. Đây là phần mềm có ít sự gián đoạn nhất của hệ điều hành và vì vậy, phần lớn là thời gian cho mã của bạn.
Baruch,

Câu trả lời:


115

Bạn có thể sử dụng chức năng này mà tôi đã viết. Bạn gọi GetTimeMs64()và nó trả về số mili giây đã trôi qua kể từ kỷ nguyên unix sử dụng đồng hồ hệ thống - giống như vậy time(NULL), ngoại trừ tính bằng mili giây.

Nó hoạt động trên cả windows và linux; nó là chủ đề an toàn.

Lưu ý rằng mức độ chi tiết là 15 ms trên windows; trên linux nó phụ thuộc vào việc triển khai, nhưng nó cũng thường là 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
Để tham khảo trong tương lai: Tôi chỉ cần ném nó vào một tệp tiêu đề và sử dụng nó. Rất vui khi có nó.
Daniel Handojo,

1
Tôi tin rằng phương pháp này gettimeofdaycó thể cho kết quả không mong muốn nếu đồng hồ hệ thống bị thay đổi. Nếu đây là một vấn đề với bạn, bạn có thể muốn xem xét clock_gettimethay thế.
Azmisov

Phương pháp này dành cho Windows có bất kỳ ưu điểm nào hơn GetTickCountkhông?
MicroVirus

Không biên dịch bằng cách sử dụnggcc -std=c99
Assimilater

@MicroVirus: vâng, GetTickCountlà thời gian trôi qua kể từ khi hệ thống được khởi động, trong khi hàm của tôi trả về thời gian kể từ kỷ nguyên UNIX, nghĩa là bạn có thể sử dụng nó cho ngày và giờ. Nếu bạn chỉ quan tâm đến thời gian trôi qua giữa hai sự kiện, tôi vẫn là lựa chọn tốt hơn vì nó là int64; GetTickCount là int32 và tràn 50 ngày một lần, nghĩa là bạn có thể nhận được kết quả kỳ lạ nếu hai sự kiện bạn đã đăng ký nằm giữa lần tràn.
Thomas Bonini

43

Tôi có một ví dụ làm việc khác sử dụng micro giây (UNIX, POSIX, v.v.).

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

Đây là tệp mà chúng tôi đã viết mã này:

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


5
Bạn nên thêm #include <sys/time.h>vào đầu ví dụ của bạn.
niekas

40

Đây là một giải pháp đơn giản trong C ++ 11 mang lại cho bạn độ phân giải thỏa mãn.

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

Hoặc trên * nix, cho 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_;
};

Đây là ví dụ sử dụng:

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

Từ https://gist.github.com/gongzhitaao/7062087


Tôi nhận được lỗi này với c của bạn ++ 11 giải pháp:/usr/lib/x86_64-linux-gnu/libstdc++.so.6: version GLIBCXX_3.4.19 not found (required by ../cpu_2d/g500)
user9869932

@julianromera bạn đang sử dụng nền tảng nào? bạn đã cài đặt thư viện libstdc ++ và g ++ chưa?
Gongzhitaao

Đó là một lưới Slurm của Linux ubuntu 12. Tôi vừa sửa xong. Tôi đã thêm -static-libstdc ++ vào cuối trình liên kết. Cảm ơn bạn đã hỏi @gongzhitaao
user9869932

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

Khi progress_timervượt ra khỏi phạm vi, nó sẽ in ra thời gian đã trôi qua kể từ khi tạo.

CẬP NHẬT : Đây là phiên bản hoạt động mà không cần Boost (được thử nghiệm trên 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
Điều này hoạt động, nhưng lưu ý rằng process_timer không được dùng nữa (đôi khi trước khi boost 1.50) - auto_cpu_timer có thể phù hợp hơn.
davidA 21/09/12

3
@meowsqueak hmm, auto_cpu_timer dường như yêu cầu liên kết thư viện hệ thống Boost, vì vậy nó không còn là giải pháp chỉ dành cho tiêu đề. Quá tệ ... đột nhiên làm cho các lựa chọn khác hấp dẫn hơn.
Tomas Andrle

1
vâng, đó là một điểm tốt, nếu bạn chưa liên kết Boost thì sẽ gặp nhiều rắc rối hơn đáng giá. Nhưng nếu bạn đã làm, nó hoạt động khá tốt.
davidA

@meowsqueak Vâng, hoặc đối với một số bài kiểm tra điểm chuẩn nhanh, chỉ cần tải phiên bản Boost cũ hơn.
Tomas Andrle

@TomasAndrle Liên kết không tồn tại nữa.
Zheng Qu

5

Windows cung cấp hàm QueryPerformanceCounter () và Unix có gettimeofday () Cả hai hàm đều có thể đo lường sự khác biệt ít nhất 1 micro giây.


Nhưng việc sử dụng windows.h bị hạn chế. Cùng một nguồn đã biên dịch phải chạy trên cả Windows và Unix. Làm thế nào để xử lý vấn đề này?
AhmetB - Google

2
Sau đó tìm kiếm một số thư viện wrapper stackoverflow.com/questions/1487695/...
Captain Comic

4
cùng một nguồn được biên dịch có vẻ như bạn muốn chạy cùng một tệp nhị phân trên cả hai hệ thống, điều này dường như không đúng. nếu bạn có nghĩa là cùng một nguồn sau đó là một #ifdefphải ok (và nó được đánh giá từ các câu trả lời bạn đã được chấp nhận), và sau đó tôi không thấy vấn đề: #ifdef WIN32 #include <windows.h> ... #else ... #endif.
chỉ ai đó

3

Trong một số chương trình tôi đã viết, tôi đã sử dụng RDTS cho mục đích như vậy. RDTSC không phải là về thời gian mà là về số chu kỳ kể từ khi bộ xử lý khởi động. Bạn phải hiệu chỉnh nó trên hệ thống của mình để có kết quả sau giây, nhưng nó thực sự tiện dụng khi bạn muốn đánh giá hiệu suất, thậm chí còn tốt hơn nếu sử dụng trực tiếp số chu kỳ mà không cố gắng thay đổi chúng trở lại giây.

(liên kết ở trên là đến một trang wikipedia tiếng Pháp, nhưng nó có các mẫu mã C ++, phiên bản tiếng Anh ở đây )


2

Tôi đề nghị sử dụng các chức năng thư viện tiêu chuẩn để lấy thông tin thời gian từ hệ thống.

Nếu bạn muốn độ phân giải tốt hơn, hãy thực hiện nhiều lần lặp thực thi hơn. Thay vì chạy chương trình một lần và lấy mẫu, hãy chạy chương trình 1000 lần hoặc hơn.


2

Tốt hơn là chạy vòng lặp bên trong nhiều lần với thời gian thực hiện chỉ một lần và trung bình bằng cách chia số lần lặp lại vòng trong hơn là chạy toàn bộ (thời gian lặp + hiệu suất) nhiều lần và trung bình. Điều này sẽ giảm chi phí của mã thời gian hiệu suất so với phần hồ sơ thực tế của bạn.

Kết hợp các cuộc gọi hẹn giờ của bạn cho hệ thống thích hợp. Đối với Windows, QueryPerformanceCounter khá nhanh và "an toàn" để sử dụng.

Bạn cũng có thể sử dụng "rdtsc" trên bất kỳ PC X86 hiện đại nào nhưng có thể có vấn đề trên một số máy đa lõi (nhảy lõi có thể thay đổi bộ đếm thời gian) hoặc nếu bạn đã bật tốc độ của một số loại.


2

(giải pháp cụ thể cho windows) Cách hiện tại (khoảng năm 2017) để có được thời gian chính xác trong windows là sử dụng "QueryPerformanceCounter". Cách làm này có lợi ích là cho kết quả rất chính xác và được Ths. Chỉ cần đưa khối mã vào một ứng dụng bảng điều khiển mới để lấy mẫu hoạt động. Có một cuộc thảo luận dài ở đây: Mua tem thời gian có độ phân giải cao

#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

Một giải pháp hoàn chỉnh cho việc lập lịch luồng, sẽ mang lại số lần chính xác như nhau cho mỗi lần kiểm tra, là biên dịch chương trình của bạn để độc lập với hệ điều hành và khởi động máy tính của bạn để chạy chương trình trong môi trường không có hệ điều hành. Tuy nhiên, điều này phần lớn là không thực tế và sẽ rất khó khăn.

Một sự thay thế tốt cho việc không sử dụng hệ điều hành chỉ là đặt mối quan hệ của luồng hiện tại thành 1 lõi và mức độ ưu tiên là cao nhất. Sự thay thế này sẽ cung cấp kết quả đủ nhất quán.

Ngoài ra, bạn nên tắt tính năng tối ưu hóa sẽ cản trở việc gỡ lỗi, điều này đối với g ++ hoặc gcc có nghĩa là thêm -Ogvào dòng lệnh , để ngăn mã đang được kiểm tra không được tối ưu hóa. Không -O0nên sử dụng cờ vì nó tạo thêm chi phí không cần thiết sẽ được bao gồm trong kết quả định thời, do đó làm sai lệch tốc độ định thời của mã.

Ngược lại, cả giả định rằng bạn sử dụng -Ofast(hoặc, ít nhất, -O3) trên bản dựng sản xuất cuối cùng và bỏ qua vấn đề loại bỏ mã "chết", -Ogthực hiện rất ít tối ưu hóa so với -Ofast; do đó -Ogcó thể mô tả sai tốc độ thực của mã trong sản phẩm cuối cùng.

Hơn nữa, tất cả các bài kiểm tra tốc độ (ở một mức độ nào đó) đều sai sót: trong sản phẩm sản xuất cuối cùng được biên dịch -Ofast, mỗi đoạn mã / phần / chức năng của mã không bị cô lập; thay vào đó, mỗi đoạn mã liên tục chuyển sang đoạn mã tiếp theo, do đó cho phép trình biên dịch có thể tham gia, hợp nhất và tối ưu hóa các đoạn mã với nhau từ khắp nơi.

Đồng thời, nếu bạn đang đo điểm chuẩn cho một đoạn mã sử dụng nhiều realloc(), thì đoạn mã đó có thể chạy chậm hơn trong một sản phẩm sản xuất có phân mảnh bộ nhớ đủ cao. Do đó, cụm từ "toàn bộ nhiều hơn tổng các phần của nó" áp dụng cho trường hợp này vì mã trong bản dựng sản xuất cuối cùng có thể chạy nhanh hơn hoặc chậm hơn đáng kể so với đoạn mã riêng lẻ mà bạn đang kiểm tra tốc độ.

Một giải pháp từng phần có thể giảm bớt sự không phù hợp đang sử dụng -Ofastđể kiểm tra tốc độ VỚI việc bổ sung asm volatile("" :: "r"(var))các biến liên quan đến kiểm tra để ngăn chặn việc loại bỏ mã chết / vòng lặp.

Dưới đây là một ví dụ về cách chuẩn các hàm căn bậc hai trên máy tính 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;
}

Ngoài ra, ghi công cho Mike Jarvis cho Bộ hẹn giờ của anh ấy.

Xin lưu ý (điều này rất quan trọng) rằng nếu bạn định chạy các đoạn mã lớn hơn, thì bạn thực sự phải giảm số lần lặp lại để ngăn máy tính của bạn không bị đóng băng.


2
Câu trả lời tốt ngoại trừ việc vô hiệu hóa tối ưu hóa. -O0Mã điểm chuẩn là một sự lãng phí lớn về thời gian vì chi phí -O0 thay vì bình thường -O2hoặc -O3 -march=nativethay đổi rất nhiều tùy thuộc vào mã và khối lượng công việc. ví dụ: vars tmp được đặt tên bổ sung tốn thời gian tại -O0. Có những cách khác để tránh tối ưu hóa mọi thứ, chẳng hạn như ẩn mọi thứ khỏi trình tối ưu hóa bằng volatilecác hàm không nội tuyến hoặc các câu lệnh asm nội tuyến trống. -O0thậm chí không thể sử dụng được vì mã có các điểm nghẽn khác nhau-O0 , không giống nhau nhưng tệ hơn.
Peter Cordes

1
Ugh, -Ogvẫn không thực tế lắm, tùy thuộc vào mã. Ít nhất -O2, tốt hơn -O3là thực tế hơn. Sử dụng asm volatile("" ::: "+r"(var))hoặc cái gì đó để làm cho trình biên dịch hiện thực hóa một giá trị trong một thanh ghi và đánh bại sự lan truyền liên tục qua nó.
Peter Cordes

@PeterCordes Cảm ơn bạn một lần nữa vì những hiểu biết của bạn. Tôi đã cập nhật nội dung với -O3và đoạn mã với asm volatile("" ::: "+r"(var)).
Jack Giffin

1
asm volatile("" ::: "+r"( i ));có vẻ không cần thiết. Trong mã được tối ưu hóa, không có lý do gì để buộc trình biên dịch hiện thực hóa icũng như i<<7bên trong vòng lặp. Bạn đang ngăn nó tối ưu hóa thành tmp -= 128thay vì chuyển đổi mọi lúc. Tuy nhiên, sử dụng kết quả của một lệnh gọi hàm là tốt, nếu nó không phải void. Thích int result = (*function_to_do)( i << 7 );. Bạn có thể sử dụng một asmtuyên bố về kết quả đó.
Peter Cordes

@PeterCordes Cảm ơn bạn rất nhiều lần nữa hoặc những hiểu biết của bạn. Bài đăng của tôi hiện có các sửa đổi cho giá trị trả về từ function_to_dođó function_to_docó thể được nội dòng mà không bị loại bỏ. Vui lòng cho tôi biết nếu bạn có thêm bất kỳ đề xuất nào.
Jack Giffin

1

Đối với các trường hợp bạn muốn tính thời gian cho cùng một đoạn mã mỗi khi nó được thực thi (ví dụ: đối với mã hồ sơ mà bạn nghĩ có thể là nút cổ chai), đây là một trình bao bọc xung quanh (một sửa đổi nhỏ đối với) chức năng của Andreas Bonini mà tôi thấy hữu ích:

#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

chỉ là một lớp đơn giản làm điểm chuẩn cho khối mã:

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 có thể sẽ cung cấp cho bạn nhiều độ chính xác mà bạn cần. Không có nơi nào đủ chính xác để cho bạn biết a = a+1;sẽ mất bao lâu , nhưng tôi lý do gì khiến bạn phải tính giờ cho một thứ mất vài nano giây?


Nó dựa vào clock()chức năng từ tiêu đề chuẩn C ++.
Petter

0

Tôi đã tạo một lambda gọi hàm cho bạn N lần và trả về giá trị trung bình cho bạn.

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

Bạn có thể tìm thấy tiêu đề c ++ 11 tại đây .


0

Tôi đã tạo một tiện ích đơn giản để đo hiệu suất của các khối mã, sử dụng high_resolution_clock của thư viện chrono: https://github.com/nfergu/codetimer .

Thời gian có thể được ghi lại trên các phím khác nhau và có thể hiển thị chế độ xem tổng hợp về thời gian cho từng phím.

Cách sử dụng như sau:

#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

Bạn cũng có thể xem [cxx-rtimers][1]trên GitHub, nơi cung cấp một số quy trình chỉ dành cho tiêu đề để thu thập thống kê về thời gian chạy của bất kỳ khối mã nào mà bạn có thể tạo một biến cục bộ. Các bộ hẹn giờ đó có các phiên bản sử dụng std :: chrono trên C ++ 11 hoặc bộ định thời từ thư viện Boost hoặc các hàm bộ đếm thời gian POSIX tiêu chuẩn. Những bộ hẹn giờ này sẽ báo cáo thời lượng trung bình, tối đa và tối thiểu được sử dụng trong một hàm, cũng như số lần nó được gọi. Chúng có thể được sử dụng đơn giản như sau:

#include <rtimers/cxx11.hpp>

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

0

Đó là cách tôi thực hiện, không cần nhiều mã, dễ hiểu, phù hợp với nhu cầu của tôi:

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

Sử dụng:

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
Mặc dù mã này có thể giải quyết câu hỏi, bao gồm giải thích về cách thức và lý do tại sao điều này giải quyết vấn đề sẽ thực sự giúp cải thiện chất lượng bài đăng của bạn và có thể dẫn đến nhiều phiếu bầu hơn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai, không chỉ người hỏi bây giờ. Vui lòng chỉnh sửa câu trả lời của bạn để thêm giải thích và đưa ra dấu hiệu về những giới hạn và giả định nào được áp dụng.
Dharman
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.