这是一个本人学习 csapp 的 learning 库
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

188 рядки
3.9 KiB

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/times.h>
#include <string.h>
#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 <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(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;
}