Search code examples
c++profilingtimingboost-timer

Aggregate wall time of code blocks in C++


I have a large codebase and I want to manually add some timers to profile some sections of the code. Some of those sections are within a loop, so I would like to aggregate all the wall time spent there for each iteration.

What I'd like to do in a Pythonic pseudo-code:

time_step_1 = 0
time_step_2 = 0
for pair in pairs:

    start_step_1 = time.now()
    run_step_1(pair)
    time_step_1 += start_step_1 - time.now()

    start_step_2 = time.now()
    run_step_2(pair)
    time_step_2 += start_step_2 - time.now()

print("Time spent in step 1", time_step_1)
print("Time spent in step 2", time_step_2)

Is there a library in C++ to do this? Otherwise would you recommend using boost::timer, create a map of timers and then resume and stop at each iteration?


Solution

  • Not very advanced, but for basic time measurement, you can use std::chrono library, specifically the std::chrono::high_resolution_clock - the clock with smallest tick period (= highest accuracy) provided by the implementation.

    For some more trivial time measurement, I have used RAII classes similar to this:

    #include <chrono>
    #include <cstdint>
    #include <iomanip>
    #include <iostream>
    #include <string>
    
    class TimeMeasureGuard {
    public:
        using clock_type = std::chrono::high_resolution_clock;
    
    private:
        const std::string m_testName;
        std::ostream& m_os;
    
        clock_type::time_point started_at;
        clock_type::time_point ended_at;
    
    public:
        TimeMeasureGuard(const std::string& testName, std::ostream& os = std::cerr)
            : m_testName(testName), m_os(os)
        {
            started_at = clock_type::now();
        }
    
        ~TimeMeasureGuard()
        {
            ended_at = clock_type::now();
    
            // Get duration
            const auto duration = ended_at - started_at;
    
            // Get duration in nanoseconds
            const auto durationNs = std::chrono::nanoseconds(duration).count();
            // ...or in microseconds:
            const auto durationUs
                = std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
    
            // Report total run time into 'm_os' stream
            m_os << "[Test " << std::quoted(m_testName) << "]: Total run time: "
                 << durationNs << " ns, " << "or: " << durationUs << " us" << std::endl;
        }
    };
    

    Of course this is a very simple class, which would deserve several improvements before being used for a real measurement.

    You can use this class like:

    std::uint64_t computeSquares()
    {
        std::uint64_t interestingNumbers = 0;
        {
            auto time_measurement = TimeMeasureGuard("Test1");
    
            for (std::uint64_t x = 0; x < 1'000; ++x) {
                for (std::uint64_t y = 0; y < 1'000; ++y) {
                    if ((x * y) % 42 == 0)
                        ++interestingNumbers;
                }
            }
        }
        return interestingNumbers;
    }
    
    int main()
    {
        std::cout << "Computing all x * y, where 'x' and 'y' are from 1 to 1'000..."
                  << std::endl;
        const auto res = computeSquares();
        std::cerr << "Interesting numbers found: " << res << std::endl;
    
        return 0;
    }
    

    And the output is:

    Computing all x * y, where 'x' and 'y' are from 1 to 1'000...
    [Test "Test1"]: Total run time: 6311371 ns, or: 6311 us
    Interesting numbers found: 111170
    

    For simple time measurement cases, this might be easier than using a whole timer library, and it's just a few lines of code, you don't need to include lots of headers.