วัดเวลาที่ผ่านไปได้อย่างง่ายดาย


297

ฉันกำลังพยายามใช้เวลา ()เพื่อวัดจุดต่าง ๆ ของโปรแกรมของฉัน

สิ่งที่ฉันไม่เข้าใจคือเหตุผลที่ค่าในก่อนและหลังเหมือนกันหรือไม่ ฉันเข้าใจว่านี่ไม่ใช่วิธีที่ดีที่สุดในการจัดทำโปรไฟล์โปรแกรมของฉันฉันแค่ต้องการดูว่าใช้เวลานานเท่าใด

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

doSomthing();
doSomthingLong();

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

ฉันเหนื่อย:

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

ฉันจะอ่านผลลัพธ์ได้**time taken = 0 26339อย่างไร นั่นหมายความว่า nanoseconds 26,339 = 26.3 มิลลิวินาที

สิ่งที่เกี่ยวกับ**time taken = 4 45025หมายความว่า 4 วินาทีและ 25 มิลลิวินาที?


10
ฉันไม่เข้าใจคำถาม แน่นอนว่าค่าต่างกัน เวลาที่ผ่านไประหว่างนั้นtime()จะส่งกลับค่าที่ต่างกัน
โทมัส

1
คุณหมายถึงอะไร "ฉันไม่เข้าใจว่าทำไมค่าในก่อนและหลังแตกต่าง" คุณได้รับเวลาปัจจุบัน (เป็นวินาทีตั้งแต่วันที่ 1 มกราคม 1970) โดยใช้time(NULL)... ครั้งที่สองที่คุณเรียกว่าจะเป็น N วินาทีหลังจากครั้งแรกและจึง ... ต่างกัน (เว้นแต่ว่าคุณกำลังทำอะไรอยู่) ไม่ใช้เวลาสักครู่จึงจะเสร็จสมบูรณ์ ... ซึ่งในกรณีนี้มันจะเหมือนกับครั้งแรก)
Brian Roach

1
คุณสามารถบอกเราได้ว่ามันพิมพ์อะไรและใช้เวลานานแค่ไหนในการใช้นาฬิกาจับเวลาหรือนาฬิกาแขวน (หรือปฏิทิน)
Matt Curtis

4
ขออภัยฉันหมายถึงทั้งสองค่าเป็น SAME ฉันพิมพ์คำถามของฉันผิด
hap497

2
ดูกระทู้นี้: stackoverflow.com/questions/275004/…
เริ่มต้น

คำตอบ:


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
ใช่นี่ควรเป็นคำตอบ
Ferenc Dajka

23
เมื่อต้องการเรียกใช้นี้คุณต้องเพิ่ม#include <chrono>คำสั่งและฉันจะเปลี่ยนเวลาการรายงานเป็น: std::cout << "Time difference (sec) = " << (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) /1000000.0 <<std::endl;(และอย่าลืม C ++ 11 ธงเมื่อรวบรวม: -std=c++11)
Antonello

1
โดยวิธีการนี้จะวัดเวลา CPU ไม่ใช่เวลานาฬิกาแขวน ขวา?
Nikos

4
@ RestlessC0bra ตามเอกสารใน cppreference "นาฬิกานี้ไม่เกี่ยวข้องกับเวลาของนาฬิกาแขวนผนัง (ตัวอย่างเช่นอาจเป็นเวลาตั้งแต่รีบูตครั้งล่าสุด) และเหมาะที่สุดสำหรับการวัดช่วงเวลา"
cylus

1
ชนิดข้อมูลนี้คืออะไร std :: chrono :: duration_cast <std :: chrono :: microseconds> (สิ้นสุด - เริ่มต้น) .count ()
sqp_125

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

time()ฟังก์ชั่นเป็นเพียงที่ถูกต้องภายในสอง แต่มีCLOCKS_PER_SEC"นาฬิกา" ภายในสอง นี่คือการวัดที่ง่ายและพกพาได้แม้ว่าจะง่ายเกินไป


