diff options
-rw-r--r-- | llvm/include/llvm/Support/Chrono.h | 55 | ||||
-rw-r--r-- | llvm/include/llvm/Support/TimeValue.h | 11 | ||||
-rw-r--r-- | llvm/lib/Support/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/Support/Chrono.cpp | 47 | ||||
-rw-r--r-- | llvm/lib/Support/TimeValue.cpp | 17 | ||||
-rw-r--r-- | llvm/lib/Support/Unix/TimeValue.inc | 54 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/TimeValue.inc | 61 | ||||
-rw-r--r-- | llvm/unittests/Support/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/unittests/Support/Chrono.cpp | 79 | ||||
-rw-r--r-- | llvm/unittests/Support/TimeValueTest.cpp | 10 |
10 files changed, 212 insertions, 124 deletions
diff --git a/llvm/include/llvm/Support/Chrono.h b/llvm/include/llvm/Support/Chrono.h new file mode 100644 index 00000000000..203439cab91 --- /dev/null +++ b/llvm/include/llvm/Support/Chrono.h @@ -0,0 +1,55 @@ +//===- llvm/Support/Chrono.h - Utilities for Timing Manipulation-*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_CHRONO_H +#define LLVM_SUPPORT_CHRONO_H + +#include "llvm/Support/Compiler.h" + +#include <chrono> +#include <ctime> + +namespace llvm { + +class raw_ostream; + +namespace sys { + +/// A time point on the system clock. This is provided for two reasons: +/// - to insulate us agains subtle differences in behavoir to differences in +/// system clock precision (which is implementation-defined and differs between +/// platforms). +/// - to shorten the type name +/// The default precision is nanoseconds. If need a specific precision specify +/// it explicitly. If unsure, use the default. If you need a time point on a +/// clock other than the system_clock, use std::chrono directly. +template <typename D = std::chrono::nanoseconds> +using TimePoint = std::chrono::time_point<std::chrono::system_clock, D>; + +/// Convert a TimePoint to std::time_t +LLVM_ATTRIBUTE_ALWAYS_INLINE inline std::time_t toTimeT(TimePoint<> TP) { + using namespace std::chrono; + return system_clock::to_time_t( + time_point_cast<system_clock::time_point::duration>(TP)); +} + +/// Convert a std::time_t to a TimePoint +LLVM_ATTRIBUTE_ALWAYS_INLINE inline TimePoint<std::chrono::seconds> +toTimePoint(std::time_t T) { + using namespace std::chrono; + return time_point_cast<seconds>(system_clock::from_time_t(T)); +} + +} // namespace sys + +raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP); + +} // namespace llvm + +#endif // LLVM_SUPPORT_CHRONO_H diff --git a/llvm/include/llvm/Support/TimeValue.h b/llvm/include/llvm/Support/TimeValue.h index 6bca58b6bc2..4b6dd15c4bb 100644 --- a/llvm/include/llvm/Support/TimeValue.h +++ b/llvm/include/llvm/Support/TimeValue.h @@ -14,6 +14,7 @@ #ifndef LLVM_SUPPORT_TIMEVALUE_H #define LLVM_SUPPORT_TIMEVALUE_H +#include "llvm/Support/Chrono.h" #include "llvm/Support/DataTypes.h" #include <string> @@ -112,6 +113,11 @@ namespace sys { this->normalize(); } + template<typename D> + TimeValue(TimePoint<D> TP) + : seconds_(sys::toTimeT(TP) + PosixZeroTimeSeconds), + nanos_((TimePoint<>(TP).time_since_epoch() % std::chrono::seconds(1)).count()) {} + /// This is a static constructor that returns a TimeValue that represents /// the current time. /// @brief Creates a TimeValue with the current time (UTC). @@ -121,6 +127,11 @@ namespace sys { /// @name Operators /// @{ public: + operator TimePoint<>() const { + return toTimePoint(seconds_ - PosixZeroTimeSeconds) + + std::chrono::nanoseconds(nanos_); + } + /// Add \p that to \p this. /// @returns this /// @brief Incrementing assignment operator. diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index cf04016da2d..d8ecfa9b862 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -37,6 +37,7 @@ add_llvm_library(LLVMSupport BranchProbability.cpp CachePruning.cpp circular_raw_ostream.cpp + Chrono.cpp COM.cpp CommandLine.cpp Compression.cpp diff --git a/llvm/lib/Support/Chrono.cpp b/llvm/lib/Support/Chrono.cpp new file mode 100644 index 00000000000..f0673be97f6 --- /dev/null +++ b/llvm/lib/Support/Chrono.cpp @@ -0,0 +1,47 @@ +//===- Support/Chrono.cpp - Utilities for Timing Manipulation ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Chrono.h" +#include "llvm/Config/config.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +using namespace sys; + +static inline struct tm getStructTM(TimePoint<> TP) { + struct tm Storage; + std::time_t OurTime = toTimeT(TP); + +#if defined(LLVM_ON_UNIX) + struct tm *LT = ::localtime_r(&OurTime, &Storage); + assert(LT); + (void)LT; +#endif +#if defined(LLVM_ON_WIN32) + int Error = ::_localtime64_s(&Storage, &OurTime); + assert(!Error); + (void)Error; +#endif + + return Storage; +} + +raw_ostream &operator<<(raw_ostream &OS, TimePoint<> TP) { + struct tm LT = getStructTM(TP); + char Buffer[sizeof("YYYY-MM-DD HH:MM:SS")]; + strftime(Buffer, sizeof(Buffer), "%Y-%m-%d %H:%M:%S", <); + return OS << Buffer << '.' + << format("%.9lu", + long((TP.time_since_epoch() % std::chrono::seconds(1)) + .count())); +} + +} // namespace llvm diff --git a/llvm/lib/Support/TimeValue.cpp b/llvm/lib/Support/TimeValue.cpp index 94a4c011693..18c84ca9fa0 100644 --- a/llvm/lib/Support/TimeValue.cpp +++ b/llvm/lib/Support/TimeValue.cpp @@ -12,7 +12,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/TimeValue.h" -#include "llvm/Config/config.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/ScopedPrinter.h" namespace llvm { @@ -45,12 +46,10 @@ void TimeValue::normalize() { } } -} // namespace llvm +std::string TimeValue::str() const { return to_string(TimePoint<>(*this)); } + +TimeValue TimeValue::now() { + return TimePoint<>(std::chrono::system_clock::now()); +} -/// Include the platform-specific portion of TimeValue class -#ifdef LLVM_ON_UNIX -#include "Unix/TimeValue.inc" -#endif -#ifdef LLVM_ON_WIN32 -#include "Windows/TimeValue.inc" -#endif +} // namespace llvm diff --git a/llvm/lib/Support/Unix/TimeValue.inc b/llvm/lib/Support/Unix/TimeValue.inc deleted file mode 100644 index 042e0dacc34..00000000000 --- a/llvm/lib/Support/Unix/TimeValue.inc +++ /dev/null @@ -1,54 +0,0 @@ -//===- Unix/TimeValue.cpp - Unix TimeValue Implementation -------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Unix specific portion of the TimeValue class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic UNIX code that -//=== is guaranteed to work on *all* UNIX variants. -//===----------------------------------------------------------------------===// - -#include "Unix.h" - -namespace llvm { - using namespace sys; - -std::string TimeValue::str() const { - time_t OurTime = time_t(this->toEpochTime()); - struct tm Storage; - struct tm *LT = ::localtime_r(&OurTime, &Storage); - assert(LT); - char Buffer1[sizeof("YYYY-MM-DD HH:MM:SS")]; - strftime(Buffer1, sizeof(Buffer1), "%Y-%m-%d %H:%M:%S", LT); - char Buffer2[sizeof("YYYY-MM-DD HH:MM:SS.MMMUUUNNN")]; - snprintf(Buffer2, sizeof(Buffer2), "%s.%.9u", Buffer1, this->nanoseconds()); - return std::string(Buffer2); -} - -TimeValue TimeValue::now() { - struct timeval the_time; - timerclear(&the_time); - if (0 != ::gettimeofday(&the_time,nullptr)) { - // This is *really* unlikely to occur because the only gettimeofday - // errors concern the timezone parameter which we're passing in as 0. - // In the unlikely case it does happen, just return MinTime, no error - // message needed. - return MinTime(); - } - - return TimeValue( - static_cast<TimeValue::SecondsType>( the_time.tv_sec + - PosixZeroTimeSeconds ), - static_cast<TimeValue::NanoSecondsType>( the_time.tv_usec * - NANOSECONDS_PER_MICROSECOND ) ); -} - -} diff --git a/llvm/lib/Support/Windows/TimeValue.inc b/llvm/lib/Support/Windows/TimeValue.inc deleted file mode 100644 index b90b4f1da00..00000000000 --- a/llvm/lib/Support/Windows/TimeValue.inc +++ /dev/null @@ -1,61 +0,0 @@ -//===- Win32/TimeValue.cpp - Win32 TimeValue Implementation -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides the Win32 implementation of the TimeValue class. -// -//===----------------------------------------------------------------------===// - -#include "WindowsSupport.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" -#include <cctype> -#include <time.h> - -using namespace llvm; -using namespace llvm::sys; - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code. -//===----------------------------------------------------------------------===// - -TimeValue TimeValue::now() { - uint64_t ft; - GetSystemTimeAsFileTime(reinterpret_cast<FILETIME *>(&ft)); - - TimeValue t(0, 0); - t.fromWin32Time(ft); - return t; -} - -std::string TimeValue::str() const { - std::string S; - struct tm *LT; -#ifdef __MINGW32__ - // Old versions of mingw don't have _localtime64_s. Remove this once we drop support - // for them. - time_t OurTime = time_t(this->toEpochTime()); - LT = ::localtime(&OurTime); - assert(LT); -#else - struct tm Storage; - __time64_t OurTime = this->toEpochTime(); - int Error = ::_localtime64_s(&Storage, &OurTime); - assert(!Error); - (void)Error; - LT = &Storage; -#endif - - char Buffer[sizeof("YYYY-MM-DD HH:MM:SS")]; - strftime(Buffer, sizeof(Buffer), "%Y-%m-%d %H:%M:%S", LT); - raw_string_ostream OS(S); - OS << format("%s.%.9u", static_cast<const char *>(Buffer), - this->nanoseconds()); - OS.flush(); - return S; -} diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt index 6ae2aed59b6..5ff5bdfccda 100644 --- a/llvm/unittests/Support/CMakeLists.txt +++ b/llvm/unittests/Support/CMakeLists.txt @@ -9,6 +9,7 @@ add_llvm_unittest(SupportTests BlockFrequencyTest.cpp BranchProbabilityTest.cpp Casting.cpp + Chrono.cpp CommandLineTest.cpp CompressionTest.cpp ConvertUTFTest.cpp diff --git a/llvm/unittests/Support/Chrono.cpp b/llvm/unittests/Support/Chrono.cpp new file mode 100644 index 00000000000..3d578780756 --- /dev/null +++ b/llvm/unittests/Support/Chrono.cpp @@ -0,0 +1,79 @@ +//===- llvm/unittest/Support/Chrono.cpp - Time utilities tests ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Chrono.h" +#include "llvm/ADT/SmallVector.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::sys; +using namespace std::chrono; + +namespace { + +TEST(Chrono, TimeTConversion) { + EXPECT_EQ(time_t(0), toTimeT(toTimePoint(time_t(0)))); + EXPECT_EQ(time_t(1), toTimeT(toTimePoint(time_t(1)))); + EXPECT_EQ(time_t(47), toTimeT(toTimePoint(time_t(47)))); + + TimePoint<> TP; + EXPECT_EQ(TP, toTimePoint(toTimeT(TP))); + TP += seconds(1); + EXPECT_EQ(TP, toTimePoint(toTimeT(TP))); + TP += hours(47); + EXPECT_EQ(TP, toTimePoint(toTimeT(TP))); +} + +TEST(Chrono, StringConversion) { + std::string S; + raw_string_ostream OS(S); + OS << system_clock::now(); + + // Do a basic sanity check on the output. + // The format we expect is YYYY-MM-DD HH:MM:SS.MMMUUUNNN + StringRef Date, Time; + std::tie(Date, Time) = StringRef(OS.str()).split(' '); + + SmallVector<StringRef, 3> Components; + Date.split(Components, '-'); + ASSERT_EQ(3u, Components.size()); + EXPECT_EQ(4u, Components[0].size()); + EXPECT_EQ(2u, Components[1].size()); + EXPECT_EQ(2u, Components[2].size()); + + StringRef Sec, Nano; + std::tie(Sec, Nano) = Time.split('.'); + + Components.clear(); + Sec.split(Components, ':'); + ASSERT_EQ(3u, Components.size()); + EXPECT_EQ(2u, Components[0].size()); + EXPECT_EQ(2u, Components[1].size()); + EXPECT_EQ(2u, Components[2].size()); + EXPECT_EQ(9u, Nano.size()); +} + +// Test that toTimePoint and toTimeT can be called with a arguments with varying +// precisions. +TEST(Chrono, ImplicitConversions) { + std::time_t TimeT = 47; + TimePoint<seconds> Sec = toTimePoint(TimeT); + TimePoint<milliseconds> Milli = toTimePoint(TimeT); + TimePoint<microseconds> Micro = toTimePoint(TimeT); + TimePoint<nanoseconds> Nano = toTimePoint(TimeT); + EXPECT_EQ(Sec, Milli); + EXPECT_EQ(Sec, Micro); + EXPECT_EQ(Sec, Nano); + EXPECT_EQ(TimeT, toTimeT(Sec)); + EXPECT_EQ(TimeT, toTimeT(Milli)); + EXPECT_EQ(TimeT, toTimeT(Micro)); + EXPECT_EQ(TimeT, toTimeT(Nano)); +} + +} // anonymous namespace diff --git a/llvm/unittests/Support/TimeValueTest.cpp b/llvm/unittests/Support/TimeValueTest.cpp index 3d2b9780c06..9e8690f57bc 100644 --- a/llvm/unittests/Support/TimeValueTest.cpp +++ b/llvm/unittests/Support/TimeValueTest.cpp @@ -37,4 +37,14 @@ TEST(TimeValue, Win32FILETIME) { EXPECT_EQ(ft1970, epoch.toWin32Time()); } +TEST(TimeValue, Chrono) { + sys::TimeValue TV; + TV.fromEpochTime(0); + sys::TimePoint<> TP = TV; + EXPECT_EQ(0u, sys::toTimeT(TP)); + + TP += std::chrono::seconds(47); + TV = TP; + EXPECT_EQ(47u, TV.toEpochTime()); +} } |