Chrono.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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. #ifndef LLVM_SUPPORT_CHRONO_H
  9. #define LLVM_SUPPORT_CHRONO_H
  10. #include "llvm/Support/Compiler.h"
  11. #include "llvm/Support/FormatProviders.h"
  12. #include <chrono>
  13. #include <ctime>
  14. namespace llvm {
  15. class raw_ostream;
  16. namespace sys {
  17. /// A time point on the system clock. This is provided for two reasons:
  18. /// - to insulate us agains subtle differences in behavoir to differences in
  19. /// system clock precision (which is implementation-defined and differs between
  20. /// platforms).
  21. /// - to shorten the type name
  22. /// The default precision is nanoseconds. If need a specific precision specify
  23. /// it explicitly. If unsure, use the default. If you need a time point on a
  24. /// clock other than the system_clock, use std::chrono directly.
  25. template <typename D = std::chrono::nanoseconds>
  26. using TimePoint = std::chrono::time_point<std::chrono::system_clock, D>;
  27. /// Convert a TimePoint to std::time_t
  28. inline std::time_t toTimeT(TimePoint<> TP) {
  29. using namespace std::chrono;
  30. return system_clock::to_time_t(
  31. time_point_cast<system_clock::time_point::duration>(TP));
  32. }
  33. /// Convert a std::time_t to a TimePoint
  34. inline TimePoint<std::chrono::seconds>
  35. toTimePoint(std::time_t T) {
  36. using namespace std::chrono;
  37. return time_point_cast<seconds>(system_clock::from_time_t(T));
  38. }
  39. /// Convert a std::time_t + nanoseconds to a TimePoint
  40. inline TimePoint<>
  41. toTimePoint(std::time_t T, uint32_t nsec) {
  42. using namespace std::chrono;
  43. return time_point_cast<nanoseconds>(system_clock::from_time_t(T))
  44. + nanoseconds(nsec);
  45. }
  46. } // namespace sys
  47. raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP);
  48. /// Format provider for TimePoint<>
  49. ///
  50. /// The options string is a strftime format string, with extensions:
  51. /// - %L is millis: 000-999
  52. /// - %f is micros: 000000-999999
  53. /// - %N is nanos: 000000000 - 999999999
  54. ///
  55. /// If no options are given, the default format is "%Y-%m-%d %H:%M:%S.%N".
  56. template <>
  57. struct format_provider<sys::TimePoint<>> {
  58. static void format(const sys::TimePoint<> &TP, llvm::raw_ostream &OS,
  59. StringRef Style);
  60. };
  61. namespace detail {
  62. template <typename Period> struct unit { static const char value[]; };
  63. template <typename Period> const char unit<Period>::value[] = "";
  64. template <> struct unit<std::ratio<3600>> { static const char value[]; };
  65. template <> struct unit<std::ratio<60>> { static const char value[]; };
  66. template <> struct unit<std::ratio<1>> { static const char value[]; };
  67. template <> struct unit<std::milli> { static const char value[]; };
  68. template <> struct unit<std::micro> { static const char value[]; };
  69. template <> struct unit<std::nano> { static const char value[]; };
  70. } // namespace detail
  71. /// Implementation of format_provider<T> for duration types.
  72. ///
  73. /// The options string of a duration type has the grammar:
  74. ///
  75. /// duration_options ::= [unit][show_unit [number_options]]
  76. /// unit ::= `h`|`m`|`s`|`ms|`us`|`ns`
  77. /// show_unit ::= `+` | `-`
  78. /// number_options ::= options string for a integral or floating point type
  79. ///
  80. /// Examples
  81. /// =================================
  82. /// | options | Input | Output |
  83. /// =================================
  84. /// | "" | 1s | 1 s |
  85. /// | "ms" | 1s | 1000 ms |
  86. /// | "ms-" | 1s | 1000 |
  87. /// | "ms-n" | 1s | 1,000 |
  88. /// | "" | 1.0s | 1.00 s |
  89. /// =================================
  90. ///
  91. /// If the unit of the duration type is not one of the units specified above,
  92. /// it is still possible to format it, provided you explicitly request a
  93. /// display unit or you request that the unit is not displayed.
  94. template <typename Rep, typename Period>
  95. struct format_provider<std::chrono::duration<Rep, Period>> {
  96. private:
  97. typedef std::chrono::duration<Rep, Period> Dur;
  98. typedef std::conditional_t<std::chrono::treat_as_floating_point<Rep>::value,
  99. double, intmax_t>
  100. InternalRep;
  101. template <typename AsPeriod> static InternalRep getAs(const Dur &D) {
  102. using namespace std::chrono;
  103. return duration_cast<duration<InternalRep, AsPeriod>>(D).count();
  104. }
  105. static std::pair<InternalRep, StringRef> consumeUnit(StringRef &Style,
  106. const Dur &D) {
  107. using namespace std::chrono;
  108. if (Style.consume_front("ns"))
  109. return {getAs<std::nano>(D), "ns"};
  110. if (Style.consume_front("us"))
  111. return {getAs<std::micro>(D), "us"};
  112. if (Style.consume_front("ms"))
  113. return {getAs<std::milli>(D), "ms"};
  114. if (Style.consume_front("s"))
  115. return {getAs<std::ratio<1>>(D), "s"};
  116. if (Style.consume_front("m"))
  117. return {getAs<std::ratio<60>>(D), "m"};
  118. if (Style.consume_front("h"))
  119. return {getAs<std::ratio<3600>>(D), "h"};
  120. return {D.count(), detail::unit<Period>::value};
  121. }
  122. static bool consumeShowUnit(StringRef &Style) {
  123. if (Style.empty())
  124. return true;
  125. if (Style.consume_front("-"))
  126. return false;
  127. if (Style.consume_front("+"))
  128. return true;
  129. assert(0 && "Unrecognised duration format");
  130. return true;
  131. }
  132. public:
  133. static void format(const Dur &D, llvm::raw_ostream &Stream, StringRef Style) {
  134. InternalRep count;
  135. StringRef unit;
  136. std::tie(count, unit) = consumeUnit(Style, D);
  137. bool show_unit = consumeShowUnit(Style);
  138. format_provider<InternalRep>::format(count, Stream, Style);
  139. if (show_unit) {
  140. assert(!unit.empty());
  141. Stream << " " << unit;
  142. }
  143. }
  144. };
  145. } // namespace llvm
  146. #endif // LLVM_SUPPORT_CHRONO_H