Search code examples
c++performancec++-chronotime-measurement

Syntactic sugar for timing a block of code in C++


Methods to time a block of code in C++ have been well documented, e.g., here and here.

In the answers to the questions linked, we usually need to write some lines of code at the start and end of the block of code being timed to start and stop the timer, and then calculate the elapsed time. For convenience, one can make a timing function, and then pass the block of code in as a function.

However, I'm curious to see if it's possible to make it even simpler by some syntactic sugar that allows me to time a block of code more like an if or while block, e.g.,

// some code

time_this_block {

    // code to time

}

// some code

This way, I won't need to put // code to time in its own separate function and then pass it to a timer function, nor would I need to create various variables of std::chrono every time I want to time a block. I can simply introduce the time_this_block with start / stop braces, and that's it. The time_this_block (statement? operation? macro?) will have some predefined behaviour, e.g. print the time elapsed to stdout.

Is this, or something similar, possible? If so, how?


Solution

  • You can use an RAII class to do the measurement.

    Something like:

    #include <chrono>
    #include <iostream>
    
    class BlockTimer {
    public:
        BlockTimer() {
            m_start = std::chrono::steady_clock::now();
        }
        ~BlockTimer() {
            auto end = std::chrono::steady_clock::now();
            auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - m_start);
            std::cout << "duration (ms): " << duration.count() << "\n";
        }
    private:
        std::chrono::steady_clock::time_point m_start;
    };
    

    Then use it in the following way:

    {
        BlockTimer btimer;
        // ... some code
    } // here the scope of `btimer` will end and it will report the duration of the block
    

    Live demo

    Notes:

    1. If you need a higher resolution measurement, you can change milliseconds to nanoseconds.

    2. If you have many blocks you wish to measure, you can add a string parameter to BlockTimer's constructor with a name/description of the block, store it in a member, and then use it to customize the measurement print in the destructor.
      Live demo with block name.

    3. A nice improvement would be to add a bEnable bool flag to BlockTimer, that will allow you to disable the measurements easily (e.g. for production vs development).
      This flag can be either a template parameter (if you can resolve it at compile time), or a contructor parameter (to assign to a member) if you want it to be determined at run time. You can then use the flag with an if (or if constexpr if it's a compile time constant) to do the measurement conditionaly.
      Live demo with bEnable determined at compiler time.
      Live demo with bEnable determined at run time.

      Of course you can also combine enhancements 2 and 3 above.