129
โปรดทราบว่าclock()วัดเวลา CPU ไม่ใช่เวลาจริงที่ผ่านไป (ซึ่งอาจมากกว่า)
jlstrecker

12
เมื่อเขียนโปรแกรมรหัสขนานสำหรับกลุ่มวิธีนี้ไม่ได้สะท้อนให้เห็นถึงเวลาจริงของโลก ...
นิโคลัสแฮมิลตัน

3
นี่เป็นวิธีที่ง่ายที่สุด คุณสนใจที่จะอัพเดทหรือแก้ไขความคิดเห็นที่เป็น @jlstrecker หรือไม่?
Lorah Attkins

5
โซลูชันที่โพสต์ด้านบนไม่ใช่โซลูชันที่ดีด้วยเหตุผลหลายประการ นี่คือคำตอบที่ถูกต้อง - stackoverflow.com/questions/2962785/…
Xofo

1
ฉันลองวิธีนี้และตามความคิดเห็นที่แนะนำตัวจับเวลาของฉันวิ่งเร็วกว่าเวลาโลกจริง
RTbecard

267

คุณสามารถสรุปกลไกการวัดเวลาและกำหนดเวลาการเรียกใช้แต่ละครั้งของการเรียกด้วยรหัสพิเศษน้อยที่สุดเพียงแค่ถูกเรียกผ่านโครงสร้างตัวจับเวลา นอกจากนี้ในเวลารวบรวมคุณสามารถกำหนดประเภทเวลา (มิลลิวินาทีนาโนวินาที ฯลฯ )

ขอขอบคุณที่ตรวจสอบโดยLoki Astariและข้อเสนอแนะในการใช้เทมเพลต variadic นี่คือสาเหตุที่การเรียกใช้ฟังก์ชันส่งต่อ

#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

