|
|
- /*
- * clock.c - Routines for using the cycle counters on x86,
- * Alpha, and Sparc boxes.
- *
- * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved.
- * May not be used, modified, or copied without permission.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/times.h>
- #include "clock.h"
-
-
- /*******************************************************
- * Machine dependent functions
- *
- * Note: the constants __i386__ and __alpha
- * are set by GCC when it calls the C preprocessor
- * You can verify this for yourself using gcc -v.
- *******************************************************/
-
- #if defined(__i386__)
- /*******************************************************
- * Pentium versions of start_counter() and get_counter()
- *******************************************************/
-
-
- /* $begin x86cyclecounter */
- /* Initialize the cycle counter */
- static unsigned cyc_hi = 0;
- static unsigned cyc_lo = 0;
-
-
- /* Set *hi and *lo to the high and low order bits of the cycle counter.
- Implementation requires assembly code to use the rdtsc instruction. */
- void access_counter(unsigned *hi, unsigned *lo)
- {
- asm("rdtsc; movl %%edx,%0; movl %%eax,%1" /* Read cycle counter */
- : "=r" (*hi), "=r" (*lo) /* and move results to */
- : /* No input */ /* the two outputs */
- : "%edx", "%eax");
- }
-
- /* Record the current value of the cycle counter. */
- void start_counter()
- {
- access_counter(&cyc_hi, &cyc_lo);
- }
-
- /* Return the number of cycles since the last call to start_counter. */
- 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: counter returns neg value: %.0f\n", result);
- }
- return result;
- }
- /* $end x86cyclecounter */
-
- #elif defined(__alpha)
-
- /****************************************************
- * Alpha versions of start_counter() and get_counter()
- ***************************************************/
-
- /* Initialize the cycle counter */
- static unsigned cyc_hi = 0;
- static unsigned cyc_lo = 0;
-
-
- /* Use Alpha cycle timer to compute cycles. Then use
- measured clock speed to compute seconds
- */
-
- /*
- * counterRoutine is an array of Alpha instructions to access
- * the Alpha's processor cycle counter. It uses the rpcc
- * instruction to access the counter. This 64 bit register is
- * divided into two parts. The lower 32 bits are the cycles
- * used by the current process. The upper 32 bits are wall
- * clock cycles. These instructions read the counter, and
- * convert the lower 32 bits into an unsigned int - this is the
- * user space counter value.
- * NOTE: The counter has a very limited time span. With a
- * 450MhZ clock the counter can time things for about 9
- * seconds. */
- static unsigned int counterRoutine[] =
- {
- 0x601fc000u,
- 0x401f0000u,
- 0x6bfa8001u
- };
-
- /* Cast the above instructions into a function. */
- static unsigned int (*counter)(void)= (void *)counterRoutine;
-
-
- void start_counter()
- {
- /* Get cycle counter */
- cyc_hi = 0;
- cyc_lo = counter();
- }
-
- double get_counter()
- {
- unsigned ncyc_hi, ncyc_lo;
- unsigned hi, lo, borrow;
- double result;
- ncyc_lo = counter();
- ncyc_hi = 0;
- 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;
- }
-
- #else
-
- /****************************************************************
- * All the other platforms for which we haven't implemented cycle
- * counter routines. Newer models of sparcs (v8plus) have cycle
- * counters that can be accessed from user programs, but since there
- * are still many sparc boxes out there that don't support this, we
- * haven't provided a Sparc version here.
- ***************************************************************/
-
- void start_counter()
- {
- printf("ERROR: You are trying to use a start_counter routine in clock.c\n");
- printf("that has not been implemented yet on this platform.\n");
- printf("Please choose another timing package in config.h.\n");
- exit(1);
- }
-
- double get_counter()
- {
- printf("ERROR: You are trying to use a get_counter routine in clock.c\n");
- printf("that has not been implemented yet on this platform.\n");
- printf("Please choose another timing package in config.h.\n");
- exit(1);
- }
- #endif
-
-
-
-
- /*******************************
- * Machine-independent functions
- ******************************/
- 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;
- }
-
- /* $begin mhz */
- /* Estimate the clock rate by measuring the cycles that elapse */
- /* 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;
- }
- /* $end mhz */
-
- /* 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 <NEVENT) {
- double newt = get_counter();
-
- if (newt-oldt >= 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(0);
- 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;
- }
-
|