Dễ dàng đo thời gian trôi qua


297

Tôi đang cố gắng sử dụng thời gian () để đo các điểm khác nhau trong chương trình của mình.

Điều tôi không hiểu là tại sao các giá trị trước và sau giống nhau? Tôi hiểu đây không phải là cách tốt nhất để lập hồ sơ chương trình của tôi, tôi chỉ muốn xem một cái gì đó mất bao lâu.

printf("**MyProgram::before time= %ld\n", time(NULL));

doSomthing();
doSomthingLong();

printf("**MyProgram::after time= %ld\n", time(NULL));

Tôi đã thử:

struct timeval diff, startTV, endTV;

gettimeofday(&startTV, NULL); 

doSomething();
doSomethingLong();

gettimeofday(&endTV, NULL); 

timersub(&endTV, &startTV, &diff);

printf("**time taken = %ld %ld\n", diff.tv_sec, diff.tv_usec);

Làm thế nào để tôi đọc một kết quả của **time taken = 0 26339? Điều đó có nghĩa là 26.339 nano giây = 26,3 ms?

Thế còn **time taken = 4 45025, điều đó có nghĩa là 4 giây và 25 ms?


10
Tôi không hiểu câu hỏi. Tất nhiên các giá trị là khác nhau. Thời gian trôi qua ở giữa, vì vậy time()trả về một giá trị khác.
Thomas

