2018年11月18日 星期日

C++ 學習筆記:chrono - Part 2 clock 與 timepoint

Example:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <chrono>
#include <iostream>
#include <iomanip>
#include <thread>
#include <ctime>
#include <string>
#include <vector>
#include <numeric>

template <typename T>
void printClockData()
{
    using PeriodType = typename T::period;

    std::cout << " - precision: ";
    std::cout << static_cast<double>(PeriodType::num) / PeriodType::den << " seconds" << std::endl;
    std::cout << " - is_steady: " << std::boolalpha << T::is_steady << std::endl;
}

std::string asString(const std::chrono::system_clock::time_point& tp)
{
    constexpr bool blUseLocalTime = false;
    std::time_t t = std::chrono::system_clock::to_time_t(tp);
    std::string ts = blUseLocalTime ? std::ctime(&t) : std::asctime(gmtime(&t));
    ts.resize(ts.size() - 1);

    return ts; 
}

volatile int sink;
int main()
{
    /* Clock */
    std::cout << "system_clock: " << std::endl;
    printClockData<std::chrono::system_clock>();
    std::cout << "\nsteady_clock: " << std::endl;
    printClockData<std::chrono::steady_clock>();
    std::cout << "\nhigh_resolution_clock: " << std::endl;
    printClockData<std::chrono::high_resolution_clock>();

    /* system_clock */
    auto system_start = std::chrono::system_clock::now();
    // do some heavy work here, more than five seconds
    using namespace std::chrono_literals;
    // std::this_thread::sleep_for(6s);
    if (std::chrono::system_clock::now() > system_start + std::chrono::seconds(5)) {
        // If someone adjust the clock, condition may produce "false"
        std::cout << "Checked!" << std::endl;
    }

    auto diffSec = std::chrono::system_clock::now() - system_start;
    auto sec = std::chrono::duration_cast<std::chrono::milliseconds>(diffSec);
    std::cout << "This program runs: " << sec.count() << " milliseconds" << std::endl;

    /* steady_clock */
    for (auto size = 1ull; size < 1000000000ull; size *= 100) {
        auto start = std::chrono::steady_clock::now();
        
        std::vector<int> Vec(size, 123);
        sink = std::accumulate(Vec.begin(), Vec.end(), 0u); // make sure it's a side effect
        
        auto end = std::chrono::steady_clock::now();
        std::chrono::duration<double> diffSec = end - start;
        std::cout << "Time to fill and iterate a vector of " << size << " ints : " << diffSec.count() << " s\n";
    }

    /* Time Point */
    std::chrono::system_clock::time_point tp;
    auto sysClockNow = std::chrono::system_clock::now();
    auto sysClockMin = std::chrono::system_clock::time_point::min();
    auto sysClockMax = std::chrono::system_clock::time_point::max();
    std::cout << "epoch:          " << asString(tp) << std::endl;
    std::cout << "current time:   " << asString(sysClockNow) << std::endl;
    std::cout << "minimum time:   " << asString(sysClockMin) << std::endl;
    std::cout << "maximum time:   " << asString(sysClockMax) << std::endl;

    /* Timepoint and Duration Arithmetic */
    using TypeDays = std::chrono::duration<int, std::ratio<3600 * 24>>;

    std::chrono::time_point<std::chrono::system_clock> timePoint;
    std::cout << "epoch:     " << asString(tp) << std::endl;

    tp += TypeDays(1) + std::chrono::hours(23) + std::chrono::minutes(55);
    auto diff = tp - std::chrono::system_clock::time_point();
    auto minutesDiff = std::chrono::duration_cast<std::chrono::minutes>(diff);
    TypeDays daysDiff = std::chrono::duration_cast<TypeDays>(diff);
    std::cout << "later:     " << asString(tp) << std::endl;
    std::cout << "diff:      " << minutesDiff.count() << " minute(s)" << std::endl;
    std::cout << "diff:      " << daysDiff.count() << " day(s)" << std::endl;

    tp -= std::chrono::hours(24 * 365);
    std::cout << "-1 year:   " << asString(tp) << std::endl;

    tp -= std::chrono::duration<int, std::ratio<3600 * 24 * 365>>(50);
    std::cout << "-50 years: " << asString(tp) << std::endl;

    tp -= std::chrono::duration<int, std::ratio<3600 * 24 * 365>>(505000);
    std::cout << "-505000 years: " << asString(tp) << std::endl;// underflow
}


chrono 的 clock 與 time point

  • clock
    • 用來定義一個 epoch (time_point) 與一個 tick period/rate (duration),不同的 clock 有不同的 epoch例如:
      • epoch: std::chrono::system_clock::time_point
      • tick period: std::chrono::system_clock::period
    • C++ 提供三種 clock:
      • system_clock
        • 系統上真實時間的 clock (system-wide real time wall clock)
        • 提供 function 可以與 C system time time_t 做轉換,且僅有 system_clock 支援此功能
        • 可能不是單調遞增的,因為系統時間可以隨時被調整
      • steady_clock
        • 單調遞增的 clock (monotonic clock)
        • 相較於 system_clock,絕對不會被調整,即隨著真實時間演進,此 clock 的 timepoint 絕對不會變小
        • 不會對應到真實時間,可以是上次 reboot 時間
        • 非常適合用來測量時間間隔
      • high_resolution_clock
        • 系統上具有最短 tick period 的 clock
        • 它可能是 system_clock 或 steady_clock 或是另外一個獨立的 clock 的別名
    • 關於 system_clock
      • std::chrono::system_clock::now() 會根據系統上的時鐘時間調整,所以有一些運算或是條件判斷是不可信的
      • 相較於 system_clock,steady_clock 時間是單調遞增的,運算或是條件式可信
    • 根據使用的 clock,提供一個 time_point 型別給 timepoint
    • 使用 clock 的 static member function now 可以取得當前的 time_point
  • timepoint
    • 給定一個 clock 下,根據一個正或負的 duration 來表示一個特定的時間點
      • 透過提取 clock 的 time_point (通常是 epoch 或是 now()),再加減上一個 duration 得到另外一個 time_point
    • time point 可以表示為(T 為上述三種 clock 任一種)
      • std::chrono::T::time_point
      • std::chrono::time_point<T>
    • 一個 clock 的 time_point 型別具有以下三個重點
      • epoch: default-construct 的 time_point 即是 epoch (講白話,起始時間)
      • min: 可產生最小的 time_point
      • max: 可產生最大的 time_point
    • timepoint 在做算術運算時,不考慮閏年


Reference:
  1. The C++ Standard Library: A Tutorial and Reference, Second Edition

沒有留言:

張貼留言