ตามความเห็นของHoward Hinnantจะเป็นการดีที่สุดที่จะไม่หนีออกจากระบบโครโน่จนกว่าเราจะต้อง ดังนั้นคลาสดังกล่าวสามารถให้ผู้ใช้เลือกที่จะโทรcountด้วยตนเองโดยการให้วิธีการคงที่พิเศษ (แสดงใน 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;

และมีประโยชน์มากที่สุดสำหรับลูกค้าที่

"ต้องการประมวลผลระยะเวลาจำนวนมากก่อน I / O (เช่นค่าเฉลี่ย)"


สมบูรณ์รหัสสามารถพบได้ที่นี่ ความพยายามของฉันที่จะสร้างเครื่องมือการเปรียบเทียบขึ้นอยู่กับโครโนจะถูกบันทึกไว้ที่นี่


หาก C ++ 17 std::invokeพร้อมใช้งานการเรียก callable in executionสามารถทำได้ดังนี้:

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

เพื่อจัดเตรียม callables ที่เป็นตัวชี้ไปยังฟังก์ชันสมาชิก


2
นีซ; ฉันมีบางอย่างที่คล้ายกันในรหัสของฉัน แต่ใช้อินเทอร์เฟซต่าง ๆ กับคลาส: ฉันมีคลาส ( code_timer) ที่ใช้เวลาเริ่มต้น ( std::chrono::system_clock::now();) ในตัวสร้างวิธีการcode_timer::ellapsedที่วัดความแตกต่างระหว่างการnow()โทรใหม่และตัวที่อยู่ในตัวสร้าง และcode_timer::resetวิธีที่รีเซ็ตเวลาเริ่มต้นเป็นnow()ผลลัพธ์ใหม่ ในการวัดการทำงานของนักแสดงในรหัสของฉันฉันใช้ฟังก์ชั่นฟรีนอกห้องเรียน สิ่งนี้ช่วยให้สามารถวัดเวลาจากการสร้างวัตถุไปจนถึงการสิ้นสุดของการเรียก asynch
utnapistim

7
<nitpick>: อย่าหลบหนีออกจากchronoระบบจนกว่าคุณจะต้อง (หลีกเลี่ยงการใช้.count()) ให้ลูกค้าโทรหา.count()เมื่อถูกบังคับให้พูดกับ I / O ซึ่งเป็นเรื่องที่โชคร้าย ลูกค้าอาจต้องการโพสต์กระบวนการระยะเวลาก่อนที่จะ I / O (เช่นค่าเฉลี่ย) และทำได้ดีที่สุดในchronoระบบ
Howard Hinnant

1
@ user3241228 1. VS2013 ไม่รองรับประเภทการส่งคืนอัตโนมัติ (เพียงแค่ตามประเภทการส่งคืน - เป็นคุณสมบัติ c ++ 14 ที่ยังไม่พร้อมใช้งาน) 2. ฉันเชื่อว่านี่คือเหตุผล แต่ฉันถาม aq เพียงเพื่อให้แน่ใจ
Nikos Athanasiou

2
ทำไมstd::forward<F>(func)ล่ะ
oliora

3
@oliora มันเป็นสิ่งเดียวกัน ฉันชอบstd::forward<decltype(func)>(func)เพราะมันสามารถนำไปใช้กับข้อโต้แย้งของ lambdas ( auto&& func) ที่Fไม่มี syntactically และง่ายต่อการสรุปในแมโครยูทิลิตี้#define fw(arg) std::forward<decltype(arg)>(arg)ที่ฉันทำในห้องสมุดเกณฑ์มาตรฐานของฉัน (ดังนั้นจึงเป็น syntactic ที่เหลือที่ฉันไม่ได้ทำอย่างละเอียดมากใน คำตอบ)
Nikos Athanasiou

56

อย่างที่ฉันเห็นจากคำถามของคุณดูเหมือนว่าคุณต้องการทราบเวลาที่ผ่านไปหลังจากการประมวลผลโค้ดบางส่วน ฉันเดาว่าคุณจะสบายใจที่จะเห็นผลลัพธ์ในวินาที ถ้าเป็นเช่นนั้นลองใช้difftime()ฟังก์ชั่นที่แสดงด้านล่าง หวังว่านี่จะช่วยแก้ปัญหาของคุณ

#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
สิ่งนี้จะทำให้ฉันเป็นจำนวนเต็มเสมอ มันควรจะเกิดขึ้นเหรอ?
sodiumnitrate

10
เวลาจะกลับมาเพียงไม่กี่วินาทีเท่านั้นดังนั้นจึงไม่สามารถใช้สำหรับการวัดที่สองย่อยได้
DeepDeadpool

31

Windows เท่านั้น: (เพิ่มแท็ก Linux หลังจากที่ฉันโพสต์คำตอบนี้)

คุณสามารถใช้GetTickCount ()เพื่อรับจำนวนมิลลิวินาทีที่ผ่านไปตั้งแต่เริ่มต้นระบบ

long int before = GetTickCount();

// Perform time-consuming operation

long int after = GetTickCount();

7
ฉันใช้มันบน linux ดังนั้นฉันไม่สามารถใช้ฟังก์ชัน GetTickCount ()
hap497

1
ไม่เป็นไรแล้ว) ขอขอบคุณที่อัปเดตแท็กโพสต์ของคุณ
RvdK

มันทำงานและให้เวลาจริงไม่ใช่เวลา CPU ฉันทดสอบโดยวางSleepEx(5000,0)แทน // ดำเนินการที่ต้องใช้เวลาและความแตกต่างafterและใช้beforeเวลาเกือบ 5 วินาที
Ruchir

14

time(NULL)ส่งคืนจำนวนวินาทีที่ผ่านไปตั้งแต่ 01/01/1970 เวลา 00:00 ( ยุค ) ดังนั้นความแตกต่างระหว่างสองค่าคือจำนวนวินาทีที่การประมวลผลของคุณใช้

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

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