1
Ý bạn là gì "Tôi không hiểu là tại sao các giá trị trước và sau lại khác nhau"? Bạn đang nhận được thời gian hiện tại (tính bằng giây kể từ ngày 1 tháng 1 năm 1970) bằng cách sử dụng time(NULL)... lần thứ hai bạn gọi sẽ là N giây sau lần đầu tiên và do đó ... khác nhau (trừ khi bạn đang làm gì đó ' T mất một giây để hoàn thành ... trong trường hợp đó, nó sẽ giống như lần đầu tiên).
Brian Roach

1
Bạn có thể cho chúng tôi biết những gì nó in, và mất bao lâu nếu bạn hẹn giờ với đồng hồ bấm giờ hoặc đồng hồ treo tường (hoặc lịch)?
Matt Curtis

4
Xin lỗi, ý tôi là cả hai giá trị đều là CÙNG. Tôi gõ sai câu hỏi của tôi.
hap497

Câu trả lời:


336
//***C++11 Style:***
#include <chrono>

std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();

std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << "[µs]" << std::endl;
std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::nanoseconds> (end - begin).count() << "[ns]" << std::endl;

10
vâng, đây sẽ là câu trả lời
Ferenc Dajka

23
Để chạy lệnh này, bạn phải thêm lệnh #include <chrono>và tôi sẽ thay đổi thời gian báo cáo là: std::cout << "Time difference (sec) = " << (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) /1000000.0 <<std::endl;(và đừng quên cờ C ++ 11 khi biên dịch -std=c++11:)
Antonello

1
Nhân tiện, điều này đo thời gian CPU, không phải thời gian đồng hồ treo tường. Đúng?
Nikos

4
@ RestlessC0bra Theo các tài liệu về cppreference, "Đồng hồ này không liên quan đến thời gian của đồng hồ treo tường (ví dụ: có thể là thời gian kể từ lần khởi động lại cuối cùng) và phù hợp nhất để đo khoảng thời gian."
trụ

1
Kiểu dữ liệu này là gì? Std :: chrono :: thời
gian_cast

272
#include <ctime>

void f() {
  using namespace std;
  clock_t begin = clock();

  code_to_time();

  clock_t end = clock();
  double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
}

Các time()chức năng là chỉ chính xác để trong vòng một giây, nhưng có một CLOCKS_PER_SEC"đồng hồ" trong vòng một giây. Đây là một phép đo dễ dàng, di động, mặc dù nó được đơn giản hóa quá mức.


129
Xin lưu ý rằng clock()đo thời gian CPU, không phải thời gian thực tế đã trôi qua (có thể lớn hơn nhiều).
jlstrecker

12
Khi lập trình mã song song cho các cụm, phương thức này không phản ánh thời gian thực ...
Nicholas Hamilton

3
Đây có vẻ là cách dễ nhất. Bạn có quan tâm để cập nhật hoặc giải quyết các bình luận được đưa ra là @jlstrecker không?
Lorah Attkins

5
Các giải pháp được đăng ở trên không phải là một giải pháp tốt vì nhiều lý do. Đây là câu trả lời đúng - stackoverflow.com/questions/2962785/ từ
Xofo

1
Tôi đã thử giải pháp này, và như các ý kiến ​​đề xuất, bộ đếm thời gian của tôi chạy nhanh hơn nhiều so với thời gian thực.
RTbecard

267

Bạn có thể trừu tượng hóa cơ chế đo thời gian và đo thời gian chạy của mỗi lần gọi với mã bổ sung tối thiểu , chỉ bằng cách được gọi thông qua cấu trúc hẹn giờ. Ngoài ra, tại thời gian biên dịch, bạn có thể tham số loại thời gian (mili giây, nano giây, v.v.).

Nhờ vào bài đánh giá của Loki Astari và gợi ý sử dụng các mẫu từ khóa. Đây là lý do tại sao cuộc gọi chức năng chuyển tiếp.

#include <iostream>
#include <chrono>

template<typename TimeT = std::chrono::milliseconds>
struct measure
{
    template<typename F, typename ...Args>
    static typename TimeT::rep execution(F&& func, Args&&... args)
    {
        auto start = std::chrono::steady_clock::now();
        std::forward<decltype(func)>(func)(std::forward<Args>(args)...);
        auto duration = std::chrono::duration_cast< TimeT> 
                            (std::chrono::steady_clock::now() - start);
        return duration.count();
    }
};

int main() {
    std::cout << measure<>::execution(functor(dummy)) << std::endl;
}

Demo

Theo nhận xét của Howard Hinnant , tốt nhất không nên thoát ra khỏi hệ thống chrono cho đến khi chúng ta phải làm vậy. Vì vậy, lớp trên có thể cung cấp cho người dùng lựa chọn gọi countthủ công bằng cách cung cấp một phương thức tĩnh bổ sung (được hiển thị trong C ++ 14)

template<typename F, typename ...Args>
static auto duration(F&& func, Args&&... args)
{
    auto start = std::chrono::steady_clock::now();
    std::forward<decltype(func)>(func)(std::forward<Args>(args)...);
    return std::chrono::duration_cast<TimeT>(std::chrono::steady_clock::now()-start);
} 

// call .count() manually later when needed (eg IO)
auto avg = (measure<>::duration(func) + measure<>::duration(func)) / 2.0;

và hữu ích nhất cho khách hàng

"muốn xử lý hậu kỳ một loạt thời lượng trước I / O (ví dụ: trung bình)"


hoàn chỉnh có thể được tìm thấy ở đây . Nỗ lực của tôi để xây dựng một công cụ đo điểm chuẩn dựa trên chrono được ghi lại ở đây .


Nếu std::invokecó sẵn C ++ 17 , việc gọi hàm có thể gọi executionđược có thể được thực hiện như sau:

invoke(forward<decltype(func)>(func), forward<Args>(args)...);

để cung cấp cho các hàm gọi là con trỏ tới các hàm thành viên.


2
Đẹp; Tôi có một cái gì đó tương tự trong mã của mình, nhưng sử dụng một giao diện khác với lớp: Tôi có một lớp ( code_timer) lấy thời gian bắt đầu ( std::chrono::system_clock::now();) trong hàm tạo, một phương thức code_timer::ellapsedđo sự khác biệt giữa một now()cuộc gọi mới và một trong hàm tạo và một code_timer::resetphương thức đặt lại thời gian bắt đầu sang một now()kết quả mới . Để đo lường sự thực thi của một functor trong mã của tôi, tôi sử dụng một hàm miễn phí, bên ngoài lớp. Điều này cho phép đo thời gian từ khi xây dựng một vật thể, cho đến khi kết thúc một cuộc gọi asynch.
utnapistim

7
<nitpick>: Không thoát ra khỏi chronohệ thống cho đến khi bạn phải (tránh sử dụng .count()). Hãy để khách hàng gọi .count()khi bị ép buộc (nói cho I / O, điều này thực sự không may). Khách hàng có thể muốn xử lý hậu kỳ một loạt thời lượng trước I / O (ví dụ: trung bình) và điều đó được thực hiện tốt nhất trong chronohệ thống.
Howard Hinnant

1
@ user3241228 1. VS2013 không hỗ trợ các loại trả về tự động (chỉ là các loại trả về theo sau - đó là tính năng c ++ 14 chưa khả dụng). 2. Tôi tin rằng đây là lý do nhưng tôi đã hỏi aq chỉ để chắc chắn
Nikos Athanasiou

2
Tại sao không std::forward<F>(func)?
oliora

3
@oliora Đó là điều tương tự. Tôi thích std::forward<decltype(func)>(func)bởi vì nó có thể áp dụng cho các đối số của lambdas ( auto&& func) Fkhông có cú pháp ở đó và dễ dàng trừu tượng hóa trong một macro tiện ích #define fw(arg) std::forward<decltype(arg)>(arg)mà tôi làm trong thư viện điểm chuẩn của mình (vì vậy đó là một cú pháp còn sót lại mà tôi không xây dựng nhiều câu trả lời)
Nikos Athanasiou

56

Như tôi có thể thấy từ câu hỏi của bạn, có vẻ như bạn muốn biết thời gian đã trôi qua sau khi thực thi một số đoạn mã. Tôi đoán bạn sẽ thấy thoải mái khi xem kết quả trong giây. Nếu vậy, hãy thử sử dụng difftime()chức năng như hình dưới đây. Hy vọng điều này sẽ giải quyết vấn đề của bạn.

#include <time.h>
#include <stdio.h>

time_t start,end;
time (&start);
.
.
.
<your code>
.
.
.
time (&end);
double dif = difftime (end,start);
printf ("Elasped time is %.2lf seconds.", dif );

4
Điều này luôn mang lại cho tôi số nguyên giây. Điều đó có nên xảy ra không?
sodiumnitrate

10
thời gian sẽ luôn chỉ trả về giây, vì vậy nó không thể được sử dụng cho các phép đo phụ thứ hai.
DeepDeadpool 20/07/2015

31

Chỉ dành cho Windows: (Thẻ Linux đã được thêm sau khi tôi đăng câu trả lời này)

Bạn có thể sử dụng GetTickCount () để lấy số mili giây đã trôi qua kể từ khi hệ thống được khởi động.

long int before = GetTickCount();

// Perform time-consuming operation

long int after = GetTickCount();

7
Tôi đang sử dụng nó trên linux. Vì vậy, tôi không thể sử dụng hàm GetTickCount ().
hap497

1
đã không bao giờ
bận

Nó hoạt động và cho thời gian thực chứ không phải thời gian CPU. Tôi đã kiểm tra nó bằng cách đặt SleepEx(5000,0)vào vị trí // Thực hiện thao tác tốn thời gian và chênh lệch afterbeforegần 5 giây.
Ruchir

14

time(NULL)trả về số giây đã trôi qua kể từ ngày 01/01/1970 lúc 00:00 ( Kỷ nguyên ). Vì vậy, sự khác biệt giữa hai giá trị là số giây mà quá trình xử lý của bạn mất.

int t0 = time(NULL);
doSomthing();
doSomthingLong();
int t1 = time(NULL);

printf ("time = %d secs\n", t1 - t0);

Bạn có thể nhận được kết quả tốt hơn với getttimeofday(), trả về thời gian hiện tại tính bằng giây, cũng như tính time()bằng micrô giây.


13

hàm thời gian (NULL) sẽ trả về số giây đã trôi qua kể từ ngày 01/01/1970 lúc 00:00. Và bởi vì, chức năng đó được gọi vào thời gian khác nhau trong chương trình của bạn, nó sẽ luôn là Thời gian khác nhau trong C ++


Tôi không biết tại sao ai đó hạ thấp, nhưng câu trả lời của bạn không hoàn toàn chính xác. Đối với người mới bắt đầu, nó không trả về thời gian ngày và nó sẽ không luôn khác.
Matt Joiner

12
struct profiler
{
    std::string name;
    std::chrono::high_resolution_clock::time_point p;
    profiler(std::string const &n) :
        name(n), p(std::chrono::high_resolution_clock::now()) { }
    ~profiler()
    {
        using dura = std::chrono::duration<double>;
        auto d = std::chrono::high_resolution_clock::now() - p;
        std::cout << name << ": "
            << std::chrono::duration_cast<dura>(d).count()
            << std::endl;
    }
};

#define PROFILE_BLOCK(pbn) profiler _pfinstance(pbn)

Cách sử dụng là dưới đây ::

{
    PROFILE_BLOCK("Some time");
    // your code or function
}

Điều này tương tự như RAII trong phạm vi

LƯU Ý đây không phải là của tôi, nhưng tôi nghĩ nó có liên quan ở đây


1
bao gồm mất tích
Stepan Yakovenko

9
#include<time.h> // for clock
#include<math.h> // for fmod
#include<cstdlib> //for system
#include <stdio.h> //for delay

using namespace std;

int main()
{


   clock_t t1,t2;

   t1=clock(); // first time capture

   // Now your time spanning loop or code goes here
   // i am first trying to display time elapsed every time loop runs

   int ddays=0; // d prefix is just to say that this variable will be used for display
   int dhh=0;
   int dmm=0;
   int dss=0;

   int loopcount = 1000 ; // just for demo your loop will be different of course

   for(float count=1;count<loopcount;count++)
   {

     t2=clock(); // we get the time now

     float difference= (((float)t2)-((float)t1)); // gives the time elapsed since t1 in milliseconds

    // now get the time elapsed in seconds

    float seconds = difference/1000; // float value of seconds
    if (seconds<(60*60*24)) // a day is not over
    {
        dss = fmod(seconds,60); // the remainder is seconds to be displayed
        float minutes= seconds/60;  // the total minutes in float
        dmm= fmod(minutes,60);  // the remainder are minutes to be displayed
        float hours= minutes/60; // the total hours in float
        dhh= hours;  // the hours to be displayed
        ddays=0;
    }
    else // we have reached the counting of days
    {
        float days = seconds/(24*60*60);
        ddays = (int)(days);
        float minutes= seconds/60;  // the total minutes in float
        dmm= fmod(minutes,60);  // the rmainder are minutes to be displayed
        float hours= minutes/60; // the total hours in float
        dhh= fmod (hours,24);  // the hours to be displayed

    }

    cout<<"Count Is : "<<count<<"Time Elapsed : "<<ddays<<" Days "<<dhh<<" hrs "<<dmm<<" mins "<<dss<<" secs";


    // the actual working code here,I have just put a delay function
    delay(1000);
    system("cls");

 } // end for loop

}// end of main 

3
Trong khi câu trả lời của bạn được đánh giá cao, chúng tôi thích một bản trước có chứa một mô tả ngắn gọn về mã. Cảm ơn.
Kev

2
Đây không phải là thời gian trôi qua, mà là thời gian xử lý.
JonnyJD

8

Các giá trị được in bởi chương trình thứ hai của bạn là giây và micro giây.

0 26339 = 0.026'339 s =   26339 µs
4 45025 = 4.045'025 s = 4045025 µs

8
#include <ctime>
#include <cstdio>
#include <iostream>
#include <chrono>
#include <sys/time.h>
using namespace std;
using namespace std::chrono;

void f1()
{
  high_resolution_clock::time_point t1 = high_resolution_clock::now();
  high_resolution_clock::time_point t2 = high_resolution_clock::now();
  double dif = duration_cast<nanoseconds>( t2 - t1 ).count();
  printf ("Elasped time is %lf nanoseconds.\n", dif );
}

void f2()
{
  timespec ts1,ts2;
  clock_gettime(CLOCK_REALTIME, &ts1);
  clock_gettime(CLOCK_REALTIME, &ts2);
  double dif = double( ts2.tv_nsec - ts1.tv_nsec );
  printf ("Elasped time is %lf nanoseconds.\n", dif );
}

void f3()
{
  struct timeval t1,t0;
  gettimeofday(&t0, 0);
  gettimeofday(&t1, 0);
  double dif = double( (t1.tv_usec-t0.tv_usec)*1000);
  printf ("Elasped time is %lf nanoseconds.\n", dif );
}
void f4()
{
  high_resolution_clock::time_point t1 , t2;
  double diff = 0;
  t1 = high_resolution_clock::now() ;
  for(int i = 1; i <= 10 ; i++)
  {
    t2 = high_resolution_clock::now() ;
    diff+= duration_cast<nanoseconds>( t2 - t1 ).count();
    t1 = t2;
  }
  printf ("high_resolution_clock:: Elasped time is %lf nanoseconds.\n", diff/10 );
}

void f5()
{
  timespec ts1,ts2;
  double diff = 0;
  clock_gettime(CLOCK_REALTIME, &ts1);
  for(int i = 1; i <= 10 ; i++)
  {
    clock_gettime(CLOCK_REALTIME, &ts2);
    diff+= double( ts2.tv_nsec - ts1.tv_nsec );
    ts1 = ts2;
  }
  printf ("clock_gettime:: Elasped time is %lf nanoseconds.\n", diff/10 );
}

void f6()
{
  struct timeval t1,t2;
  double diff = 0;
  gettimeofday(&t1, 0);
  for(int i = 1; i <= 10 ; i++)
  {
    gettimeofday(&t2, 0);
    diff+= double( (t2.tv_usec-t1.tv_usec)*1000);
    t1 = t2;
  }
  printf ("gettimeofday:: Elasped time is %lf nanoseconds.\n", diff/10 );
}

int main()
{
  //  f1();
  //  f2();
  //  f3();
  f6();
  f4();
  f5();
  return 0;
}

4

C ++ std :: chrono có một lợi ích rõ ràng là đa nền tảng. Tuy nhiên, nó cũng giới thiệu một chi phí đáng kể so với POSIX clock_gettime (). Trên hộp Linux của tôi, tất cả các std::chrono::xxx_clock::now()hương vị thực hiện gần giống nhau:

std::chrono::system_clock::now()
std::chrono::steady_clock::now()
std::chrono::high_resolution_clock::now()

Mặc dù POSIX clock_gettime(CLOCK_MONOTONIC, &time)nên giống như steady_clock::now()nhưng nó nhanh hơn x3 lần!

Đây là bài kiểm tra của tôi, cho sự hoàn chỉnh.

#include <stdio.h>
#include <chrono>
#include <ctime>

void print_timediff(const char* prefix, const struct timespec& start, const 
struct timespec& end)
{
    double milliseconds = end.tv_nsec >= start.tv_nsec
                        ? (end.tv_nsec - start.tv_nsec) / 1e6 + (end.tv_sec - start.tv_sec) * 1e3
                        : (start.tv_nsec - end.tv_nsec) / 1e6 + (end.tv_sec - start.tv_sec - 1) * 1e3;
    printf("%s: %lf milliseconds\n", prefix, milliseconds);
}

int main()
{
    int i, n = 1000000;
    struct timespec start, end;

    // Test stopwatch
    clock_gettime(CLOCK_MONOTONIC, &start);
    for (i = 0; i < n; ++i) {
        struct timespec dummy;
        clock_gettime(CLOCK_MONOTONIC, &dummy);
    }
    clock_gettime(CLOCK_MONOTONIC, &end);
    print_timediff("clock_gettime", start, end);

    // Test chrono system_clock
    clock_gettime(CLOCK_MONOTONIC, &start);
    for (i = 0; i < n; ++i)
        auto dummy = std::chrono::system_clock::now();
    clock_gettime(CLOCK_MONOTONIC, &end);
    print_timediff("chrono::system_clock::now", start, end);

    // Test chrono steady_clock
    clock_gettime(CLOCK_MONOTONIC, &start);
    for (i = 0; i < n; ++i)
        auto dummy = std::chrono::steady_clock::now();
    clock_gettime(CLOCK_MONOTONIC, &end);
    print_timediff("chrono::steady_clock::now", start, end);

    // Test chrono high_resolution_clock
    clock_gettime(CLOCK_MONOTONIC, &start);
    for (i = 0; i < n; ++i)
        auto dummy = std::chrono::high_resolution_clock::now();
    clock_gettime(CLOCK_MONOTONIC, &end);
    print_timediff("chrono::high_resolution_clock::now", start, end);

    return 0;
}

Và đây là đầu ra tôi nhận được khi được biên dịch với gcc7.2 -O3:

clock_gettime: 24.484926 milliseconds
chrono::system_clock::now: 85.142108 milliseconds
chrono::steady_clock::now: 87.295347 milliseconds
chrono::high_resolution_clock::now: 84.437838 milliseconds

3

Cuộc time(NULL)gọi hàm sẽ trả về số giây đã trôi qua kể từ epoc: ngày 1 tháng 1 năm 1970. Có lẽ điều bạn muốn làm là lấy sự khác biệt giữa hai dấu thời gian:

size_t start = time(NULL);
doSomthing();
doSomthingLong();

printf ("**MyProgram::time elapsed= %lds\n", time(NULL) - start);

3

Như những người khác đã lưu ý, hàm time () trong thư viện chuẩn C không có độ phân giải tốt hơn một giây. Hàm C di động hoàn toàn duy nhất có thể cung cấp độ phân giải tốt hơn có vẻ là clock (), nhưng đo thời gian của bộ xử lý thay vì thời gian của đồng hồ. Nếu một trong số đó là nội dung để giới hạn bản thân trong các nền tảng POSIX (ví dụ: Linux), thì hàm clock_gettime () là một lựa chọn tốt.

Kể từ C ++ 11, có nhiều phương tiện thời gian tốt hơn có sẵn cung cấp độ phân giải tốt hơn ở dạng rất dễ mang theo trên các trình biên dịch và hệ điều hành khác nhau. Tương tự, thư viện boost :: datetime cung cấp các lớp thời gian có độ phân giải cao, có tính di động cao.

Một thách thức trong việc sử dụng bất kỳ phương tiện nào trong số này là thời gian trễ được giới thiệu bằng cách truy vấn đồng hồ hệ thống. Từ việc thử nghiệm với clock_gettime (), boost :: datetime và std :: chrono, sự chậm trễ này có thể dễ dàng trở thành vấn đề của micro giây. Vì vậy, khi đo thời lượng của bất kỳ phần nào trong mã của bạn, bạn cần cho phép có lỗi đo ở kích thước này hoặc cố gắng sửa lỗi không có lỗi đó theo một cách nào đó. Lý tưởng nhất là bạn có thể muốn thu thập nhiều phép đo thời gian được thực hiện bởi chức năng của mình và tính thời gian trung bình hoặc tối đa / tối thiểu được thực hiện trong nhiều lần chạy.

Để giúp giải quyết tất cả các vấn đề về tính di động và thu thập số liệu này, tôi đã phát triển thư viện cxx-rtimers có sẵn trên Github để cố gắng cung cấp API đơn giản cho các khối thời gian của mã C ++, tính toán các lỗi không và thống kê báo cáo từ nhiều bộ định thời được nhúng trong mã của bạn. Nếu bạn có trình biên dịch C ++ 11, bạn chỉ cần #include <rtimers/cxx11.hpp>sử dụng một cái gì đó như:

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

Khi thoát khỏi chương trình, bạn sẽ nhận được một bản tóm tắt các số liệu thống kê thời gian được viết cho std :: cerr, chẳng hạn như:

Timer(expensiveFunc): <t> = 6.65289us, std = 3.91685us, 3.842us <= t <= 63.257us (n=731)

trong đó cho thấy thời gian trung bình, độ lệch chuẩn của nó, giới hạn trên và dưới và số lần hàm này được gọi.

Nếu bạn muốn sử dụng các hàm thời gian dành riêng cho Linux, bạn có thể #include <rtimers/posix.hpp>hoặc nếu bạn có các thư viện Boost nhưng trình biên dịch C ++ cũ hơn, bạn có thể #include <rtimers/boost.hpp>. Ngoài ra còn có các phiên bản của các lớp hẹn giờ này có thể thu thập thông tin thời gian thống kê từ nhiều luồng. Ngoài ra còn có các phương pháp cho phép bạn ước tính sai số không liên quan đến hai truy vấn liên tiếp ngay lập tức của đồng hồ hệ thống.


2

Bên trong chức năng sẽ truy cập đồng hồ của hệ thống, đó là lý do tại sao nó trả về các giá trị khác nhau mỗi khi bạn gọi nó. Nói chung với các ngôn ngữ phi chức năng, có thể có nhiều tác dụng phụ và trạng thái ẩn trong các hàm mà bạn không thể thấy chỉ bằng cách nhìn vào tên và đối số của hàm.


2

Từ những gì nhìn thấy, tv_sec lưu trữ các giây trôi qua trong khi tv_usec lưu trữ các micrô giây trôi qua riêng biệt. Và họ không chuyển đổi lẫn nhau. Do đó, chúng phải được thay đổi thành đơn vị thích hợp và được thêm vào để có tổng thời gian trôi qua.

struct timeval startTV, endTV;

gettimeofday(&startTV, NULL); 

doSomething();
doSomethingLong();

gettimeofday(&endTV, NULL); 

printf("**time taken in microseconds = %ld\n",
    (endTV.tv_sec * 1e6 + endTV.tv_usec - (startTV.tv_sec * 1e6 + startTV.tv_usec))
    );

2

Trên linux, clock_gettime () là một trong những lựa chọn tốt. Bạn phải liên kết thư viện thời gian thực (-lrt).

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>

#define BILLION  1000000000L;

int main( int argc, char **argv )
  {
    struct timespec start, stop;
    double accum;

    if( clock_gettime( CLOCK_REALTIME, &start) == -1 ) {
      perror( "clock gettime" );
      exit( EXIT_FAILURE );
    }

    system( argv[1] );

    if( clock_gettime( CLOCK_REALTIME, &stop) == -1 ) {
      perror( "clock gettime" );
      exit( EXIT_FAILURE );
    }

    accum = ( stop.tv_sec - start.tv_sec )
          + ( stop.tv_nsec - start.tv_nsec )
            / BILLION;
    printf( "%lf\n", accum );
    return( EXIT_SUCCESS );
  }

2

Tôi cần phải đo thời gian thực hiện các chức năng riêng lẻ trong một thư viện. Tôi không muốn phải bọc mọi cuộc gọi của mọi chức năng bằng chức năng đo thời gian vì nó xấu và làm sâu sắc ngăn xếp cuộc gọi. Tôi cũng không muốn đặt mã hẹn giờ ở trên cùng và dưới cùng của mọi chức năng vì nó gây ra sự lộn xộn khi chức năng có thể thoát sớm hoặc ném ngoại lệ chẳng hạn. Vì vậy, những gì tôi đã làm là tạo ra một bộ đếm thời gian sử dụng thời gian của chính nó để đo thời gian.

Theo cách này, tôi có thể đo thời gian treo tường, một khối mã đã lấy bằng cách chỉ khởi tạo một trong các đối tượng này ở đầu khối mã được đề cập (hàm hoặc bất kỳ phạm vi nào thực sự) và sau đó cho phép hàm hủy bỏ đo thời gian trôi qua kể từ khi xây dựng khi trường hợp đi ra khỏi phạm vi. Bạn có thể tìm thấy ví dụ đầy đủ ở đây nhưng cấu trúc cực kỳ đơn giản:

template <typename clock_t = std::chrono::steady_clock>
struct scoped_timer {
  using duration_t = typename clock_t::duration;
  const std::function<void(const duration_t&)> callback;
  const std::chrono::time_point<clock_t> start;

  scoped_timer(const std::function<void(const duration_t&)>& finished_callback) :
      callback(finished_callback), start(clock_t::now()) { }
  scoped_timer(std::function<void(const duration_t&)>&& finished_callback) :
      callback(finished_callback), start(clock_t::now()) { }
  ~scoped_timer() { callback(clock_t::now() - start); }
};

Cấu trúc sẽ gọi lại cho bạn trên functor được cung cấp khi nó vượt ra ngoài phạm vi để bạn có thể làm gì đó với thông tin về thời gian (in nó hoặc lưu trữ nó hoặc bất cứ điều gì). Nếu bạn cần làm một cái gì đó thậm chí phức tạp hơn, bạn thậm chí có thể sử dụng std::bindvới các std::placeholdershàm gọi lại với nhiều đối số hơn.

Đây là một ví dụ nhanh về việc sử dụng nó:

void test(bool should_throw) {
  scoped_timer<> t([](const scoped_timer<>::duration_t& elapsed) {
    auto e = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(elapsed).count();
    std::cout << "took " << e << "ms" << std::endl;
  });

  std::this_thread::sleep_for(std::chrono::seconds(1));

  if (should_throw)
    throw nullptr;

  std::this_thread::sleep_for(std::chrono::seconds(1));
}

Nếu bạn muốn thận trọng hơn, bạn cũng có thể sử dụng newdeleterõ ràng bắt đầu và dừng bộ hẹn giờ mà không cần dựa vào phạm vi để làm điều đó cho bạn.


1

Chúng giống nhau vì chức năng doS Something của bạn xảy ra nhanh hơn độ chi tiết của bộ đếm thời gian. Thử:

printf ("**MyProgram::before time= %ld\n", time(NULL));

for(i = 0; i < 1000; ++i) {
    doSomthing();
    doSomthingLong();
}

printf ("**MyProgram::after time= %ld\n", time(NULL));

1

Lý do cả hai giá trị là như nhau là vì quy trình dài của bạn không mất nhiều thời gian - ít hơn một giây. Bạn có thể thử chỉ cần thêm một vòng lặp dài (for (int i = 0; i <100000000; i ++);) ở cuối hàm để đảm bảo đây là vấn đề, sau đó chúng ta có thể đi từ đó ...

Trong trường hợp điều trên là đúng, bạn sẽ cần tìm một chức năng hệ thống khác (tôi hiểu bạn làm việc trên linux, vì vậy tôi không thể giúp bạn với tên hàm) để đo thời gian chính xác hơn. Tôi chắc chắn có một chức năng mô phỏng giống như GetTickCount () trong linux, bạn chỉ cần tìm nó.


1

Tôi thường sử dụng như sau:

#include <chrono>
#include <type_traits>

using perf_clock = std::conditional<
    std::chrono::high_resolution_clock::is_steady,
    std::chrono::high_resolution_clock,
    std::chrono::steady_clock
>::type;

using floating_seconds = std::chrono::duration<double>;

template<class F, class... Args>
floating_seconds run_test(Func&& func, Args&&... args)
{
   const auto t0 = perf_clock::now();
   std::forward<Func>(func)(std::forward<Args>(args)...);
   return floating_seconds(perf_clock::now() - t0);
} 

Nó giống như @ nikos-athanasiou đề xuất ngoại trừ việc tôi tránh sử dụng đồng hồ không ổn định và sử dụng số giây trôi nổi như một khoảng thời gian.


1
Về vấn đề này typeswitch : Điển hình high_resolution_clocklà một typedef cho một trong hai system_clockhoặc steady_clock. Vì vậy, để theo dõi rằng std::conditionalnếu is_steadyphần đó là đúng, thì bạn chọn phần high_resolution_clockđó là (một typedef to) steady_clock. Nếu nó sai thì bạn chọn steady_clocklại. Chỉ cần sử dụng steady_clocktừ đầu ...
Nikos Athanasiou

@ nikos-athanasiou Tôi hoàn toàn đồng ý với nhận xét từ 5gon12eder rằng trường hợp "điển hình" không được yêu cầu bởi tiêu chuẩn nên một số STL có thể được thực hiện theo một cách khác. Tôi thích để mã của mình chung chung hơn và không liên quan đến chi tiết triển khai.
oliora

Nó không bắt buộc nhưng được nêu rõ ràng trong 20.12.7.3 : high_resolution_clock may be a synonym for system_clock or steady_clock. Lý do là thế này: high_resolution_clockđại diện cho đồng hồ có thời gian đánh dấu ngắn nhất, vì vậy dù thực hiện thế nào, nó đều có hai lựa chọn, có ổn định hay không. Dù chúng tôi có lựa chọn nào, nói rằng việc triển khai sẽ khác với hai đồng hồ còn lại giống như nói rằng chúng tôi có triển khai tốt hơn cho đồng hồ ổn định (hoặc không) mà chúng tôi chọn không sử dụng (cho đồng hồ ổn định hoặc không đồng hồ). Biết thế nào là tốt, biết tại sao tốt hơn
Nikos Athanasiou

@ nikos-athanasiou Tôi muốn an toàn 100%, đặc biệt khi chi phí này không tốn chi phí thời gian chạy và không thể phát hiện được. Bạn có thể dựa vào "có thể" và các giả định nếu bạn muốn.
oliora

au chống lại bạn của tôi, đó là bạn dựa vào "may", nhưng phù hợp với bản thân. Nếu bạn muốn chắc chắn 100% và tiếp tục viết điều này sau đó, bạn cũng nên tìm cách, cho bạn và người dùng mã của bạn, để tránh các điểm thời gian trộn không chính xác của các đồng hồ khác nhau (nếu loại công tắc này có nghĩa, nó sẽ hoạt động khác nhau trên các nền tảng khác nhau). Chúc vui vẻ!
Nikos Athanasiou

0

Trả lời ba câu hỏi cụ thể của OP .

"Điều tôi không hiểu là tại sao các giá trị trước và sau giống nhau? "

Câu hỏi và mã mẫu đầu tiên cho thấy time()có độ phân giải 1 giây, vì vậy câu trả lời phải là hai hàm thực thi trong chưa đầy 1 giây. Nhưng đôi khi, nó sẽ (dường như phi logic) thông báo 1 giây nếu hai dấu thời gian đặt trên ranh giới một giây.

Ví dụ tiếp theo sử dụng gettimeofday()để lấp đầy cấu trúc này

struct timeval {
    time_t      tv_sec;     /* seconds */
    suseconds_t tv_usec;    /* microseconds */
};

câu hỏi thứ hai hỏi : "Làm thế nào để tôi đọc kết quả **time taken = 0 26339? Điều đó có nghĩa là 26.339 nano giây = 26,3 ms?"

Câu trả lời thứ hai của tôi là thời gian thực hiện là 0 giây và 26339 micro giây, tức là 0,026339 giây, đưa ra ví dụ đầu tiên thực hiện trong chưa đầy 1 giây.

Câu hỏi thứ ba hỏi : "Thế còn **time taken = 4 45025, điều đó có nghĩa là 4 giây và 25 ms?"

Câu trả lời thứ ba của tôi là thời gian thực hiện là 4 giây và 45025 micro giây, tức là 4.045025 giây, điều đó cho thấy OP đã thay đổi các tác vụ được thực hiện bởi hai chức năng mà anh ta đã hẹn giờ trước đó.


0
#include <ctime>
#include <functional>

using namespace std;

void f() {
  clock_t begin = clock();

  // ...code to measure time...

  clock_t end = clock();

  function<double(double, double)> convtime = [](clock_t begin, clock_t end)
  {
     return double(end - begin) / CLOCKS_PER_SEC;
  };

  printf("Elapsed time: %.2g sec\n", convtime(begin, end));

}

Ví dụ tương tự với một ví dụ có sẵn ở đây, chỉ với chức năng chuyển đổi bổ sung + in ra.


0

Tôi đã tạo một lớp để tự động đo thời gian đã trôi qua, Vui lòng kiểm tra mã (c ++ 11) trong liên kết này: https://github.com/sonnt174/Common/blob/master/time_measure.h

Ví dụ về cách sử dụng lớp TimeMeasure:

void test_time_measure(std::vector<int> arr) {
  TimeMeasure<chrono::microseconds> time_mea;  // create time measure obj
  std::sort(begin(arr), end(arr));
}

Tôi thích tuyên bố in của bạn với các đơn vị. Điều gì sẽ làm cho mã của bạn chuyển sang gcc và clang? ( Wandbox.org )
Howard Hinnant

1
@HowardHinnant: cảm ơn vì đã đánh địa chỉ, tôi cũng đã cập nhật mã cho gcc và clang.
Sirn Nguyễn Trương

0

Matlab có hương vị!

ticbắt đầu đồng hồ bấm giờ để đo hiệu suất. Hàm ghi lại thời gian nội bộ khi thực hiện lệnh tic. Hiển thị thời gian đã trôi qua với tocchức năng.

#include <iostream>
#include <ctime>
#include <thread>
using namespace std;

clock_t START_TIMER;

clock_t tic()
{
    return START_TIMER = clock();
}

void toc(clock_t start = START_TIMER)
{
    cout
        << "Elapsed time: "
        << (clock() - start) / (double)CLOCKS_PER_SEC << "s"
        << endl;
}

int main()
{
    tic();
    this_thread::sleep_for(2s);
    toc();

    return 0;
}

-4

Bạn có thể sử dụng thư viện SFML , đó là Thư viện đa phương tiện đơn giản và nhanh chóng. Nó bao gồm nhiều lớp hữu ích và được xác định rõ như Đồng hồ, Ổ cắm, Âm thanh, Đồ họa, v.v ... Thật dễ sử dụng và rất được khuyến khích.

Đây là một ví dụ cho câu hỏi này.

sf::Clock clock;
...
Time time1 = clock.getElapsedTime();
...
Time time2 = clock.restart();
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.