Several questions about <chrono> header in C++ 11
Asked Answered
B

2

10

I have several questions about new <chrono> header in C++ 11. Using Windows 7, Visual Studio 2012.

Looking at the example http://en.cppreference.com/w/cpp/chrono

#include <iostream>
#include <chrono>
#include <ctime>

int fibonacci(int n)
{
    if (n < 3) return 1;
    return fibonacci(n-1) + fibonacci(n-2);
}

int main()
{
    std::chrono::time_point<std::chrono::system_clock> start, end;
    start = std::chrono::system_clock::now();
    int result = fibonacci(42);
    end = std::chrono::system_clock::now();

    int elapsed_seconds = std::chrono::duration_cast<std::chrono::seconds>
                             (end-start).count();
    std::time_t end_time = std::chrono::system_clock::to_time_t(end);

    std::cout << "finished computation at " << std::ctime(&end_time)
              << "elapsed time: " << elapsed_seconds << "s\n";
}

Possible output

finished computation at Sat Jun 16 20:42:57 2012
elapsed time: 3s
  1. I have noticed that example uses std::chrono::system_clock::now(); does it mean it can be used to measure only elapsed time and not the CPU time ??? And if I want to measure CPU time, what Clocks should I use ?
  2. Notice that elapsed time: 3s is output is rounded to whole integer. Is there way to make it more granulated?
Buckthorn answered 2/12, 2012 at 4:7 Comment(4)
2. Well, yeah, you used seconds. Use milliseconds and voila, more granulated! Heck, use nanoseconds if you want.Vicarious
@Vicarious Hm ....great advice. double elapsed_seconds = (std::chrono::duration_cast<std::chrono::milliseconds> (end-start).count())/1000;Buckthorn
Aside: Just so that you're aware, I've encountered a compiler that took end to mean std::end. It might have been GCC 4.7.1, but I could be wrong. I know the latest version of GCC no longer does that, but it's something to watch out for if you have other compilers that will use this.Vicarious
<chrono> is a header (and namespace), not a class. I corrected that for you.Winou
A
15
  1. Correct

    According to the standard:

    system_clock represent[s] wall clock time from the system-wide realtime clock.

    The <chrono> library does not provide a mechanism for measuring CPU time, so if you want that you'll have to fall back on the old <ctime> library and use std::clock().

    (And if you're targeting Windows you'll have to fall back on whatever platform-specific API Windows provides for getting CPU time since, as you point out, their std::clock() doesn't work correctly.)

    system_clock is more like a counterpart to std::time() than to std::clock(). (E.g., note that system_clock provides conversions between system_clock::time_points and time_t.) I imagine that the lack of a clock in <chrono> for measuring CPU time is due to time constraints on the standard committee and the fact that that functionality is less used than the system's wall clock and real-time clocks.

    If you want CPU time but also want the benefits that <chrono> provides, you should implement a clock type that conforms to the Clock concept outlined in the standard and which provides CPU time, perhaps implemented internally using std::clock().

  2. The line that says

    int elapsed_seconds = std::chrono::duration_cast<std::chrono::seconds>
                        (end-start).count();
    

    is what causes the time to be rounded to an integral number of seconds. You can choose any period you'd like, or you can use a floating point representation in order to allow non-integral values:

    std::int64_t elapsed_attoseconds =
        std::chrono::duration_cast<std::chrono::duration<std::int64_t, std::atto>>
            (end-start).count();
    
    double elapsed_seconds =
        std::chrono::duration_cast<std::chrono::duration<double,std::ratio<1>>>
            (end-start).count();
    

    Note that in real code you should avoid using .count() to escape the strong typing provided by chrono::duration until you absolutely must.

    auto total_duration = end - start;
    auto seconds = std::chrono::duration_cast<std::chrono::seconds>(total_duration);
    auto milli = std::chrono::duration_cast<std::chrono::milliseconds>(total_duration - seconds);
    
    std::cout << seconds.count() << "s " << milli.count() << "ms\n";
    
Alix answered 2/12, 2012 at 5:37 Comment(2)
Problem is std::clock() measures wall time on Windows, and CPU time on Linux.Buckthorn
@Buckthorn Yeah, that's unfortunate. Microsoft should fix their implementation to match the standard specification.Alix
T
4

1) I'm fairly certain the highest resolution you can get is to use std::chrono::high_resolution_clock and then don't do any duration casting:

int elapsed_ticks = (end-start).count();

2) Change the argument of duration_cast to something like nanoseconds:

int elapsed_seconds = std::chrono::duration_cast<std::chrono::nanoseconds>
                             (end-start).count();
Treachery answered 2/12, 2012 at 4:21 Comment(2)
As an (important) note, there is a "bug" in the current std::chrono::high_resolution_clock in VS2012 in that it is much, much lower resolution that using QueryPerformanceCounter and doing some math. See: bit.ly/QX86s6Bini
This bug is still present in VS2013 preview.Rossie

© 2022 - 2024 — McMap. All rights reserved.