//===-- Time.cpp ----------------------------------------------------------===// // // The KLEE Symbolic Virtual Machine // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "klee/Internal/Support/ErrorHandling.h" #include "klee/Internal/System/Time.h" #include #include #include #include #include using namespace klee; /* 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()); } // 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*=(unsigned factor) { duration *= factor; return *this; } time::Span& time::Span::operator*=(double factor) { duration = std::chrono::microseconds((std::uint64_t)((double)toMicroseconds() * factor)); 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, double factor) { return time::Span(std::chrono::microseconds((std::uint64_t)((double)span.toMicroseconds() * factor))); }; time::Span time::operator*(double factor, const time::Span &span) { return time::Span(std::chrono::microseconds((std::uint64_t)((double)span.toMicroseconds() * factor))); }; time::Span time::operator*(const time::Span &span, unsigned factor) { return time::Span(span.duration * factor); } time::Span time::operator*(unsigned factor, const time::Span &span) { return time::Span(span.duration * factor); } time::Span time::operator/(const time::Span &span, unsigned divisor) { return time::Span(span.duration / divisor); } 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'; } // 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)); } // 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; } std::uint64_t time::Span::toMicroseconds() const { return (std::uint64_t)std::chrono::duration_cast(duration).count(); } double time::Span::toSeconds() const { return std::chrono::duration_cast(duration).count() / (double)1000000000; } 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()); } // 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(); } /// 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)); } } /// Returns point in time using a monotonic steady clock time::Point time::getWallTime() { return time::Point(std::chrono::steady_clock::now()); }