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