forked from Seterplus/CSAPP
-
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
82 changed files
with
1,238,622 additions
and
2 deletions.
There are no files selected for viewing
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,26 @@ | ||
# | ||
# Makefile for the malloc lab driver | ||
# | ||
CC = gcc | ||
CFLAGS = -Wall -Wextra -Werror -O2 -g -DDRIVER -std=gnu99 | ||
|
||
OBJS = mdriver.o mm.o memlib.o fsecs.o fcyc.o clock.o ftimer.o | ||
|
||
all: mdriver | ||
|
||
mdriver: $(OBJS) | ||
$(CC) $(CFLAGS) -o mdriver $(OBJS) | ||
|
||
mdriver.o: mdriver.c fsecs.h fcyc.h clock.h memlib.h config.h mm.h | ||
memlib.o: memlib.c memlib.h | ||
mm.o: mm.c mm.h memlib.h | ||
fsecs.o: fsecs.c fsecs.h config.h | ||
fcyc.o: fcyc.c fcyc.h | ||
ftimer.o: ftimer.c ftimer.h config.h | ||
clock.o: clock.c clock.h | ||
|
||
clean: | ||
rm -f *~ *.o mdriver | ||
|
||
|
||
|
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,45 @@ | ||
##################################################################### | ||
# CS:APP Malloc Lab | ||
# Handout files for students | ||
###################################################################### | ||
|
||
*********** | ||
Main Files: | ||
*********** | ||
|
||
mdriver | ||
Once you've run make, run ./mdriver to test your solution. | ||
|
||
traces/ | ||
Directory that contains the trace files that the driver uses | ||
to test your solution. Files orners.rep, short2.rep, and malloc.rep | ||
are tiny trace files that you can use for debugging correctness. | ||
|
||
********************************** | ||
Other support files for the driver | ||
********************************** | ||
|
||
config.h Configures the malloc lab driver | ||
fsecs.{c,h} Wrapper function for the different timer packages | ||
clock.{c,h} Routines for accessing the Pentium and Alpha cycle counters | ||
fcyc.{c,h} Timer functions based on cycle counters | ||
ftimer.{c,h} Timer functions based on interval timers and gettimeofday() | ||
memlib.{c,h} Models the heap and sbrk function | ||
|
||
******************************* | ||
Building and running the driver | ||
******************************* | ||
To build the driver, type "make" to the shell. | ||
|
||
To run the driver on a tiny test trace: | ||
|
||
unix> ./mdriver -V -f traces/malloc.rep | ||
|
||
To get a list of the driver flags: | ||
|
||
unix> ./mdriver -h | ||
|
||
The -V option prints out helpful tracing information | ||
|
||
|
||
|
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,297 @@ | ||
/* | ||
* 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 <string.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__) || defined(__x86_64__) | ||
/******************************************************* | ||
* 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 */ | ||
/* Get the clock rate from /proc */ | ||
double mhz_full(int verbose, int sleeptime __attribute__((unused))) | ||
{ | ||
static char buf[2048]; | ||
|
||
FILE *fp = fopen("/proc/cpuinfo", "r"); | ||
double mhz = 0.0; | ||
|
||
while (fgets(buf, 2048, fp)) { | ||
if (strstr(buf, "cpu MHz")) { | ||
sscanf(buf, "cpu MHz\t: %lf", &mhz); | ||
break; | ||
} | ||
} | ||
fclose(fp); | ||
if (verbose) | ||
printf("Processor clock rate ~= %.1f MHz\n", mhz); | ||
return mhz; | ||
|
||
#if 0 | ||
double rate; | ||
|
||
start_counter(); | ||
sleep(sleeptime); | ||
rate = get_counter() / (1e6*sleeptime); | ||
if (verbose) | ||
printf("Processor clock rate ~= %.1f MHz\n", rate); | ||
return rate; | ||
#endif | ||
} | ||
/* $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; | ||
} | ||
|
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,22 @@ | ||
/* 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 (using a default sleeptime) */ | ||
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.