Measuring execution time of a function in C++
我想知道某个函数在我的C++程序上在Linux上执行的时间。然后,我想做一个速度比较。我看到了一些时间函数,但最后从Boost得到了这个结果。Chrono:
1 | process_user_cpu_clock, captures user-CPU time spent by the current process |
现在,我还不清楚是否使用了上述函数,我会得到CPU在该函数上花费的唯一时间吗?
其次,我找不到任何使用上述函数的例子。有人能帮我使用上述功能吗?
P.S:现在,我正在使用
这是一个非常容易使用的方法在C++ 11中。您必须使用来自
像这样使用它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include <iostream> #include <chrono> using namespace std; using namespace std::chrono; void function() { long long number = 0; for( long long i = 0; i != 2000000; ++i ) { number += 5; } } int main() { high_resolution_clock::time_point t1 = high_resolution_clock::now(); function(); high_resolution_clock::time_point t2 = high_resolution_clock::now(); auto duration = duration_cast<microseconds>( t2 - t1 ).count(); cout << duration; return 0; } |
这将测量函数的持续时间。
注意:不需要总是获得相同的输出,因为您的计算机的CPU可以被运行在您的计算机上的其他进程使用得更少或更多。当你解决一个数学问题时,你的思想或多或少会集中起来,所以你会在不同的时间解决这个问题。在人类的头脑中,我们可以记住一个数学问题的解决方案,尽管对于一台计算机来说,相同的过程总是新的,所以,正如我所说,不需要总是得到相同的结果!
下面是一个函数,它将测量作为参数传递的任何函数的执行时间:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include <chrono> #include <utility> typedef std::chrono::high_resolution_clock::time_point TimeVar; #define duration(a) std::chrono::duration_cast<std::chrono::nanoseconds>(a).count() #define timeNow() std::chrono::high_resolution_clock::now() template<typename F, typename... Args> double funcTime(F func, Args&&... args){ TimeVar t1=timeNow(); func(std::forward<Args>(args)...); return duration(timeNow()-t1); } |
示例用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include <iostream> #include typedef std::string String; //first test function doing something int countCharInString(String s, char delim){ int count=0; String::size_type pos = s.find_first_of(delim); while ((pos = s.find_first_of(delim, pos)) != String::npos){ count++;pos++; } return count; } //second test function doing the same thing in different way int countWithAlgorithm(String s, char delim){ return std::count(s.begin(),s.end(),delim); } int main(){ std::cout<<"norm:"<<funcTime(countCharInString,"precision=10",'=')<<" "; std::cout<<"algo:"<<funcTime(countWithAlgorithm,"precision=10",'='); return 0; } |
输出:
1 2 | norm: 15555 algo: 2976 |
查找函数执行时间所用的简单程序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include <iostream> #include <ctime> // time_t #include <cstdio> void function() { for(long int i=0;i<1000000000;i++) { // do nothing } } int main() { time_t begin,end; // time_t is a datatype to store time values. time (&begin); // note time before execution function(); time (&end); // note time after execution double difference = difftime (end,begin); printf ("time taken for function() %.2lf seconds. ", difference ); return 0; } |
在ScottMeyers的书中,我发现了一个通用通用通用lambda表达式的例子,它可以用来测量函数执行时间。(C++ 14)
1 2 3 4 5 6 7 8 9 10 | auto timeFuncInvocation = [](auto&& func, auto&&... params) { // get time before function invocation const auto& start = high_resolution_clock::now(); // function invocation using perfect forwarding std::forward<decltype(func)>(func)(std::forward<decltype(params)>(params)...); // get time after function invocation const auto& stop = high_resolution_clock::now(); return stop - start; }; |
问题是,您只度量一个执行,因此结果可能非常不同。为了得到可靠的结果,您应该测量大量的执行。根据Andrei Alexandrescu在代码::Dive 2015会议上的演讲-快速编写代码I:
测量时间:tm=t+tq+tn+to
在哪里?
TM-测量(观察)时间
t-实际利息时间
TQ—量化噪声增加的时间
tn-各种噪声源增加的时间
到-开销时间(测量、循环、调用函数)
根据他在后面的讲座中所说的,你应该把这么多的执行作为你的结果。我鼓励你看看他解释原因的讲座。
还有一个非常好的谷歌图书馆-https://github.com/google/benchmark。这个库使用简单,功能强大。你可以在YouTube上查看钱德勒·卡拉斯的一些讲座,他在那里使用这个图书馆进行实践。例如,2017年CPPCON:Chandler Carruth"无路可走";
示例用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #include <iostream> #include <chrono> #include <vector> auto timeFuncInvocation = [](auto&& func, auto&&... params) { // get time before function invocation const auto& start = high_resolution_clock::now(); // function invocation using perfect forwarding for(auto i = 0; i < 100000/*largeNumber*/; ++i) { std::forward<decltype(func)>(func)(std::forward<decltype(params)>(params)...); } // get time after function invocation const auto& stop = high_resolution_clock::now(); return (stop - start)/100000/*largeNumber*/; }; void f(std::vector<int>& vec) { vec.push_back(1); } void f2(std::vector<int>& vec) { vec.emplace_back(1); } int main() { std::vector<int> vec; std::vector<int> vec2; std::cout << timeFuncInvocation(f, vec).count() << std::endl; std::cout << timeFuncInvocation(f2, vec2).count() << std::endl; std::vector<int> vec3; vec3.reserve(100000); std::vector<int> vec4; vec4.reserve(100000); std::cout << timeFuncInvocation(f, vec3).count() << std::endl; std::cout << timeFuncInvocation(f2, vec4).count() << std::endl; return 0; } |
编辑:当然,您总是需要记住,您的编译器是否可以优化某些东西。像perf这样的工具在这种情况下是有用的。
老C++的简单方法,或者C:
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include <time.h> // includes clock_t and CLOCKS_PER_SEC int main() { clock_t start, end; start = clock(); // ...code to measure... end = clock(); double duration_sec = double(end-start)/CLOCKS_PER_SEC; return 0; } |
以秒为单位的定时精度为
- It is a very easy to use method in C++11.
- We can use std::chrono::high_resolution_clock from header
- We can write a method to print the method execution time in a much readable form.
例如,要找到1到1亿之间的所有素数,大约需要1分40秒。因此执行时间打印为:
1 | Execution Time: 1 Minutes, 40 Seconds, 715 MicroSeconds, 715000 NanoSeconds |
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | #include <iostream> #include <chrono> using namespace std; using namespace std::chrono; typedef high_resolution_clock Clock; typedef Clock::time_point ClockTime; void findPrime(long n, string file); void printExecutionTime(ClockTime start_time, ClockTime end_time); int main() { long n = long(1E+8); // N = 100 million ClockTime start_time = Clock::now(); // Write all the prime numbers from 1 to N to the file"prime.txt" findPrime(n,"C:\\prime.txt"); ClockTime end_time = Clock::now(); printExecutionTime(start_time, end_time); } void printExecutionTime(ClockTime start_time, ClockTime end_time) { auto execution_time_ns = duration_cast<nanoseconds>(end_time - start_time).count(); auto execution_time_ms = duration_cast<microseconds>(end_time - start_time).count(); auto execution_time_sec = duration_cast<seconds>(end_time - start_time).count(); auto execution_time_min = duration_cast<minutes>(end_time - start_time).count(); auto execution_time_hour = duration_cast<hours>(end_time - start_time).count(); cout <<" Execution Time:"; if(execution_time_hour > 0) cout <<"" << execution_time_hour <<" Hours,"; if(execution_time_min > 0) cout <<"" << execution_time_min % 60 <<" Minutes,"; if(execution_time_sec > 0) cout <<"" << execution_time_sec % 60 <<" Seconds,"; if(execution_time_ms > 0) cout <<"" << execution_time_ms % long(1E+3) <<" MicroSeconds,"; if(execution_time_ns > 0) cout <<"" << execution_time_ns % long(1E+6) <<" NanoSeconds,"; } |
下面是一个非常好的只包含头的类模板,用于测量函数或任何代码块的运行时间:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #ifndef EXECUTION_TIMER_H #define EXECUTION_TIMER_H template<class Resolution = std::chrono::milliseconds> class ExecutionTimer { public: using Clock = std::conditional_t<std::chrono::high_resolution_clock::is_steady, std::chrono::high_resolution_clock, std::chrono::steady_clock>; private: const Clock::time_point mStart = Clock::now(); public: ExecutionTimer() = default; ~ExecutionTimer() { const auto end = Clock::now(); std::ostringstream strStream; strStream <<"Destructor Elapsed:" << std::chrono::duration_cast<Resolution>( end - mStart ).count() << std::endl; std::cout << strStream.str() << std::endl; } inline void stop() { const auto end = Clock::now(); std::ostringstream strStream; strStream <<"Stop Elapsed:" << std::chrono::duration_cast<Resolution>(end - mStart).count() << std::endl; std::cout << strStream.str() << std::endl; } }; // ExecutionTimer #endif // EXECUTION_TIMER_H |
以下是它的一些用途:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | int main() { { // empty scope to display ExecutionTimer's destructor's message // displayed in milliseconds ExecutionTimer<std::chrono::milliseconds> timer; // function or code block here timer.stop(); } { // same as above ExecutionTimer<std::chrono::microseconds> timer; // code block here... timer.stop(); } { // same as above ExecutionTimer<std::chrono::nanoseconds> timer; // code block here... timer.stop(); } { // same as above ExecutionTimer<std::chrono::seconds> timer; // code block here... timer.stop(); } return 0; } |
由于类是一个模板,因此我们可以轻松地指定希望如何测量和显示时间。这是一个非常方便的工具类模板做基准,非常容易使用。