คุณสามารถได้ผลลัพธ์ที่ดีกว่าด้วยgetttimeofday()ซึ่งจะคืนค่าเวลาปัจจุบันเป็นวินาทีเช่นเดียวกับtime()ในไมโครวินาที


13

ฟังก์ชัน time (NULL) จะคืนค่าจำนวนวินาทีที่ผ่านไปตั้งแต่ 01/01/1970 เวลา 00:00 น และเนื่องจากฟังก์ชั่นนั้นถูกเรียกในเวลาที่ต่างกันในโปรแกรมของคุณมันจะเป็นเวลาที่แตกต่าง ใน C ++ เสมอ


ฉันไม่รู้ว่าทำไมมีคน downvote แต่คำตอบของคุณไม่ถูกต้องทั้งหมด สำหรับผู้เริ่มต้นจะไม่ส่งคืนวันที่และจะไม่แตกต่างกันเสมอไป
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)

การใช้งานด้านล่าง ::

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

นี่คล้ายกับ RAII ในขอบเขต

หมายเหตุนี่ไม่ใช่ของฉัน แต่ฉันคิดว่ามันเกี่ยวข้องกันที่นี่


1
รวมการสูญหาย
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
ในขณะที่คำตอบของคุณได้รับการชื่นชมเราชอบคำนำสั้น ๆ ที่มีคำอธิบายสั้น ๆ ของรหัส ขอบคุณ
Kev

2
นี่ไม่ใช่เวลาที่ผ่านไป แต่เวลาตัวประมวลผล
JonnyJD

8

ค่าที่พิมพ์โดยโปรแกรมที่สองของคุณคือวินาทีและไมโครวินาที

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 มีข้อดีที่ชัดเจนของการเป็น cross-platform อย่างไรก็ตามมันยังแนะนำค่าใช้จ่ายที่สำคัญเมื่อเทียบกับ POSIX clock_gettime () ในกล่อง Linux ของฉันstd::chrono::xxx_clock::now()รสชาติทั้งหมดมีประสิทธิภาพเหมือนกัน:

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

แม้ว่า POSIX clock_gettime(CLOCK_MONOTONIC, &time)ควรเป็นเช่นเดียวกับsteady_clock::now()แต่เร็วกว่า x3 เท่า!

นี่คือการทดสอบของฉันเพื่อความสมบูรณ์

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

และนี่คือผลลัพธ์ที่ฉันได้รับเมื่อรวบรวมด้วย 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

การtime(NULL)เรียกใช้ฟังก์ชั่นจะคืนค่าจำนวนวินาทีที่ผ่านไปตั้งแต่ epoc: 1 มกราคม 1970 บางทีสิ่งที่คุณหมายถึงต้องทำคือเอาความแตกต่างระหว่างการประทับเวลาสองครั้ง:

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

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

3

ดังที่คนอื่น ๆ ได้จดบันทึกไว้แล้วฟังก์ชั่น time () ในไลบรารีมาตรฐาน C ไม่มีความละเอียดที่ดีกว่าหนึ่งวินาที ฟังก์ชั่น C แบบพกพาอย่างเต็มที่เท่านั้นที่อาจให้ความละเอียดที่ดีกว่าปรากฏว่าเป็นนาฬิกา () แต่จะวัดเวลาตัวประมวลผลแทนที่จะใช้เวลาวอลล์ล็อค ถ้ามีเนื้อหาที่จะ จำกัด ตัวเองให้แพลตฟอร์ม POSIX (เช่น Linux), ฟังก์ชั่น clock_gettime () เป็นตัวเลือกที่ดี

