Export epoch time via proc_global_info (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 22 Sep 2016 18:15:50 +0000 (14:15 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 22 Sep 2016 18:44:07 +0000 (14:44 -0400)
The kernel was internally maintaining basically the same structure that
benchutil/alarm was maintaining: a mapping from epoch time to TSC ticks.
Now that info is exported to userspace.

This allows us to implement gettimeofday() and clock_gettime() in
userspace, which means we can remove SYS_gettimeofday.

Rebuild glibc.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/include/ros/bits/syscall.h
kern/include/ros/procinfo.h
kern/src/syscall.c
kern/src/time.c
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/Versions
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/clock_gettime.c
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/gettimeofday.c
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/parlib-compat.c
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/time.c
user/benchutil/alarm.c
user/parlib/include/parlib/timing.h

index 8cae072..764fbf9 100644 (file)
@@ -79,7 +79,7 @@
 #define SYS_tap_fds                            126
 
 /* Misc syscalls */
 #define SYS_tap_fds                            126
 
 /* Misc syscalls */
-#define SYS_gettimeofday               140
+/* was #define SYS_gettimeofday        140 */
 #define SYS_tcgetattr                  141
 #define SYS_tcsetattr                  142
 #define SYS_setuid                             143
 #define SYS_tcgetattr                  141
 #define SYS_tcsetattr                  142
 #define SYS_setuid                             143
index d5fe58d..e5a3641 100644 (file)
@@ -71,6 +71,8 @@ struct proc_global_info {
        uint64_t tsc_freq;
        uint64_t tsc_overhead;
        uint64_t bus_freq;
        uint64_t tsc_freq;
        uint64_t tsc_overhead;
        uint64_t bus_freq;
+       uint64_t walltime_ns_last;
+       uint64_t tsc_cycles_last;
 } __attribute__((aligned(PGSIZE)));
 #define PROCGINFO_NUM_PAGES  (sizeof(struct proc_global_info) / PGSIZE)
 
 } __attribute__((aligned(PGSIZE)));
 #define PROCGINFO_NUM_PAGES  (sizeof(struct proc_global_info) / PGSIZE)
 
index 9d82597..300010a 100644 (file)
@@ -2078,13 +2078,6 @@ intreg_t sys_rmdir(struct proc *p, const char *path, size_t path_l)
        return retval;
 }
 
        return retval;
 }
 
