diff options
Diffstat (limited to 'lab6_malloclab/clock.c')
-rw-r--r-- | lab6_malloclab/clock.c | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/lab6_malloclab/clock.c b/lab6_malloclab/clock.c new file mode 100644 index 0000000..f35135b --- /dev/null +++ b/lab6_malloclab/clock.c @@ -0,0 +1,279 @@ +/* + * 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; +} + |