3

I was working with the Chrono library for time measurement. I find out the following code and I know how to use it.

class Timer {
private:
    std::chrono::time_point<std::chrono::high_resolution_clock> pr_StartTime;
    std::chrono::time_point<std::chrono::high_resolution_clock> pr_EndTime;

public:
    Timer() 
    {
        Start();
    }

    ~Timer() 
    {
        Finish();
    }

    void Start() 
    {
        pr_StartTime = std::chrono::high_resolution_clock::now();
    }

    void Finish()
    {
        pr_EndTime = std::chrono::high_resolution_clock::now();

        auto StartTimeMs = std::chrono::time_point_cast<std::chrono::microseconds>(pr_StartTime).time_since_epoch().count();
        auto EndTimeMs = std::chrono::time_point_cast<std::chrono::microseconds>(pr_EndTime).time_since_epoch().count();
        auto Duration = EndTimeMs - StartTimeMs;
        std::cout << "Duration " << Duration << " microseconds." << std::endl;
    }
};

But I didn't realize why the developer used time_since_epoch().count() in casting step. Why we should use time_since_epoch() and count()?

  • I have no idea why they are calling `time_since_epoch`. Maybe Howard Hinnat will have an idea. – NathanOliver Oct 21 '19 at 14:04
  • 3
    This seems like more of a common error where people escape the chrono types ASAP instead of as late as possible. Chrono types offer subtraction where you don't have to keep track of the units involved yourself. The code then makes it even worse by using `Ms` for "microseconds". – chris Oct 21 '19 at 14:05
  • For the record: [std::chrono::time_point<>::time_since_epoch()](https://en.cppreference.com/w/cpp/chrono/time_point/time_since_epoch), [std::chrono::duration<>::count](https://en.cppreference.com/w/cpp/chrono/duration/count) – Scheff's Cat Oct 21 '19 at 14:08

1 Answers1

5

Here is a slight rewrite of your Timer. I'll explain each change I made below:

class Timer {
private:
    std::chrono::steady_clock::time_point pr_StartTime;
    std::chrono::steady_clock::time_point pr_EndTime;

public:
    Timer() 
    {
        Start();
    }

    ~Timer() 
    {
        Finish();
    }

    void Start() 
    {
        pr_StartTime = std::chrono::steady_clock::now();
    }

    void Finish()
    {
        using namespace std::chrono;
        pr_EndTime = steady_clock::now();
        auto Duration = duration_cast<microseconds>(pr_EndTime-pr_StartTime);
        std::cout << "Duration " << Duration.count() << " microseconds." << std::endl;
    }
};
  • I switched from high_resolution_clock to steady_clock because high_resolution_clock is always a typedef to either steady_clock or system_clock. See https://stackoverflow.com/a/31553641/576911 for the difference between these two clocks. I prefer to choose either steady_clock or system_clock, so I know what I'm getting.

  • std::chrono::steady_clock::time_point is simply a more concise way to name the type std::chrono::time_point<std::chrono::steady_clock>. Both are correct.

  • When you subtract two time_points, you get a duration. It is simpler to just subtract the time_points, get the duration, and then cast that duration to the desired precision. What you have is not incorrect, just a more convoluted and less safe way to achieve the same result.

  • Unfortunately to print, one must extract the integral value from the Duration with the .count() member function. I avoid doing that until the last statement, as it is akin to a dangerous reinterpret_cast from duration to integral. In C++20, you will no longer have to use .count() to print durations.

  • I prefer to issue a using namespace std::chrono; at function scope instead of writing std::chrono:: multiple times. I simply find it more readable, but this is just my subjective opinion on readability.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • Thank you, but it doesn't work for me. When I run you code for runtime execution measurement of my code, it shows me 0 microseconds for the duration. –  Oct 21 '19 at 18:15
  • You could try casting to nanoseconds. Maybe what you're timing is taking less than a microsecond. The other possibility is that your `Timer` object is a temporary, constructing and destructing within the same statement, and again timing less than a microsecond. – Howard Hinnant Oct 21 '19 at 19:10
  • 1
    Or it could be the type-o I just corrected in my answer. :-) – Howard Hinnant Oct 21 '19 at 19:17