-intreg_t sys_gettimeofday(struct proc *p, int *buf)
-{
-       struct timeval tv = nsec2timeval(epoch_nsec());
-
-       return memcpy_to_user_errno(p, buf, &tv, sizeof(tv));
-}
-
 intreg_t sys_tcgetattr(struct proc *p, int fd, void *termios_p)
 {
        int retval = 0;
 intreg_t sys_tcgetattr(struct proc *p, int fd, void *termios_p)
 {
        int retval = 0;
@@ -2612,7 +2605,6 @@ const struct sys_table_entry syscall_table[] = {
        [SYS_getcwd] = {(syscall_t)sys_getcwd, "getcwd"},
        [SYS_mkdir] = {(syscall_t)sys_mkdir, "mkdir"},
        [SYS_rmdir] = {(syscall_t)sys_rmdir, "rmdir"},
        [SYS_getcwd] = {(syscall_t)sys_getcwd, "getcwd"},
        [SYS_mkdir] = {(syscall_t)sys_mkdir, "mkdir"},
        [SYS_rmdir] = {(syscall_t)sys_rmdir, "rmdir"},
-       [SYS_gettimeofday] = {(syscall_t)sys_gettimeofday, "gettime"},
        [SYS_tcgetattr] = {(syscall_t)sys_tcgetattr, "tcgetattr"},
        [SYS_tcsetattr] = {(syscall_t)sys_tcsetattr, "tcsetattr"},
        [SYS_setuid] = {(syscall_t)sys_setuid, "setuid"},
        [SYS_tcgetattr] = {(syscall_t)sys_tcgetattr, "tcgetattr"},
        [SYS_tcsetattr] = {(syscall_t)sys_tcsetattr, "tcsetattr"},
        [SYS_setuid] = {(syscall_t)sys_setuid, "setuid"},
index 7538cba..2515803 100644 (file)
@@ -104,33 +104,21 @@ uint64_t nsec2tsc(uint64_t nsec)
 }
 
 /*
 }
 
 /*
- * Rudimentary timekeeping implementation.
- *
- * Nothing here yet apart from the base walltime and TSC cycle values
- * at system init time.
- */
-static struct {
-       uint64_t        walltime_ns_last;
-       uint64_t        tsc_cycles_last;
-} timekeeping;
-
-
-/*
  * Return nanoseconds since the UNIX epoch, 1st January, 1970.
  */
 uint64_t epoch_nsec(void)
 {
  * Return nanoseconds since the UNIX epoch, 1st January, 1970.
  */
 uint64_t epoch_nsec(void)
 {
-       uint64_t cycles = read_tsc() - timekeeping.tsc_cycles_last;
+       uint64_t cycles = read_tsc() - __proc_global_info.tsc_cycles_last;
 
 
-       return timekeeping.walltime_ns_last + tsc2nsec(cycles);
+       return __proc_global_info.walltime_ns_last + tsc2nsec(cycles);
 }
 
 void time_init(void)
 {
        train_timing();
 
 }
 
 void time_init(void)
 {
        train_timing();
 
-       timekeeping.walltime_ns_last = read_persistent_clock();
-       timekeeping.tsc_cycles_last  = read_tsc();
+       __proc_global_info.walltime_ns_last = read_persistent_clock();
+       __proc_global_info.tsc_cycles_last  = read_tsc();
 
        cycles_to_nsec_init(__proc_global_info.tsc_freq);
        nsec_to_cycles_init(__proc_global_info.tsc_freq);
 
        cycles_to_nsec_init(__proc_global_info.tsc_freq);
        nsec_to_cycles_init(__proc_global_info.tsc_freq);
index 055c70f..2bee28d 100644 (file)
@@ -75,6 +75,9 @@ libc {
     timerfd_gettime;
     add_timespecs;
     subtract_timespecs;
     timerfd_gettime;
     add_timespecs;
     subtract_timespecs;
+    epoch_nsec;
+    epoch_nsec_to_tsc;
+    tsc_to_epoch_nsec;
 
     # Weak symbols in parlib-compat.c
     __vcoreid;
 
     # Weak symbols in parlib-compat.c
     __vcoreid;
index ee246eb..2846314 100644 (file)
@@ -6,21 +6,18 @@
  *
  * TODO:
  * - consider supporting more clocks.
  *
  * TODO:
  * - consider supporting more clocks.
- * - read the TSC and add the offset in userspace (part of a generic overhaul of
- *   the time library functions).
  */
 
 #include <time.h>
 #include <sys/time.h>
  */
 
 #include <time.h>
 #include <sys/time.h>
+#include <parlib/timing.h>
 
 int __clock_gettime(clockid_t clk_id, struct timespec *tp)
 {
 
 int __clock_gettime(clockid_t clk_id, struct timespec *tp)
 {
-       struct timeval tv;
+       uint64_t epoch_ns = epoch_nsec();
 
 
-       if (gettimeofday(&tv, 0))
-               return -1;
-       tp->tv_sec = tv.tv_sec;
-       tp->tv_nsec = tv.tv_usec * 1000;
+       tp->tv_sec = epoch_ns / 1000000000;
+       tp->tv_nsec = epoch_ns % 1000000000;
        return 0;
 }
 weak_alias(__clock_gettime, clock_gettime)
        return 0;
 }
 weak_alias(__clock_gettime, clock_gettime)
index b454c00..476098f 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <errno.h>
 #include <sys/time.h>
 
 #include <errno.h>
 #include <sys/time.h>
-#include <ros/syscall.h>
+#include <parlib/timing.h>
 
 #undef __gettimeofday
 
 
 #undef __gettimeofday
 
@@ -30,7 +30,11 @@ __gettimeofday (tv, tz)
      struct timeval *tv;
      struct timezone *tz;
 {
      struct timeval *tv;
      struct timezone *tz;
 {
-  return ros_syscall(SYS_gettimeofday, tv, 0, 0, 0, 0, 0);
+       uint64_t epoch_ns = epoch_nsec();
+
+       tv->tv_sec = epoch_ns / 1000000000;
+       tv->tv_usec = (epoch_ns % 1000000000) / 1000;
+       return 0;
 }
 libc_hidden_def (__gettimeofday)
 weak_alias (__gettimeofday, gettimeofday)
 }
 libc_hidden_def (__gettimeofday)
 weak_alias (__gettimeofday, gettimeofday)
index be133fd..10b3c31 100644 (file)
@@ -9,6 +9,7 @@
 #include <parlib/stdio.h>
 #include <parlib/assert.h>
 #include <parlib/spinlock.h>
 #include <parlib/stdio.h>
 #include <parlib/assert.h>
 #include <parlib/spinlock.h>
+#include <parlib/timing.h>
 #include <stdbool.h>
 
 /* Here we define functions and variables that are really defined in parlib, but
 #include <stdbool.h>
 
 /* Here we define functions and variables that are really defined in parlib, but
index 3aa0248..8abf8ac 100644 (file)
@@ -1,6 +1,8 @@
 #include <time.h>
 #include <stdbool.h>
 #include <sys/time.h>
 #include <time.h>
 #include <stdbool.h>
 #include <sys/time.h>
+#include <parlib/timing.h>
+#include <ros/procinfo.h>
 
 time_t
 time(time_t* p)
 
 time_t
 time(time_t* p)
@@ -43,3 +45,25 @@ void subtract_timespecs(struct timespec *diff, const struct timespec *minuend,
        diff->tv_nsec = borrow_amt + minuend->tv_nsec - subtrahend->tv_nsec;
        diff->tv_sec = minuend->tv_sec - subtrahend->tv_sec - (borrow_amt ? 1 : 0);
 }
        diff->tv_nsec = borrow_amt + minuend->tv_nsec - subtrahend->tv_nsec;
        diff->tv_sec = minuend->tv_sec - subtrahend->tv_sec - (borrow_amt ? 1 : 0);
 }
+
+/* Declared in parlib/timing.h */
+
+uint64_t epoch_nsec_to_tsc(uint64_t epoch_ns)
+{
+       return nsec2tsc(epoch_ns - __proc_global_info.walltime_ns_last) +
+              __proc_global_info.tsc_cycles_last;
+}
+
+uint64_t tsc_to_epoch_nsec(uint64_t tsc)
+{
+       return tsc2nsec(tsc - __proc_global_info.tsc_cycles_last) +
+              __proc_global_info.walltime_ns_last;
+}
+
+uint64_t epoch_nsec(void)
+{
+       /* in case we get called before the constructor.  it's a little racy, but
+        * this all happens when we're single threaded.  for those curious, this
+        * seems to happen a lot due to the proliferation of gettimeofday calls. */
+       return tsc_to_epoch_nsec(read_tsc());
+}
index 17bf7b4..0d5bc59 100644 (file)
@@ -121,25 +121,6 @@ static void handle_user_alarm(struct event_msg *ev_msg, unsigned int ev_type,
 /* One chain to rule them all. */
 struct timer_chain global_tchain;
 
 /* One chain to rule them all. */
 struct timer_chain global_tchain;
 
-/* Unix time offsets so we can allow people to specify an absolute unix time to
- * an alarm, rather than an absolute time in terms of raw tsc ticks.  This
- * value is initialized when the timer service is started. */
-static struct {
-       uint64_t tod; // The initial time of day in microseconds
-       uint64_t tsc; // The initial value of the tsc counter
-} unixtime_offsets;
-
-static inline void init_unixtime_offsets()
-{
-       struct timeval tv;
-
-       /* There's a bit of slack here, where the TSC time is taken after the
-        * corresponding gettimeofday value. */
-       gettimeofday(&tv, NULL);
-       unixtime_offsets.tsc = read_tsc();
-       unixtime_offsets.tod = tv.tv_sec*1000000 + tv.tv_usec;
-}
-
 /* Helper, resets the earliest/latest times, based on the elements of the list.
  * If the list is empty, we set the times to be the 12345 poison time.  Since
  * the list is empty, the alarm shouldn't be going off. */
 /* Helper, resets the earliest/latest times, based on the elements of the list.
  * If the list is empty, we set the times to be the 12345 poison time.  Since
  * the list is empty, the alarm shouldn't be going off. */
@@ -160,9 +141,6 @@ static void __attribute__((constructor)) init_alarm_service(void)
        int ctlfd, timerfd, alarmid;
        struct event_queue *ev_q;
 
        int ctlfd, timerfd, alarmid;
        struct event_queue *ev_q;
 
-       /* Initialize the unixtime_offsets */
-       init_unixtime_offsets();
-
        /* Sets up timer chain (only one chain per process) */
        spin_pdr_init(&global_tchain.lock);
        TAILQ_INIT(&global_tchain.waiters);
        /* Sets up timer chain (only one chain per process) */
        spin_pdr_init(&global_tchain.lock);
        TAILQ_INIT(&global_tchain.waiters);
@@ -218,10 +196,7 @@ static void __set_awaiter_abs(struct alarm_waiter *waiter, uint64_t abs_time)
  * to go off. */
 void set_awaiter_abs_unix(struct alarm_waiter *waiter, uint64_t abs_usec)
 {
  * to go off. */
 void set_awaiter_abs_unix(struct alarm_waiter *waiter, uint64_t abs_usec)
 {
-       uint64_t abs_tsc;
-
-       abs_tsc = usec2tsc(abs_usec - unixtime_offsets.tod) + unixtime_offsets.tsc;
-       __set_awaiter_abs(waiter, abs_tsc);
+       __set_awaiter_abs(waiter, epoch_nsec_to_tsc(abs_usec * 1000));
 }
 
 /* Give this a relative time from now, in microseconds.  This might be easier to
 }
 
 /* Give this a relative time from now, in microseconds.  This might be easier to
index eb15a8a..a696f59 100644 (file)
@@ -21,4 +21,8 @@ uint64_t usec2tsc(uint64_t usec);
 uint64_t nsec2tsc(uint64_t nsec);
 uint64_t nsec(void);
 
 uint64_t nsec2tsc(uint64_t nsec);
 uint64_t nsec(void);
 
+uint64_t epoch_nsec_to_tsc(uint64_t epoch_ns);
+uint64_t tsc_to_epoch_nsec(uint64_t tsc);
+uint64_t epoch_nsec(void);
+
 __END_DECLS
 __END_DECLS