1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 02:52:53 +02:00

Add Chrono.h - std::chrono support header

Summary:
std::chrono mostly covers the functionality of llvm::sys::TimeValue and
lldb_private::TimeValue. This header adds a bit of utility functions and
typedefs, which make the usage of the library and porting code from TimeValues
easier.

Rationale:
- TimePoint typedef - precision of system_clock is implementation defined -
  using a well-defined precision helps maintain consistency between platforms,
  makes it interact better with existing TimeValue classes, and avoids cases
  there a time point is implicitly convertible to a specific precision on some
  platforms but not on others.
- system_clock::to_time_t only accepts time_points with the default system
  precision (even though time_t has only second precision on all platforms we
  support). To avoid the need for explicit casts, I have added a toTimeT()
  wrapper function. toTimePoint(time_t) was not strictly necessary, but I have
  added it for symmetry.

Reviewers: zturner, mehdi_amini

Subscribers: beanz, mgorny, llvm-commits, modocache

Differential Revision: https://reviews.llvm.org/D25416

llvm-svn: 284590
This commit is contained in:
Pavel Labath 2016-10-19 13:58:55 +00:00
parent 3d94a0d81d
commit 79a60cfd95
10 changed files with 212 additions and 124 deletions

View File

@ -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

View File

@ -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.

View File

@ -37,6 +37,7 @@ add_llvm_library(LLVMSupport
BranchProbability.cpp
CachePruning.cpp
circular_raw_ostream.cpp
Chrono.cpp
COM.cpp
CommandLine.cpp
Compression.cpp

47
lib/Support/Chrono.cpp Normal file
View File

@ -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", &LT);
return OS << Buffer << '.'
<< format("%.9lu",
long((TP.time_since_epoch() % std::chrono::seconds(1))
.count()));
}
} // namespace llvm

View File

@ -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)); }
/// 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
TimeValue TimeValue::now() {
return TimePoint<>(std::chrono::system_clock::now());
}
} // namespace llvm

View File

@ -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 ) );
}
}

View File

@ -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;
}

View File

@ -9,6 +9,7 @@ add_llvm_unittest(SupportTests
BlockFrequencyTest.cpp
BranchProbabilityTest.cpp
Casting.cpp
Chrono.cpp
CommandLineTest.cpp
CompressionTest.cpp
ConvertUTFTest.cpp

View File

@ -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

View File

@ -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());
}
}