📄 clock.c
字号:
/* * 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -