1 /*
2  *  Created by Phil on 05/08/2013.
3  *  Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
4  *
5  *  Distributed under the Boost Software License, Version 1.0. (See accompanying
6  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7  */
8 
9 #include "catch_timer.h"
10 
11 #include <chrono>
12 
13 static const uint64_t nanosecondsInSecond = 1000000000;
14 
15 namespace Catch {
16 
getCurrentNanosecondsSinceEpoch()17     auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
18         return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
19     }
20 
21     namespace {
estimateClockResolution()22         auto estimateClockResolution() -> uint64_t {
23             uint64_t sum = 0;
24             static const uint64_t iterations = 1000000;
25 
26             auto startTime = getCurrentNanosecondsSinceEpoch();
27 
28             for( std::size_t i = 0; i < iterations; ++i ) {
29 
30                 uint64_t ticks;
31                 uint64_t baseTicks = getCurrentNanosecondsSinceEpoch();
32                 do {
33                     ticks = getCurrentNanosecondsSinceEpoch();
34                 } while( ticks == baseTicks );
35 
36                 auto delta = ticks - baseTicks;
37                 sum += delta;
38 
39                 // If we have been calibrating for over 3 seconds -- the clock
40                 // is terrible and we should move on.
41                 // TBD: How to signal that the measured resolution is probably wrong?
42                 if (ticks > startTime + 3 * nanosecondsInSecond) {
43                     return sum / ( i + 1u );
44                 }
45             }
46 
47             // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers
48             // - and potentially do more iterations if there's a high variance.
49             return sum/iterations;
50         }
51     }
getEstimatedClockResolution()52     auto getEstimatedClockResolution() -> uint64_t {
53         static auto s_resolution = estimateClockResolution();
54         return s_resolution;
55     }
56 
start()57     void Timer::start() {
58        m_nanoseconds = getCurrentNanosecondsSinceEpoch();
59     }
getElapsedNanoseconds() const60     auto Timer::getElapsedNanoseconds() const -> uint64_t {
61         return getCurrentNanosecondsSinceEpoch() - m_nanoseconds;
62     }
getElapsedMicroseconds() const63     auto Timer::getElapsedMicroseconds() const -> uint64_t {
64         return getElapsedNanoseconds()/1000;
65     }
getElapsedMilliseconds() const66     auto Timer::getElapsedMilliseconds() const -> unsigned int {
67         return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
68     }
getElapsedSeconds() const69     auto Timer::getElapsedSeconds() const -> double {
70         return getElapsedMicroseconds()/1000000.0;
71     }
72 
73 
74 } // namespace Catch
75