Add get_absolute_time() syscall + implement std::chrono::steady_clock::now() using it.
authorSimon Gerber <simon.gerber@inf.ethz.ch>
Fri, 20 Feb 2015 16:46:17 +0000 (17:46 +0100)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Mon, 9 Mar 2015 14:36:21 +0000 (15:36 +0100)
This addresses T64.  Needs revising and more work to make it available on
architectures other than x86_64.

This may not quite satisfy the requirements mandated for
std::chrono::steady_clock, but is good enough to make steady_clock workable
for code that needs to work with millisecond precision durations.

Signed-off-by: Simon Gerber <simon.gerber@inf.ethz.ch>

include/barrelfish/syscalls.h
include/barrelfish_kpi/syscalls.h
kernel/arch/x86_64/syscall.c
kernel/include/syscall.h
kernel/syscall.c
lib/barrelfish/arch/x86_64/syscalls.c
lib/cxx/cxx/chrono.cpp
usr/tests/cxx/Hakefile
usr/tests/cxx/cxxtest.hpp
usr/tests/cxx/stl_chrono.cpp [new file with mode: 0644]
usr/tests/cxx/test.cpp

index 93b6152..9a72da3 100644 (file)
@@ -55,6 +55,10 @@ errval_t sys_reboot(void);
  */
 errval_t sys_print(const char *string, size_t length);
 
+/**
+ * \brief get time elapsed since system boot.
+ */
+uint64_t sys_get_absolute_time(void);
 __END_DECLS
 
 #endif //LIBBARRELFISH_SYSCALL_H
index 66d2e22..0825075 100644 (file)
@@ -60,8 +60,9 @@ struct sysret {
 
 #define SYSCALL_X86_RELOAD_LDT      8     ///< Reload the LDT register (x86_64)
 #define SYSCALL_SUSPEND             9     ///< Suspend the CPU
+#define SYSCALL_GET_ABS_TIME        10    ///< Get time elapsed since boot
 
-#define SYSCALL_COUNT               10     ///< Number of syscalls [0..SYSCALL_COUNT - 1]
+#define SYSCALL_COUNT               11     ///< Number of syscalls [0..SYSCALL_COUNT - 1]
 
 /*
  * To understand system calls it might be helpful to know that there
index 282e076..e68ee9c 100644 (file)
@@ -1195,6 +1195,10 @@ struct sysret sys_syscall(uint64_t syscall, uint64_t arg0, uint64_t arg1,
         TRACE(KERNEL, SC_SUSPEND, 1);
         break;
 
+    case SYSCALL_GET_ABS_TIME:
+        retval = sys_get_absolute_time();
+        break;
+
     case SYSCALL_DEBUG:
         switch(arg0) {
         case DEBUG_CONTEXT_COUNTER_RESET:
index 3713053..ae6c9c0 100644 (file)
@@ -63,6 +63,7 @@ struct sysret sys_kernel_add_kcb(struct kcb* new_kcb);
 struct sysret sys_kernel_remove_kcb(struct kcb* kcb_addr);
 struct sysret sys_kernel_suspend_kcb_sched(bool toggle);
 struct sysret sys_handle_kcb_identify(struct capability* to);
+struct sysret sys_get_absolute_time(void);
 
 /*
  * Monitor syscalls
index 5a2142f..dcec184 100644 (file)
@@ -623,3 +623,15 @@ struct sysret sys_handle_kcb_identify(struct capability* to)
         .value = mem_to_local_phys(vkcb) | OBJBITS_KCB,
     };
 }
+
+struct sysret sys_get_absolute_time(void)
+{
+    // Return kernel_now.
+    // XXX: this may not provide all the properties of absolute time we want,
+    // but should be sufficient to implement stuff that needs timing with 1/10
+    // of a second accuracy range.
+    return (struct sysret) {
+        .error = SYS_ERR_OK,
+        .value = kernel_now + kcb_current->kernel_off,
+    };
+}
index 24317a8..a7b20d0 100644 (file)
@@ -34,3 +34,10 @@ errval_t sys_print(const char *string, size_t length)
 {
     return syscall3(SYSCALL_PRINT, (uintptr_t)string, length).error;
 }
+
+uint64_t sys_get_absolute_time(void)
+{
+    struct sysret r = syscall1(SYSCALL_GET_ABS_TIME);
+    assert(err_is_ok(r.error));
+    return r.value;
+}
index bf6d785..f5924e6 100644 (file)
@@ -119,6 +119,17 @@ steady_clock::now() _NOEXCEPT
     return time_point(duration(fp()));
 }
 
+#elif defined (BARRELFISH)
+#include <barrelfish/syscalls.h>
+// For BF we're doing something similar to the Mach code above where we use
+// the number of milliseconds elapsed since boot for steady_clock.
+steady_clock::time_point
+steady_clock::now() _NOEXCEPT
+{
+    auto t = static_cast<steady_clock::rep>(sys_get_absolute_time() * 1000 * 1000);
+    return time_point(duration(t));
+}
+
 #else  // __APPLE__
 // FIXME: We assume that clock_gettime(CLOCK_MONOTONIC) works on
 // non-apple systems.  Instead, we should check _POSIX_TIMERS and
index b7d39d1..4a4a07e 100644 (file)
@@ -23,6 +23,7 @@
         "stl_templates.cpp",
         "stl_threads.cpp",
         "stl_io.cpp",
+        "stl_chrono.cpp",
         "cxx11.cpp"
     ],
     --addLibraries = [ 
index 5d0109c..f915184 100644 (file)
@@ -14,5 +14,6 @@ void stl_map_test(void);
 void stl_exception_test(void);
 void stl_thread_test(void);
 void cx11_test(void);
+void stl_chrono_test(void);
 
 #endif /* CXXTEST_H_ */
diff --git a/usr/tests/cxx/stl_chrono.cpp b/usr/tests/cxx/stl_chrono.cpp
new file mode 100644 (file)
index 0000000..f1e2faf
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <iostream>
+#include <chrono>
+#include <thread>
+#include <string>
+
+#include "cxxtest.hpp"
+
+static void func(int d)
+{
+    using namespace std::chrono;
+    steady_clock::time_point start = steady_clock::now();
+    steady_clock::time_point current, notified;
+    while (true) {
+        current = steady_clock::now();
+        if (duration_cast<std::chrono::duration<double>>
+                (current - start).count() >= d){
+            break;
+        }
+        else {
+            // notify user how much time of the experiment has passed
+            long diff = duration_cast<std::chrono::duration
+                <double>>(current - notified).count();
+            if (diff >= (d/100.0)) {
+                notified = high_resolution_clock::now();
+                diff = duration_cast<std::chrono::duration
+                    <double>>(notified - start).count();
+                std::cout << (int) (100.0 * diff / d)
+                    << "% completed." << std::endl;
+            }
+            // sleep for a while
+            std::this_thread::sleep_for(std::chrono::milliseconds(500));
+        }
+    }
+}
+
+static void timeout_test(void) {
+    auto s = std::chrono::steady_clock::now();
+    std::thread t(func, 10);
+    t.join();
+    auto d = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - s);
+    std::cout << ((d.count() >= 10) ? "PASS" : "FAIL") << std::endl;
+}
+
+void stl_chrono_test(void)
+{
+    timeout_test();
+}
index 39f18bc..5ccae69 100644 (file)
@@ -23,6 +23,8 @@ int main(int argc,
     cx11_test();
     stl_thread_test();
 
+    stl_chrono_test();
+
     std::cout << "Tests done: SUCCESS" << std::endl;
     return 0;
 }