-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
765 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
CC = gcc | ||
CFLAGS = -Wall -O3 -D__i386__ | ||
|
||
mountain: mountain.c fcyc2.c clock.c | ||
$(CC) $(CFLAGS) -o mountain mountain.c fcyc2.c clock.c | ||
|
||
clean: | ||
rm -f mountain *.o *~ | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
This directory contains code for generating a memory mountain, as | ||
described in Computer Systems: A Programmer's Perspective | ||
|
||
clock.{c,h} - routines for using x86 and Alpha cycle timers | ||
fcyc2.{c,h} - routines that estimate the number of cycles required | ||
by a function f that takes two arguments. | ||
Makefile - memory mountain makefile | ||
mountain.c - program that generates the memory mountain. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
#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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* Routines for using cycle counter */ | ||
|
||
/* Start the counter */ | ||
void start_counter(); | ||
|
||
/* Get # cycles since counter started */ | ||
double get_counter(); | ||
|
||
|
||
/* Measure overhead for counter */ | ||
double ovhd(); | ||
|
||
/* Determine clock rate of processor */ | ||
double mhz(int verbose); | ||
|
||
/* Determine clock rate of processor, having more control over accuracy */ | ||
double mhz_full(int verbose, int sleeptime); | ||
|
||
/** Special counters that compensate for timer interrupt overhead */ | ||
|
||
void start_comp_counter(); | ||
|
||
double get_comp_counter(); |
Oops, something went wrong.