ตั้งแต่ C ++ 11 มีสิ่งอำนวยความสะดวกด้านจังหวะที่ดีกว่ามากที่ให้ความละเอียดที่ดีกว่าในรูปแบบที่ควรพกพาได้ดีในคอมไพเลอร์และระบบปฏิบัติการที่แตกต่างกัน ในทำนองเดียวกัน boost :: datetime library ให้คลาสการกำหนดเวลาความละเอียดสูงที่ควรพกพาได้อย่างดี

สิ่งหนึ่งที่ท้าทายในการใช้สิ่งอำนวยความสะดวกเหล่านี้คือการหน่วงเวลาที่แนะนำโดยการสอบถามนาฬิการะบบ จากการทดลองกับ clock_gettime (), เพิ่ม :: datetimeและ std :: chrono, ความล่าช้านี้อาจเป็นเรื่องของไมโครวินาที ดังนั้นเมื่อทำการวัดระยะเวลาของส่วนใดส่วนหนึ่งของรหัสของคุณคุณจำเป็นต้องอนุญาตให้มีข้อผิดพลาดในการวัดขนาดใกล้เคียงกับขนาดนี้หรือพยายามแก้ไขให้เป็นศูนย์ข้อผิดพลาดด้วยวิธีใดวิธีหนึ่ง ตามหลักแล้วคุณอาจต้องการรวบรวมการวัดหลายครั้งของฟังก์ชั่นของคุณและคำนวณค่าเฉลี่ยหรือเวลาสูงสุด / ต่ำสุดในการวิ่งหลายครั้ง

เพื่อช่วยในเรื่องความสะดวกในการพกพาและการรวบรวมสถิติเหล่านี้ฉันได้พัฒนาไลบรารี่ cxx-rtimers ที่มีอยู่ในGithubซึ่งพยายามให้ API ง่าย ๆ สำหรับบล็อกช่วงเวลาของรหัส C ++, คำนวณข้อผิดพลาดเป็นศูนย์และสถิติการรายงานจากตัวจับเวลาหลายตัว ในรหัสของคุณ หากคุณมีคอมไพเลอร์ C ++ 11 คุณก็สามารถ#include <rtimers/cxx11.hpp>ใช้สิ่งต่อไปนี้

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

เมื่อออกจากโปรแกรมคุณจะได้รับข้อมูลสรุปเกี่ยวกับสถิติเวลาที่เขียนไปยัง std :: cerr เช่น:

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

ซึ่งแสดงเวลาเฉลี่ย, ค่าเบี่ยงเบนมาตรฐาน, ขีด จำกัด บนและล่างและจำนวนครั้งที่ฟังก์ชันนี้ถูกเรียกใช้

หากคุณต้องการที่จะใช้ฟังก์ชั่นลินุกซ์เฉพาะเวลาที่คุณสามารถ#include <rtimers/posix.hpp>หรือถ้าคุณมีห้องสมุด Boost แต่เก่า C ++ #include <rtimers/boost.hpp>คอมไพเลอร์ที่คุณสามารถ นอกจากนี้ยังมีเวอร์ชันของคลาสตัวจับเวลาเหล่านี้ที่สามารถรวบรวมข้อมูลเวลาทางสถิติจากข้ามหลายเธรด นอกจากนี้ยังมีวิธีการที่ช่วยให้คุณสามารถประเมินค่าศูนย์ข้อผิดพลาดที่เกี่ยวข้องกับการสอบถามที่ต่อเนื่องกันสองครั้งของนาฬิการะบบ


2

ภายในฟังก์ชั่นจะเข้าถึงนาฬิกาของระบบซึ่งเป็นสาเหตุที่มันส่งกลับค่าที่แตกต่างกันทุกครั้งที่คุณเรียกมัน โดยทั่วไปด้วยภาษาที่ไม่สามารถใช้งานได้อาจมีผลข้างเคียงมากมายและสถานะที่ซ่อนอยู่ในฟังก์ชั่นที่คุณไม่สามารถมองเห็นได้เพียงแค่ดูที่ชื่อและอาร์กิวเมนต์ของฟังก์ชัน


2

