1 //===- llvm/Support/Chrono.h - Utilities for Timing Manipulation-*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_SUPPORT_CHRONO_H 10 #define LLVM_SUPPORT_CHRONO_H 11 12 #include "llvm/Support/Compiler.h" 13 #include "llvm/Support/FormatProviders.h" 14 15 #include <chrono> 16 #include <ctime> 17 #include <ratio> 18 19 namespace llvm { 20 21 class raw_ostream; 22 23 namespace sys { 24 25 /// A time point on the system clock. This is provided for two reasons: 26 /// - to insulate us against subtle differences in behavior to differences in 27 /// system clock precision (which is implementation-defined and differs 28 /// between platforms). 29 /// - to shorten the type name 30 /// The default precision is nanoseconds. If you need a specific precision 31 /// specify it explicitly. If unsure, use the default. If you need a time point 32 /// on a clock other than the system_clock, use std::chrono directly. 33 template <typename D = std::chrono::nanoseconds> 34 using TimePoint = std::chrono::time_point<std::chrono::system_clock, D>; 35 36 // utc_clock and utc_time are only available since C++20. Add enough code to 37 // support formatting date/time in UTC. 38 class UtcClock : public std::chrono::system_clock {}; 39 40 template <typename D = std::chrono::nanoseconds> 41 using UtcTime = std::chrono::time_point<UtcClock, D>; 42 43 /// Convert a std::time_t to a UtcTime 44 inline UtcTime<std::chrono::seconds> toUtcTime(std::time_t T) { 45 using namespace std::chrono; 46 return UtcTime<seconds>(seconds(T)); 47 } 48 49 /// Convert a TimePoint to std::time_t 50 inline std::time_t toTimeT(TimePoint<> TP) { 51 using namespace std::chrono; 52 return system_clock::to_time_t( 53 time_point_cast<system_clock::time_point::duration>(TP)); 54 } 55 56 /// Convert a UtcTime to std::time_t 57 inline std::time_t toTimeT(UtcTime<> TP) { 58 using namespace std::chrono; 59 return system_clock::to_time_t(time_point<system_clock, seconds>( 60 duration_cast<seconds>(TP.time_since_epoch()))); 61 } 62 63 /// Convert a std::time_t to a TimePoint 64 inline TimePoint<std::chrono::seconds> 65 toTimePoint(std::time_t T) { 66 using namespace std::chrono; 67 return time_point_cast<seconds>(system_clock::from_time_t(T)); 68 } 69 70 /// Convert a std::time_t + nanoseconds to a TimePoint 71 inline TimePoint<> 72 toTimePoint(std::time_t T, uint32_t nsec) { 73 using namespace std::chrono; 74 return time_point_cast<nanoseconds>(system_clock::from_time_t(T)) 75 + nanoseconds(nsec); 76 } 77 78 } // namespace sys 79 80 raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP); 81 raw_ostream &operator<<(raw_ostream &OS, sys::UtcTime<> TP); 82 83 /// Format provider for TimePoint<> 84 /// 85 /// The options string is a strftime format string, with extensions: 86 /// - %L is millis: 000-999 87 /// - %f is micros: 000000-999999 88 /// - %N is nanos: 000000000 - 999999999 89 /// 90 /// If no options are given, the default format is "%Y-%m-%d %H:%M:%S.%N". 91 template <> 92 struct format_provider<sys::TimePoint<>> { 93 static void format(const sys::TimePoint<> &TP, llvm::raw_ostream &OS, 94 StringRef Style); 95 }; 96 97 template <> struct format_provider<sys::UtcTime<std::chrono::seconds>> { 98 static void format(const sys::UtcTime<std::chrono::seconds> &TP, 99 llvm::raw_ostream &OS, StringRef Style); 100 }; 101 102 namespace detail { 103 template <typename Period> struct unit { static const char value[]; }; 104 template <typename Period> const char unit<Period>::value[] = ""; 105 106 template <> struct unit<std::ratio<3600>> { static const char value[]; }; 107 template <> struct unit<std::ratio<60>> { static const char value[]; }; 108 template <> struct unit<std::ratio<1>> { static const char value[]; }; 109 template <> struct unit<std::milli> { static const char value[]; }; 110 template <> struct unit<std::micro> { static const char value[]; }; 111 template <> struct unit<std::nano> { static const char value[]; }; 112 } // namespace detail 113 114 /// Implementation of format_provider<T> for duration types. 115 /// 116 /// The options string of a duration type has the grammar: 117 /// 118 /// duration_options ::= [unit][show_unit [number_options]] 119 /// unit ::= `h`|`m`|`s`|`ms|`us`|`ns` 120 /// show_unit ::= `+` | `-` 121 /// number_options ::= options string for a integral or floating point type 122 /// 123 /// Examples 124 /// ================================= 125 /// | options | Input | Output | 126 /// ================================= 127 /// | "" | 1s | 1 s | 128 /// | "ms" | 1s | 1000 ms | 129 /// | "ms-" | 1s | 1000 | 130 /// | "ms-n" | 1s | 1,000 | 131 /// | "" | 1.0s | 1.00 s | 132 /// ================================= 133 /// 134 /// If the unit of the duration type is not one of the units specified above, 135 /// it is still possible to format it, provided you explicitly request a 136 /// display unit or you request that the unit is not displayed. 137 138 template <typename Rep, typename Period> 139 struct format_provider<std::chrono::duration<Rep, Period>> { 140 private: 141 typedef std::chrono::duration<Rep, Period> Dur; 142 typedef std::conditional_t<std::chrono::treat_as_floating_point<Rep>::value, 143 double, intmax_t> 144 InternalRep; 145 146 template <typename AsPeriod> static InternalRep getAs(const Dur &D) { 147 using namespace std::chrono; 148 return duration_cast<duration<InternalRep, AsPeriod>>(D).count(); 149 } 150 151 static std::pair<InternalRep, StringRef> consumeUnit(StringRef &Style, 152 const Dur &D) { 153 using namespace std::chrono; 154 if (Style.consume_front("ns")) 155 return {getAs<std::nano>(D), "ns"}; 156 if (Style.consume_front("us")) 157 return {getAs<std::micro>(D), "us"}; 158 if (Style.consume_front("ms")) 159 return {getAs<std::milli>(D), "ms"}; 160 if (Style.consume_front("s")) 161 return {getAs<std::ratio<1>>(D), "s"}; 162 if (Style.consume_front("m")) 163 return {getAs<std::ratio<60>>(D), "m"}; 164 if (Style.consume_front("h")) 165 return {getAs<std::ratio<3600>>(D), "h"}; 166 return {D.count(), detail::unit<Period>::value}; 167 } 168 169 static bool consumeShowUnit(StringRef &Style) { 170 if (Style.empty()) 171 return true; 172 if (Style.consume_front("-")) 173 return false; 174 if (Style.consume_front("+")) 175 return true; 176 assert(0 && "Unrecognised duration format"); 177 return true; 178 } 179 180 public: 181 static void format(const Dur &D, llvm::raw_ostream &Stream, StringRef Style) { 182 InternalRep count; 183 StringRef unit; 184 std::tie(count, unit) = consumeUnit(Style, D); 185 bool show_unit = consumeShowUnit(Style); 186 187 format_provider<InternalRep>::format(count, Stream, Style); 188 189 if (show_unit) { 190 assert(!unit.empty()); 191 Stream << " " << unit; 192 } 193 } 194 }; 195 196 } // namespace llvm 197 198 #endif // LLVM_SUPPORT_CHRONO_H 199