aboutsummaryrefslogtreecommitdiffhomepage
path: root/lib/Support/Time.cpp
diff options
context:
space:
mode:
authorFrank Busse <bb0xfb@gmail.com>2017-11-24 16:58:27 +0000
committerCristian Cadar <c.cadar@imperial.ac.uk>2018-10-30 22:22:26 +0200
commit3caf3e985e4f35ac6ac04f61b92f11d2569550c6 (patch)
tree4c8cb1ce7e8d7bdf4f890e76b98ea2ef77370f66 /lib/Support/Time.cpp
parent652c2bdc171a448a2d6082040eebec366946ad33 (diff)
downloadklee-3caf3e985e4f35ac6ac04f61b92f11d2569550c6.tar.gz
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)
Diffstat (limited to 'lib/Support/Time.cpp')
-rw-r--r--lib/Support/Time.cpp201
1 files changed, 168 insertions, 33 deletions
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 <chrono>
-#include <llvm/Support/Chrono.h>
-#else
-#include "llvm/Support/TimeValue.h"
-#endif
+#include <cstdint>
+#include <regex>
+#include <sstream>
+#include <tuple>
+#include <sys/resource.h>
-#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<double> d(value);
+ duration = std::chrono::duration_cast<std::chrono::microseconds>(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<std::chrono::seconds>(duration);
+ const auto usecs = std::chrono::duration_cast<std::chrono::microseconds>(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<std::chrono::microseconds>(duration).count();
}
-sys::TimePoint<> util::getWallTimeVal() {
- return std::chrono::system_clock::now();
+double time::Span::toSeconds() const {
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(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<std::uint32_t, std::uint8_t, std::uint8_t> time::Span::toHMS() const {
+ auto d = duration;
+ const auto h = std::chrono::duration_cast<std::chrono::hours>(d);
+ const auto m = std::chrono::duration_cast<std::chrono::minutes>(d -= h);
+ const auto s = std::chrono::duration_cast<std::chrono::seconds>(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<std::uint64_t>(usage.ru_utime.tv_sec)) +
+ time::microseconds(static_cast<std::uint64_t>(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());
+}
+