31

Let me ask my question by this test program:

#include <iostream>
#include <chrono>

using std::chrono::nanoseconds;
using std::chrono::duration_cast;

int main(int argc, char* argv[])
{
    std::cout 
      << "Resolution (nano) = " 
      << (double) std::chrono::high_resolution_clock::period::num / 
                  std::chrono::high_resolution_clock::period::den * 
                  1000 * 1000 * 1000 
      << std::endl;

    auto t1 = std::chrono::high_resolution_clock::now();
    std::cout << "How many nanoseconds does std::cout take?" << std::endl;
    auto t2 = std::chrono::high_resolution_clock::now();

    auto diff = t2-t1;
    nanoseconds ns = duration_cast<nanoseconds>(diff);

    std::cout << "std::cout takes " << ns.count() << " nanoseconds" 
              << std::endl;
    return 0;
}

Output on my machine:

Resolution (nano) = 100

How many nanoseconds does std::cout take?

std::cout takes 1000200 nanoseconds

I receive either 1000200 or 1000300 or 1000400 or 1000500 or 1000600 or 2000600 as a result (= 1 or 2 microsecond). Obviously, either the resolution of std::chrono is not 100 nano-seconds or the way I measure the time of std::cout is wrong. (Why do I never receive something between 1 and 2 microseconds, for example 1500000?)

I need a high-resolution timer in C++. The OS itself provides a high-resolution timer, because I'm able to measure things with microsecond-precision using the C# Stopwatch class on the same machine. So I would just need to correctly use the high-resolution timer that the OS has!

How do I fix my program to produce the expected results?

Community
  • 1
  • 1
Oleg Vazhnev
  • 23,239
  • 54
  • 171
  • 305
  • 1
    I can't answer the question, but for what it's worth, this code produces correct (nanosecond precision) results on my machine, so the problem is most likely in your library implementation. – Mankarse Apr 30 '13 at 11:58
  • Related: http://stackoverflow.com/questions/8386128/how-to-get-the-precision-of-high-resolution-clock – stefan Apr 30 '13 at 11:58
  • Are you using VS2012? – David Apr 30 '13 at 12:01

3 Answers3

53

I'm going to guess you are using Visual Studio 2012. If not, disregard this answer. Visual Studio 2012 typedef's high_resolution_clock to system_clock. Sadly, this means it has crappy precision (around 1 ms). I wrote a better high-resolution clock which uses QueryPerformanceCounter for use in Visual Studio 2012...

HighResClock.h:

    struct HighResClock
    {
        typedef long long                              rep;
        typedef std::nano                              period;
        typedef std::chrono::duration<rep, period>     duration;
        typedef std::chrono::time_point<HighResClock>  time_point;
        static const bool is_steady = true;

        static time_point now();
    };

HighResClock.cpp:

namespace
{
    const long long g_Frequency = []() -> long long
    {
        LARGE_INTEGER frequency;
        QueryPerformanceFrequency(&frequency);
        return frequency.QuadPart;
    }();
}

HighResClock::time_point HighResClock::now()
{
    LARGE_INTEGER count;
    QueryPerformanceCounter(&count);
    return time_point(duration(count.QuadPart * static_cast<rep>(period::den) / g_Frequency));
}

