Merged the timing and measurement stuff together and cleaned it up a bit
authorKevin Klues <klueska@cs.berkeley.edu>
Fri, 22 May 2009 07:50:49 +0000 (00:50 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Fri, 22 May 2009 07:50:49 +0000 (00:50 -0700)
This involved moving some things around as well as renaiming some things.  I'm still not
happy with the name timer.h/c because these names imply fucntionality such as being able to
set an interrrupt based timer, etc.  But we can change this later if we want to.  I also made
some small modifications to finally get rid of all remnants of the "jos" tainted throughout
our code.  Additionally, there was some reorganization of who includes what header files so as
to be consistent with what is really needed by any individual file.

12 files changed:
GNUmakefile
conf/env.mk
inc/measure.h
inc/timer.h
inc/x86.h
kern/Makefrag
kern/apic.c
kern/env.h
lib/Makefrag
lib/timer.c
user/Makefrag
user/null.c

index c763ae6..ecb7492 100644 (file)
@@ -29,25 +29,25 @@ endif
 
 TOP = .
 
-# Cross-compiler jos toolchain
+# Cross-compiler ros toolchain
 #
 # This Makefile will automatically use the cross-compiler toolchain
-# installed as 'i386-jos-elf-*', if one exists.  If the host tools ('gcc',
+# installed as 'i386-ros-elf-*', if one exists.  If the host tools ('gcc',
 # 'objdump', and so forth) compile for a 32-bit x86 ELF target, that will
 # be detected as well.  If you have the right compiler toolchain installed
 # using a different name, set GCCPREFIX explicitly in conf/env.mk
 
 # try to infer the correct GCCPREFIX
 ifndef GCCPREFIX
-GCCPREFIX := $(shell if i386-jos-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; \
-       then echo 'i386-jos-elf-'; \
+GCCPREFIX := $(shell if i386-ros-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; \
+       then echo 'i386-ros-elf-'; \
        elif objdump -i 2>&1 | grep 'elf32-i386' >/dev/null 2>&1; \
        then echo ''; \
        else echo "***" 1>&2; \
        echo "*** Error: Couldn't find an i386-*-elf version of GCC/binutils." 1>&2; \
-       echo "*** Is the directory with i386-jos-elf-gcc in your PATH?" 1>&2; \
+       echo "*** Is the directory with i386-ros-elf-gcc in your PATH?" 1>&2; \
        echo "*** If your i386-*-elf toolchain is installed with a command" 1>&2; \
-       echo "*** prefix other than 'i386-jos-elf-', set your GCCPREFIX" 1>&2; \
+       echo "*** prefix other than 'i386-ros-elf-', set your GCCPREFIX" 1>&2; \
        echo "*** environment variable to that prefix and run 'make' again." 1>&2; \
        echo "*** To turn off this error, run 'gmake GCCPREFIX= ...'." 1>&2; \
        echo "***" 1>&2; exit 1; fi)
index 5a9815b..96ef79f 100644 (file)
@@ -17,7 +17,7 @@ HANDIN_EMAIL = 6.828-handin@pdos.lcs.mit.edu
 
 ##
 ## If your system-standard GNU toolchain is ELF-compatible, then comment
-## out the following line to use those tools (as opposed to the i386-jos-elf
+## out the following line to use those tools (as opposed to the i386-ros-elf
 ## tools that the 6.828 make system looks for by default).
 ##
 # GCCPREFIX=''
index 0aac3af..af228f9 100644 (file)
@@ -3,8 +3,37 @@
 
 #include <inc/types.h>
 #include <inc/stdio.h>
+#include <inc/timer.h>
 #include <inc/x86.h>
 
+/* Macro for printing out debug information about our measurement setup.
+ * If MEASURE_DEBUG is set to 1, debug info will be printed.  If set to 0
+ * no debug info will be printed.
+ */
+#define MEASURE_DEBUG  1
+#if MEASURE_DEBUG
+#ifndef ROS_KERNEL
+       #define mdebug(string, ...)     cprintf(string, ## __VA_ARGS__)
+#else
+       #define mdebug(string, ...)     printk(string, ## __VA_ARGS__)
+#endif
+#else
+       #define mdebug(string, ...)
+#endif
+
+#define __measure_runtime(__CODE_BLOCK__)                                      \
+({                                                                             \
+       uint64_t time = start_timing();                                            \
+       __CODE_BLOCK__;                                                            \
+       stop_timing(time);                                                         \
+})
+
+#define measure_func_runtime(func, ...)                                        \
+({                                                                             \
+       __measure_runtime(func(__VA_ARGS__));                                      \
+})
+
+
 #define measure_function(func, iters, name)                                    \
 ({                                                                             \
        uint64_t ticks;                                                            \
                               desc_name, i_iters, o_iters, name)
 
 #endif /* !ROS_INC_MEASURE_H */
+
+
+
index e40e308..363486c 100644 (file)
@@ -6,37 +6,56 @@
 #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;
 
-// vanilla variety
-uint64_t start_timing() __attribute__((noinline));
-uint64_t stop_timing(uint64_t val, uint64_t overhead) __attribute__((noinline));
-//void print_timerpool(
-//allocate if not null
-//starttiming
-//stoptiming
-#define FUNCBEGIN(tag)                                                 \
-static timer_t*  _timer_##tag = 0;                             \
-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 FUNCEND(tag)                                                                                                           \
-({                                                                                                                                                     \
-_timer_##tag->curr_run = stop_timing(_timer_##tag->curr_run, 0);                       \
-_timer_##tag->aggr_run += _timer_##tag->curr_run;                                                      \
+#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_TIMER_H */
 
index 23c768f..c57faba 100644 (file)
--- a/inc/x86.h
+++ b/inc/x86.h
@@ -66,6 +66,7 @@ static __inline uint32_t read_ebp(void) __attribute__((always_inline));
 static __inline uint32_t read_esp(void) __attribute__((always_inline));
 static __inline void cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp);
 static __inline uint64_t read_tsc(void) __attribute__((always_inline));
+static __inline uint64_t read_tsc_serialized(void) __attribute__((always_inline));
 static __inline uint64_t read_msr(uint32_t reg) __attribute__((always_inline));
 static __inline void write_msr(uint32_t reg, uint64_t val) __attribute__((always_inline));
 static __inline uint32_t read_mmreg32(uint32_t reg) __attribute__((always_inline));
@@ -312,9 +313,17 @@ cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *e
 static __inline uint64_t
 read_tsc(void)
 {
-        uint64_t tsc;
-        __asm __volatile("rdtsc" : "=A" (tsc));
-        return tsc;
+       uint64_t tsc;
+       __asm __volatile("rdtsc" : "=A" (tsc));
+       return tsc;
+}
+
+static __inline uint64_t 
+read_tsc_serialized(void)
+{
+    uint64_t tsc;
+    __asm __volatile("cpuid; rdtsc" : "=A" (tsc));
+       return tsc;
 }
 
 // Might need to mfence rdmsr.  supposedly wrmsr serializes, but not for x2APIC
index 74e8a3b..fb81423 100644 (file)
@@ -94,8 +94,8 @@ $(OBJDIR)/kern/bochs.img: $(OBJDIR)/kern/kernel $(OBJDIR)/boot/boot
 
 all: $(OBJDIR)/kern/bochs.img
 
-grub: $(OBJDIR)/jos-grub
+grub: $(OBJDIR)/ros-grub
 
-$(OBJDIR)/jos-grub: $(OBJDIR)/kern/kernel
+$(OBJDIR)/ros-grub: $(OBJDIR)/kern/kernel
        @echo + oc $@
        $(V)$(OBJCOPY) --adjust-vma=0x10000000 $^ $@
index 9c20f43..28b56e3 100644 (file)
@@ -11,7 +11,6 @@
 #include <kern/apic.h>
 
 system_timing_t system_timing = {0, 0, 0xffff, 0};
-uint64_t timing_overhead = 0;
 
 /*
  * Remaps the Programmable Interrupt Controller to use IRQs 32-47
@@ -93,39 +92,6 @@ uint32_t lapic_get_default_id(void)
        return (ebx & 0xFF000000) >> 24;
 }
 
-void train_timing() 
-{
-       uint16_t num_runs = 0;
-       uint16_t num_times_zero = 0;
-       uint64_t cum_overhead = 0;
-       
-       //Do this while 1/3 of all runs have not equaled 0 yet
-       do {
-               /* Run 100 times, counting how many out of that 100 
-                * were equal to 0, adjusting the global timing_overhead
-                * in the process.
-                */
-               for(int i=0; i<100; i++) {
-                       uint64_t time = start_timing();
-                       uint64_t diff = stop_timing(time, timing_overhead);
-                       
-                       /* 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; 
-                       cum_overhead += diff;
-
-                       //TODO: Consider using diff < 2  instead of 
-                       // strictly == 0 in case forcing a 0 restriction is too strict 
-                       if(diff == 0) num_times_zero++;
-                       num_runs++;
-                       timing_overhead = (cum_overhead/num_runs);
-                       printk("Timing Differences: %llu\n", diff);
-               }
-       } while(num_runs/num_times_zero > 2);
-}
-
 // timer init calibrates both tsc timer and lapic timer using PIT
 void timer_init(void){
        uint64_t tscval[2];
@@ -149,7 +115,6 @@ void timer_init(void){
        system_timing.bus_freq = (timercount[0] - timercount[1])*128;
                
        cprintf("Bus Frequency: %llu\n", system_timing.bus_freq);
-       train_timing();
 }
 
 void pit_set_timer(uint32_t divisor, uint32_t mode)
index d08613f..4104edf 100644 (file)
@@ -3,6 +3,7 @@
 #ifndef ROS_KERN_ENV_H
 #define ROS_KERN_ENV_H
 
+#include <inc/x86.h>
 #include <inc/env.h>
 
 #ifndef ROS_MULTIENV
index 3ec563d..1be2b36 100644 (file)
@@ -31,6 +31,6 @@ $(OBJDIR)/lib/%.o: lib/%.S
        @mkdir -p $(@D)
        $(V)$(NATIVECC) -nostdinc $(USER_CFLAGS) -c -o $@ $<
 
-$(OBJDIR)/lib/libjos.a: $(LIB_OBJFILES)
+$(OBJDIR)/lib/libros.a: $(LIB_OBJFILES)
        @echo + ar $@
        $(V)$(AR) r $@ $(LIB_OBJFILES)
index 6498e36..ccd3c73 100644 (file)
@@ -1,20 +1,66 @@
 #include <inc/x86.h>
 #include <inc/timer.h>
 
-// TODO: export timing_overhead to user level 
+/* 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;
 
-uint64_t read_tsc_serialized() __attribute__((noinline)) 
+/* 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))
 {
-       cpuid(0, 0, 0, 0, 0);
-       return read_tsc();
+    return read_tsc_serialized();
 }
 
-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))
 {
-       return read_tsc_serialized();
+    return (read_tsc_serialized() - val - timing_overhead);
 }
 
-uint64_t stop_timing(uint64_t val, uint64_t overhead) __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() 
 {
-       return (read_tsc_serialized() - val - overhead);
+       int i;
+       register uint64_t cum_overhead = 0;
+       register uint64_t time, diff;
+
+       //Do this 3 times outside the loop to warm up cpuid
+       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++) {
+               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; 
+               cum_overhead += diff;
+       }
+       timing_overhead = (cum_overhead/i);
 }
index 87f9763..c3da208 100644 (file)
@@ -5,8 +5,8 @@ $(OBJDIR)/user/%.o: user/%.c
        @mkdir -p $(@D)
        $(V)$(CC) -nostdinc $(USER_CFLAGS) -c -o $@ $<
 
-$(OBJDIR)/user/%: $(OBJDIR)/ivylib/libivyuser.a $(OBJDIR)/user/%.o $(OBJDIR)/lib/entry.o $(OBJDIR)/lib/libjos.a user/user.ld
+$(OBJDIR)/user/%: $(OBJDIR)/ivylib/libivyuser.a $(OBJDIR)/user/%.o $(OBJDIR)/lib/entry.o $(OBJDIR)/lib/libros.a user/user.ld
        @echo + ld $@
-       $(V)$(LD) -o $@ $(ULDFLAGS) $(LDFLAGS) -nostdlib $(OBJDIR)/lib/entry.o $@.o -L$(OBJDIR)/ivylib -livyuser -L$(OBJDIR)/lib -ljos $(GCC_LIB)
+       $(V)$(LD) -o $@ $(ULDFLAGS) $(LDFLAGS) -nostdlib $(OBJDIR)/lib/entry.o $@.o -L$(OBJDIR)/ivylib -livyuser -L$(OBJDIR)/lib -lros $(GCC_LIB)
        $(V)$(OBJDUMP) -S $@ > $@.asm
        $(V)$(NM) -n $@ > $@.sym
index 4b7587a..46e2499 100644 (file)
@@ -26,7 +26,7 @@ uint64_t total(uint64_t (COUNT(length) array)[], int length)
 
 void umain(void)
 {
-       FUNCBEGIN(tst);
+       TAGGED_TIMING_BEGIN(tst);
        async_desc_t *desc1, *desc2;
        async_rsp_t rsp1, rsp2;
        cache_buster_async(&desc1, 20, 0xdeadbeef);
@@ -42,7 +42,7 @@ void umain(void)
        // making calls beyond the ring size and won't wait on any extra calls.
        measure_async_call(null_async(&desc), desc, 100, 100, "Async Null");
        
-       FUNCEND(tst);
+    TAGGED_TIMING_END(tst);
        // Spin to make sure we don't have any resources deallocated before done
        while(1);
 }