Index: include/llvm/Support/Chrono.h =================================================================== --- /dev/null +++ include/llvm/Support/Chrono.h @@ -0,0 +1,117 @@ +//===- 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 +#include + +namespace llvm { + +class raw_ostream; + +namespace sys { + +/// A time point on the system clock. The only way this differs from +/// std::chrono::system_clock::time_point is that we explicitly specify the +/// duration to be nanoseconds (default duration of system_clock is +/// implementation-defined). +using TimePoint = std::chrono::time_point; + +/// Convert a TimePoint to std::time_t +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 +inline TimePoint toTimePoint(std::time_t T) { + return std::chrono::system_clock::from_time_t(T); +} + +/// Convert a struct timespec to a TimePoint. Note that timespec can be used +/// both as a time point and a duration. If the input represents a duration, +/// use toDuration(). +inline TimePoint toTimePoint(const struct timespec &TS) { + return toTimePoint(TS.tv_sec) + std::chrono::nanoseconds(TS.tv_nsec); +} + +/// Convert a struct timeval to a TimePoint. Note that timeval can be used +/// both as a time point and a duration. If the input represents a duration, +/// use toDuration(). +inline TimePoint toTimePoint(const struct timeval &TV) { + return toTimePoint(TV.tv_sec) + std::chrono::microseconds(TV.tv_usec); +} + +/// Convert a struct timespec to a duration. Note that timespec can be used +/// both as a time point and a duration. If the input represents a time point, +/// use toTimePoint(). +inline std::chrono::nanoseconds toDuration(const struct timespec &TS) { + return std::chrono::seconds(TS.tv_sec) + std::chrono::nanoseconds(TS.tv_nsec); +} + +/// Convert a struct timeval to a duration. Note that timeval can be used both +/// as a time point and a duration. If the input represents a time point, use +/// toTimePoint(). +inline std::chrono::microseconds toDuration(const struct timeval &TV) { + return std::chrono::seconds(TV.tv_sec) + + std::chrono::microseconds(TV.tv_usec); +} + +/// Convert a duration to struct timespec. +inline struct timespec toTimeSpec(std::chrono::nanoseconds NS) { + using namespace std::chrono; + + struct timespec RetVal; + RetVal.tv_sec = duration_cast(NS).count(); + RetVal.tv_nsec = (NS % seconds(1)).count(); + return RetVal; +} + +/// Convert a time point to struct timespec. +inline struct timespec toTimeSpec(TimePoint TP) { + using namespace std::chrono; + + struct timespec RetVal; + RetVal.tv_sec = toTimeT(TP); + RetVal.tv_nsec = (TP.time_since_epoch() % seconds(1)).count(); + return RetVal; +} + +/// Convert a duration to struct timeval. +inline struct timeval toTimeVal(std::chrono::microseconds US) { + using namespace std::chrono; + + struct timeval RetVal; + RetVal.tv_sec = duration_cast(US).count(); + RetVal.tv_usec = (US % seconds(1)).count(); + return RetVal; +} + +/// Convert a time point to struct timeval. +inline struct timeval toTimeVal(TimePoint TP) { + using namespace std::chrono; + + struct timeval RetVal; + RetVal.tv_sec = toTimeT(TP); + RetVal.tv_usec = + (duration_cast(TP.time_since_epoch()) % seconds(1)).count(); + return RetVal; +} + +} // namespace sys + +raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint TP); + +} // namespace llvm + +#endif // LLVM_SUPPORT_CHRONO_H Index: include/llvm/Support/TimeValue.h =================================================================== --- include/llvm/Support/TimeValue.h +++ 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,10 @@ this->normalize(); } + TimeValue(TimePoint TP) + : seconds_(sys::toTimeT(TP) + PosixZeroTimeSeconds), + nanos_((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 +126,12 @@ /// @name Operators /// @{ public: + operator TimePoint() { + return std::chrono::system_clock::from_time_t(seconds_ - + PosixZeroTimeSeconds) + + std::chrono::nanoseconds(nanos_); + } + /// Add \p that to \p this. /// @returns this /// @brief Incrementing assignment operator. Index: lib/Support/CMakeLists.txt =================================================================== --- lib/Support/CMakeLists.txt +++ 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: lib/Support/Chrono.cpp =================================================================== --- /dev/null +++ lib/Support/Chrono.cpp @@ -0,0 +1,20 @@ +//===- lib/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. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Chrono.h" +#include "llvm/Config/config.h" +#include "llvm/Support/raw_ostream.h" + +/// Include the platform-specific portion +#ifdef LLVM_ON_UNIX +#include "Unix/Chrono.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Chrono.inc" +#endif Index: lib/Support/Unix/Chrono.inc =================================================================== --- /dev/null +++ lib/Support/Unix/Chrono.inc @@ -0,0 +1,31 @@ +//===- Unix/Chrono.inc - 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. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Format.h" + +namespace llvm { + +using namespace sys; + +raw_ostream &operator<<(raw_ostream &OS, TimePoint TP) { + struct timespec TS = toTimeSpec(TP); + struct tm Storage; + struct tm *LT = ::localtime_r(&TS.tv_sec, &Storage); + assert(LT); + char Buffer[sizeof "YYYY-MM-DD HH:MM:SS"]; + strftime(Buffer, sizeof Buffer, "%Y-%m-%d %H:%M:%S", LT); + return OS << Buffer << '.' << format("%.9lu", long(TS.tv_nsec)); +} + +} // namespace llvm Index: unittests/Support/CMakeLists.txt =================================================================== --- unittests/Support/CMakeLists.txt +++ unittests/Support/CMakeLists.txt @@ -9,6 +9,7 @@ BlockFrequencyTest.cpp BranchProbabilityTest.cpp Casting.cpp + Chrono.cpp CommandLineTest.cpp CompressionTest.cpp ConvertUTFTest.cpp Index: unittests/Support/Chrono.cpp =================================================================== --- /dev/null +++ unittests/Support/Chrono.cpp @@ -0,0 +1,93 @@ +//===- 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 "gtest/gtest.h" + +using namespace llvm::sys; +using namespace std::chrono; + +static bool operator==(const struct timeval &LHS, const struct timeval &RHS) { + return LHS.tv_sec == RHS.tv_sec && LHS.tv_usec == RHS.tv_usec; +} + +static bool operator==(const struct timespec &LHS, const struct timespec &RHS) { + return LHS.tv_sec == RHS.tv_sec && LHS.tv_nsec == RHS.tv_nsec; +} + +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, system_clock::from_time_t(toTimeT(TP))); + TP += seconds(1); + EXPECT_EQ(TP, system_clock::from_time_t(toTimeT(TP))); + TP += hours(47); + EXPECT_EQ(TP, system_clock::from_time_t(toTimeT(TP))); +} + +TEST(Chrono, TimeSpecDuration) { + struct timespec TS; + + TS = toTimeSpec(seconds(1) + nanoseconds(47)); + EXPECT_EQ(1, TS.tv_sec); + EXPECT_EQ(47, TS.tv_nsec); + EXPECT_EQ(seconds(1) + nanoseconds(47), toDuration(TS)); + + TS = toTimeSpec(nanoseconds(999999999)); + EXPECT_EQ(0, TS.tv_sec); + EXPECT_EQ(999999999, TS.tv_nsec); +} + +TEST(Chrono, TimeSpecTimePoint) { + struct timespec TS; + TS.tv_sec = 1; + TS.tv_nsec = 47; + EXPECT_EQ(TS, toTimeSpec(toTimePoint(TS))); + + TimePoint TP; + EXPECT_EQ(TP, toTimePoint(toTimeSpec(TP))); + TP += seconds(1); + EXPECT_EQ(TP, toTimePoint(toTimeSpec(TP))); + TP += nanoseconds(47); + EXPECT_EQ(TP, toTimePoint(toTimeSpec(TP))); +} + +TEST(Chrono, TimeValDuration) { + struct timeval TV; + + TV = toTimeVal(seconds(1) + microseconds(47)); + EXPECT_EQ(1, TV.tv_sec); + EXPECT_EQ(47, TV.tv_usec); + EXPECT_EQ(seconds(1) + microseconds(47), toDuration(TV)); + + TV = toTimeVal(microseconds(999999)); + EXPECT_EQ(0, TV.tv_sec); + EXPECT_EQ(999999, TV.tv_usec); +} + +TEST(Chrono, TimeValTimePoint) { + struct timeval TV; + TV.tv_sec = 1; + TV.tv_usec = 47; + EXPECT_EQ(TV, toTimeVal(toTimePoint(TV))); + + TimePoint TP; + EXPECT_EQ(TP, toTimePoint(toTimeVal(TP))); + TP += seconds(1); + EXPECT_EQ(TP, toTimePoint(toTimeVal(TP))); + TP += microseconds(47); + EXPECT_EQ(TP, toTimePoint(toTimeVal(TP))); +} + +} // anonymous namespace Index: unittests/Support/TimeValueTest.cpp =================================================================== --- unittests/Support/TimeValueTest.cpp +++ 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()); +} }