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 /// Convert a TimePoint to std::time_t 37 inline std::time_t toTimeT(TimePoint<> TP) { 38 using namespace std::chrono; 39 return system_clock::to_time_t( 40 time_point_cast<system_clock::time_point::duration>(TP)); 41 } 42 43 /// Convert a std::time_t to a TimePoint 44 inline TimePoint<std::chrono::seconds> 45 toTimePoint(std::time_t T) { 46 using namespace std::chrono; 47 return time_point_cast<seconds>(system_clock::from_time_t(T)); 48 } 49 50 /// Convert a std::time_t + nanoseconds to a TimePoint 51 inline TimePoint<> 52 toTimePoint(std::time_t T, uint32_t nsec) { 53 using namespace std::chrono; 54 return time_point_cast<nanoseconds>(system_clock::from_time_t(T)) 55 + nanoseconds(nsec); 56 } 57 58 } // namespace sys 59 60 raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP); 61 62 /// Format provider for TimePoint<> 63 /// 64 /// The options string is a strftime format string, with extensions: 65 /// - %L is millis: 000-999 66 /// - %f is micros: 000000-999999 67 /// - %N is nanos: 000000000 - 999999999 68 /// 69 /// If no options are given, the default format is "%Y-%m-%d %H:%M:%S.%N". 70 template <> 71 struct format_provider<sys::TimePoint<>> { 72 static void format(const sys::TimePoint<> &TP, llvm::raw_ostream &OS, 73 StringRef Style); 74 }; 75 76 namespace detail { 77 template <typename Period> struct unit { static const char value[]; }; 78 template <typename Period> const char unit<Period>::value[] = ""; 79 80 template <> struct unit<std::ratio<3600>> { static const char value[]; }; 81 template <> struct unit<std::ratio<60>> { static const char value[]; }; 82 template <> struct unit<std::ratio<1>> { static const char value[]; }; 83 template <> struct unit<std::milli> { static const char value[]; }; 84 template <> struct unit<std::micro> { static const char value[]; }; 85 template <> struct unit<std::nano> { static const char value[]; }; 86 } // namespace detail 87 88 /// Implementation of format_provider<T> for duration types. 89 /// 90 /// The options string of a duration type has the grammar: 91 /// 92 /// duration_options ::= [unit][show_unit [number_options]] 93 /// unit ::= `h`|`m`|`s`|`ms|`us`|`ns` 94 /// show_unit ::= `+` | `-` 95 /// number_options ::= options string for a integral or floating point type 96 /// 97 /// Examples 98 /// ================================= 99 /// | options | Input | Output | 100 /// ================================= 101 /// | "" | 1s | 1 s | 102 /// | "ms" | 1s | 1000 ms | 103 /// | "ms-" | 1s | 1000 | 104 /// | "ms-n" | 1s | 1,000 | 105 /// | "" | 1.0s | 1.00 s | 106 /// ================================= 107 /// 108 /// If the unit of the duration type is not one of the units specified above, 109 /// it is still possible to format it, provided you explicitly request a 110 /// display unit or you request that the unit is not displayed. 111 112 template <typename Rep, typename Period> 113 struct format_provider<std::chrono::duration<Rep, Period>> { 114 private: 115 typedef std::chrono::duration<Rep, Period> Dur; 116 typedef std::conditional_t<std::chrono::treat_as_floating_point<Rep>::value, 117 double, intmax_t> 118 InternalRep; 119 120 template <typename AsPeriod> static InternalRep getAs(const Dur &D) { 121 using namespace std::chrono; 122 return duration_cast<duration<InternalRep, AsPeriod>>(D).count(); 123 } 124 125 static std::pair<InternalRep, StringRef> consumeUnit(StringRef &Style, 126 const Dur &D) { 127 using namespace std::chrono; 128 if (Style.consume_front("ns")) 129 return {getAs<std::nano>(D), "ns"}; 130 if (Style.consume_front("us")) 131 return {getAs<std::micro>(D), "us"}; 132 if (Style.consume_front("ms")) 133 return {getAs<std::milli>(D), "ms"}; 134 if (Style.consume_front("s")) 135 return {getAs<std::ratio<1>>(D), "s"}; 136 if (Style.consume_front("m")) 137 return {getAs<std::ratio<60>>(D), "m"}; 138 if (Style.consume_front("h")) 139 return {getAs<std::ratio<3600>>(D), "h"}; 140 return {D.count(), detail::unit<Period>::value}; 141 } 142 143 static bool consumeShowUnit(StringRef &Style) { 144 if (Style.empty()) 145 return true; 146 if (Style.consume_front("-")) 147 return false; 148 if (Style.consume_front("+")) 149 return true; 150 assert(0 && "Unrecognised duration format"); 151 return true; 152 } 153 154 public: 155 static void format(const Dur &D, llvm::raw_ostream &Stream, StringRef Style) { 156 InternalRep count; 157 StringRef unit; 158 std::tie(count, unit) = consumeUnit(Style, D); 159 bool show_unit = consumeShowUnit(Style); 160 161 format_provider<InternalRep>::format(count, Stream, Style); 162 163 if (show_unit) { 164 assert(!unit.empty()); 165 Stream << " " << unit; 166 } 167 } 168 }; 169 170 } // namespace llvm 171 172 #endif // LLVM_SUPPORT_CHRONO_H 173