From 19a2df49ef7ad2c3644855f89f65e9fed456bd6f Mon Sep 17 00:00:00 2001 From: GentleCold <1952173800@qq.com> Date: Wed, 28 Dec 2022 15:47:44 +0800 Subject: [PATCH] add malloc lab --- CMakeLists.txt | 1 + labs/bomb_lab/solve_note.md | 25 + labs/malloclab_lab/Makefile | 30 ++ labs/malloclab_lab/README | 52 ++ labs/malloclab_lab/clock.c | 279 ++++++++++ labs/malloclab_lab/clock.h | 22 + labs/malloclab_lab/clock.o | Bin 0 -> 3000 bytes labs/malloclab_lab/config.h | 72 +++ labs/malloclab_lab/fcyc.c | 251 +++++++++ labs/malloclab_lab/fcyc.h | 68 +++ labs/malloclab_lab/fcyc.o | Bin 0 -> 3472 bytes labs/malloclab_lab/fsecs.c | 57 +++ labs/malloclab_lab/fsecs.h | 4 + labs/malloclab_lab/fsecs.o | Bin 0 -> 1292 bytes labs/malloclab_lab/ftimer.c | 106 ++++ labs/malloclab_lab/ftimer.h | 14 + labs/malloclab_lab/ftimer.o | Bin 0 -> 2188 bytes labs/malloclab_lab/mdriver | Bin 0 -> 32528 bytes labs/malloclab_lab/mdriver.c | 1017 +++++++++++++++++++++++++++++++++++++ labs/malloclab_lab/mdriver.o | Bin 0 -> 19476 bytes labs/malloclab_lab/memlib.c | 101 ++++ labs/malloclab_lab/memlib.h | 11 + labs/malloclab_lab/memlib.o | Bin 0 -> 2284 bytes labs/malloclab_lab/mm.c | 110 ++++ labs/malloclab_lab/mm.h | 23 + labs/malloclab_lab/mm.o | Bin 0 -> 2160 bytes labs/malloclab_lab/short1-bal.rep | 16 + labs/malloclab_lab/short2-bal.rep | 16 + quiz/storage_mountain/clock.c | 188 +++++++ quiz/storage_mountain/clock.h | 23 + quiz/storage_mountain/fcyc2.c | 299 +++++++++++ quiz/storage_mountain/fcyc2.h | 41 ++ quiz/storage_mountain/mountain.c | 116 +++++ quiz/storage_mountain/mountain.h | 45 ++ quiz/test_quiz.c | 2 +- 35 files changed, 2988 insertions(+), 1 deletion(-) create mode 100644 labs/malloclab_lab/Makefile create mode 100644 labs/malloclab_lab/README create mode 100644 labs/malloclab_lab/clock.c create mode 100644 labs/malloclab_lab/clock.h create mode 100644 labs/malloclab_lab/clock.o create mode 100644 labs/malloclab_lab/config.h create mode 100644 labs/malloclab_lab/fcyc.c create mode 100644 labs/malloclab_lab/fcyc.h create mode 100644 labs/malloclab_lab/fcyc.o create mode 100644 labs/malloclab_lab/fsecs.c create mode 100644 labs/malloclab_lab/fsecs.h create mode 100644 labs/malloclab_lab/fsecs.o create mode 100644 labs/malloclab_lab/ftimer.c create mode 100644 labs/malloclab_lab/ftimer.h create mode 100644 labs/malloclab_lab/ftimer.o create mode 100644 labs/malloclab_lab/mdriver create mode 100644 labs/malloclab_lab/mdriver.c create mode 100644 labs/malloclab_lab/mdriver.o create mode 100644 labs/malloclab_lab/memlib.c create mode 100644 labs/malloclab_lab/memlib.h create mode 100644 labs/malloclab_lab/memlib.o create mode 100644 labs/malloclab_lab/mm.c create mode 100644 labs/malloclab_lab/mm.h create mode 100644 labs/malloclab_lab/mm.o create mode 100644 labs/malloclab_lab/short1-bal.rep create mode 100644 labs/malloclab_lab/short2-bal.rep create mode 100644 quiz/storage_mountain/clock.c create mode 100644 quiz/storage_mountain/clock.h create mode 100644 quiz/storage_mountain/fcyc2.c create mode 100644 quiz/storage_mountain/fcyc2.h create mode 100644 quiz/storage_mountain/mountain.c create mode 100644 quiz/storage_mountain/mountain.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ba4430..880ca2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ set(EXECUTABLE_OUTPUT_PATH ${BUILD_PATH}) # EXE set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BUILD_PATH}) # LIB add_executable(TestQuiz quiz/test_quiz.c) +add_executable(Mountain quiz/storage_mountain/mountain.c quiz/storage_mountain/clock.c quiz/storage_mountain/fcyc2.c) if(CMAKE_BUILD_TYPE AND (CMAKE_BUILD_TYPE STREQUAL "Debug")) add_definitions(-DDEBUG) diff --git a/labs/bomb_lab/solve_note.md b/labs/bomb_lab/solve_note.md index 454887f..a9bfbae 100644 --- a/labs/bomb_lab/solve_note.md +++ b/labs/bomb_lab/solve_note.md @@ -76,3 +76,28 @@ cmpl 得知第一个数字需要小于 0x7 ### 8. 查看函数 phase_5 +需输入字符串 + +循环根据输入字符串的 asc 值的第四位索引内置的字符串 + +用 gdb 查看最后得到的字符串是 flyers + +得到 phase_5 + +### 9. 查看函数 phase_6 + +调用函数 read_six_numbers 知需输入 6 个数字 + +第一个循环说明每个数字需互不相同且小于等于 6 + +第二个循环对每个数字作 7 - x + +第三个循环根据数字得到 6 个相当于链表的地址 + +第四个循环改变链表顺序 + +第五个循环说明得到的 6 个地址指向的数字需大于等于下一个地址指向的数字 + +得到 phase_6 + +**注意:0x30和0x40相差16而不是10!!** diff --git a/labs/malloclab_lab/Makefile b/labs/malloclab_lab/Makefile new file mode 100644 index 0000000..3d5dc9e --- /dev/null +++ b/labs/malloclab_lab/Makefile @@ -0,0 +1,30 @@ +# +# Students' Makefile for the Malloc Lab +# +TEAM = bovik +VERSION = 1 +HANDINDIR = /afs/cs.cmu.edu/academic/class/15213-f01/malloclab/handin + +CC = gcc +CFLAGS = -Wall -O2 -m32 + +OBJS = mdriver.o mm.o memlib.o fsecs.o fcyc.o clock.o ftimer.o + +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 + +handin: + cp mm.c $(HANDINDIR)/$(TEAM)-$(VERSION)-mm.c + +clean: + rm -f *~ *.o mdriver + + diff --git a/labs/malloclab_lab/README b/labs/malloclab_lab/README new file mode 100644 index 0000000..12c238a --- /dev/null +++ b/labs/malloclab_lab/README @@ -0,0 +1,52 @@ +##################################################################### +# CS:APP Malloc Lab +# Handout files for students +# +# Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved. +# May not be used, modified, or copied without permission. +# +###################################################################### + +*********** +Main Files: +*********** + +mm.{c,h} + Your solution malloc package. mm.c is the file that you + will be handing in, and is the only file you should modify. + +mdriver.c + The malloc driver that tests your mm.c file + +short{1,2}-bal.rep + Two tiny tracefiles to help you get started. + +Makefile + Builds the driver + +********************************** +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 short1-bal.rep + +The -V option prints out helpful tracing and summary information. + +To get a list of the driver flags: + + unix> mdriver -h + diff --git a/labs/malloclab_lab/clock.c b/labs/malloclab_lab/clock.c new file mode 100644 index 0000000..f35135b --- /dev/null +++ b/labs/malloclab_lab/clock.c @@ -0,0 +1,279 @@ +/* + * 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 +#include +#include +#include +#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 = 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; +} + diff --git a/labs/malloclab_lab/clock.h b/labs/malloclab_lab/clock.h new file mode 100644 index 0000000..54d26ac --- /dev/null +++ b/labs/malloclab_lab/clock.h @@ -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(); diff --git a/labs/malloclab_lab/clock.o b/labs/malloclab_lab/clock.o new file mode 100644 index 0000000000000000000000000000000000000000..ec5b10fcbb97327f31ceaf6bf96c5b1f70b93511 GIT binary patch literal 3000 zcma)7ZD?Cn7(V&vmUU?s=htK%Ug2(Q*DY&C9JSV&((Xg4rMORMX~?qMr7UUc%}w3v z*ecO#m{pmA2>zIef7BoQB?v>^QY`*ZHWf+MrA73|N=KO>!|9+t&%Ni=Z1}?i?|shu zzR!8z_k7;dJG*wdTrQ!SOL)Y;nhg=WPbmJA6yYz-a zpT2oEr8ku7;1PvRSoZ0gOLbmow9i~DFU-!pxFSE<;)MT@yvjb^KZVNdexI(P@8#qQ zUj6!=#l^)+r>;38MpV5A_U3PRQP9tYV&QSS=5;K_p_i&n`AKhY{~W_ie9iMRQ;=8Pj~9|r8?F)bKBBTvX5mpK(F-a!6~oKidDJ6 z{G{I7Uz}K~H-DoZq3oHt!BaEKPu3UT<~AH;LCxibN)0niSh_YlS1FD9=C@Z$^cNyd zQ4I1C7{b}l>ix=3Huv_&iq0%^-!F|gscY5b@U$~or_?^(H}6N8l~SdY|2uK|Jv9Sg zX|7!3N22n#({q)wIm1~ZCcvjwMtkBf{RJhiKEsqrstc0Jc==C(7B@`5vZG@9E{ zDV6Q>;#fv}m35ry{IW`E-i_QvS7B=2^R`{Zs<)PN*O6&1&3(iCXXi$)&VO0Go^5s& z6Ic%{CW~9Ds>!|!IDB?3*X%uGjrqy8nO}-rJRx?PX2xvQ5}DkPWtf_2SUGbjs|^`P zwUKx#XS8bTL(K!VqQ}f6jBGYzYKc@PaZEGgmZ6<`3f}O5_S~M)T07cUw-94dpmuC;!z z_jR16HL%s&9w8niwg-H9_ugUvw~4+Mhz7aW$1}MP5`~OIoN*n2sJpv1;A_YDohwsL zN02)PxeSRw$Q^gL2mE-vD90*O+hI(;f)sy{s}?8wet;A8CEue`FKV%> zQ1(RHiXR4Arh`eaSSX(GLo?YGoCh>{QtE_LE{vcNqQ7m>yZk84;CBOXNBE!J`FfjJs8N_ z$MIZy-j(%IS0TDo2X;2{*qR{ZD|Zh%JTI!z$JPvC{B2aw$a~i5+F!<_|7nSRQiO~q5X z!fLx${JyB{#Jm6M)T=X4_u6^6{;b1=FKeMF9o?no5jEmrXq-QVd|i6~o3Bo*L-N?8 z~Tx^wYzC){#VFyryD4pjb3gKHs{~@4itUIO@AoVolGK6mh`6f`kIn-Z* zt{V9-D+NgXO~@D)nfHqPv%quE`QA|f7`kfYe+p6W3jM-<>O%>UIFX1Y2W?1YY#27o zm^Fwe0S|*|Io)`Ie~6g;l}L}$jv7{#=ZImNA{HAMHV22SfmkAWOk_rqM?^X~8XL%^ zQX-o&jA1aU2=Fb%Ob;&wvj)>fRyg6S%#E0f3meNlA@)c-An^qv-j~x7-zVZ?a7|n| z=U)Kbxabw?82_up>$GFBZc6=@#K*8)p&j`S5fML0`$Iy!L&PEe zgm#Rdr2dEy-$}hJaaQ6j>0gG&fc${O`+>}}N#b_ek*}LN;+fRJAD8xbrT!EB821|y kyaj2$Baz2|evR{ntxY1&F7;O=o|kw{;vW(>b3Aze0Jj1&8~^|S literal 0 HcmV?d00001 diff --git a/labs/malloclab_lab/config.h b/labs/malloclab_lab/config.h new file mode 100644 index 0000000..f2ff5d8 --- /dev/null +++ b/labs/malloclab_lab/config.h @@ -0,0 +1,72 @@ +#ifndef __CONFIG_H_ +#define __CONFIG_H_ + +/* + * config.h - malloc lab configuration file + * + * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved. + * May not be used, modified, or copied without permission. + */ + +/* + * This is the default path where the driver will look for the + * default tracefiles. You can override it at runtime with the -t flag. + */ +#define TRACEDIR "/afs/cs/project/ics2/im/labs/malloclab/traces/" + +/* + * This is the list of default tracefiles in TRACEDIR that the driver + * will use for testing. Modify this if you want to add or delete + * traces from the driver's test suite. For example, if you don't want + * your students to implement realloc, you can delete the last two + * traces. + */ +#define DEFAULT_TRACEFILES \ + "amptjp-bal.rep",\ + "cccp-bal.rep",\ + "cp-decl-bal.rep",\ + "expr-bal.rep",\ + "coalescing-bal.rep",\ + "random-bal.rep",\ + "random2-bal.rep",\ + "binary-bal.rep",\ + "binary2-bal.rep",\ + "realloc-bal.rep",\ + "realloc2-bal.rep" + +/* + * This constant gives the estimated performance of the libc malloc + * package using our traces on some reference system, typically the + * same kind of system the students use. Its purpose is to cap the + * contribution of throughput to the performance index. Once the + * students surpass the AVG_LIBC_THRUPUT, they get no further benefit + * to their score. This deters students from building extremely fast, + * but extremely stupid malloc packages. + */ +#define AVG_LIBC_THRUPUT 600E3 /* 600 Kops/sec */ + + /* + * This constant determines the contributions of space utilization + * (UTIL_WEIGHT) and throughput (1 - UTIL_WEIGHT) to the performance + * index. + */ +#define UTIL_WEIGHT .60 + +/* + * Alignment requirement in bytes (either 4 or 8) + */ +#define ALIGNMENT 8 + +/* + * Maximum heap size in bytes + */ +#define MAX_HEAP (20*(1<<20)) /* 20 MB */ + +/***************************************************************************** + * Set exactly one of these USE_xxx constants to "1" to select a timing method + *****************************************************************************/ +#define USE_FCYC 0 /* cycle counter w/K-best scheme (x86 & Alpha only) */ +#define USE_ITIMER 0 /* interval timer (any Unix box) */ +#define USE_GETTOD 1 /* gettimeofday (any Unix box) */ + +#endif /* __CONFIG_H */ diff --git a/labs/malloclab_lab/fcyc.c b/labs/malloclab_lab/fcyc.c new file mode 100644 index 0000000..420b306 --- /dev/null +++ b/labs/malloclab_lab/fcyc.c @@ -0,0 +1,251 @@ +/* + * fcyc.c - Estimate the time (in CPU cycles) used by a function f + * + * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved. + * May not be used, modified, or copied without permission. + * + * Uses the cycle timer routines in clock.c to estimate the + * the time in CPU cycles for a function f. + */ +#include +#include +#include + +#include "fcyc.h" +#include "clock.h" + +/* Default values */ +#define K 3 /* Value of K in K-best scheme */ +#define MAXSAMPLES 20 /* Give up after MAXSAMPLES */ +#define EPSILON 0.01 /* K samples should be EPSILON of each other*/ +#define COMPENSATE 0 /* 1-> try to compensate for clock ticks */ +#define CLEAR_CACHE 0 /* Clear cache before running test function */ +#define CACHE_BYTES (1<<19) /* Max cache size in bytes */ +#define CACHE_BLOCK 32 /* Cache block size in bytes */ + +static int kbest = K; +static int maxsamples = MAXSAMPLES; +static double epsilon = EPSILON; +static int compensate = COMPENSATE; +static int clear_cache = CLEAR_CACHE; +static int cache_bytes = CACHE_BYTES; +static int cache_block = CACHE_BLOCK; + +static int *cache_buf = NULL; + +static double *values = NULL; +static int samplecount = 0; + +/* for debugging only */ +#define KEEP_VALS 0 +#define KEEP_SAMPLES 0 + +#if KEEP_SAMPLES +static double *samples = NULL; +#endif + +/* + * init_sampler - Start new sampling process + */ +static void init_sampler() +{ + if (values) + free(values); + values = calloc(kbest, sizeof(double)); +#if KEEP_SAMPLES + if (samples) + free(samples); + /* Allocate extra for wraparound analysis */ + samples = calloc(maxsamples+kbest, sizeof(double)); +#endif + samplecount = 0; +} + +/* + * add_sample - Add new sample + */ +static void add_sample(double val) +{ + int pos = 0; + if (samplecount < kbest) { + pos = samplecount; + values[pos] = val; + } else if (val < values[kbest-1]) { + pos = kbest-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--; + } +} + +/* + * has_converged- Have kbest minimum measurements converged within epsilon? + */ +static int has_converged() +{ + return + (samplecount >= kbest) && + ((1 + epsilon)*values[0] >= values[kbest-1]); +} + +/* + * clear - Code to clear cache + */ +static volatile int sink = 0; + +static void clear() +{ + int x = sink; + int *cptr, *cend; + int incr = cache_block/sizeof(int); + if (!cache_buf) { + cache_buf = malloc(cache_bytes); + if (!cache_buf) { + fprintf(stderr, "Fatal error. Malloc returned null when trying to clear cache\n"); + exit(1); + } + } + cptr = (int *) cache_buf; + cend = cptr + cache_bytes/sizeof(int); + while (cptr < cend) { + x += *cptr; + cptr += incr; + } + sink = x; +} + +/* + * fcyc - Use K-best scheme to estimate the running time of function f + */ +double fcyc(test_funct f, void *argp) +{ + double result; + init_sampler(); + if (compensate) { + do { + double cyc; + if (clear_cache) + clear(); + start_comp_counter(); + f(argp); + cyc = get_comp_counter(); + add_sample(cyc); + } while (!has_converged() && samplecount < maxsamples); + } else { + do { + double cyc; + if (clear_cache) + clear(); + start_counter(); + f(argp); + cyc = get_counter(); + add_sample(cyc); + } while (!has_converged() && samplecount < maxsamples); + } +#ifdef DEBUG + { + int i; + printf(" %d smallest values: [", kbest); + for (i = 0; i < kbest; i++) + printf("%.0f%s", values[i], i==kbest-1 ? "]\n" : ", "); + } +#endif + result = values[0]; +#if !KEEP_VALS + free(values); + values = NULL; +#endif + return result; +} + + +/************************************************************* + * Set the various parameters used by the measurement routines + ************************************************************/ + +/* + * set_fcyc_clear_cache - When set, will run code to clear cache + * before each measurement. + * Default = 0 + */ +void set_fcyc_clear_cache(int clear) +{ + clear_cache = clear; +} + +/* + * set_fcyc_cache_size - Set size of cache to use when clearing cache + * Default = 1<<19 (512KB) + */ +void set_fcyc_cache_size(int bytes) +{ + if (bytes != cache_bytes) { + cache_bytes = bytes; + if (cache_buf) { + free(cache_buf); + cache_buf = NULL; + } + } +} + +/* + * set_fcyc_cache_block - Set size of cache block + * Default = 32 + */ +void set_fcyc_cache_block(int bytes) { + cache_block = bytes; +} + + +/* + * set_fcyc_compensate- When set, will attempt to compensate for + * timer interrupt overhead + * Default = 0 + */ +void set_fcyc_compensate(int compensate_arg) +{ + compensate = compensate_arg; +} + +/* + * set_fcyc_k - Value of K in K-best measurement scheme + * Default = 3 + */ +void set_fcyc_k(int k) +{ + kbest = k; +} + +/* + * set_fcyc_maxsamples - Maximum number of samples attempting to find + * K-best within some tolerance. + * When exceeded, just return best sample found. + * Default = 20 + */ +void set_fcyc_maxsamples(int maxsamples_arg) +{ + maxsamples = maxsamples_arg; +} + +/* + * set_fcyc_epsilon - Tolerance required for K-best + * Default = 0.01 + */ +void set_fcyc_epsilon(double epsilon_arg) +{ + epsilon = epsilon_arg; +} + + + + + diff --git a/labs/malloclab_lab/fcyc.h b/labs/malloclab_lab/fcyc.h new file mode 100644 index 0000000..d398278 --- /dev/null +++ b/labs/malloclab_lab/fcyc.h @@ -0,0 +1,68 @@ +/* + * fcyc.h - prototypes for the routines in fcyc.c that estimate the + * time in CPU cycles used by a test function f + * + * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved. + * May not be used, modified, or copied without permission. + * + */ + +/* The test function takes a generic pointer as input */ +typedef void (*test_funct)(void *); + +/* Compute number of cycles used by test function f */ +double fcyc(test_funct f, void* argp); + +/********************************************************* + * Set the various parameters used by measurement routines + *********************************************************/ + +/* + * set_fcyc_clear_cache - When set, will run code to clear cache + * before each measurement. + * Default = 0 + */ +void set_fcyc_clear_cache(int clear); + +/* + * set_fcyc_cache_size - Set size of cache to use when clearing cache + * Default = 1<<19 (512KB) + */ +void set_fcyc_cache_size(int bytes); + +/* + * set_fcyc_cache_block - Set size of cache block + * Default = 32 + */ +void set_fcyc_cache_block(int bytes); + +/* + * set_fcyc_compensate- When set, will attempt to compensate for + * timer interrupt overhead + * Default = 0 + */ +void set_fcyc_compensate(int compensate_arg); + +/* + * set_fcyc_k - Value of K in K-best measurement scheme + * Default = 3 + */ +void set_fcyc_k(int k); + +/* + * set_fcyc_maxsamples - Maximum number of samples attempting to find + * K-best within some tolerance. + * When exceeded, just return best sample found. + * Default = 20 + */ +void set_fcyc_maxsamples(int maxsamples_arg); + +/* + * set_fcyc_epsilon - Tolerance required for K-best + * Default = 0.01 + */ +void set_fcyc_epsilon(double epsilon_arg); + + + + diff --git a/labs/malloclab_lab/fcyc.o b/labs/malloclab_lab/fcyc.o new file mode 100644 index 0000000000000000000000000000000000000000..37f1661ef5d3a055c5406c5da1a6aef8e01f4e07 GIT binary patch literal 3472 zcma)8ZERCj7(V?N7TD@Qh$us@S_Ks9hBIOK0fPzrKqVqz0$J_4Tehrgm)qM75Rjw} zt+iUCCd8QNLKG7cLQLd`;YXp!nEp@^;}&R~QR8raVDJNtI-lpvMh}f7K$1%&32WTt?>f0vuEMCdBBI~#!^e5 zy6NLR-KDxSnfKEtT>WP=(rNFOT;r!#CMG6wb@e4rZhgJ42F=7>r$UV%bB+dcH7!o%;#P~ z;Q1x*@aGqMr_-fwcs!l!g&i4ewGwD8M)Ovt4TYxJ%zO6@BV#h@3sp@0g0Ix_(Up;* zhQj9;OT$;cSh!r=vUy|ryV~qs9DAS|kL)})v-h(5i67kk1#?mQn?EyuxK1{m?46OT zeuw60-ZRH_rs-tgm5g*xpQ_#38Y*V)35@-TJo^g=87g&pfX;(00pEQVdb#w2-T>tc zmQi|xQH=en{+^f^JBLSqA@$fmEnJ&q-#r_%v&s6;nnPn>!9IQx{m;{zlafKK zc#QJpU(lbkqFnEcQX>hn9vUx1^KvTKbZ?-vE#Q-Z2IXF0Ac2$QOP`vB{muNEJHCKY z7Lz;3EQ;27NPkxcNxNHSXle&JNx4rLV5YqSgH>E^mh`DQ)zKM`7A4F0T(AG)j`5MA zw=|FIS!5KU$)`^|KI_QZFLph-f}uR9YrM%!C$+>0v{Qgd-g~Ub(faS1;EVZfZ-#&6L&{To!CtvNR=G!`_Ca z!TQEUmdfEdCW~v=!@{-O=bBsX^*)Uwv=~~QviwQ(e{I^k+ON4+PxIF{7yZ=; z=W8DHdz+^Vu@J5YPryZ_Dg%%~A5~~`pp8~&i=kbr&{jg@rXg*s1d}_v&2XCtCQZY_4!dROv7o8%Fh#H( zJ1l~2$)pGx2@-lY1RF&#lIZT%<8X;5Og*^v!A(n&W;oIXKXleRLQx~!t=nV$51bDl zrZ`3Ut^`i!Ayb9(XPJvSRkp0h>zL31bmY9)pYIA!?k$SjAvT~f2bx{z!*V+++qPdv zg`a)F@T@TYQdAcDt+1N%Nk7`D5$Vrz2!6L&P5Gpab)7;f;_czCaO+d*J+G{MTnse8pw6J-nIIj!W*5y-uAPVB>X-VOh2fXs>2g(uGw-!F@M z-M^U*??7tjHJ1hSeoW&!m#3~4*sJtKOzYfS^$A1KEu8lo@D~%{NkEpio zp8zlC=M}raxt_MY|6iPHxp)LN!%;kwt6_;AyhSfK?2LP$g1=V5->l$=!R>o(Cg#hv zvJ2zMUjikNAGeJ_@((NcXa)bFg8u<--;EsaY8-)mIB&cc$!`WPfb&m{d>OcX7m}|B zA9dKbfZKNE;&ynbA)03v?4aZV?Qgnoq zp-3X$s~g+(cA@tqJ7bBskl!*Pzh$8|eEGWUb}A~8o$*P!(?kedmpyts88&s%9o}J$ z1eKq|kPHEtpHGoA+wnma(LSRSzWR<%Q)VinhOT1( zr`c*J;mXN}oTHaTew#zd&RtlKNk^$!b1aMH8BJh{U&TP$7uk%acS|)kgp)(W3ZWs0}-PAIw8-9 z`+6aImESYe@pJJ!Ir4ao9RI#=DEncB#}uBR{RSaEAmRf0f;#$rqwGH_oPq^#YeLK* z-YCQZApMpQkzb?2W`z#{na3u@QwlRg^y9rud|BxOK>8n2{5@s=RPnDB|3%>x^ksjf gB;3$8C~Q~ws=_l0FDU$3p%3$7zdD8W3R@KZ1EOnrSpWb4 literal 0 HcmV?d00001 diff --git a/labs/malloclab_lab/fsecs.c b/labs/malloclab_lab/fsecs.c new file mode 100644 index 0000000..ae2346d --- /dev/null +++ b/labs/malloclab_lab/fsecs.c @@ -0,0 +1,57 @@ +/**************************** + * High-level timing wrappers + ****************************/ +#include +#include "fsecs.h" +#include "fcyc.h" +#include "clock.h" +#include "ftimer.h" +#include "config.h" + +static double Mhz; /* estimated CPU clock frequency */ + +extern int verbose; /* -v option in mdriver.c */ + +/* + * init_fsecs - initialize the timing package + */ +void init_fsecs(void) +{ + Mhz = 0; /* keep gcc -Wall happy */ + +#if USE_FCYC + if (verbose) + printf("Measuring performance with a cycle counter.\n"); + + /* set key parameters for the fcyc package */ + set_fcyc_maxsamples(20); + set_fcyc_clear_cache(1); + set_fcyc_compensate(1); + set_fcyc_epsilon(0.01); + set_fcyc_k(3); + Mhz = mhz(verbose > 0); +#elif USE_ITIMER + if (verbose) + printf("Measuring performance with the interval timer.\n"); +#elif USE_GETTOD + if (verbose) + printf("Measuring performance with gettimeofday().\n"); +#endif +} + +/* + * fsecs - Return the running time of a function f (in seconds) + */ +double fsecs(fsecs_test_funct f, void *argp) +{ +#if USE_FCYC + double cycles = fcyc(f, argp); + return cycles/(Mhz*1e6); +#elif USE_ITIMER + return ftimer_itimer(f, argp, 10); +#elif USE_GETTOD + return ftimer_gettod(f, argp, 10); +#endif +} + + diff --git a/labs/malloclab_lab/fsecs.h b/labs/malloclab_lab/fsecs.h new file mode 100644 index 0000000..59e095d --- /dev/null +++ b/labs/malloclab_lab/fsecs.h @@ -0,0 +1,4 @@ +typedef void (*fsecs_test_funct)(void *); + +void init_fsecs(void); +double fsecs(fsecs_test_funct f, void *argp); diff --git a/labs/malloclab_lab/fsecs.o b/labs/malloclab_lab/fsecs.o new file mode 100644 index 0000000000000000000000000000000000000000..eedc7ad136bf54dc28359c2e5e7e39bca85b1d25 GIT binary patch literal 1292 zcma)6&ubG=5S~r8HfkGGJP3`t&?u?WM-p;~UKA3opjA)`fmc9HM3EM*XncTXoiC=mnwg_FB?;+*KWCRVvl>W#F~l^}>Q6 zTB_A9I)#;Hzo+_6MN~y;vD}Zn(z8-o6e|l!6m^f|!(wgRChKX&nwzohmpmilxi~{~ z9(XV7+{)T<9J3c$=Mk@Eod(BAMC-nCn~W+ckXx!6iR$U(1ZOrk_TjG+-6$bDAWDL5>@SaH^fnd2@8Cik+(3G57e!3<_EN7**B zvPo4g?!nMv`cC#l>OCJq?-^D+eAGjI^qj1>!-)$VGh*r)-{552rr$#o2k!p`!=LN` zAKk~2rm4~FnAQ3xKRqV1m5w(u4yF0k&1x5SdW6PLO QxXykmOXL9gVN^B#0g_{iw*UYD literal 0 HcmV?d00001 diff --git a/labs/malloclab_lab/ftimer.c b/labs/malloclab_lab/ftimer.c new file mode 100644 index 0000000..ea08560 --- /dev/null +++ b/labs/malloclab_lab/ftimer.c @@ -0,0 +1,106 @@ +/* + * ftimer.c - Estimate the time (in seconds) used by a function f + * + * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved. + * May not be used, modified, or copied without permission. + * + * Function timers that estimate the running time (in seconds) of a function f. + * ftimer_itimer: version that uses the interval timer + * ftimer_gettod: version that uses gettimeofday + */ +#include +#include +#include "ftimer.h" + +/* function prototypes */ +static void init_etime(void); +static double get_etime(void); + +/* + * ftimer_itimer - Use the interval timer to estimate the running time + * of f(argp). Return the average of n runs. + */ +double ftimer_itimer(ftimer_test_funct f, void *argp, int n) +{ + double start, tmeas; + int i; + + init_etime(); + start = get_etime(); + for (i = 0; i < n; i++) + f(argp); + tmeas = get_etime() - start; + return tmeas / n; +} + +/* + * ftimer_gettod - Use gettimeofday to estimate the running time of + * f(argp). Return the average of n runs. + */ +double ftimer_gettod(ftimer_test_funct f, void *argp, int n) +{ + int i; + struct timeval stv, etv; + double diff; + + gettimeofday(&stv, NULL); + for (i = 0; i < n; i++) + f(argp); + gettimeofday(&etv,NULL); + diff = 1E3*(etv.tv_sec - stv.tv_sec) + 1E-3*(etv.tv_usec-stv.tv_usec); + diff /= n; + return (1E-3*diff); +} + + +/* + * Routines for manipulating the Unix interval timer + */ + +/* The initial value of the interval timer */ +#define MAX_ETIME 86400 + +/* static variables that hold the initial value of the interval timer */ +static struct itimerval first_u; /* user time */ +static struct itimerval first_r; /* real time */ +static struct itimerval first_p; /* prof time*/ + +/* init the timer */ +static void init_etime(void) +{ + first_u.it_interval.tv_sec = 0; + first_u.it_interval.tv_usec = 0; + first_u.it_value.tv_sec = MAX_ETIME; + first_u.it_value.tv_usec = 0; + setitimer(ITIMER_VIRTUAL, &first_u, NULL); + + first_r.it_interval.tv_sec = 0; + first_r.it_interval.tv_usec = 0; + first_r.it_value.tv_sec = MAX_ETIME; + first_r.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &first_r, NULL); + + first_p.it_interval.tv_sec = 0; + first_p.it_interval.tv_usec = 0; + first_p.it_value.tv_sec = MAX_ETIME; + first_p.it_value.tv_usec = 0; + setitimer(ITIMER_PROF, &first_p, NULL); +} + +/* return elapsed real seconds since call to init_etime */ +static double get_etime(void) { + struct itimerval v_curr; + struct itimerval r_curr; + struct itimerval p_curr; + + getitimer(ITIMER_VIRTUAL, &v_curr); + getitimer(ITIMER_REAL,&r_curr); + getitimer(ITIMER_PROF,&p_curr); + + return (double) ((first_p.it_value.tv_sec - r_curr.it_value.tv_sec) + + (first_p.it_value.tv_usec - r_curr.it_value.tv_usec)*1e-6); +} + + + + diff --git a/labs/malloclab_lab/ftimer.h b/labs/malloclab_lab/ftimer.h new file mode 100644 index 0000000..3400603 --- /dev/null +++ b/labs/malloclab_lab/ftimer.h @@ -0,0 +1,14 @@ +/* + * Function timers + */ +typedef void (*ftimer_test_funct)(void *); + +/* Estimate the running time of f(argp) using the Unix interval timer. + Return the average of n runs */ +double ftimer_itimer(ftimer_test_funct f, void *argp, int n); + + +/* Estimate the running time of f(argp) using gettimeofday + Return the average of n runs */ +double ftimer_gettod(ftimer_test_funct f, void *argp, int n); + diff --git a/labs/malloclab_lab/ftimer.o b/labs/malloclab_lab/ftimer.o new file mode 100644 index 0000000000000000000000000000000000000000..e4552d7d49b57842a734fd12642243a334144db2 GIT binary patch literal 2188 zcma)7UuauZ7(X|;v6;qeoB<~*n1|~YU3O_lkvgX~By%F|n9l0MrXfv}wzxDkxsh&^ zD#WUx6!#!LihGeMK8Ucly^L(T&PQROtPA2(AL_$Us*_>-{cgUKT`PhIK7QYy-}%mW zzH`pK?;IX~-Y^WMhoQpiuBFts;a+6Khm^9^eVXcHb8~zxXUAJP+w@GEGdJ#ZyIuH_ z;v-G_hQt@rzH?D%`*L;)f!MiN&q&{ZK?iaDemGV0@_6S`d+lvC`P!?;hi^1D(_YTz zT(#=jFF-ew)KA%CQpM_$o%14ea(EHDr$9?Vd-o*+T3UR5bvhq&#W}_Fr+5(>99|^R zQ=sjF*2^&{zJKMQA33;FFCrvprl?+o)%S96+Z=w5jW7S|c2~A;p0wl3R{3nRZL|*A z-Rn>N+W2kbBZOM6J-9w?$I+X?=H>K>&h0nyueV!UYZv!2N54Pp3r~joVSv49nKt|4 zud}kX`~dnH%n$l5O$XJdt-^=%;Q_~>4?<7ySbp%2MIX{le>dybe*6yQ#X6VBKyjVh zCs17HT3e~LUoL$1`_-?Xz4OJb?Y-9G<<7# zdH8@cH1c@Qi}H2vjWaJRV<~Fvj+y3%xNh|8GpKN%S?gG6#xf5<<(*xCJj`pEv7#%X zj1~JJoU!8Xn;9$7j2yPc!UKkt$h56^_No=jcvduX#bUokAui-B=6(YFulb?(tV9;m zGr{Rj{dC1GOev@C)_ORrwOZ+v-BmG@N4H9Ss^I$|+VWmC`)e z^HsOx9636>vH) zaUTytbWfnFS75wFMTTBCxF$n?;F~f8C!e7OVLtYWxr6yqIJY_Y^w9aVtug2~)vd1f z6aV=~pdDO+wyExw34DVgbV$Ef)?^^gH=2ZK+ZJ8hF#98{`X5Z+7w+HI9wqE|u20AM z!A`TD0hPWR_Sbw8_5y_8f}N-+w=I4Ywtnl3pWGH#Wp}PpsyRh9Q*!eq8mc^3tGoFH z!G>Usj5(hzlk#HKxBEeKtJCC@UM)`-PIK9ZAR!#;UcsjY$AAV7dP1;B#MWD4e=2xh z@EgI4f>(ecH2k{QKMQUOZV6)h{yIB=rc!8 literal 0 HcmV?d00001 diff --git a/labs/malloclab_lab/mdriver b/labs/malloclab_lab/mdriver new file mode 100644 index 0000000000000000000000000000000000000000..ae6a5a14bebff45ac102afbde85f960ec7fe4446 GIT binary patch literal 32528 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 literal 0 HcmV?d00001 diff --git a/labs/malloclab_lab/mdriver.c b/labs/malloclab_lab/mdriver.c new file mode 100644 index 0000000..3aa8a3c --- /dev/null +++ b/labs/malloclab_lab/mdriver.c @@ -0,0 +1,1017 @@ +/* + * mdriver.c - CS:APP Malloc Lab Driver + * + * Uses a collection of trace files to tests a malloc/free/realloc + * implementation in mm.c. + * + * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved. + * May not be used, modified, or copied without permission. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mm.h" +#include "memlib.h" +#include "fsecs.h" +#include "config.h" + +/********************** + * Constants and macros + **********************/ + +/* Misc */ +#define MAXLINE 1024 /* max string size */ +#define HDRLINES 4 /* number of header lines in a trace file */ +#define LINENUM(i) (i+5) /* cnvt trace request nums to linenums (origin 1) */ + +/* Returns true if p is ALIGNMENT-byte aligned */ +#define IS_ALIGNED(p) ((((unsigned int)(p)) % ALIGNMENT) == 0) + +/****************************** + * The key compound data types + *****************************/ + +/* Records the extent of each block's payload */ +typedef struct range_t { + char *lo; /* low payload address */ + char *hi; /* high payload address */ + struct range_t *next; /* next list element */ +} range_t; + +/* Characterizes a single trace operation (allocator request) */ +typedef struct { + enum {ALLOC, FREE, REALLOC} type; /* type of request */ + int index; /* index for free() to use later */ + int size; /* byte size of alloc/realloc request */ +} traceop_t; + +/* Holds the information for one trace file*/ +typedef struct { + int sugg_heapsize; /* suggested heap size (unused) */ + int num_ids; /* number of alloc/realloc ids */ + int num_ops; /* number of distinct requests */ + int weight; /* weight for this trace (unused) */ + traceop_t *ops; /* array of requests */ + char **blocks; /* array of ptrs returned by malloc/realloc... */ + size_t *block_sizes; /* ... and a corresponding array of payload sizes */ +} trace_t; + +/* + * Holds the params to the xxx_speed functions, which are timed by fcyc. + * This struct is necessary because fcyc accepts only a pointer array + * as input. + */ +typedef struct { + trace_t *trace; + range_t *ranges; +} speed_t; + +/* Summarizes the important stats for some malloc function on some trace */ +typedef struct { + /* defined for both libc malloc and student malloc package (mm.c) */ + double ops; /* number of ops (malloc/free/realloc) in the trace */ + int valid; /* was the trace processed correctly by the allocator? */ + double secs; /* number of secs needed to run the trace */ + + /* defined only for the student malloc package */ + double util; /* space utilization for this trace (always 0 for libc) */ + + /* Note: secs and util are only defined if valid is true */ +} stats_t; + +/******************** + * Global variables + *******************/ +int verbose = 0; /* global flag for verbose output */ +static int errors = 0; /* number of errs found when running student malloc */ +char msg[MAXLINE]; /* for whenever we need to compose an error message */ + +/* Directory where default tracefiles are found */ +static char tracedir[MAXLINE] = TRACEDIR; + +/* The filenames of the default tracefiles */ +static char *default_tracefiles[] = { + DEFAULT_TRACEFILES, NULL +}; + + +/********************* + * Function prototypes + *********************/ + +/* these functions manipulate range lists */ +static int add_range(range_t **ranges, char *lo, int size, + int tracenum, int opnum); +static void remove_range(range_t **ranges, char *lo); +static void clear_ranges(range_t **ranges); + +/* These functions read, allocate, and free storage for traces */ +static trace_t *read_trace(char *tracedir, char *filename); +static void free_trace(trace_t *trace); + +/* Routines for evaluating the correctness and speed of libc malloc */ +static int eval_libc_valid(trace_t *trace, int tracenum); +static void eval_libc_speed(void *ptr); + +/* Routines for evaluating correctnes, space utilization, and speed + of the student's malloc package in mm.c */ +static int eval_mm_valid(trace_t *trace, int tracenum, range_t **ranges); +static double eval_mm_util(trace_t *trace, int tracenum, range_t **ranges); +static void eval_mm_speed(void *ptr); + +/* Various helper routines */ +static void printresults(int n, stats_t *stats); +static void usage(void); +static void unix_error(char *msg); +static void malloc_error(int tracenum, int opnum, char *msg); +static void app_error(char *msg); + +/************** + * Main routine + **************/ +int main(int argc, char **argv) +{ + int i; + char c; + char **tracefiles = NULL; /* null-terminated array of trace file names */ + int num_tracefiles = 0; /* the number of traces in that array */ + trace_t *trace = NULL; /* stores a single trace file in memory */ + range_t *ranges = NULL; /* keeps track of block extents for one trace */ + stats_t *libc_stats = NULL;/* libc stats for each trace */ + stats_t *mm_stats = NULL; /* mm (i.e. student) stats for each trace */ + speed_t speed_params; /* input parameters to the xx_speed routines */ + + int team_check = 1; /* If set, check team structure (reset by -a) */ + int run_libc = 0; /* If set, run libc malloc (set by -l) */ + int autograder = 0; /* If set, emit summary info for autograder (-g) */ + + /* temporaries used to compute the performance index */ + double secs, ops, util, avg_mm_util, avg_mm_throughput, p1, p2, perfindex; + int numcorrect; + + /* + * Read and interpret the command line arguments + */ + while ((c = getopt(argc, argv, "f:t:hvVgal")) != EOF) { + switch (c) { + case 'g': /* Generate summary info for the autograder */ + autograder = 1; + break; + case 'f': /* Use one specific trace file only (relative to curr dir) */ + num_tracefiles = 1; + if ((tracefiles = realloc(tracefiles, 2*sizeof(char *))) == NULL) + unix_error("ERROR: realloc failed in main"); + strcpy(tracedir, "./"); + tracefiles[0] = strdup(optarg); + tracefiles[1] = NULL; + break; + case 't': /* Directory where the traces are located */ + if (num_tracefiles == 1) /* ignore if -f already encountered */ + break; + strcpy(tracedir, optarg); + if (tracedir[strlen(tracedir)-1] != '/') + strcat(tracedir, "/"); /* path always ends with "/" */ + break; + case 'a': /* Don't check team structure */ + team_check = 0; + break; + case 'l': /* Run libc malloc */ + run_libc = 1; + break; + case 'v': /* Print per-trace performance breakdown */ + verbose = 1; + break; + case 'V': /* Be more verbose than -v */ + verbose = 2; + break; + case 'h': /* Print this message */ + usage(); + exit(0); + default: + usage(); + exit(1); + } + } + + /* + * Check and print team info + */ + if (team_check) { + /* Students must fill in their team information */ + if (!strcmp(team.teamname, "")) { + printf("ERROR: Please provide the information about your team in mm.c.\n"); + exit(1); + } else + printf("Team Name:%s\n", team.teamname); + if ((*team.name1 == '\0') || (*team.id1 == '\0')) { + printf("ERROR. You must fill in all team member 1 fields!\n"); + exit(1); + } + else + printf("Member 1 :%s:%s\n", team.name1, team.id1); + + if (((*team.name2 != '\0') && (*team.id2 == '\0')) || + ((*team.name2 == '\0') && (*team.id2 != '\0'))) { + printf("ERROR. You must fill in all or none of the team member 2 ID fields!\n"); + exit(1); + } + else if (*team.name2 != '\0') + printf("Member 2 :%s:%s\n", team.name2, team.id2); + } + + /* + * If no -f command line arg, then use the entire set of tracefiles + * defined in default_traces[] + */ + if (tracefiles == NULL) { + tracefiles = default_tracefiles; + num_tracefiles = sizeof(default_tracefiles) / sizeof(char *) - 1; + printf("Using default tracefiles in %s\n", tracedir); + } + + /* Initialize the timing package */ + init_fsecs(); + + /* + * Optionally run and evaluate the libc malloc package + */ + if (run_libc) { + if (verbose > 1) + printf("\nTesting libc malloc\n"); + + /* Allocate libc stats array, with one stats_t struct per tracefile */ + libc_stats = (stats_t *)calloc(num_tracefiles, sizeof(stats_t)); + if (libc_stats == NULL) + unix_error("libc_stats calloc in main failed"); + + /* Evaluate the libc malloc package using the K-best scheme */ + for (i=0; i < num_tracefiles; i++) { + trace = read_trace(tracedir, tracefiles[i]); + libc_stats[i].ops = trace->num_ops; + if (verbose > 1) + printf("Checking libc malloc for correctness, "); + libc_stats[i].valid = eval_libc_valid(trace, i); + if (libc_stats[i].valid) { + speed_params.trace = trace; + if (verbose > 1) + printf("and performance.\n"); + libc_stats[i].secs = fsecs(eval_libc_speed, &speed_params); + } + free_trace(trace); + } + + /* Display the libc results in a compact table */ + if (verbose) { + printf("\nResults for libc malloc:\n"); + printresults(num_tracefiles, libc_stats); + } + } + + /* + * Always run and evaluate the student's mm package + */ + if (verbose > 1) + printf("\nTesting mm malloc\n"); + + /* Allocate the mm stats array, with one stats_t struct per tracefile */ + mm_stats = (stats_t *)calloc(num_tracefiles, sizeof(stats_t)); + if (mm_stats == NULL) + unix_error("mm_stats calloc in main failed"); + + /* Initialize the simulated memory system in memlib.c */ + mem_init(); + + /* Evaluate student's mm malloc package using the K-best scheme */ + for (i=0; i < num_tracefiles; i++) { + trace = read_trace(tracedir, tracefiles[i]); + mm_stats[i].ops = trace->num_ops; + if (verbose > 1) + printf("Checking mm_malloc for correctness, "); + mm_stats[i].valid = eval_mm_valid(trace, i, &ranges); + if (mm_stats[i].valid) { + if (verbose > 1) + printf("efficiency, "); + mm_stats[i].util = eval_mm_util(trace, i, &ranges); + speed_params.trace = trace; + speed_params.ranges = ranges; + if (verbose > 1) + printf("and performance.\n"); + mm_stats[i].secs = fsecs(eval_mm_speed, &speed_params); + } + free_trace(trace); + } + + /* Display the mm results in a compact table */ + if (verbose) { + printf("\nResults for mm malloc:\n"); + printresults(num_tracefiles, mm_stats); + printf("\n"); + } + + /* + * Accumulate the aggregate statistics for the student's mm package + */ + secs = 0; + ops = 0; + util = 0; + numcorrect = 0; + for (i=0; i < num_tracefiles; i++) { + secs += mm_stats[i].secs; + ops += mm_stats[i].ops; + util += mm_stats[i].util; + if (mm_stats[i].valid) + numcorrect++; + } + avg_mm_util = util/num_tracefiles; + + /* + * Compute and print the performance index + */ + if (errors == 0) { + avg_mm_throughput = ops/secs; + + p1 = UTIL_WEIGHT * avg_mm_util; + if (avg_mm_throughput > AVG_LIBC_THRUPUT) { + p2 = (double)(1.0 - UTIL_WEIGHT); + } + else { + p2 = ((double) (1.0 - UTIL_WEIGHT)) * + (avg_mm_throughput/AVG_LIBC_THRUPUT); + } + + perfindex = (p1 + p2)*100.0; + printf("Perf index = %.0f (util) + %.0f (thru) = %.0f/100\n", + p1*100, + p2*100, + perfindex); + + } + else { /* There were errors */ + perfindex = 0.0; + printf("Terminated with %d errors\n", errors); + } + + if (autograder) { + printf("correct:%d\n", numcorrect); + printf("perfidx:%.0f\n", perfindex); + } + + exit(0); +} + + +/***************************************************************** + * The following routines manipulate the range list, which keeps + * track of the extent of every allocated block payload. We use the + * range list to detect any overlapping allocated blocks. + ****************************************************************/ + +/* + * add_range - As directed by request opnum in trace tracenum, + * we've just called the student's mm_malloc to allocate a block of + * size bytes at addr lo. After checking the block for correctness, + * we create a range struct for this block and add it to the range list. + */ +static int add_range(range_t **ranges, char *lo, int size, + int tracenum, int opnum) +{ + char *hi = lo + size - 1; + range_t *p; + char msg[MAXLINE]; + + assert(size > 0); + + /* Payload addresses must be ALIGNMENT-byte aligned */ + if (!IS_ALIGNED(lo)) { + sprintf(msg, "Payload address (%p) not aligned to %d bytes", + lo, ALIGNMENT); + malloc_error(tracenum, opnum, msg); + return 0; + } + + /* The payload must lie within the extent of the heap */ + if ((lo < (char *)mem_heap_lo()) || (lo > (char *)mem_heap_hi()) || + (hi < (char *)mem_heap_lo()) || (hi > (char *)mem_heap_hi())) { + sprintf(msg, "Payload (%p:%p) lies outside heap (%p:%p)", + lo, hi, mem_heap_lo(), mem_heap_hi()); + malloc_error(tracenum, opnum, msg); + return 0; + } + + /* The payload must not overlap any other payloads */ + for (p = *ranges; p != NULL; p = p->next) { + if ((lo >= p->lo && lo <= p-> hi) || + (hi >= p->lo && hi <= p->hi)) { + sprintf(msg, "Payload (%p:%p) overlaps another payload (%p:%p)\n", + lo, hi, p->lo, p->hi); + malloc_error(tracenum, opnum, msg); + return 0; + } + } + + /* + * Everything looks OK, so remember the extent of this block + * by creating a range struct and adding it the range list. + */ + if ((p = (range_t *)malloc(sizeof(range_t))) == NULL) + unix_error("malloc error in add_range"); + p->next = *ranges; + p->lo = lo; + p->hi = hi; + *ranges = p; + return 1; +} + +/* + * remove_range - Free the range record of block whose payload starts at lo + */ +static void remove_range(range_t **ranges, char *lo) +{ + range_t *p; + range_t **prevpp = ranges; + int size; + + for (p = *ranges; p != NULL; p = p->next) { + if (p->lo == lo) { + *prevpp = p->next; + size = p->hi - p->lo + 1; + free(p); + break; + } + prevpp = &(p->next); + } +} + +/* + * clear_ranges - free all of the range records for a trace + */ +static void clear_ranges(range_t **ranges) +{ + range_t *p; + range_t *pnext; + + for (p = *ranges; p != NULL; p = pnext) { + pnext = p->next; + free(p); + } + *ranges = NULL; +} + + +/********************************************** + * The following routines manipulate tracefiles + *********************************************/ + +/* + * read_trace - read a trace file and store it in memory + */ +static trace_t *read_trace(char *tracedir, char *filename) +{ + FILE *tracefile; + trace_t *trace; + char type[MAXLINE]; + char path[MAXLINE]; + unsigned index, size; + unsigned max_index = 0; + unsigned op_index; + + if (verbose > 1) + printf("Reading tracefile: %s\n", filename); + + /* Allocate the trace record */ + if ((trace = (trace_t *) malloc(sizeof(trace_t))) == NULL) + unix_error("malloc 1 failed in read_trance"); + + /* Read the trace file header */ + strcpy(path, tracedir); + strcat(path, filename); + if ((tracefile = fopen(path, "r")) == NULL) { + sprintf(msg, "Could not open %s in read_trace", path); + unix_error(msg); + } + fscanf(tracefile, "%d", &(trace->sugg_heapsize)); /* not used */ + fscanf(tracefile, "%d", &(trace->num_ids)); + fscanf(tracefile, "%d", &(trace->num_ops)); + fscanf(tracefile, "%d", &(trace->weight)); /* not used */ + + /* We'll store each request line in the trace in this array */ + if ((trace->ops = + (traceop_t *)malloc(trace->num_ops * sizeof(traceop_t))) == NULL) + unix_error("malloc 2 failed in read_trace"); + + /* We'll keep an array of pointers to the allocated blocks here... */ + if ((trace->blocks = + (char **)malloc(trace->num_ids * sizeof(char *))) == NULL) + unix_error("malloc 3 failed in read_trace"); + + /* ... along with the corresponding byte sizes of each block */ + if ((trace->block_sizes = + (size_t *)malloc(trace->num_ids * sizeof(size_t))) == NULL) + unix_error("malloc 4 failed in read_trace"); + + /* read every request line in the trace file */ + index = 0; + op_index = 0; + while (fscanf(tracefile, "%s", type) != EOF) { + switch(type[0]) { + case 'a': + fscanf(tracefile, "%u %u", &index, &size); + trace->ops[op_index].type = ALLOC; + trace->ops[op_index].index = index; + trace->ops[op_index].size = size; + max_index = (index > max_index) ? index : max_index; + break; + case 'r': + fscanf(tracefile, "%u %u", &index, &size); + trace->ops[op_index].type = REALLOC; + trace->ops[op_index].index = index; + trace->ops[op_index].size = size; + max_index = (index > max_index) ? index : max_index; + break; + case 'f': + fscanf(tracefile, "%ud", &index); + trace->ops[op_index].type = FREE; + trace->ops[op_index].index = index; + break; + default: + printf("Bogus type character (%c) in tracefile %s\n", + type[0], path); + exit(1); + } + op_index++; + + } + fclose(tracefile); + assert(max_index == trace->num_ids - 1); + assert(trace->num_ops == op_index); + + return trace; +} + +/* + * free_trace - Free the trace record and the three arrays it points + * to, all of which were allocated in read_trace(). + */ +void free_trace(trace_t *trace) +{ + free(trace->ops); /* free the three arrays... */ + free(trace->blocks); + free(trace->block_sizes); + free(trace); /* and the trace record itself... */ +} + +/********************************************************************** + * The following functions evaluate the correctness, space utilization, + * and throughput of the libc and mm malloc packages. + **********************************************************************/ + +/* + * eval_mm_valid - Check the mm malloc package for correctness + */ +static int eval_mm_valid(trace_t *trace, int tracenum, range_t **ranges) +{ + int i, j; + int index; + int size; + int oldsize; + char *newp; + char *oldp; + char *p; + + /* Reset the heap and free any records in the range list */ + mem_reset_brk(); + clear_ranges(ranges); + + /* Call the mm package's init function */ + if (mm_init() < 0) { + malloc_error(tracenum, 0, "mm_init failed."); + return 0; + } + + /* Interpret each operation in the trace in order */ + for (i = 0; i < trace->num_ops; i++) { + index = trace->ops[i].index; + size = trace->ops[i].size; + + switch (trace->ops[i].type) { + + case ALLOC: /* mm_malloc */ + + /* Call the student's malloc */ + if ((p = mm_malloc(size)) == NULL) { + malloc_error(tracenum, i, "mm_malloc failed."); + return 0; + } + + /* + * Test the range of the new block for correctness and add it + * to the range list if OK. The block must be be aligned properly, + * and must not overlap any currently allocated block. + */ + if (add_range(ranges, p, size, tracenum, i) == 0) + return 0; + + /* ADDED: cgw + * fill range with low byte of index. This will be used later + * if we realloc the block and wish to make sure that the old + * data was copied to the new block + */ + memset(p, index & 0xFF, size); + + /* Remember region */ + trace->blocks[index] = p; + trace->block_sizes[index] = size; + break; + + case REALLOC: /* mm_realloc */ + + /* Call the student's realloc */ + oldp = trace->blocks[index]; + if ((newp = mm_realloc(oldp, size)) == NULL) { + malloc_error(tracenum, i, "mm_realloc failed."); + return 0; + } + + /* Remove the old region from the range list */ + remove_range(ranges, oldp); + + /* Check new block for correctness and add it to range list */ + if (add_range(ranges, newp, size, tracenum, i) == 0) + return 0; + + /* ADDED: cgw + * Make sure that the new block contains the data from the old + * block and then fill in the new block with the low order byte + * of the new index + */ + oldsize = trace->block_sizes[index]; + if (size < oldsize) oldsize = size; + for (j = 0; j < oldsize; j++) { + if (newp[j] != (index & 0xFF)) { + malloc_error(tracenum, i, "mm_realloc did not preserve the " + "data from old block"); + return 0; + } + } + memset(newp, index & 0xFF, size); + + /* Remember region */ + trace->blocks[index] = newp; + trace->block_sizes[index] = size; + break; + + case FREE: /* mm_free */ + + /* Remove region from list and call student's free function */ + p = trace->blocks[index]; + remove_range(ranges, p); + mm_free(p); + break; + + default: + app_error("Nonexistent request type in eval_mm_valid"); + } + + } + + /* As far as we know, this is a valid malloc package */ + return 1; +} + +/* + * eval_mm_util - Evaluate the space utilization of the student's package + * The idea is to remember the high water mark "hwm" of the heap for + * an optimal allocator, i.e., no gaps and no internal fragmentation. + * Utilization is the ratio hwm/heapsize, where heapsize is the + * size of the heap in bytes after running the student's malloc + * package on the trace. Note that our implementation of mem_sbrk() + * doesn't allow the students to decrement the brk pointer, so brk + * is always the high water mark of the heap. + * + */ +static double eval_mm_util(trace_t *trace, int tracenum, range_t **ranges) +{ + int i; + int index; + int size, newsize, oldsize; + int max_total_size = 0; + int total_size = 0; + char *p; + char *newp, *oldp; + + /* initialize the heap and the mm malloc package */ + mem_reset_brk(); + if (mm_init() < 0) + app_error("mm_init failed in eval_mm_util"); + + for (i = 0; i < trace->num_ops; i++) { + switch (trace->ops[i].type) { + + case ALLOC: /* mm_alloc */ + index = trace->ops[i].index; + size = trace->ops[i].size; + + if ((p = mm_malloc(size)) == NULL) + app_error("mm_malloc failed in eval_mm_util"); + + /* Remember region and size */ + trace->blocks[index] = p; + trace->block_sizes[index] = size; + + /* Keep track of current total size + * of all allocated blocks */ + total_size += size; + + /* Update statistics */ + max_total_size = (total_size > max_total_size) ? + total_size : max_total_size; + break; + + case REALLOC: /* mm_realloc */ + index = trace->ops[i].index; + newsize = trace->ops[i].size; + oldsize = trace->block_sizes[index]; + + oldp = trace->blocks[index]; + if ((newp = mm_realloc(oldp,newsize)) == NULL) + app_error("mm_realloc failed in eval_mm_util"); + + /* Remember region and size */ + trace->blocks[index] = newp; + trace->block_sizes[index] = newsize; + + /* Keep track of current total size + * of all allocated blocks */ + total_size += (newsize - oldsize); + + /* Update statistics */ + max_total_size = (total_size > max_total_size) ? + total_size : max_total_size; + break; + + case FREE: /* mm_free */ + index = trace->ops[i].index; + size = trace->block_sizes[index]; + p = trace->blocks[index]; + + mm_free(p); + + /* Keep track of current total size + * of all allocated blocks */ + total_size -= size; + + break; + + default: + app_error("Nonexistent request type in eval_mm_util"); + + } + } + + return ((double)max_total_size / (double)mem_heapsize()); +} + + +/* + * eval_mm_speed - This is the function that is used by fcyc() + * to measure the running time of the mm malloc package. + */ +static void eval_mm_speed(void *ptr) +{ + int i, index, size, newsize; + char *p, *newp, *oldp, *block; + trace_t *trace = ((speed_t *)ptr)->trace; + + /* Reset the heap and initialize the mm package */ + mem_reset_brk(); + if (mm_init() < 0) + app_error("mm_init failed in eval_mm_speed"); + + /* Interpret each trace request */ + for (i = 0; i < trace->num_ops; i++) + switch (trace->ops[i].type) { + + case ALLOC: /* mm_malloc */ + index = trace->ops[i].index; + size = trace->ops[i].size; + if ((p = mm_malloc(size)) == NULL) + app_error("mm_malloc error in eval_mm_speed"); + trace->blocks[index] = p; + break; + + case REALLOC: /* mm_realloc */ + index = trace->ops[i].index; + newsize = trace->ops[i].size; + oldp = trace->blocks[index]; + if ((newp = mm_realloc(oldp,newsize)) == NULL) + app_error("mm_realloc error in eval_mm_speed"); + trace->blocks[index] = newp; + break; + + case FREE: /* mm_free */ + index = trace->ops[i].index; + block = trace->blocks[index]; + mm_free(block); + break; + + default: + app_error("Nonexistent request type in eval_mm_valid"); + } +} + +/* + * eval_libc_valid - We run this function to make sure that the + * libc malloc can run to completion on the set of traces. + * We'll be conservative and terminate if any libc malloc call fails. + * + */ +static int eval_libc_valid(trace_t *trace, int tracenum) +{ + int i, newsize; + char *p, *newp, *oldp; + + for (i = 0; i < trace->num_ops; i++) { + switch (trace->ops[i].type) { + + case ALLOC: /* malloc */ + if ((p = malloc(trace->ops[i].size)) == NULL) { + malloc_error(tracenum, i, "libc malloc failed"); + unix_error("System message"); + } + trace->blocks[trace->ops[i].index] = p; + break; + + case REALLOC: /* realloc */ + newsize = trace->ops[i].size; + oldp = trace->blocks[trace->ops[i].index]; + if ((newp = realloc(oldp, newsize)) == NULL) { + malloc_error(tracenum, i, "libc realloc failed"); + unix_error("System message"); + } + trace->blocks[trace->ops[i].index] = newp; + break; + + case FREE: /* free */ + free(trace->blocks[trace->ops[i].index]); + break; + + default: + app_error("invalid operation type in eval_libc_valid"); + } + } + + return 1; +} + +/* + * eval_libc_speed - This is the function that is used by fcyc() to + * measure the running time of the libc malloc package on the set + * of traces. + */ +static void eval_libc_speed(void *ptr) +{ + int i; + int index, size, newsize; + char *p, *newp, *oldp, *block; + trace_t *trace = ((speed_t *)ptr)->trace; + + for (i = 0; i < trace->num_ops; i++) { + switch (trace->ops[i].type) { + case ALLOC: /* malloc */ + index = trace->ops[i].index; + size = trace->ops[i].size; + if ((p = malloc(size)) == NULL) + unix_error("malloc failed in eval_libc_speed"); + trace->blocks[index] = p; + break; + + case REALLOC: /* realloc */ + index = trace->ops[i].index; + newsize = trace->ops[i].size; + oldp = trace->blocks[index]; + if ((newp = realloc(oldp, newsize)) == NULL) + unix_error("realloc failed in eval_libc_speed\n"); + + trace->blocks[index] = newp; + break; + + case FREE: /* free */ + index = trace->ops[i].index; + block = trace->blocks[index]; + free(block); + break; + } + } +} + +/************************************* + * Some miscellaneous helper routines + ************************************/ + + +/* + * printresults - prints a performance summary for some malloc package + */ +static void printresults(int n, stats_t *stats) +{ + int i; + double secs = 0; + double ops = 0; + double util = 0; + + /* Print the individual results for each trace */ + printf("%5s%7s %5s%8s%10s%6s\n", + "trace", " valid", "util", "ops", "secs", "Kops"); + for (i=0; i < n; i++) { + if (stats[i].valid) { + printf("%2d%10s%5.0f%%%8.0f%10.6f%6.0f\n", + i, + "yes", + stats[i].util*100.0, + stats[i].ops, + stats[i].secs, + (stats[i].ops/1e3)/stats[i].secs); + secs += stats[i].secs; + ops += stats[i].ops; + util += stats[i].util; + } + else { + printf("%2d%10s%6s%8s%10s%6s\n", + i, + "no", + "-", + "-", + "-", + "-"); + } + } + + /* Print the aggregate results for the set of traces */ + if (errors == 0) { + printf("%12s%5.0f%%%8.0f%10.6f%6.0f\n", + "Total ", + (util/n)*100.0, + ops, + secs, + (ops/1e3)/secs); + } + else { + printf("%12s%6s%8s%10s%6s\n", + "Total ", + "-", + "-", + "-", + "-"); + } + +} + +/* + * app_error - Report an arbitrary application error + */ +void app_error(char *msg) +{ + printf("%s\n", msg); + exit(1); +} + +/* + * unix_error - Report a Unix-style error + */ +void unix_error(char *msg) +{ + printf("%s: %s\n", msg, strerror(errno)); + exit(1); +} + +/* + * malloc_error - Report an error returned by the mm_malloc package + */ +void malloc_error(int tracenum, int opnum, char *msg) +{ + errors++; + printf("ERROR [trace %d, line %d]: %s\n", tracenum, LINENUM(opnum), msg); +} + +/* + * usage - Explain the command line arguments + */ +static void usage(void) +{ + fprintf(stderr, "Usage: mdriver [-hvVal] [-f ] [-t ]\n"); + fprintf(stderr, "Options\n"); + fprintf(stderr, "\t-a Don't check the team structure.\n"); + fprintf(stderr, "\t-f Use as the trace file.\n"); + fprintf(stderr, "\t-g Generate summary info for autograder.\n"); + fprintf(stderr, "\t-h Print this message.\n"); + fprintf(stderr, "\t-l Run libc malloc as well.\n"); + fprintf(stderr, "\t-t Directory to find default traces.\n"); + fprintf(stderr, "\t-v Print per-trace performance breakdowns.\n"); + fprintf(stderr, "\t-V Print additional debug info.\n"); +} diff --git a/labs/malloclab_lab/mdriver.o b/labs/malloclab_lab/mdriver.o new file mode 100644 index 0000000000000000000000000000000000000000..632c774937080fca2be4865694e625034c67e787 GIT binary patch literal 19476 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 WT1o+1 +#include +#include +#include +#include +#include +#include + +#include "memlib.h" +#include "config.h" + +/* private variables */ +static char *mem_start_brk; /* points to first byte of heap */ +static char *mem_brk; /* points to last byte of heap */ +static char *mem_max_addr; /* largest legal heap address */ + +/* + * mem_init - initialize the memory system model + */ +void mem_init(void) +{ + /* allocate the storage we will use to model the available VM */ + if ((mem_start_brk = (char *)malloc(MAX_HEAP)) == NULL) { + fprintf(stderr, "mem_init_vm: malloc error\n"); + exit(1); + } + + mem_max_addr = mem_start_brk + MAX_HEAP; /* max legal heap address */ + mem_brk = mem_start_brk; /* heap is empty initially */ +} + +/* + * mem_deinit - free the storage used by the memory system model + */ +void mem_deinit(void) +{ + free(mem_start_brk); +} + +/* + * mem_reset_brk - reset the simulated brk pointer to make an empty heap + */ +void mem_reset_brk() +{ + mem_brk = mem_start_brk; +} + +/* + * mem_sbrk - simple model of the sbrk function. Extends the heap + * by incr bytes and returns the start address of the new area. In + * this model, the heap cannot be shrunk. + */ +void *mem_sbrk(int incr) +{ + char *old_brk = mem_brk; + + if ( (incr < 0) || ((mem_brk + incr) > mem_max_addr)) { + errno = ENOMEM; + fprintf(stderr, "ERROR: mem_sbrk failed. Ran out of memory...\n"); + return (void *)-1; + } + mem_brk += incr; + return (void *)old_brk; +} + +/* + * mem_heap_lo - return address of the first heap byte + */ +void *mem_heap_lo() +{ + return (void *)mem_start_brk; +} + +/* + * mem_heap_hi - return address of last heap byte + */ +void *mem_heap_hi() +{ + return (void *)(mem_brk - 1); +} + +/* + * mem_heapsize() - returns the heap size in bytes + */ +size_t mem_heapsize() +{ + return (size_t)(mem_brk - mem_start_brk); +} + +/* + * mem_pagesize() - returns the page size of the system + */ +size_t mem_pagesize() +{ + return (size_t)getpagesize(); +} diff --git a/labs/malloclab_lab/memlib.h b/labs/malloclab_lab/memlib.h new file mode 100644 index 0000000..247c732 --- /dev/null +++ b/labs/malloclab_lab/memlib.h @@ -0,0 +1,11 @@ +#include + +void mem_init(void); +void mem_deinit(void); +void *mem_sbrk(int incr); +void mem_reset_brk(void); +void *mem_heap_lo(void); +void *mem_heap_hi(void); +size_t mem_heapsize(void); +size_t mem_pagesize(void); + diff --git a/labs/malloclab_lab/memlib.o b/labs/malloclab_lab/memlib.o new file mode 100644 index 0000000000000000000000000000000000000000..90193bd59dfddbb7795d61c5bf807e428d257d75 GIT binary patch literal 2284 zcma)8L1-LR82)E>V`H1HR*e)JaD=t3mJHdjN~wyGB=(@xu(Svj+{|X)W|!>ll-b#4 zTSP0d(jW_a=)r>rOFc&LAfi$*bc?-;SFb%(%*DG9zwga^n`!Xi5C44c`~UxaZ{C}k zfA^Ecci(m#N31!Ll|3d>$|jkThLe()L$*}o#?I9JTtQ^cdHB!n?(X&N+vAAGll=i> zo0BZMox^40-qi3G+5LsW_;U&7xRRbOvbj*0&=TMb>v3%W{aaMr%oTKmGW{PAkp3^c z>ZD#^IOxa6h4ozSi}MBd`tQA?&fVAaJ*?+9C+%&pE?G(@C_x?G)pUaYc~?JTbGuyp zufv11>Gg;G%hJDdf;xKfjfc*#|NZe1KQ+cJ47u)~JSC8pYE>HTMqIhvI^(wdW;0xI zRTPEML6OCB`MoltDCtzAHMizBnkw+zvfp;YZtR9N=ECTT=XoeUJ3oKMJ$a$pZO2`= zoIDA>1iuEiZv-_0I3B(DaOx~WXYo)EGepn%jB%{_7!gLDFNugf z&H#+DEx3yq9}tbPZTJjgV?b?Q=SnN~tKxOyD8afNMXKq=suznF_^~fuwbKzV3Q1U9 z^ooztl6Wg&tEJkQ(GFwfojrG9x)b{=Yp8>ks#j`}-%@tz|AWt?2)8@h>m0_fFkp;( zq8)?Vy_4@8NcPITvz%wg7wAR9%_k|nlonFDj(7^r`gEN=N9L(Vn}JhemIOvU-itNn z=x-XdbvF_8Y!Q%ptUG6ry0p6pzMKs8l{NJD4eB5+I}E1G(lx|5&X^qQeoNKaeXJsu zKEEw&ehxA2nQ?o5M=-W$f}z}jaF+vPcHQ)vOa*x1wh=sxF`asRcGOPm74Y1CMa-Jj zv)p1jo|C`X4o3E9_oaS%1#-LVWJ(ra1A2gd-pn}2^LwUQ&i966%bBy59lf1NB&(Hd zmg}WYmi&OQPtw>cp2CW+YL;AhE^qAP3;Xyx`}h+0GMxQ|dLIC-QEwT34bDEpd>c4` z`-ZOrt+D==w!;d3 z8vM8swsl=y`Iivc8`m47ai?)L5xeBCDos{ZJQ^qGm&tR_I3BzVu0h>b!1+x(PvG~5 zIF@|R863bx@C-hlz|=R%pBDMl@XrnMoT>Yb!7YP70W;5v+#`qnA4I%X4;Y6&|9)`Z m5rZ!nJYld1%%Cy3tj9O|y20}X>jwGUng7b*cLupG +#include +#include +#include +#include + +#include "mm.h" +#include "memlib.h" + +/********************************************************* + * NOTE TO STUDENTS: Before you do anything else, please + * provide your team information in the following struct. + ********************************************************/ +team_t team = { + /* Team name */ + "ateam", + /* First member's full name */ + "Harry Bovik", + /* First member's email address */ + "bovik@cs.cmu.edu", + /* Second member's full name (leave blank if none) */ + "", + /* Second member's email address (leave blank if none) */ + "" +}; + +/* single word (4) or double word (8) alignment */ +#define ALIGNMENT 8 + +/* rounds up to the nearest multiple of ALIGNMENT */ +#define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~0x7) + + +#define SIZE_T_SIZE (ALIGN(sizeof(size_t))) + +/* + * mm_init - initialize the malloc package. + */ +int mm_init(void) +{ + return 0; +} + +/* + * mm_malloc - Allocate a block by incrementing the brk pointer. + * Always allocate a block whose size is a multiple of the alignment. + */ +void *mm_malloc(size_t size) +{ + int newsize = ALIGN(size + SIZE_T_SIZE); + void *p = mem_sbrk(newsize); + if (p == (void *)-1) + return NULL; + else { + *(size_t *)p = size; + return (void *)((char *)p + SIZE_T_SIZE); + } +} + +/* + * mm_free - Freeing a block does nothing. + */ +void mm_free(void *ptr) +{ +} + +/* + * mm_realloc - Implemented simply in terms of mm_malloc and mm_free + */ +void *mm_realloc(void *ptr, size_t size) +{ + void *oldptr = ptr; + void *newptr; + size_t copySize; + + newptr = mm_malloc(size); + if (newptr == NULL) + return NULL; + copySize = *(size_t *)((char *)oldptr - SIZE_T_SIZE); + if (size < copySize) + copySize = size; + memcpy(newptr, oldptr, copySize); + mm_free(oldptr); + return newptr; +} + + + + + + + + + + + + + + diff --git a/labs/malloclab_lab/mm.h b/labs/malloclab_lab/mm.h new file mode 100644 index 0000000..d41eef7 --- /dev/null +++ b/labs/malloclab_lab/mm.h @@ -0,0 +1,23 @@ +#include + +extern int mm_init (void); +extern void *mm_malloc (size_t size); +extern void mm_free (void *ptr); +extern void *mm_realloc(void *ptr, size_t size); + + +/* + * Students work in teams of one or two. Teams enter their team name, + * personal names and login IDs in a struct of this + * type in their bits.c file. + */ +typedef struct { + char *teamname; /* ID1+ID2 or ID1 */ + char *name1; /* full name of first member */ + char *id1; /* login ID of first member */ + char *name2; /* full name of second member (if any) */ + char *id2; /* login ID of second member */ +} team_t; + +extern team_t team; + diff --git a/labs/malloclab_lab/mm.o b/labs/malloclab_lab/mm.o new file mode 100644 index 0000000000000000000000000000000000000000..19793166db68252f7e0a95a7d4542a642fe39da1 GIT binary patch literal 2160 zcma)7&ube;6dq}nRB_a`Yzz&=Z3T6MOPxUqrX;0MuNBEAb?s2wNx?L0NnZcJT1l){ z#V)0xC{1mQA*WtisIR^CP`&|?lhB=lmaLH)kn8EbI^?Sr@9``&x=X6DU| z^sq2hjKyL?OH3G|%Y@jw5JpA=7#97aFNj}K1ODoLk9`!hYm@)J06 zorUcaI!nG&a>ZoH^ENZ%_0QMVMVa5RN>f(cmUNa{VG}L_`k`+r-5DG@5EJ?Q`q~JG}Cu_%+&1zGim*1ChlC$ zo2k4aYFq=j2vx@}mS8`E(qDzL<~OYQtzntz#|g_EXkVB%M`q0Iq?wsFhb(j0GDoa{ z7JAG9>%dH7vXu1{lOBbW4q(!BKH?15e9Za~?)_yFy_X5`q7%(A*tLil=c*WII|`Ew z!Bgvsan{AqX9#`6HNV_VhGhgN)^!=;)h-F*J?D7rY(}0}Kh|pk^;wZ$iHzuvUlKCH znRojf{}_A`%CqA5d7wTga>lf9{E8yHQ+?d8>&gl~_F8StC%UC-wO$dny>atBx#IYC zqhkB3t=hUQZwPy0YG&M;vS*6L*}|MXXN^x4Y~ebt-7I_S9KP&14$*VMI*3&on<98c zuVK!3uMn>Td$5=+FwrN(rt&{j{_m9kSE9Q7F>H``f|yju_d?En5i`Izt^j|hh`z!t zh0lp>ylif|eyI%fy%1Nm#aC)A+3@NO$MZMC+RiH4SaKa9SG;=jxbDEmi!6Uuj_Z~qwVKcHIJPs&v&U%(iYvWmesfvm@u##*fZHk9@FTSXa+ zK2mT^--XTm|H{j%F*kq|)*A}V;LCc{yh2@X3{G`jf;_H|@*y<3k39s2;p0Ad9rQkC zVYBWPKG~I%a>rm4MdHQ#q>3R)6 z!sZyAw+C{{1SLA}d+_Lfe@8&?m%mWV<2giYfr=kcco9yXzs{r0TDr$D#VJVeKR^Ou T9SZMWH19bk`Z +#include +#include +#include +#include +#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 = 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; +} diff --git a/quiz/storage_mountain/clock.h b/quiz/storage_mountain/clock.h new file mode 100644 index 0000000..e56bf53 --- /dev/null +++ b/quiz/storage_mountain/clock.h @@ -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(); diff --git a/quiz/storage_mountain/fcyc2.c b/quiz/storage_mountain/fcyc2.c new file mode 100644 index 0000000..0751d3e --- /dev/null +++ b/quiz/storage_mountain/fcyc2.c @@ -0,0 +1,299 @@ +/* Compute time used by a function f that takes two integer args */ +#include +#include +#include + +#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 + +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 = 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); +} + + + + + + diff --git a/quiz/storage_mountain/fcyc2.h b/quiz/storage_mountain/fcyc2.h new file mode 100644 index 0000000..7097c18 --- /dev/null +++ b/quiz/storage_mountain/fcyc2.h @@ -0,0 +1,41 @@ +/* Find number of cycles used by function that takes 2 arguments */ + +/* Function to be tested takes two integer arguments */ +typedef int (*test_funct)(int, int); + +/* Compute time used by function f */ +double fcyc2(test_funct f, int param1, int param2, int clear_cache); + +/********* These routines are used to help with the analysis *********/ + +/* +Parameters: + k: How many samples must be within epsilon for convergence + epsilon: What is tolerance + maxsamples: How many samples until give up? +*/ + +/* Full version of fcyc with control over parameters */ +double fcyc2_full(test_funct f, int param1, int param2, int clear_cache, + int k, double epsilon, int maxsamples, int compensate); + +/* Get current minimum */ +double get_min(); + +/* What is convergence status for k minimum measurements within epsilon + Returns 0 if not converged, #samples if converged, and -1 if can't + reach convergence +*/ + +int has_converged(int k, double epsilon, int maxsamples); + +/* What is error of current measurement */ +double err(int k); + +/************* Try other clocking methods *****************/ + +/* Full version that uses the time of day clock */ +double fcyc2_full_tod(test_funct f, int param1, int param2, int clear_cache, + int k, double epsilon, int maxsamples, int compensate); + +double fcyc2_tod(test_funct f, int param1, int param2, int clear_cache); diff --git a/quiz/storage_mountain/mountain.c b/quiz/storage_mountain/mountain.c new file mode 100644 index 0000000..e343497 --- /dev/null +++ b/quiz/storage_mountain/mountain.c @@ -0,0 +1,116 @@ +/* mountain.c - Generate the memory mountain. */ +/* $begin mountainmain */ +#include +#include +#include "fcyc2.h" /* measurement routines */ +#include "clock.h" /* routines to access the cycle counter */ + +#define MINBYTES (1 << 14) /* First working set size */ +#define MAXBYTES (1 << 27) /* Last working set size */ +#define MAXSTRIDE 15 /* Stride x8 bytes */ +#define MAXELEMS MAXBYTES/sizeof(long) + +/* $begin mountainfuns */ +long data[MAXELEMS]; /* The global array we'll be traversing */ + +/* $end mountainfuns */ +/* $end mountainmain */ +void init_data(long *data, int n); +int test(int elems, int stride); +double run(int size, int stride, double Mhz); + +/* $begin mountainmain */ +int main() +{ + int size; /* Working set size (in bytes) */ + int stride; /* Stride (in array elements) */ + double Mhz; /* Clock frequency */ + + FILE *fp = NULL; + fp = fopen("mountain.txt", "w+"); + + init_data(data, MAXELEMS); /* Initialize each element in data */ + Mhz = mhz(0); /* Estimate the clock frequency */ +/* $end mountainmain */ + /* Not shown in the text */ + fprintf(fp, "Clock frequency is approx. %.1f MHz\n", Mhz); + fprintf(fp, "Memory mountain (MB/sec)\n"); + + fprintf(fp, "\t"); + for (stride = 1; stride <= MAXSTRIDE; stride++) + fprintf(fp, "s%d\t", stride); + fprintf(fp, "\n"); + + /* $begin mountainmain */ + for (size = MAXBYTES; size >= MINBYTES; size >>= 1) { +/* $end mountainmain */ + /* Not shown in the text */ + if (size > (1 << 20)) + fprintf(fp, "%dm\t", size / (1 << 20)); + else + fprintf(fp, "%dk\t", size / 1024); + +/* $begin mountainmain */ + for (stride = 1; stride <= MAXSTRIDE; stride++) { + fprintf(fp, "%.0f\t", run(size, stride, Mhz)); + + } + fprintf(fp, "\n"); + } + + fclose(fp); + exit(0); +} +/* $end mountainmain */ + +/* init_data - initializes the array */ +void init_data(long *data, int n) +{ + int i; + + for (i = 0; i < n; i++) + data[i] = i; +} + +/* $begin mountainfuns */ +/* test - Iterate over first "elems" elements of array "data" with + * stride of "stride", using 4x4 loop unrolling. + */ +int test(int elems, int stride) +{ + long i, sx2 = stride*2, sx3 = stride*3, sx4 = stride*4; + long acc0 = 0, acc1 = 0, acc2 = 0, acc3 = 0; + long length = elems; + long limit = length - sx4; + + /* Combine 4 elements at a time */ + for (i = 0; i < limit; i += sx4) { + acc0 = acc0 + data[i]; + acc1 = acc1 + data[i+stride]; + acc2 = acc2 + data[i+sx2]; + acc3 = acc3 + data[i+sx3]; + } + + /* Finish any remaining elements */ + for (; i < length; i += stride) { + acc0 = acc0 + data[i]; + } + return ((acc0 + acc1) + (acc2 + acc3)); +} + +/* run - Run test(elems, stride) and return read throughput (MB/s). + * "size" is in bytes, "stride" is in array elements, and Mhz is + * CPU clock frequency in Mhz. + */ +double run(int size, int stride, double Mhz) +{ + double cycles; + int elems = size / sizeof(double); + + test(elems, stride); /* Warm up the cache */ //line:mem:warmup + cycles = fcyc2(test, elems, stride, 0); /* Call test(elems,stride) */ //line:mem:fcyc + return (size / stride) / (cycles / Mhz); /* Convert cycles to MB/s */ //line:mem:bwcompute +} +/* $end mountainfuns */ + + diff --git a/quiz/storage_mountain/mountain.h b/quiz/storage_mountain/mountain.h new file mode 100644 index 0000000..99decd1 --- /dev/null +++ b/quiz/storage_mountain/mountain.h @@ -0,0 +1,45 @@ +// +// Created by GentleCold on 2022/11/7. +// + +#ifndef CSAPPLEARNING_MOUNTAIN_H +#define CSAPPLEARNING_MOUNTAIN_H + +#include + +#define MAXELEMS 10000 +long data[MAXELEMS]; + +int read(int elems, int stride) { + long i, sx2 = stride * 2, sx3 = stride * 3, sx4 = stride * 4; + long acc0 = 0, acc1 = 0, acc2 = 0, acc3 = 0; + long length = elems; + long limit = length - sx4; + + for (i = 0; i < limit; i += sx4) { + acc0 += data[i]; + acc1 += data[i + stride]; + acc2 += data[i + sx2]; + acc3 += data[i + sx3]; + } + + for (; i < length; i += stride) { + acc0 += data[i]; + } + + return ((acc0 + acc1) + (acc2 + acc3)); +} + +double run(int size, int stride, double Mhz) { + double cycles; + int elems = size / sizeof(double); + + read(elems, stride); + cycles = fcyc2(); +} + +int mountain() { + +} + +#endif //CSAPPLEARNING_MOUNTAIN_H diff --git a/quiz/test_quiz.c b/quiz/test_quiz.c index 2bf9a41..f636cbb 100644 --- a/quiz/test_quiz.c +++ b/quiz/test_quiz.c @@ -3,7 +3,7 @@ // #include "test.h" - +#include "storage_mountain/mountain.h" void test_all() { EXPECT_EQ_TRUE(-1 > 0x80); // compare as int