จากสิ่งที่เห็นคือ tv_sec เก็บวินาทีที่ผ่านไปในขณะที่ tv_usec เก็บ microseconds ที่ผ่านไปแยกต่างหาก และพวกเขาไม่ใช่การแปลงซึ่งกันและกัน ดังนั้นจะต้องเปลี่ยนเป็นหน่วยที่เหมาะสมและเพิ่มเพื่อให้เวลาทั้งหมดผ่านไป

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

บน linux clock_gettime () เป็นหนึ่งในตัวเลือกที่ดี คุณต้องเชื่อมโยงไลบรารีแบบเรียลไทม์ (-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

ฉันต้องการวัดเวลาดำเนินการของแต่ละฟังก์ชั่นภายในห้องสมุด ฉันไม่ต้องการตัดทุกการเรียกของทุกฟังก์ชั่นด้วยฟังก์ชั่นการวัดเวลาเพราะมันน่าเกลียดและทำให้สแต็คการโทรลึกขึ้น ฉันยังไม่ต้องการใส่รหัสตัวจับเวลาที่ด้านบนและด้านล่างของทุกฟังก์ชั่นเพราะมันจะเลอะเมื่อฟังก์ชั่นสามารถออกก่อนกำหนดหรือโยนข้อยกเว้นได้ ดังนั้นสิ่งที่ฉันทำคือการตั้งเวลาที่ใช้ชีวิตของตัวเองเพื่อวัดเวลา

ด้วยวิธีนี้ฉันสามารถวัดกำแพงเวลาบล็อกของรหัสโดยเพียงแค่สร้างวัตถุเหล่านี้ที่จุดเริ่มต้นของบล็อกรหัสในคำถาม (ฟังก์ชั่นหรือขอบเขตใด ๆ จริง ๆ ) แล้วปล่อยให้ตัวทำลายอินสแตนซ์วัดเวลา ก่อสร้างเมื่ออินสแตนซ์ออกนอกขอบเขต คุณสามารถค้นหาตัวอย่างทั้งหมดได้ที่นี่แต่โครงสร้างนั้นง่ายมาก:

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

struct จะโทรกลับหาคุณใน functor ที่ให้ไว้เมื่อมันออกนอกขอบเขตเพื่อให้คุณสามารถทำอะไรกับข้อมูลเวลา (พิมพ์หรือเก็บมันหรืออะไรก็ตาม) หากคุณต้องการที่จะทำบางสิ่งบางอย่างที่ซับซ้อนมากขึ้นคุณยังสามารถใช้std::bindกับstd::placeholdersฟังก์ชั่นการโทรกลับที่มีการขัดแย้งมากขึ้น

นี่คือตัวอย่างการใช้งาน:

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

หากคุณต้องการให้มีการไตร่ตรองมากขึ้นคุณยังสามารถใช้newและdeleteเพื่อเริ่มและหยุดตัวจับเวลาอย่างชัดเจนโดยไม่ต้องอาศัยการกำหนดขอบเขตเพื่อทำเพื่อคุณ


1

พวกเขาเหมือนกันเพราะฟังก์ชั่น doSomething ของคุณเกิดขึ้นเร็วกว่าความละเอียดของตัวจับเวลา ลอง:

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

เหตุผลที่ค่าทั้งสองเหมือนกันนั้นเป็นเพราะคุณ กระบวนงานที่ยาวไม่ใช้เวลานาน - น้อยกว่าหนึ่งวินาที คุณสามารถลองเพิ่มลูปแบบยาว (สำหรับ (int i = 0; i <100000000; i ++);) ที่ท้ายฟังก์ชั่นเพื่อให้แน่ใจว่านี่เป็นปัญหาจากนั้นเราจะไปจากที่นั่น ...

ในกรณีข้างต้นกลายเป็นจริงคุณจะต้องค้นหาฟังก์ชั่นระบบอื่น (ฉันเข้าใจว่าคุณทำงานกับ linux ดังนั้นฉันจึงไม่สามารถช่วยคุณใช้ชื่อฟังก์ชั่น) ในการวัดเวลาได้แม่นยำยิ่งขึ้น ฉันแน่ใจว่ามีฟังก์ชั่น simular สำหรับ GetTickCount () ใน linux คุณเพียงแค่ต้องค้นหามัน


1

ฉันมักจะใช้ต่อไปนี้:

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

เป็นเช่นเดียวกับ @ nikos-athanasiou ที่เสนอยกเว้นว่าฉันหลีกเลี่ยงการใช้นาฬิกาที่ไม่นิ่งและใช้จำนวนวินาทีที่ลอยตัวเป็นระยะเวลา


1
เกี่ยวกับเรื่องนี้typeswitch : โดยปกติhigh_resolution_clockเป็น typedef สำหรับทั้งหรือsystem_clock steady_clockดังนั้นเพื่อติดตามว่าstd::conditionalถ้าis_steadyส่วนหนึ่งเป็นความจริงแล้วคุณเลือกhigh_resolution_clockซึ่งเป็น (ก typedef steady_clockเพียง) ถ้ามันผิดคุณเลือกsteady_clockอีกครั้ง เพียงใช้steady_clockตั้งแต่ต้น ...
Nikos Athanasiou

@ nikos-athanasiou ฉันเห็นด้วยอย่างสมบูรณ์กับความคิดเห็นจาก 5gon12eder ว่ากรณี "ทั่วไป" ไม่จำเป็นต้องใช้มาตรฐานดังนั้น STL บางตัวอาจถูกนำไปใช้ในวิธีที่แตกต่างกัน ฉันต้องการให้รหัสของฉันเป็นแบบทั่วไปมากกว่าและไม่เกี่ยวข้องกับรายละเอียดการใช้งาน
oliora

มันไม่จำเป็นต้องใช้ แต่ระบุไว้อย่างชัดเจนใน20.12.7.3high_resolution_clock may be a synonym for system_clock or steady_clock : เหตุผลก็คือ: high_resolution_clockแสดงนาฬิกาที่มีระยะเวลาขีดที่สั้นที่สุดดังนั้นไม่ว่าจะใช้งานอะไรก็ตามมันมีสองตัวเลือก ไม่ว่าเราจะเลือกแบบใดการบอกว่าการนำไปใช้จะแตกต่างจากนาฬิกาสองเรือนอื่น ๆ ก็เหมือนกับการพูดว่าเรามีการติดตั้งที่ดีขึ้นสำหรับนาฬิกาที่มั่นคง (หรือไม่) ที่เราเลือกที่จะไม่ใช้ การรู้ว่าอะไรดีอย่างไรการรู้ว่าทำไมจึงดีกว่า
Nikos Athanasiou

@ nikos-athanasiou ฉันต้องการความปลอดภัย 100% โดยเฉพาะอย่างยิ่งเมื่อค่าใช้จ่ายนี้ฉันไม่มีค่าใช้จ่ายในการดำเนินการและค่าใช้จ่ายในการรวบรวมเวลาที่ตรวจไม่ได้ คุณอาจพึ่งพา "พฤษภาคม" และสมมติฐานหากคุณต้องการ
โอลิโอรา

au ตรงกันข้ามกับเพื่อนของฉันคุณเป็นคนที่ต้องพึ่ง "พฤษภาคม" แต่ก็เหมาะสมกับตัวเอง ถ้าคุณต้องการที่จะแน่ใจ 100% และเขียนมันต่อไปคุณควรหาวิธีสำหรับคุณและผู้ใช้รหัสของคุณเพื่อหลีกเลี่ยงการผสมเวลาของนาฬิกาที่แตกต่างกัน (ถ้าสวิตช์ประเภทนี้ได้รับความหมาย มันจะทำงานแตกต่างกันไปในแต่ละแพลตฟอร์ม) มีความสุข!
Nikos Athanasiou

0

เพื่อตอบคำถามสามข้อของ OP

"สิ่งที่ฉันไม่เข้าใจคือสาเหตุที่คุณค่าในก่อนและหลังเหมือนกัน "

คำถามแรกและการแสดงโค้ดตัวอย่างที่time()มีความละเอียด 1 วินาทีดังนั้นคำตอบที่จะต้องมีความว่าทั้งสองฟังก์ชั่นการดำเนินการในเวลาน้อยกว่า 1 วินาที แต่บางครั้งมันจะ (แจ้งชัดไร้เหตุผล) แจ้ง1 วินาทีถ้าตัวจับเวลาทั้งสองทำเครื่องหมายคร่อมเขตแดนหนึ่งวินาที

ตัวอย่างถัดไปใช้gettimeofday()ซึ่งเติมโครงสร้างนี้

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

และคำถามที่สองถามว่า: "ฉันจะอ่านผลลัพธ์ได้**time taken = 0 26339อย่างไรนั่นหมายถึง 26,339 nanoseconds = 26.3 msec"

คำตอบที่สองของฉันคือเวลาที่ใช้คือ 0 วินาทีและ 26339 microseconds นั่นคือ 0.026339 วินาทีซึ่งแสดงตัวอย่างแรกที่ดำเนินการในเวลาน้อยกว่า 1 วินาที

คำถามที่สามถาม: "สิ่งที่เกี่ยวกับ**time taken = 4 45025หมายความว่า 4 วินาทีและ 25 มิลลิวินาที?"

คำตอบที่สามของฉันคือเวลาที่ใช้คือ 4 วินาทีและ 45025 microseconds นั่นคือ 4.045025 วินาทีซึ่งแสดงว่า OP ได้เปลี่ยนแปลงงานที่ทำโดยสองฟังก์ชันที่เขาตั้งเวลาไว้ก่อนหน้านี้


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

}

