Helpers for converting time to and from tsc ticks
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 4 Aug 2011 06:53:14 +0000 (23:53 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:06 +0000 (17:36 -0700)
Don't refer to system_timing.tsc_freq directly.  The helpers handle
things such as wraparound/overflow, which was definitely a problem when
dealing with nsec.

Incidentally, wraparound/overflow is possibly why Dave had those
"impossible" numbers back in the day.

kern/arch/i686/apic.c
kern/arch/i686/kdebug.c
kern/include/ros/common.h
kern/include/time.h
kern/src/alarm.c
kern/src/monitor.c
kern/src/process.c
kern/src/syscall.c
kern/src/time.c

index 7f9fcb0..c220f17 100644 (file)
@@ -13,7 +13,7 @@
 #include <arch/x86.h>
 #include <arch/arch.h>
 #include <arch/apic.h>
-#include <ros/time.h>
+#include <time.h>
 #include <assert.h>
 #include <stdio.h>
 
@@ -168,7 +168,7 @@ void udelay(uint64_t usec)
                uint64_t start, end, now;
 
                start = read_tsc();
-        end = start + (system_timing.tsc_freq * usec) / 1000000;
+        end = start + usec2tsc(usec);
         //cprintf("start %llu, end %llu\n", start, end);
                if (end == 0) cprintf("This is terribly wrong \n");
                do {
index 44e3c42..a3c41ad 100644 (file)
@@ -273,7 +273,18 @@ void *debug_get_fn_addr(char *fn_name)
 
        // String table validity checks (from above)
        {
+               /* this tripped a couple times, probably erroneously.  Will try to
+                * catch. */
                int stabstrsz = stabstr_end - stabstr;
+               if (stabstr_end <= stabstr) {
+                       printk("stabstr_end %08p, stabstr %08p\n", stabstr_end, stabstr);
+                       warn("Crap, possible corrupt stabs.");
+               }
+               if (stabstr[stabstrsz-1] != 0) {
+                       printk("stabstr %08p, stabstr[last] %08p\n", stabstr,
+                              stabstr[stabstrsz-1]);
+                       warn("Crap, possible corrupt stabs.");
+               }
                if (stabstr_end <= stabstr || stabstr[stabstrsz-1] != 0)
                        return 0;
        }
index 3e551cb..b286202 100644 (file)
@@ -97,6 +97,14 @@ static inline uintptr_t ROUNDUPPWR2(uintptr_t value)
        return 1 << LOG2_UP(value);
 }
 
+/* We wraparound if UINT_MAX < a * b, which is also UINT_MAX / a < b. */
+static inline bool mult_will_overflow_u64(uint64_t a, uint64_t b)
+{
+       if (!a)
+               return FALSE;
+       return (uint64_t)(-1) / a < b;
+}
+
 // Return the offset of 'member' relative to the beginning of a struct type
 #ifndef offsetof
 #define offsetof(type, member)  ((size_t) (&((type*)0)->member))
index 3507e44..111dc91 100644 (file)
@@ -18,5 +18,13 @@ struct itimerspec {
 };
 
 void udelay(uint64_t usec);
+uint64_t tsc2sec(uint64_t tsc_time);
+uint64_t tsc2msec(uint64_t tsc_time);
+uint64_t tsc2usec(uint64_t tsc_time);
+uint64_t tsc2nsec(uint64_t tsc_time);
+uint64_t sec2tsc(uint64_t sec);
+uint64_t msec2tsc(uint64_t msec);
+uint64_t usec2tsc(uint64_t usec);
+uint64_t nsec2tsc(uint64_t nsec);
 
 #endif /* ROS_KERN_TIME_H */
index fcfc828..6f1fb1b 100644 (file)
@@ -68,7 +68,7 @@ void set_awaiter_rel(struct alarm_waiter *waiter, uint64_t usleep)
 {
        uint64_t now, then;
        now = read_tsc();
-       then = now + usleep * (system_timing.tsc_freq / 1000000);
+       then = now + usec2tsc(usleep);
        /* This will go off if we wrap-around the TSC.  It'll never happen for legit
         * values, but this might catch some bugs with large usleeps. */
        assert(now < then);
@@ -257,7 +257,7 @@ void set_pcpu_alarm_interrupt(uint64_t time, struct timer_chain *tchain)
                if (time <= now)
                        rel_usec = 1;
                else
-                       rel_usec = (time - now) / (system_timing.tsc_freq / 1000000);
+                       rel_usec = tsc2usec(time - now);
                rel_usec = MAX(rel_usec, 1);
                printd("Setting alarm for %llu, it is now %llu, rel_time %llu "
                       "tchain %08p\n", time, now, rel_usec, pcpui_tchain);
index 8c5a7b7..496423b 100644 (file)
@@ -624,8 +624,7 @@ int mon_measure(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
                return 1;
        }
        printk("[Tired Giraffe Accent] Took %llu usec (%llu nsec) to finish.\n",
-              diff * 1000000 / system_timing.tsc_freq,
-              diff * 1000000000 / system_timing.tsc_freq);
+              tsc2usec(diff), tsc2nsec(diff));
        return 0;
 }
 
