这是一个本人学习 csapp 的 learning 库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

299 rivejä
6.3 KiB

/* Compute time used by a function f that takes two integer args */
#include <stdlib.h>
#include <sys/times.h>
#include <stdio.h>
#include "clock.h"
#include "fcyc2.h"
static double *values = NULL;
int samplecount = 0;
#define KEEP_VALS 1
#define KEEP_SAMPLES 1
#if KEEP_SAMPLES
double *samples = NULL;
#endif
/* Start new sampling process */
static void init_sampler(int k, int maxsamples)
{
if (values)
free(values);
values = calloc(k, sizeof(double));
#if KEEP_SAMPLES
if (samples)
free(samples);
/* Allocate extra for wraparound analysis */
samples = calloc(maxsamples+k, sizeof(double));
#endif
samplecount = 0;
}
/* Add new sample. */
void add_sample(double val, int k)
{
int pos = 0;
if (samplecount < k) {
pos = samplecount;
values[pos] = val;
} else if (val < values[k-1]) {
pos = k-1;
values[pos] = val;
}
#if KEEP_SAMPLES
samples[samplecount] = val;
#endif
samplecount++;
/* Insertion sort */
while (pos > 0 && values[pos-1] > values[pos]) {
double temp = values[pos-1];
values[pos-1] = values[pos];
values[pos] = temp;
pos--;
}
}
/* Get current minimum */
double get_min()
{
return values[0];
}
/* What is relative error for kth smallest sample */
double err(int k)
{
if (samplecount < k)
return 1000.0;
return (values[k-1] - values[0])/values[0];
}
/* Have k minimum measurements converged within epsilon? */
int has_converged(int k_arg, double epsilon_arg, int maxsamples)
{
if ((samplecount >= k_arg) &&
((1 + epsilon_arg)*values[0] >= values[k_arg-1]))
return samplecount;
if ((samplecount >= maxsamples))
return -1;
return 0;
}
/* Code to clear cache */
/* Pentium III has 512K L2 cache, which is 128K ints */
#define ASIZE (1 << 17)
/* Cache block size is 32 bytes */
#define STRIDE 8
static int stuff[ASIZE];
static int sink;
static void clear()
{
int x = sink;
int i;
for (i = 0; i < ASIZE; i += STRIDE)
x += stuff[i];
sink = x;
}
double fcyc2_full(test_funct f, int param1, int param2, int clear_cache,
int k, double epsilon, int maxsamples, int compensate)
{
double result;
init_sampler(k, maxsamples);
if (compensate) {
do {
double cyc;
if (clear_cache)
clear();
f(param1, param2); /* warm cache */
start_comp_counter();
f(param1, param2);
cyc = get_comp_counter();
add_sample(cyc, k);
} while (!has_converged(k, epsilon, maxsamples) && samplecount < maxsamples);
} else {
do {
double cyc;
if (clear_cache)
clear();
f(param1, param2); /* warm cache */
start_counter();
f(param1, param2);
cyc = get_counter();
add_sample(cyc, k);
} while (!has_converged(k, epsilon, maxsamples) && samplecount < maxsamples);
}
#ifdef DEBUG
{
int i;
printf(" %d smallest values: [", k);
for (i = 0; i < k; i++)
printf("%.0f%s", values[i], i==k-1 ? "]\n" : ", ");
}
#endif
result = values[0];
#if !KEEP_VALS
free(values);
values = NULL;
#endif
return result;
}
double fcyc2(test_funct f, int param1, int param2, int clear_cache)
{
return fcyc2_full(f, param1, param2, clear_cache, 3, 0.01, 500, 0);
}
/******************* Version that uses gettimeofday *************/
static double Mhz = 0.0;
#include <sys/time.h>
static struct timeval tstart;
/* Record current time */
void start_counter_tod()
{
if (Mhz == 0)
Mhz = mhz_full(0, 10);
gettimeofday(&tstart, NULL);
}
/* Get number of seconds since last call to start_timer */
double get_counter_tod()
{
struct timeval tfinish;
long sec, usec;
gettimeofday(&tfinish, NULL);
sec = tfinish.tv_sec - tstart.tv_sec;
usec = tfinish.tv_usec - tstart.tv_usec;
return (1e6 * sec + usec)*Mhz;
}
/** 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_tod();
oldt = get_counter_tod();
while (e <NEVENT) {
double newt = get_counter_tod();
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_tod() {
struct tms t;
if (cyc_per_tick == 0.0)
callibrate(0);
times(&t);
start_tick = t.tms_utime;
start_counter_tod();
}
double get_comp_counter_tod() {
double time = get_counter_tod();
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;
}
double fcyc2_full_tod(test_funct f, int param1, int param2, int clear_cache,
int k, double epsilon, int maxsamples, int compensate)
{
double result;
init_sampler(k, maxsamples);
if (compensate) {
do {
double cyc;
if (clear_cache)
clear();
start_comp_counter_tod();
f(param1, param2);
cyc = get_comp_counter_tod();
add_sample(cyc, k);
} while (!has_converged(k, epsilon, maxsamples) && samplecount < maxsamples);
} else {
do {
double cyc;
if (clear_cache)
clear();
start_counter_tod();
f(param1, param2);
cyc = get_counter_tod();
add_sample(cyc, k);
} while (!has_converged(k, epsilon, maxsamples) && samplecount < maxsamples);
}
#ifdef DEBUG
{
int i;
printf(" %d smallest values: [", k);
for (i = 0; i < k; i++)
printf("%.0f%s", values[i], i==k-1 ? "]\n" : ", ");
}
#endif
result = values[0];
#if !KEEP_VALS
free(values);
values = NULL;
#endif
return result;
}
double fcyc2_tod(test_funct f, int param1, int param2, int clear_cache)
{
return fcyc2_full_tod(f, param1, param2, clear_cache, 3, 0.01, 20, 0);
}