xref: /freebsd/contrib/llvm-project/llvm/lib/Support/Chrono.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===- Support/Chrono.cpp - Utilities for Timing Manipulation ---*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/Support/Chrono.h"
100b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h"
110b57cec5SDimitry Andric #include "llvm/Support/Format.h"
120b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric namespace llvm {
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric using namespace sys;
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric const char llvm::detail::unit<std::ratio<3600>>::value[] = "h";
190b57cec5SDimitry Andric const char llvm::detail::unit<std::ratio<60>>::value[] = "m";
200b57cec5SDimitry Andric const char llvm::detail::unit<std::ratio<1>>::value[] = "s";
210b57cec5SDimitry Andric const char llvm::detail::unit<std::milli>::value[] = "ms";
220b57cec5SDimitry Andric const char llvm::detail::unit<std::micro>::value[] = "us";
230b57cec5SDimitry Andric const char llvm::detail::unit<std::nano>::value[] = "ns";
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric static inline struct tm getStructTM(TimePoint<> TP) {
260b57cec5SDimitry Andric   struct tm Storage;
270b57cec5SDimitry Andric   std::time_t OurTime = toTimeT(TP);
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric #if defined(LLVM_ON_UNIX)
300b57cec5SDimitry Andric   struct tm *LT = ::localtime_r(&OurTime, &Storage);
310b57cec5SDimitry Andric   assert(LT);
320b57cec5SDimitry Andric   (void)LT;
330b57cec5SDimitry Andric #endif
340b57cec5SDimitry Andric #if defined(_WIN32)
350b57cec5SDimitry Andric   int Error = ::localtime_s(&Storage, &OurTime);
360b57cec5SDimitry Andric   assert(!Error);
370b57cec5SDimitry Andric   (void)Error;
380b57cec5SDimitry Andric #endif
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   return Storage;
410b57cec5SDimitry Andric }
420b57cec5SDimitry Andric 
43*5f757f3fSDimitry Andric static inline struct tm getStructTMUtc(UtcTime<> TP) {
44*5f757f3fSDimitry Andric   struct tm Storage;
45*5f757f3fSDimitry Andric   std::time_t OurTime = toTimeT(TP);
46*5f757f3fSDimitry Andric 
47*5f757f3fSDimitry Andric #if defined(LLVM_ON_UNIX)
48*5f757f3fSDimitry Andric   struct tm *LT = ::gmtime_r(&OurTime, &Storage);
49*5f757f3fSDimitry Andric   assert(LT);
50*5f757f3fSDimitry Andric   (void)LT;
51*5f757f3fSDimitry Andric #endif
52*5f757f3fSDimitry Andric #if defined(_WIN32)
53*5f757f3fSDimitry Andric   int Error = ::gmtime_s(&Storage, &OurTime);
54*5f757f3fSDimitry Andric   assert(!Error);
55*5f757f3fSDimitry Andric   (void)Error;
56*5f757f3fSDimitry Andric #endif
57*5f757f3fSDimitry Andric 
58*5f757f3fSDimitry Andric   return Storage;
59*5f757f3fSDimitry Andric }
60*5f757f3fSDimitry Andric 
610b57cec5SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, TimePoint<> TP) {
620b57cec5SDimitry Andric   struct tm LT = getStructTM(TP);
630b57cec5SDimitry Andric   char Buffer[sizeof("YYYY-MM-DD HH:MM:SS")];
640b57cec5SDimitry Andric   strftime(Buffer, sizeof(Buffer), "%Y-%m-%d %H:%M:%S", &LT);
650b57cec5SDimitry Andric   return OS << Buffer << '.'
660b57cec5SDimitry Andric             << format("%.9lu",
670b57cec5SDimitry Andric                       long((TP.time_since_epoch() % std::chrono::seconds(1))
680b57cec5SDimitry Andric                                .count()));
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric 
71*5f757f3fSDimitry Andric template <class T>
72*5f757f3fSDimitry Andric static void format(const T &Fractional, struct tm &LT, raw_ostream &OS,
730b57cec5SDimitry Andric                    StringRef Style) {
740b57cec5SDimitry Andric   using namespace std::chrono;
750b57cec5SDimitry Andric   // Handle extensions first. strftime mangles unknown %x on some platforms.
760b57cec5SDimitry Andric   if (Style.empty()) Style = "%Y-%m-%d %H:%M:%S.%N";
770b57cec5SDimitry Andric   std::string Format;
780b57cec5SDimitry Andric   raw_string_ostream FStream(Format);
790b57cec5SDimitry Andric   for (unsigned I = 0; I < Style.size(); ++I) {
800b57cec5SDimitry Andric     if (Style[I] == '%' && Style.size() > I + 1) switch (Style[I + 1]) {
810b57cec5SDimitry Andric         case 'L':  // Milliseconds, from Ruby.
820b57cec5SDimitry Andric           FStream << llvm::format(
830b57cec5SDimitry Andric               "%.3lu", (long)duration_cast<milliseconds>(Fractional).count());
840b57cec5SDimitry Andric           ++I;
850b57cec5SDimitry Andric           continue;
860b57cec5SDimitry Andric         case 'f':  // Microseconds, from Python.
870b57cec5SDimitry Andric           FStream << llvm::format(
880b57cec5SDimitry Andric               "%.6lu", (long)duration_cast<microseconds>(Fractional).count());
890b57cec5SDimitry Andric           ++I;
900b57cec5SDimitry Andric           continue;
910b57cec5SDimitry Andric         case 'N':  // Nanoseconds, from date(1).
920b57cec5SDimitry Andric           FStream << llvm::format(
9306c3fb27SDimitry Andric               "%.9lu", (long)duration_cast<nanoseconds>(Fractional).count());
940b57cec5SDimitry Andric           ++I;
950b57cec5SDimitry Andric           continue;
960b57cec5SDimitry Andric         case '%':  // Consume %%, so %%f parses as (%%)f not %(%f)
970b57cec5SDimitry Andric           FStream << "%%";
980b57cec5SDimitry Andric           ++I;
990b57cec5SDimitry Andric           continue;
1000b57cec5SDimitry Andric       }
1010b57cec5SDimitry Andric     FStream << Style[I];
1020b57cec5SDimitry Andric   }
1030b57cec5SDimitry Andric   FStream.flush();
1040b57cec5SDimitry Andric   char Buffer[256];  // Should be enough for anywhen.
1050b57cec5SDimitry Andric   size_t Len = strftime(Buffer, sizeof(Buffer), Format.c_str(), &LT);
1060b57cec5SDimitry Andric   OS << (Len ? Buffer : "BAD-DATE-FORMAT");
1070b57cec5SDimitry Andric }
1080b57cec5SDimitry Andric 
109*5f757f3fSDimitry Andric void format_provider<UtcTime<std::chrono::seconds>>::format(
110*5f757f3fSDimitry Andric     const UtcTime<std::chrono::seconds> &T, raw_ostream &OS, StringRef Style) {
111*5f757f3fSDimitry Andric   using namespace std::chrono;
112*5f757f3fSDimitry Andric   UtcTime<seconds> Truncated =
113*5f757f3fSDimitry Andric       UtcTime<seconds>(duration_cast<seconds>(T.time_since_epoch()));
114*5f757f3fSDimitry Andric   auto Fractional = T - Truncated;
115*5f757f3fSDimitry Andric   struct tm LT = getStructTMUtc(Truncated);
116*5f757f3fSDimitry Andric   llvm::format(Fractional, LT, OS, Style);
117*5f757f3fSDimitry Andric }
118*5f757f3fSDimitry Andric 
119*5f757f3fSDimitry Andric void format_provider<TimePoint<>>::format(const TimePoint<> &T, raw_ostream &OS,
120*5f757f3fSDimitry Andric                                           StringRef Style) {
121*5f757f3fSDimitry Andric   using namespace std::chrono;
122*5f757f3fSDimitry Andric   TimePoint<seconds> Truncated = time_point_cast<seconds>(T);
123*5f757f3fSDimitry Andric   auto Fractional = T - Truncated;
124*5f757f3fSDimitry Andric   struct tm LT = getStructTM(Truncated);
125*5f757f3fSDimitry Andric   llvm::format(Fractional, LT, OS, Style);
126*5f757f3fSDimitry Andric }
127*5f757f3fSDimitry Andric 
1280b57cec5SDimitry Andric } // namespace llvm
129