ตัวอย่างที่คล้ายกับตัวอย่างที่มีให้ที่นี่เท่านั้นที่มีฟังก์ชันการแปลงเพิ่มเติม + พิมพ์ออกมา


0

ฉันได้สร้างคลาสเพื่อวัดเวลาที่ผ่านไปโดยอัตโนมัติโปรดตรวจสอบรหัส (c ++ 11) ในลิงค์นี้: https://github.com/sonnt174/Common/blob/master/time_measure.h

ตัวอย่างวิธีการใช้คลาส TimeMeasure:

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

ฉันชอบคำสั่งพิมพ์ของคุณกับหน่วย สิ่งที่ต้องใช้ในการย้ายรหัสของคุณไปยัง gcc และ clang คืออะไร ( wandbox.org )
Howard Hinnant

1
@HowardHinnant: ขอบคุณที่กล่าวถึงฉันได้อัปเดตโค้ดสำหรับ gcc และ clang เช่นกัน
Sirn Nguyen Truong

0

Matlab รส!

ticเริ่มจับเวลานาฬิกาจับเวลาเพื่อวัดประสิทธิภาพ ฟังก์ชั่นบันทึกเวลาภายในที่การดำเนินการของคำสั่ง tic แสดงเวลาที่ผ่านไปด้วยtocฟังก์ชั่น

#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

คุณสามารถใช้ไลบรารี SFMLซึ่งเป็นไลบรารีมัลติมีเดียที่ง่ายและรวดเร็ว มันมีคลาสที่มีประโยชน์และกำหนดชัดเจนมากมายเช่นนาฬิกา, ซ็อกเก็ต, เสียง, กราฟิก ฯลฯ มันใช้งานง่ายและแนะนำเป็นอย่างยิ่ง

นี่คือตัวอย่างสำหรับคำถามนี้

sf::Clock clock;
...
Time time1 = clock.getElapsedTime();
...
Time time2 = clock.restart();
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.