#include #include #include #include #include #include "clock.h" /* Keep track of most recent reading of cycle counter */ static unsigned cyc_hi = 0; static unsigned cyc_lo = 0; void access_counter(unsigned *hi, unsigned *lo) { /* Get cycle counter */ asm("rdtsc; movl %%edx,%0; movl %%eax,%1" : "=r" (*hi), "=r" (*lo) : /* No input */ : "%edx", "%eax"); } void start_counter() { access_counter(&cyc_hi, &cyc_lo); } double get_counter() { unsigned ncyc_hi, ncyc_lo; unsigned hi, lo, borrow; double result; /* Get cycle counter */ access_counter(&ncyc_hi, &ncyc_lo); /* Do double precision subtraction */ lo = ncyc_lo - cyc_lo; borrow = lo > ncyc_lo; hi = ncyc_hi - cyc_hi - borrow; result = (double) hi * (1 << 30) * 4 + lo; if (result < 0) { fprintf(stderr, "Error: Cycle counter returning negative value: %.0f\n", result); } return result; } double ovhd() { /* Do it twice to eliminate cache effects */ int i; double result; for (i = 0; i < 2; i++) { start_counter(); result = get_counter(); } return result; } /* Keep track of clock speed */ double cpu_ghz = 0.0; /* Get megahertz from /etc/proc */ #define MAXBUF 512 double core_mhz(int verbose) { static char buf[MAXBUF]; FILE *fp = fopen("/proc/cpuinfo", "r"); cpu_ghz = 0.0; if (!fp) { fprintf(stderr, "Can't open /proc/cpuinfo to get clock information\n"); cpu_ghz = 1.0; return cpu_ghz * 1000.0; } while (fgets(buf, MAXBUF, fp)) { if (strstr(buf, "cpu MHz")) { double cpu_mhz = 0.0; sscanf(buf, "cpu MHz\t: %lf", &cpu_mhz); cpu_ghz = cpu_mhz / 1000.0; break; } } fclose(fp); if (cpu_ghz == 0.0) { fprintf(stderr, "Can't open /proc/cpuinfo to get clock information\n"); cpu_ghz = 1.0; return cpu_ghz * 1000.0; } if (verbose) { printf("Processor Clock Rate ~= %.4f GHz (extracted from file)\n", cpu_ghz); } return cpu_ghz * 1000; } double mhz(int verbose) { double val = core_mhz(verbose); return val; } /* Determine clock rate by measuring cycles elapsed while sleeping for sleeptime seconds */ double mhz_full(int verbose, int sleeptime) { double rate; start_counter(); sleep(sleeptime); rate = get_counter()/(1e6*sleeptime); if (verbose) printf("Processor Clock Rate ~= %.1f MHz\n", rate); return rate; } ///* Version using a default sleeptime */ //double mhz(int verbose) //{ // return mhz_full(verbose, 2); //} /** Special counters that compensate for timer interrupt overhead */ static double cyc_per_tick = 0.0; #define NEVENT 100 #define THRESHOLD 1000 #define RECORDTHRESH 3000 /* Attempt to see how much time is used by timer interrupt */ static void callibrate(int verbose) { double oldt; struct tms t; clock_t oldc; int e = 0; times(&t); oldc = t.tms_utime; start_counter(); oldt = get_counter(); while (e = THRESHOLD) { clock_t newc; times(&t); newc = t.tms_utime; if (newc > oldc) { double cpt = (newt-oldt)/(newc-oldc); if ((cyc_per_tick == 0.0 || cyc_per_tick > cpt) && cpt > RECORDTHRESH) cyc_per_tick = cpt; /* if (verbose) printf("Saw event lasting %.0f cycles and %d ticks. Ratio = %f\n", newt-oldt, (int) (newc-oldc), cpt); */ e++; oldc = newc; } oldt = newt; } } if (verbose) printf("Setting cyc_per_tick to %f\n", cyc_per_tick); } static clock_t start_tick = 0; void start_comp_counter() { struct tms t; if (cyc_per_tick == 0.0) callibrate(1); times(&t); start_tick = t.tms_utime; start_counter(); } double get_comp_counter() { double time = get_counter(); double ctime; struct tms t; clock_t ticks; times(&t); ticks = t.tms_utime - start_tick; ctime = time - ticks*cyc_per_tick; /* printf("Measured %.0f cycles. Ticks = %d. Corrected %.0f cycles\n", time, (int) ticks, ctime); */ return ctime; }