From 3caf3e985e4f35ac6ac04f61b92f11d2569550c6 Mon Sep 17 00:00:00 2001 From: Frank Busse Date: Fri, 24 Nov 2017 16:58:27 +0000 Subject: Base time API upon std::chrono This should not change the behaviour of KLEE and mimics the old API. - functions moved from util into time namespace - uses time points and time spans instead of double - CLI arguments now have the form "3h5min8us" Changed command line parameters: - batch-time (double to string) - istats-write-interval (double to string) - max-instruction-time (double to string) - max-solver-time (double to string) - max-time (double to string) - min-query-time-to-log (double to string) - seed-time (double to string) - stats-write-interval (double to string) - uncovered-update-interval (double to string) - added: log-timed-out-queries (replaces negative max-solver-time) --- lib/Support/Time.cpp | 201 +++++++++++++++++++++++++++++++++++++++++--------- lib/Support/Timer.cpp | 24 +----- 2 files changed, 171 insertions(+), 54 deletions(-) (limited to 'lib/Support') diff --git a/lib/Support/Time.cpp b/lib/Support/Time.cpp index f508e6fa..7cd9659b 100644 --- a/lib/Support/Time.cpp +++ b/lib/Support/Time.cpp @@ -7,58 +7,193 @@ // //===----------------------------------------------------------------------===// -#include "klee/Config/Version.h" +#include "klee/Internal/Support/ErrorHandling.h" #include "klee/Internal/System/Time.h" -#if LLVM_VERSION_CODE >= LLVM_VERSION(4, 0) -#include -#include -#else -#include "llvm/Support/TimeValue.h" -#endif +#include +#include +#include +#include +#include -#include "llvm/Support/Process.h" -using namespace llvm; using namespace klee; -#if LLVM_VERSION_CODE >= LLVM_VERSION(4, 0) -double util::durationToDouble(std::chrono::nanoseconds dur) -{ - return dur.count() / 1e9; + +/* Why std::chrono: + * - C++11 + * - separation between time points and durations + * - good performance on Linux and macOS (similar to gettimeofday) + * and not: + * - clock_gettime(CLOCK_MONOTONIC_COARSE): software clock, Linux-specific + * - clock_gettime(CLOCK_MONOTONIC): slowest on macOS, C-like API + * - gettimeofday: C-like API, non-monotonic + * + * TODO: add time literals with C++14 + */ + +// === Point === + +// operators +time::Point& time::Point::operator+=(const time::Span &span) { point += span.duration; return *this; } +time::Point& time::Point::operator-=(const time::Span &span) { point -= span.duration; return *this; } + +time::Point time::operator+(const time::Point &point, const time::Span &span) { return time::Point(point.point + span.duration); } +time::Point time::operator+(const time::Span &span, const time::Point &point) { return time::Point(point.point + span.duration); } +time::Point time::operator-(const time::Point &point, const time::Span &span) { return time::Point(point.point - span.duration); } +time::Span time::operator-(const time::Point &lhs, const time::Point &rhs) { return time::Span(lhs.point - rhs.point); } +bool time::operator==(const time::Point &lhs, const time::Point &rhs) { return lhs.point == rhs.point; } +bool time::operator!=(const time::Point &lhs, const time::Point &rhs) { return lhs.point != rhs.point; } +bool time::operator<(const time::Point &lhs, const time::Point &rhs) { return lhs.point < rhs.point; } +bool time::operator<=(const time::Point &lhs, const time::Point &rhs) { return lhs.point <= rhs.point; } +bool time::operator>(const time::Point &lhs, const time::Point &rhs) { return lhs.point > rhs.point; } +bool time::operator>=(const time::Point &lhs, const time::Point &rhs) { return lhs.point >= rhs.point; } + + +// === Span === + +// ctors +/// returns span from string in old (X.Y) and new (3h4min) format +time::Span::Span(const std::string &s) { + if (s.empty()) return; + + std::regex re("^([0-9]*\\.?[0-9]+)|((([0-9]+)(h|min|s|ms|us|ns))+)$", std::regex::extended); + std::regex nre("([0-9]+)(h|min|s|ms|us|ns)", std::regex::extended); + std::smatch match; + std::string submatch; + + // error + if (!std::regex_match(s, match, re)) goto error; + + // old (double) format + submatch = match[1].str(); + if (match[1].matched) { + errno = 0; + auto value = std::stod(submatch); + if (errno) goto error; + + std::chrono::duration d(value); + duration = std::chrono::duration_cast(d); + } + + // new (string) format + submatch = match[2].str(); + for (std::smatch m; std::regex_search(submatch, m, nre); submatch = m.suffix()) { + errno = 0; + const auto value = std::stoull(m[1]); + if (errno) goto error; + + Duration d; + if (m[2] == "h") d = std::chrono::hours(value); + else if (m[2] == "min") d = std::chrono::minutes(value); + else if (m[2] == "s") d = std::chrono::seconds(value); + else if (m[2] == "ms") d = std::chrono::milliseconds(value); + else if (m[2] == "us") d = std::chrono::microseconds(value); + else if (m[2] == "ns") d = std::chrono::nanoseconds(value); + else goto error; + + duration += d; + } + + return; + +error: + klee_error("Illegal number format: %s", s.c_str()); } -double util::getUserTime() { - sys::TimePoint<> now; - std::chrono::nanoseconds user, sys; +// operators +time::Span& time::Span::operator=(const time::Duration &d) { duration = d; return *this; }; +time::Span& time::Span::operator+=(const time::Span &other) { duration += other.duration; return *this; } +time::Span& time::Span::operator-=(const time::Span &other) { duration -= other.duration; return *this; } +time::Span& time::Span::operator*=(const time::Duration::rep &rep) { duration *= rep; return *this; } + +time::Span time::operator+(const time::Span &lhs, const time::Span &rhs) { return time::Span(lhs.duration + rhs.duration); } +time::Span time::operator-(const time::Span &lhs, const time::Span &rhs) { return time::Span(lhs.duration - rhs.duration); } +time::Span time::operator*(const time::Span &span, const time::Duration::rep &rep) { return time::Span(span.duration * rep); } +time::Span time::operator*(const time::Duration::rep &rep, const time::Span &span) { return time::Span(span.duration * rep); } +time::Span time::operator/(const time::Span &span, const time::Duration::rep &rep) { return time::Span(span.duration / rep); } +bool time::operator==(const time::Span &lhs, const time::Span &rhs) { return lhs.duration == rhs.duration; } +bool time::operator<=(const time::Span &lhs, const time::Span &rhs) { return lhs.duration <= rhs.duration; } +bool time::operator>=(const time::Span &lhs, const time::Span &rhs) { return lhs.duration >= rhs.duration; } +bool time::operator<(const time::Span &lhs, const time::Span &rhs) { return lhs.duration < rhs.duration; } +bool time::operator>(const time::Span &lhs, const time::Span &rhs) { return lhs.duration > rhs.duration; } + +std::ostream& time::operator<<(std::ostream &stream, time::Span span) { return stream << span.toSeconds() << 's'; } +llvm::raw_ostream& time::operator<<(llvm::raw_ostream &stream, time::Span span) { return stream << span.toSeconds() << 's'; } + - sys::Process::GetTimeUsage(now, user, sys); +// units +time::Span time::hours(std::uint16_t ticks) { return time::Span(std::chrono::hours(ticks)); } +time::Span time::minutes(std::uint16_t ticks) { return time::Span(std::chrono::minutes(ticks)); } +time::Span time::seconds(std::uint64_t ticks) { return time::Span(std::chrono::seconds(ticks)); } +time::Span time::milliseconds(std::uint64_t ticks) { return time::Span(std::chrono::milliseconds(ticks)); } +time::Span time::microseconds(std::uint64_t ticks) { return time::Span(std::chrono::microseconds(ticks)); } +time::Span time::nanoseconds(std::uint64_t ticks) { return time::Span(std::chrono::nanoseconds(ticks)); } - return durationToDouble(user); + +// conversions +time::Span::operator time::Duration() const { return duration; } + +time::Span::operator bool() const { return duration.count() != 0; } + +time::Span::operator timeval() const { + timeval tv{}; + const auto secs = std::chrono::duration_cast(duration); + const auto usecs = std::chrono::duration_cast(duration - secs); + tv.tv_sec = secs.count(); + tv.tv_usec = usecs.count(); + return tv; } -double util::getWallTime() { - return durationToDouble(getWallTimeVal().time_since_epoch()); +std::uint64_t time::Span::toMicroseconds() const { + return (std::uint64_t)std::chrono::duration_cast(duration).count(); } -sys::TimePoint<> util::getWallTimeVal() { - return std::chrono::system_clock::now(); +double time::Span::toSeconds() const { + return std::chrono::duration_cast(duration).count() / (double)1000000000; } -#else -double util::getUserTime() { - sys::TimeValue now(0,0),user(0,0),sys(0,0); - sys::Process::GetTimeUsage(now,user,sys); - return (user.seconds() + (double) user.nanoseconds() * 1e-9); +std::tuple time::Span::toHMS() const { + auto d = duration; + const auto h = std::chrono::duration_cast(d); + const auto m = std::chrono::duration_cast(d -= h); + const auto s = std::chrono::duration_cast(d -= m); + + return std::make_tuple((std::uint32_t) h.count(), (std::uint8_t) m.count(), (std::uint8_t) s.count()); } -double util::getWallTime() { - sys::TimeValue now = getWallTimeVal(); - return (now.seconds() + ((double) now.nanoseconds() * 1e-9)); + +// methods +/// Returns information about clock +std::string time::getClockInfo() { + std::stringstream buffer; + buffer << "Using monotonic steady clock with " + << std::chrono::steady_clock::period::num + << '/' + << std::chrono::steady_clock::period::den + << "s resolution\n"; + return buffer.str(); } -sys::TimeValue util::getWallTimeVal() { - return sys::TimeValue::now(); + +/// Returns time spent by this process in user mode +time::Span time::getUserTime() { + rusage usage{}; + auto ret = ::getrusage(RUSAGE_SELF, &usage); + + if (ret) { + klee_warning("getrusage returned with error, return (0,0)"); + return {}; + } else { + return time::seconds(static_cast(usage.ru_utime.tv_sec)) + + time::microseconds(static_cast(usage.ru_utime.tv_usec)); + } } -#endif + + +/// Returns point in time using a monotonic steady clock +time::Point time::getWallTime() { + return time::Point(std::chrono::steady_clock::now()); +} + diff --git a/lib/Support/Timer.cpp b/lib/Support/Timer.cpp index 0e727bb4..4e52feb5 100644 --- a/lib/Support/Timer.cpp +++ b/lib/Support/Timer.cpp @@ -9,32 +9,14 @@ #include "klee/Config/Version.h" #include "klee/Internal/Support/Timer.h" - #include "klee/Internal/System/Time.h" using namespace klee; -using namespace llvm; - -#if LLVM_VERSION_CODE >= LLVM_VERSION(4, 0) WallTimer::WallTimer() { - start = util::getWallTimeVal(); + start = time::getWallTime(); } -uint64_t WallTimer::check() { - auto now = util::getWallTimeVal(); - return std::chrono::duration_cast(now - - start).count(); +time::Span WallTimer::check() { + return time::Span(time::getWallTime() - start); } - -#else - -WallTimer::WallTimer() { - startMicroseconds = util::getWallTimeVal().usec(); -} - -uint64_t WallTimer::check() { - return util::getWallTimeVal().usec() - startMicroseconds; -} - -#endif -- cgit 1.4.1