Index: llvm/trunk/include/llvm/Support/Chrono.h =================================================================== --- llvm/trunk/include/llvm/Support/Chrono.h +++ llvm/trunk/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 +#include + +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 +using TimePoint = std::chrono::time_point; + +/// 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(TP)); +} + +/// Convert a std::time_t to a TimePoint +LLVM_ATTRIBUTE_ALWAYS_INLINE inline TimePoint +toTimePoint(std::time_t T) { + using namespace std::chrono; + return time_point_cast(system_clock::from_time_t(T)); +} + +} // namespace sys + +raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP); + +} // namespace llvm + +#endif // LLVM_SUPPORT_CHRONO_H Index: llvm/trunk/include/llvm/Support/TimeValue.h =================================================================== --- llvm/trunk/include/llvm/Support/TimeValue.h +++ llvm/trunk/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 @@ -112,6 +113,11 @@ this->normalize(); } + template + TimeValue(TimePoint 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 @@ /// @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. Index: llvm/trunk/lib/Support/CMakeLists.txt =================================================================== --- llvm/trunk/lib/Support/CMakeLists.txt +++ llvm/trunk/lib/Support/CMakeLists.txt @@ -37,6 +37,7 @@ BranchProbability.cpp CachePruning.cpp circular_raw_ostream.cpp + Chrono.cpp COM.cpp CommandLine.cpp Compression.cpp Index: llvm/trunk/lib/Support/Chrono.cpp =================================================================== --- llvm/trunk/lib/Support/Chrono.cpp +++ llvm/trunk/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 Index: llvm/trunk/lib/Support/TimeValue.cpp =================================================================== --- llvm/trunk/lib/Support/TimeValue.cpp +++ llvm/trunk/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 @@ } } -} // 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 Index: llvm/trunk/lib/Support/Unix/TimeValue.inc =================================================================== --- llvm/trunk/lib/Support/Unix/TimeValue.inc +++ llvm/trunk/lib/Support/Unix/TimeValue.inc @@ -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( the_time.tv_sec + - PosixZeroTimeSeconds ), - static_cast( the_time.tv_usec * - NANOSECONDS_PER_MICROSECOND ) ); -} - -} Index: llvm/trunk/lib/Support/Windows/TimeValue.inc =================================================================== --- llvm/trunk/lib/Support/Windows/TimeValue.inc +++ llvm/trunk/lib/Support/Windows/TimeValue.inc @@ -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 -#include - -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(&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(Buffer), - this->nanoseconds()); - OS.flush(); - return S; -} Index: llvm/trunk/unittests/Support/CMakeLists.txt =================================================================== --- llvm/trunk/unittests/Support/CMakeLists.txt +++ llvm/trunk/unittests/Support/CMakeLists.txt @@ -9,6 +9,7 @@ BlockFrequencyTest.cpp BranchProbabilityTest.cpp Casting.cpp + Chrono.cpp CommandLineTest.cpp CompressionTest.cpp ConvertUTFTest.cpp Index: llvm/trunk/unittests/Support/Chrono.cpp =================================================================== --- llvm/trunk/unittests/Support/Chrono.cpp +++ llvm/trunk/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 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 Sec = toTimePoint(TimeT); + TimePoint Milli = toTimePoint(TimeT); + TimePoint Micro = toTimePoint(TimeT); + TimePoint 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 Index: llvm/trunk/unittests/Support/TimeValueTest.cpp =================================================================== --- llvm/trunk/unittests/Support/TimeValueTest.cpp +++ llvm/trunk/unittests/Support/TimeValueTest.cpp @@ -37,4 +37,14 @@ 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()); +} }