index e2bccf8..fd7d801 100644 (file)
@@ -965,7 +965,7 @@ bool __proc_preempt_all(struct proc *p)
 void proc_preempt_core(struct proc *p, uint32_t pcoreid, uint64_t usec)
 {
        bool self_ipi_pending = FALSE;
-       uint64_t warn_time = read_tsc() + usec * 1000000 / system_timing.tsc_freq;
+       uint64_t warn_time = read_tsc() + usec2tsc(usec);
 
        /* DYING could be okay */
        if (p->state != PROC_RUNNING_M) {
@@ -996,7 +996,7 @@ void proc_preempt_core(struct proc *p, uint32_t pcoreid, uint64_t usec)
 void proc_preempt_all(struct proc *p, uint64_t usec)
 {
        bool self_ipi_pending = FALSE;
-       uint64_t warn_time = read_tsc() + usec * 1000000 / system_timing.tsc_freq;
+       uint64_t warn_time = read_tsc() + usec2tsc(usec);
 
        spin_lock(&p->proc_lock);
        /* DYING could be okay */
index 6d1b424..8bfb0a4 100644 (file)
@@ -1264,6 +1264,7 @@ intreg_t sys_gettimeofday(struct proc *p, int *buf)
        spin_unlock(&gtod_lock);
 
        long long dt = read_tsc();
+       /* TODO: This probably wants its own function, using a struct timeval */
        int kbuf[2] = {t0+dt/system_timing.tsc_freq,
            (dt%system_timing.tsc_freq)*1000000/system_timing.tsc_freq};
 
index 40bf131..1815258 100644 (file)
@@ -1,10 +1,3 @@
-
-// zra: why is this in the kernel?
-
-#ifdef __SHARC__
-#pragma nosharc
-#endif
-
 #include <arch/arch.h>
 #include <ros/time.h>
 #include <stdio.h>
@@ -88,3 +81,72 @@ void timer_interrupt(struct trapframe *tf, void *data)
        struct timer_chain *pcpui_tchain = &per_cpu_info[core_id()].tchain;
        trigger_tchain(pcpui_tchain);
 }
+
+/* We can overflow/wraparound when we multiply up, but we have to divide last,
+ * or else we lose precision.  If we're too big and will overflow, we'll
+ * sacrifice precision for correctness, and degrade to the next lower level
+ * (losing 3 digits worth).  The recursive case shouldn't overflow, since it
+ * called something that scaled down the tsc_time by more than 1000. */
+uint64_t tsc2sec(uint64_t tsc_time)
+{
+       return tsc_time / system_timing.tsc_freq;
+}
+
+uint64_t tsc2msec(uint64_t tsc_time)
+{
+       if (mult_will_overflow_u64(tsc_time, 1000))
+               return tsc2sec(tsc_time) * 1000;
+       else 
+               return (tsc_time * 1000) / system_timing.tsc_freq;
+}
+
+uint64_t tsc2usec(uint64_t tsc_time)
+{
+       if (mult_will_overflow_u64(tsc_time, 1000000))
+               return tsc2msec(tsc_time) * 1000;
+       else
+               return (tsc_time * 1000000) / system_timing.tsc_freq;
+}
+
+uint64_t tsc2nsec(uint64_t tsc_time)
+{
+       if (mult_will_overflow_u64(tsc_time, 1000000000))
+               return tsc2usec(tsc_time) * 1000;
+       else
+               return (tsc_time * 1000000000) / system_timing.tsc_freq;
+}
+
+uint64_t sec2tsc(uint64_t sec)
+{
+       if (mult_will_overflow_u64(sec, system_timing.tsc_freq)) {
+               /* in this case, we simply can't express the number of ticks */
+               warn("Wraparound in sec2tsc(), rounding up");
+               return (uint64_t)(-1);
+       } else {
+               return sec * system_timing.tsc_freq;
+       }
+}
+
+uint64_t msec2tsc(uint64_t msec)
+{
+       if (mult_will_overflow_u64(msec, system_timing.tsc_freq))
+               return sec2tsc(msec / 1000);
+       else
+               return (msec * system_timing.tsc_freq) / 1000;
+}
+
+uint64_t usec2tsc(uint64_t usec)
+{
+       if (mult_will_overflow_u64(usec, system_timing.tsc_freq))
+               return msec2tsc(usec / 1000);
+       else
+               return (usec * system_timing.tsc_freq) / 1000000;
+}
+
+uint64_t nsec2tsc(uint64_t nsec)
+{
+       if (mult_will_overflow_u64(nsec, system_timing.tsc_freq))
+               return usec2tsc(nsec / 1000);
+       else
+               return (nsec * system_timing.tsc_freq) / 1000000000;
+}