Reworks timing infrastructure (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 14 Mar 2013 23:31:18 +0000 (16:31 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 14 Mar 2013 23:39:10 +0000 (16:39 -0700)
All of the old timing training stuff is moved out of kernel headers, and
is more in line with the recent TSC knowledge.  People can still use
stop_ and start_timing as convenience wrappers around
read_tsc_serialized().

Remove /ros/time.h from your cross compiler's kernel headers.  For
instance, for x86, rm YOUR_XCC_LOC/i686-ros/sys-include/ros/time.h.

kern/arch/i686/apic.h
kern/arch/riscv/time.h
kern/arch/sparc/time.h
kern/include/ros/time.h [deleted file]
kern/include/time.h
kern/src/init.c
kern/src/manager.c
kern/src/monitor.c
kern/src/syscall.c
kern/src/time.c

index 7194427..943bd42 100644 (file)
 typedef struct system_timing {
        uint64_t tsc_freq;
        uint64_t bus_freq;
+       uint64_t timing_overhead;
        uint16_t pit_divisor;
        uint8_t pit_mode;
 } system_timing_t;
index d4ec70d..eee274f 100644 (file)
@@ -7,6 +7,7 @@
 
 typedef struct system_timing {
        uint64_t tsc_freq;
+       uint64_t timing_overhead;
 } system_timing_t;
 
 extern system_timing_t system_timing;
index 8d3bef1..758a4b0 100644 (file)
@@ -9,6 +9,7 @@
 
 typedef struct system_timing {
        uint64_t tsc_freq;
+       uint64_t timing_overhead;
 } system_timing_t;
 
 extern system_timing_t system_timing;
diff --git a/kern/include/ros/time.h b/kern/include/ros/time.h
deleted file mode 100644 (file)
index 56f755b..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef ROS_INC_TIME_H
-#define ROS_INC_TIME_H
-
-#include <pool.h>
-#include <string.h>
-
-#define TIMER_TAG_SIZE 20
-#define MAX_TIMERS 20
-
-/* start_timing()
- * This function simply reads the tsc in a serialized fashion and returns its
- * value.  It is pusposefully annotated with a noinline so that the overheads 
- * assocaited with calling it are as deterministic as possible.
- */
-uint64_t start_timing() __attribute__((noinline));
-
-/* stop_timing()
- * This function reads the tsc in a serialized fashion and subtracts the value
- * it reads from the value passed in as a paramter in order to determine the 
- * difference between the two values.  A global timing_overhead value is also 
- * subtracted to compensate for the overhead associated with calling both
- * start and stop timing and returning their values.
- * This function is purposefully annotated with a noinline so that 
- * the overheads assocaited with calling it are as deterministic as possible.
- */
-uint64_t stop_timing(uint64_t val) __attribute__((noinline));
-
-/* train_timing()
- * This function is intended to train the timing_overhead variable for use by
- * stop_timing().  It runs through a loop calling start/stop and averaging the 
- * overhead of calling them without doing any useful work in between.
- */
-void train_timing();
-
-/* timer_t
- * This struct is used to keep track of counter values as they are spread
- * throughput code and timing measurements are made calling TAGGED_TIMING_BEGIN
- * and TAGGED_TIMING_END
- */
-typedef struct Timer{
-       uint64_t curr_run;
-       uint64_t aggr_run;
-       char label[TIMER_TAG_SIZE];
-} timer_t;
-
-//TODO: ifdef measurement? error check when pool runs low
-#define TAGGED_TIMING_BEGIN(tag)                    \
-       static timer_t* _timer_##tag = NULL;            \
-       if (_timer_##tag == NULL) {                     \
-               _timer_##tag = POOL_GET(&timer_pool);       \
-               strcpy((_timer_##tag->label), #tag);        \
-               _timer_##tag->aggr_run = 0;                 \
-       }                                               \
-       _timer_##tag->curr_run = start_timing();
-#define TAGGED_TIMING_END(tag)                                              \
-({                                                                          \
-       _timer_##tag->curr_run = stop_timing(_timer_##tag->curr_run);           \
-       _timer_##tag->aggr_run += _timer_##tag->curr_run;                       \
-})
-
-#endif /* ROS_INC_TIME_H */
index 111dc91..c3292ae 100644 (file)
@@ -17,6 +17,7 @@ struct itimerspec {
   struct timespec  it_value;     /* Timer expiration */
 };
 
+void train_timing();
 void udelay(uint64_t usec);
 uint64_t tsc2sec(uint64_t tsc_time);
 uint64_t tsc2msec(uint64_t tsc_time);
@@ -27,4 +28,61 @@ uint64_t msec2tsc(uint64_t msec);
 uint64_t usec2tsc(uint64_t usec);
 uint64_t nsec2tsc(uint64_t nsec);
 
+/* Just takes a time measurement.  Meant to be paired with stop_timing.  Use
+ * this if you don't want to muck with overheads or subtraction. */
+static inline __attribute__((always_inline))
+uint64_t start_timing(void)
+{
+    return read_tsc_serialized();
+}
+
+/* Takes a time measurement and subtracts the start time and timing overhead,
+ * to return the detected elapsed time.  Use this if you don't want to muck
+ * with overheads or subtraction. */
+static inline __attribute__((always_inline))
+uint64_t stop_timing(uint64_t start_time)
+{
+    uint64_t diff = read_tsc_serialized();
+    diff -= start_time;
+    diff -= system_timing.timing_overhead;
+       if ((int64_t) diff < 0) {
+               return 1;
+       }
+       return diff;
+}
+
+/* Ancient measurement crap below.  TODO: use or lose it */
+
+#if 0
+#include <pool.h>
+#include <string.h>
+
+#define TIMER_TAG_SIZE 20
+#define MAX_TIMERS 20
+/* timer_t
+ * This struct is used to keep track of counter values as they are spread
+ * throughput code and timing measurements are made calling TAGGED_TIMING_BEGIN
+ * and TAGGED_TIMING_END
+ */
+typedef struct Timer{
+       uint64_t curr_run;
+       uint64_t aggr_run;
+       char label[TIMER_TAG_SIZE];
+} timer_t;
+
+#define TAGGED_TIMING_BEGIN(tag)                    \
+       static timer_t* _timer_##tag = NULL;            \
+       if (_timer_##tag == NULL) {                     \
+               _timer_##tag = POOL_GET(&timer_pool);       \
+               strcpy((_timer_##tag->label), #tag);        \
+               _timer_##tag->aggr_run = 0;                 \
+       }                                               \
+       _timer_##tag->curr_run = start_timing();
+#define TAGGED_TIMING_END(tag)                                              \
+({                                                                          \
+       _timer_##tag->curr_run = stop_timing(_timer_##tag->curr_run);           \
+       _timer_##tag->aggr_run += _timer_##tag->curr_run;                       \
+})
+
+#endif
 #endif /* ROS_KERN_TIME_H */
index bd45cf1..dd1a027 100644 (file)
@@ -8,13 +8,13 @@
 #error "Yeah, it's not possible to build ROS with BSD on Core 0, sorry......"
 #else
 
-#include <ros/time.h>
 #include <arch/arch.h>
 #include <arch/console.h>
 #include <multiboot.h>
 #include <stab.h>
 #include <smp.h>
 
+#include <time.h>
 #include <atomic.h>
 #include <stdio.h>
 #include <string.h>
index 422a77f..dd69e74 100644 (file)
@@ -31,7 +31,7 @@
 #include <string.h>
 #include <pmap.h>
 #include <arch/console.h>
-#include <ros/time.h>
+#include <time.h>
 #include <ros/arch/membar.h>
 
 /*
index 2102129..54d0b51 100644 (file)
@@ -27,8 +27,8 @@
 #include <elf.h>
 #include <event.h>
 #include <trap.h>
+#include <time.h>
 
-#include <ros/time.h>
 #include <ros/memlayout.h>
 #include <ros/event.h>
 
index 4cdc267..830de0a 100644 (file)
@@ -9,7 +9,7 @@
 #include <arch/arch.h>
 #include <arch/mmu.h>
 #include <arch/console.h>
-#include <ros/time.h>
+#include <time.h>
 #include <error.h>
 
 #include <elf.h>
index 1815258..9364ca0 100644 (file)
@@ -1,76 +1,44 @@
 #include <arch/arch.h>
-#include <ros/time.h>
+#include <time.h>
 #include <stdio.h>
 #include <schedule.h>
 #include <multiboot.h>
 #include <pmap.h>
 #include <smp.h>
 
-/* timing_overhead
- * Any user space process that links to this file will get its own copy.  
- * This means it will manually have to call tune_timing itself before it 
- * makes its first measurement.
- */
-uint64_t timing_overhead = 0;
-
-/* start_timing()
- * This function simply reads the tsc in a serialized fashion and returns its
- * value.  It is pusposefully annotated with a noinline so that the overheads 
- * assocaited with calling it are as deterministic as possible.
- */
-uint64_t start_timing()
-{
-    return read_tsc_serialized();
-}
-
-/* stop_timing()
- * This function reads the tsc in a serialized fashion and subtracts the value
- * it reads from the value passed in as a paramter in order to determine the 
- * difference between the two values.  A global timing_overhead value is also 
- * subtracted to compensate for the overhead associated with calling both
- * start and stop timing and returning their values.
- * This function is purposefully annotated with a noinline so that 
- * the overheads assocaited with calling it are as deterministic as possible.
- */
-uint64_t stop_timing(uint64_t val)
-{
-    uint64_t diff = (read_tsc_serialized() - val - timing_overhead);
-       if ((int64_t) diff < 0) 
-               return 1;
-       return diff;
-}
-
-/* train_timing()
- * This function is intended to train the timing_overhead variable for use by
- * stop_timing().  It runs through a loop calling start/stop and averaging the 
- * overhead of calling them without doing any useful work in between.
- */
+/* Determines the overhead of tsc timing.  Note the start/stop calls are
+ * inlined, so we're trying to determine the lowest amount of overhead
+ * attainable by using the TSC (or whatever timing source).
+ *
+ * For more detailed TSC measurements, use test_rdtsc() in k/a/i/rdtsc_test.c */
 void train_timing() 
 {
-       int i;
-       // set training overhead to be something large
-       register uint64_t training_overhead = 0xffffffff;
-       register uint64_t time, diff;
+       uint64_t min_overhead = UINT64_MAX;
+       uint64_t max_overhead = 0;
+       uint64_t time, diff;
+       int8_t irq_state = 0;
 
-       //Do this 3 times outside the loop to warm up cpuid
+       /* Reset this, in case we run it again.  The use of start/stop to determine
+        * the overhead relies on timing_overhead being 0. */
+       system_timing.timing_overhead = 0;
+       /* timing might use cpuid, in which case we warm it up to avoid some extra
+        * variance */
        time = start_timing();
        diff = stop_timing(time);
        time = start_timing();
        diff = stop_timing(time);
        time = start_timing();
        diff = stop_timing(time);
-       for(i=0; i<10000; i++) {
+       disable_irqsave(&irq_state);
+       for (int i = 0; i < 10000; i++) {
                time = start_timing();
                diff = stop_timing(time);
-               
-               /* In case diff was negative, I want to add its absolute value
-                * to the cumulative error, otherwise, just diff itself
-                */
-               if((int64_t)diff < 0)
-                       diff = (uint64_t)(~0) - diff + 1;
-               training_overhead = MIN(training_overhead, diff);
+               min_overhead = MIN(min_overhead, diff);
+               max_overhead = MAX(max_overhead, diff);
        }
-       timing_overhead = training_overhead;
+       enable_irqsave(&irq_state);
+       system_timing.timing_overhead = min_overhead;
+       printk("TSC overhead (Min: %llu, Max: %llu)\n", min_overhead, max_overhead);
 }
 
 /* Convenience wrapper called when a core's timer interrupt goes off.  Not to be