Elegant timelines in C ++

I am interested in calculating the execution time of a free function or a member function (template or not). Call TheFunc function in question, its call

TheFunc(/*parameters*/); 

or

 ReturnType ret = TheFunc(/*parameters*/); 

Of course, I could wrap these function calls as follows:

 double duration = 0.0 ; std::clock_t start = std::clock(); TheFunc(/*parameters*/); duration = static_cast<double>(std::clock() - start) / static_cast<double>(CLOCKS_PER_SEC); 

or

 double duration = 0.0 ; std::clock_t start = std::clock(); ReturnType ret = TheFunc(/*parameters*/); duration = static_cast<double>(std::clock() - start) / static_cast<double>(CLOCKS_PER_SEC); 

but I would like to do something more elegant than this, namely (and from now on I will stick to the void return type) as follows:

 Timer thetimer ; double duration = 0.0; thetimer(*TheFunc)(/*parameters*/, duration); 

where Timer is some time class that I would like to create, and this would allow me to write the previous code in such a way that after turning off the last line of the previous code, the double duration will contain the execution time

 TheFunc(/*parameters*/); 

but I don’t see how to do this, and if the syntax / solution I am aiming for is optimal ...

+5
source share
4 answers

With a variation template, you can:

 template <typename F, typename ... Ts> double Time_function(F&& f, Ts&&...args) { std::clock_t start = std::clock(); std::forward<F>(f)(std::forward<Ts>(args)...); return static_cast<double>(std::clock() - start) / static_cast<double>(CLOCKS_PER_SEC); } 
+6
source

I really like boost::cpu_timer::auto_cpu_timer , and when I cannot use boost, I just hack my own:

 #include <cmath> #include <string> #include <chrono> #include <iostream> class AutoProfiler { public: AutoProfiler(std::string name) : m_name(std::move(name)), m_beg(std::chrono::high_resolution_clock::now()) { } ~AutoProfiler() { auto end = std::chrono::high_resolution_clock::now(); auto dur = std::chrono::duration_cast<std::chrono::microseconds>(end - m_beg); std::cout << m_name << " : " << dur.count() << " musec\n"; } private: std::string m_name; std::chrono::time_point<std::chrono::high_resolution_clock> m_beg; }; void foo(std::size_t N) { long double x {1.234e5}; for(std::size_t k = 0; k < N; k++) { x += std::sqrt(x); } } int main() { { AutoProfiler p("N = 10"); foo(10); } { AutoProfiler p("N = 1,000,000"); foo(1000000); } } 

This timer works thanks to RAII. When you build an object within an area, you store a time point at that point in time. When you leave the scope (that is, in the appropriate } ), the timer first saves the time point, then calculates the number of ticks (which you can convert to human-readable duration) and finally displays them.

Of course boost::timer::auto_cpu_timer much more complicated than my simple implementation, but I often find that my implementation is more than sufficient for my purposes.

An example run on my computer:

 $ g++ -o example example.com -std=c++14 -Wall -Wextra $ ./example N = 10 : 0 musec N = 1,000,000 : 10103 musec 

EDIT

I really liked the implementation proposed by @ Jarod42. I modified it a bit to offer some flexibility regarding the desired "units" of output.

By default, the number of microseconds passed is returned (an integer, usually std::size_t ), but you can request output at any time of your choice.

I think this is a more flexible approach than the one I suggested earlier, because now I can do other things, for example, take measurements and store them in a container (as in the example).

Thanks to @ Jarod42 for inspiration.

 #include <cmath> #include <string> #include <chrono> #include <algorithm> #include <iostream> template<typename Duration = std::chrono::microseconds, typename F, typename ... Args> typename Duration::rep profile(F&& fun, Args&&... args) { const auto beg = std::chrono::high_resolution_clock::now(); std::forward<F>(fun)(std::forward<Args>(args)...); const auto end = std::chrono::high_resolution_clock::now(); return std::chrono::duration_cast<Duration>(end - beg).count(); } void foo(std::size_t N) { long double x {1.234e5}; for(std::size_t k = 0; k < N; k++) { x += std::sqrt(x); } } int main() { std::size_t N { 1000000 }; // profile in default mode (microseconds) std::cout << "foo(1E6) takes " << profile(foo, N) << " microseconds" << std::endl; // profile in custom mode (eg, milliseconds) std::cout << "foo(1E6) takes " << profile<std::chrono::milliseconds>(foo, N) << " milliseconds" << std::endl; // To create an average of `M` runs we can create a vector to hold // `M` values of the type used by the clock representation, fill // them with the samples, and take the average std::size_t M {100}; std::vector<typename std::chrono::milliseconds::rep> samples(M); for(auto & sample : samples) { sample = profile(foo, N); } auto avg = std::accumulate(samples.begin(), samples.end(), 0) / static_cast<long double>(M); std::cout << "average of " << M << " runs: " << avg << " microseconds" << std::endl; } 

Output (compiled using g++ example.cpp -std=c++14 -Wall -Wextra -O3 ):

 foo(1E6) takes 10073 microseconds foo(1E6) takes 10 milliseconds average of 100 runs: 10068.6 microseconds 
+4
source

You can do it in the MatLab way. Very old school, but simple, often good:

  tic(); a = f(c); toc(); //print to stdout, or auto elapsed = toc(); //store in variable 

tic() and toc() can work with a global variable. If this is not enough, you can create local variables using some macro magic:

  tic(A); a = f(c); toc(A); 
+1
source

I'm a fan of using RAII wrappers for this type of thing.

The following example is a bit detailed, but it is more flexible, since it works with arbitrary areas, and is not limited to a single function call:

 class timing_context { public: std::map<std::string, double> timings; }; class timer { public: timer(timing_context& ctx, std::string name) : ctx(ctx), name(name), start(std::clock()) {} ~timer() { ctx.timings[name] = static_cast<double>(std::clock() - start) / static_cast<double>(CLOCKS_PER_SEC); } timing_context& ctx; std::string name; std::clock_t start; }; timing_context ctx; int main() { timer_total(ctx, "total"); { timer t(ctx, "foo"); // Do foo } { timer t(ctx, "bar"); // Do bar } // Access ctx.timings } 

The disadvantage is that you can have many areas that only serve to destroy the synchronization object.

This might or may not meet your requirements, as your request was a bit vague, but it illustrates how using RAII semantics can do for some really nice multiple and clean code. It can probably be modified to look much better!

0
source

All Articles