]> Zhao Yanbai Git Server - minix.git/commitdiff
Servers request TSC freq from kernel rather than each one measuring it individually
authorErik van der Kouwe <erik@minix3.org>
Tue, 11 Jan 2011 11:03:37 +0000 (11:03 +0000)
committerErik van der Kouwe <erik@minix3.org>
Tue, 11 Jan 2011 11:03:37 +0000 (11:03 +0000)
lib/libsys/tsc_util.c

index daa8a8c04116b6513a657a0546dbbace4070bc49..545991c9b9bec4dac58c4bb37ed75d73f5ff006e 100644 (file)
 
 #include "sysutil.h"
 
-#define CALIBRATE_TICKS(h) ((h)/5)
+#ifndef CONFIG_MAX_CPUS
+#define CONFIG_MAX_CPUS 1
+#endif
+
 #define MICROHZ                1000000         /* number of micros per second */
 #define MICROSPERTICK(h)       (MICROHZ/(h))   /* number of micros per HZ tick */
 
                        panic("calibrate failed: %d", r); \
        }
 
-static u32_t calib_tsc, Hz = 0;
+static u32_t calib_mhz, Hz = 0;
 static int calibrated = 0;
 
 int
 tsc_calibrate(void)
 {
-       u64_t start, end, diff;
-       struct tms tms;
-       unsigned long t = 0;
+       struct cpu_info cpu_info[CONFIG_MAX_CPUS];
 
        /* Get HZ. */
        Hz = sys_hz();
 
-       /* Wait for clock to tick. */
-       while(!t || (t == times(&tms)))
-               t = times(&tms);
-
-       t++;
-
-       /* Wait for clock to tick CALIBRATE_TICKS times, and time
-        * this using the TSC.
+       /* Obtain CPU frequency from kernel */
+       if (sys_getcpuinfo(&cpu_info)) {
+               printf("tsc_calibrate: cannot get cpu info\n");
+               return -1;
+       }
+       
+       /* For now, use the frequency of the first CPU; everything here will 
+        * break down in case we get scheduled on multiple CPUs with different 
+        * frequencies regardless
         */
-       read_tsc_64(&start);
-       while(times(&tms) < t+CALIBRATE_TICKS(Hz)) ;
-       read_tsc_64(&end);
-
-       diff = sub64(end, start);
-       if(ex64hi(diff) != 0)
-         panic("tsc_calibrate: CALIBRATE_TICKS too high for TSC frequency");
-       calib_tsc = ex64lo(diff);
-#if 0
-       printf("tsc_calibrate: "
-               "%lu cycles/%d ticks of %d Hz; %lu cycles/s\n",
-                       calib_tsc, CALIBRATE_TICKS(Hz), Hz,
-                       div64u(mul64u(calib_tsc, Hz), CALIBRATE_TICKS(Hz)));
-#endif
+       calib_mhz = cpu_info[0].freq;
        calibrated = 1;
 
        return OK;
@@ -73,8 +62,7 @@ micro_delay(u32_t micros)
        CALIBRATE;
 
        /* We have to know when to end the delay. */
-       end = add64u(now, div64u(mul64u(calib_tsc,
-               micros * Hz / CALIBRATE_TICKS(Hz)), MICROHZ));
+       end = add64(now, mul64u(micros, calib_mhz * 1000));
 
        /* If we have to wait for at least one HZ tick, use the regular
         * tickdelay first. Round downwards on purpose, so the average
@@ -95,38 +83,16 @@ micro_delay(u32_t micros)
 u32_t tsc_64_to_micros(u64_t tsc)
 {
        u64_t tmp;
-       u32_t imv;
 
        CALIBRATE;
 
-       /* Various formulas provide various levels of accuracy depending on
-        * what still fits in a 64-bit number.
-        */
-       if (ex64hi(tsc) != 0) {
-               if (ex64hi(tsc) < ULONG_MAX) {
-                       tmp = mul64u(ex64hi(tsc) + 1, MICROHZ);
-
-                       if (ex64hi(tmp) == 0) {
-                               imv = div64u(mul64(tsc, cvu64(MICROHZ)),
-                                       calib_tsc);
-
-                               tmp = mul64u(imv, CALIBRATE_TICKS(Hz));
-
-                               if (ex64hi(tmp) == 0) {
-                                       /* Mid accuracy. */
-                                       return ex64lo(tmp) / Hz;
-                               }
-                       }
-               }
-
-               /* Low accuracy for large numbers. */
-               return div64u(mul64u(div64u(tsc, calib_tsc),
-                       MICROHZ * CALIBRATE_TICKS(Hz)), Hz);
+       tmp = div64u64(tsc, calib_mhz);
+       if (ex64hi(tmp)) {
+               printf("tsc_64_to_micros: more than 2^32ms\n");
+               return ~0UL;
+       } else {
+               return ex64lo(tmp);
        }
-
-       /* High accuracy for small numbers (the common case). */
-       return div64u(mul64u(ex64lo(tsc), MICROHZ * CALIBRATE_TICKS(Hz)),
-               calib_tsc) / Hz;
 }
 
 u32_t tsc_to_micros(u32_t low, u32_t high)
@@ -138,5 +104,5 @@ u32_t tsc_get_khz(void)
 {
        CALIBRATE;
 
-       return calib_tsc / (CALIBRATE_TICKS(Hz) * MICROSPERTICK(Hz)) * 1000;
+       return calib_mhz * 1000;
 }