Skip to content

Commit

Permalink
Reapply "Add Chrono.h - std::chrono support header"
Browse files Browse the repository at this point in the history
This is a resubmission of r284590. The mingw build should be fixed now. The
problem was we were matching time_t with _localtime_64s, which was incorrect on
_USE_32BIT_TIME_T systems. Instead I use localtime_s, which should always
evaluate to the correct function.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@284720 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
labath committed Oct 20, 2016
1 parent b4c99dd commit 911bb94
Show file tree
Hide file tree
Showing 10 changed files with 212 additions and 124 deletions.
55 changes: 55 additions & 0 deletions include/llvm/Support/Chrono.h
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions include/llvm/Support/TimeValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -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).
Expand All @@ -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.
Expand Down
1 change: 1 addition & 0 deletions lib/Support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ add_llvm_library(LLVMSupport
BranchProbability.cpp
CachePruning.cpp
circular_raw_ostream.cpp
Chrono.cpp
COM.cpp
CommandLine.cpp
Compression.cpp
Expand Down
47 changes: 47 additions & 0 deletions lib/Support/Chrono.cpp
Original file line number Diff line number Diff line change
@@ -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 = ::localtime_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
17 changes: 8 additions & 9 deletions lib/Support/TimeValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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
54 changes: 0 additions & 54 deletions lib/Support/Unix/TimeValue.inc

This file was deleted.

61 changes: 0 additions & 61 deletions lib/Support/Windows/TimeValue.inc

This file was deleted.

1 change: 1 addition & 0 deletions unittests/Support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ add_llvm_unittest(SupportTests
BlockFrequencyTest.cpp
BranchProbabilityTest.cpp
Casting.cpp
Chrono.cpp
CommandLineTest.cpp
CompressionTest.cpp
ConvertUTFTest.cpp
Expand Down
79 changes: 79 additions & 0 deletions unittests/Support/Chrono.cpp
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions unittests/Support/TimeValueTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}

0 comments on commit 911bb94

Please sign in to comment.