(I left out an assert and #ifs to see if it's being compiled on Visual Studio 2012 from the above code.)

You can use this clock anywhere and in the same way as standard clocks.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
David
  • 27,652
  • 18
  • 89
  • 138
  • `VS2012 typedef's high_resolution_clock to system_clock` why? if I still want to use c++11 high res timer how can I force VS2012 to do that? – Oleg Vazhnev Apr 30 '13 at 12:11
  • 5
    @javapowered They did it because they believe they have too much market share and want to turn people off of using VS. Visual Studio sucks in a number of ways, this is one of them. Above is how high_resolution_clock _should've_ been implemented in VS's standard library... It's simple too so I don't know why they just went and `typedef`'d it to `system_clock`. Maybe it just slipped through the cracks. – David Apr 30 '13 at 12:14
  • 4
    Interesting to know that *The VC++ 2012 implementation has been acknowledged as a bug by MS's standard library maintainer*. - (http://stackoverflow.com/questions/13263277/difference-between-stdsystem-clock-and-stdsteady-clock) – SChepurin Apr 30 '13 at 12:30
  • 8
    A bug was [reported](https://connect.microsoft.com/VisualStudio/feedback/details/719443/) for this issue, but no news on a fix yet - you could always use boost in the meantime. – icabod Apr 30 '13 at 12:31
  • 1
    Update As indicated by the last comment the bug is fixed but the fix will not be available till the next version of visual C++ "Thanks for reporting this bug. We've fixed it, and the fix will be available in the next major version of VC (i.e. after 2013)." – Michael Shaffer Dec 30 '14 at 19:32
  • Is it possible to cast the result from HighResClock::now to a time_point in some way? – Lallen Jun 30 '15 at 12:09
  • @Lallen you could either just use `high_resolution_clock::time_point` as the `time_point` for `HighResClock` which would be fine, or see [`duration_cast`](http://en.cppreference.com/w/cpp/chrono/duration/duration_cast) – David Jun 30 '15 at 15:44
  • 5
    Using Visual Studio 2015, `std::chrono::high_resolution_clock` is now `typedef` to `std::chrono::steady_clock`. Straight from `typedef steady_clock high_resolution_clock;` – Mark A. Ropper Sep 25 '15 at 11:06
  • 1
    @David, your multiplication `count.QuadPart * static_cast(period::den)` overflows on a system which has been running without a shutdown for a long time. After this overflow the clock starts producing wrong results. – Serge Rogatch Nov 12 '15 at 10:12
  • 5
    And to add to the comment from Mark - steady_clock (and by extension high_resolution_clock) use QueryPerformanceCounter in VS2015. – etarion Sep 26 '16 at 13:10
  • Mingw64 also has this issue. Might be worth mentioning. – Timmmm Apr 28 '17 at 10:57
  • I can use like this: HighResClock::time_point startTime1 = HighResClock::now(); HighResClock::time_point endTime1 = HighResClock::now(); HighResClock::duration deltaTime1 = (endTime1 - startTime1); std::cout << "Size of count: " << sizeof(deltaTime1.count()) << std::endl; std::cout << "Delta Time 1: " << deltaTime1.count() << std::endl; Nanoseconds delta between end time and start time is ~(+/-)5000. This is around 5 microseconds error. I want to know if is possible to measure function call time in nanoseconds (epilogue + prologue) correctly. – LXSoft Aug 16 '18 at 14:59
8

The resolution of a clock is not necessarily the same as the smallest duration that can be represented by the data type the clock uses. In this case your implementation uses a data type which can represent a duration as small as 100 nanoseconds, but the underlying clock doesn't actually have such a resolution.


The low resolution of Visual Studio's high_resolution_clock has been an issue for several years. Microsoft's C++ standard library maintainer, Stephan T. Lavavej, has indicated that this has been fixed in Visual Studio 2015 via the use of QueryPerformanceCounter().

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
bames53
  • 86,085
  • 15
  • 179
  • 244
2

Maybe the implementation doesn't implement the higher resolution timer?

It seems you are using Windows (you mention C#), so if you use a timer and you are indeed using Windows, you can use QueryPerformanceFrequency and QueryPerformanceCounter.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
graham.reeds
  • 16,230
  • 17
  • 74
  • 137
  • are the QPC functions also mapped to something in the std::chrono namespace? – stijn Apr 30 '13 at 11:56
  • @stefan: What's your source on that claim? – interjay Apr 30 '13 at 12:04
  • 1
    The standard just says "Objects of class high_resolution_clock represent clocks with the shortest tick period." It doesn't say in what context - the world, the system, or the implementation. IMO, this phrasing just means that no other implementation-provided clock may be more accurate. In particular, if system_clock or steady_clock were more accurate, that would be invalid. As for cppreference.com, it's a community-edited wiki and has zero normative meaning. – Sebastian Redl Apr 30 '13 at 12:16