commit 1667f3744a4b90c90a636c9c61d68aed3f2d0dfc Author: TuDatTr Date: Fri Dec 11 15:48:42 2020 +0100 Initial commit diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1712d8c --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +# +# Student makefile for Cache Lab +# Note: requires a 64-bit x86-64 system +# +CC = gcc +CFLAGS = -g -Wall -Werror -std=c99 -m64 + +all: csim test-trans tracegen + # Generate a handin tar file each time you compile + -tar -cvf ${USER}-handin.tar csim.c trans.c + +csim: csim.c cachelab.c cachelab.h + $(CC) $(CFLAGS) -o csim csim.c cachelab.c -lm + +test-trans: test-trans.c trans.o cachelab.c cachelab.h + $(CC) $(CFLAGS) -o test-trans test-trans.c cachelab.c trans.o + +tracegen: tracegen.c trans.o cachelab.c + $(CC) $(CFLAGS) -O0 -o tracegen tracegen.c trans.o cachelab.c + +trans.o: trans.c + $(CC) $(CFLAGS) -O0 -c trans.c + +# +# Clean the src dirctory +# +clean: + rm -rf *.o + rm -f *.tar + rm -f csim + rm -f test-trans tracegen + rm -f trace.all trace.f* + rm -f .csim_results .marker diff --git a/README b/README new file mode 100644 index 0000000..5af6f01 --- /dev/null +++ b/README @@ -0,0 +1,39 @@ +This is the handout directory for the CS:APP Cache Lab. + +************************ +Running the autograders: +************************ + +Before running the autograders, compile your code: + linux> make + +Check the correctness of your simulator: + linux> ./test-csim + +Check the correctness and performance of your transpose functions: + linux> ./test-trans -M 32 -N 32 + linux> ./test-trans -M 64 -N 64 + linux> ./test-trans -M 61 -N 67 + +Check everything at once (this is the program that your instructor runs): + linux> ./driver.py + +****** +Files: +****** + +# You will modifying and handing in these two files +csim.c Your cache simulator +trans.c Your transpose function + +# Tools for evaluating your simulator and transpose function +Makefile Builds the simulator and tools +README This file +driver.py* The driver program, runs test-csim and test-trans +cachelab.c Required helper functions +cachelab.h Required header file +csim-ref* The executable reference cache simulator +test-csim* Tests your cache simulator +test-trans.c Tests your transpose function +tracegen.c Helper program used by test-trans +traces/ Trace files used by test-csim.c diff --git a/cachelab.c b/cachelab.c new file mode 100644 index 0000000..85ac5e4 --- /dev/null +++ b/cachelab.c @@ -0,0 +1,83 @@ +/* + * cachelab.c - Cache Lab helper functions + */ +#include +#include +#include +#include "cachelab.h" +#include + +trans_func_t func_list[MAX_TRANS_FUNCS]; +int func_counter = 0; + +/* + * printSummary - Summarize the cache simulation statistics. Student cache simulators + * must call this function in order to be properly autograded. + */ +void printSummary(int hits, int misses, int evictions) +{ + printf("hits:%d misses:%d evictions:%d\n", hits, misses, evictions); + FILE* output_fp = fopen(".csim_results", "w"); + assert(output_fp); + fprintf(output_fp, "%d %d %d\n", hits, misses, evictions); + fclose(output_fp); +} + +/* + * initMatrix - Initialize the given matrix + */ +void initMatrix(int M, int N, int A[N][M], int B[M][N]) +{ + int i, j; + srand(time(NULL)); + for (i = 0; i < N; i++){ + for (j = 0; j < M; j++){ + // A[i][j] = i+j; /* The matrix created this way is symmetric */ + A[i][j]=rand(); + B[j][i]=rand(); + } + } +} + +void randMatrix(int M, int N, int A[N][M]) { + int i, j; + srand(time(NULL)); + for (i = 0; i < N; i++){ + for (j = 0; j < M; j++){ + // A[i][j] = i+j; /* The matrix created this way is symmetric */ + A[i][j]=rand(); + } + } +} + +/* + * correctTrans - baseline transpose function used to evaluate correctness + */ +void correctTrans(int M, int N, int A[N][M], int B[M][N]) +{ + int i, j, tmp; + for (i = 0; i < N; i++){ + for (j = 0; j < M; j++){ + tmp = A[i][j]; + B[j][i] = tmp; + } + } +} + + + +/* + * registerTransFunction - Add the given trans function into your list + * of functions to be tested + */ +void registerTransFunction(void (*trans)(int M, int N, int[N][M], int[M][N]), + char* desc) +{ + func_list[func_counter].func_ptr = trans; + func_list[func_counter].description = desc; + func_list[func_counter].correct = 0; + func_list[func_counter].num_hits = 0; + func_list[func_counter].num_misses = 0; + func_list[func_counter].num_evictions =0; + func_counter++; +} diff --git a/cachelab.h b/cachelab.h new file mode 100644 index 0000000..02f7730 --- /dev/null +++ b/cachelab.h @@ -0,0 +1,37 @@ +/* + * cachelab.h - Prototypes for Cache Lab helper functions + */ + +#ifndef CACHELAB_TOOLS_H +#define CACHELAB_TOOLS_H + +#define MAX_TRANS_FUNCS 100 + +typedef struct trans_func{ + void (*func_ptr)(int M,int N,int[N][M],int[M][N]); + char* description; + char correct; + unsigned int num_hits; + unsigned int num_misses; + unsigned int num_evictions; +} trans_func_t; + +/* + * printSummary - This function provides a standard way for your cache + * simulator * to display its final hit and miss statistics + */ +void printSummary(int hits, /* number of hits */ + int misses, /* number of misses */ + int evictions); /* number of evictions */ + +/* Fill the matrix with data */ +void initMatrix(int M, int N, int A[N][M], int B[M][N]); + +/* The baseline trans function that produces correct results. */ +void correctTrans(int M, int N, int A[N][M], int B[M][N]); + +/* Add the given function to the function list */ +void registerTransFunction( + void (*trans)(int M,int N,int[N][M],int[M][N]), char* desc); + +#endif /* CACHELAB_TOOLS_H */ diff --git a/csim-ref b/csim-ref new file mode 100755 index 0000000..ef7cb79 Binary files /dev/null and b/csim-ref differ diff --git a/csim.c b/csim.c new file mode 100644 index 0000000..2b6c08c --- /dev/null +++ b/csim.c @@ -0,0 +1,13 @@ +#include "cachelab.h" + +struct cache_line { + unsigned char v; + unsigned int tag; + unsigned long timestamp; +}; + +int main() +{ + printSummary(0, 0, 0); + return 0; +} diff --git a/driver.py b/driver.py new file mode 100755 index 0000000..98d7f24 --- /dev/null +++ b/driver.py @@ -0,0 +1,137 @@ +#!/usr//bin/python2.7 +# +# driver.py - The driver tests the correctness of the student's cache +# simulator and the correctness and performance of their transpose +# function. It uses ./test-csim to check the correctness of the +# simulator and it runs ./test-trans on three different sized +# matrices (32x32, 64x64, and 61x67) to test the correctness and +# performance of the transpose function. +# +import subprocess; +import re; +import os; +import sys; +import optparse; + +# +# computeMissScore - compute the score depending on the number of +# cache misses +# +def computeMissScore(miss, lower, upper, full_score): + if miss <= lower: + return full_score + if miss >= upper: + return 0 + + score = (miss - lower) * 1.0 + range = (upper- lower) * 1.0 + return round((1 - score / range) * full_score, 1) + +# +# main - Main function +# +def main(): + + # Configure maxscores here + maxscore= {}; + maxscore['csim'] = 51 + maxscore['transc'] = 1 + maxscore['trans32'] = 15 + maxscore['trans64'] = 15 + maxscore['trans61'] = 19 + + # Parse the command line arguments + p = optparse.OptionParser() + p.add_option("-A", action="store_true", dest="autograde", + help="emit autoresult string for Autolab"); + opts, args = p.parse_args() + autograde = opts.autograde + + # Check the correctness of the cache simulator + print "Part A: Testing cache simulator" + print "Running ./test-csim" + p = subprocess.Popen("./test-csim", + shell=True, stdout=subprocess.PIPE) + stdout_data = p.communicate()[0] + + # Emit the output from test-csim + stdout_data = re.split('\n', stdout_data) + for line in stdout_data: + if re.match("TEST_CSIM_RESULTS", line): + resultsim = re.findall(r'(\d+)', line) + else: + print "%s" % (line) + + # Check the correctness and performance of the transpose function + # 32x32 transpose + print "Part B: Testing transpose function" + print "Running ./test-trans -M 32 -N 32" + p = subprocess.Popen("./test-trans -M 32 -N 32 | grep TEST_TRANS_RESULTS", + shell=True, stdout=subprocess.PIPE) + stdout_data = p.communicate()[0] + result32 = re.findall(r'(\d+)', stdout_data) + + # 64x64 transpose + print "Running ./test-trans -M 64 -N 64" + p = subprocess.Popen("./test-trans -M 64 -N 64 | grep TEST_TRANS_RESULTS", + shell=True, stdout=subprocess.PIPE) + stdout_data = p.communicate()[0] + result64 = re.findall(r'(\d+)', stdout_data) + + # 61x67 transpose + print "Running ./test-trans -M 61 -N 67" + p = subprocess.Popen("./test-trans -M 61 -N 67 | grep TEST_TRANS_RESULTS", + shell=True, stdout=subprocess.PIPE) + stdout_data = p.communicate()[0] + result61 = re.findall(r'(\d+)', stdout_data) + + # Compute the scores for each step + csim_cscore = map(int, resultsim[0:1]) + trans_cscore = int(result32[0]) * int(result64[0]) * int(result61[0]); + miss32 = int(result32[1]) + miss64 = int(result64[1]) + miss61 = int(result61[1]) + trans32_score = computeMissScore(miss32, 300, 600, maxscore['trans32']) * int(result32[0]) + trans64_score = computeMissScore(miss64, 1300, 2000, maxscore['trans64']) * int(result64[0]) + trans61_score = computeMissScore(miss61, 2000, 3000, maxscore['trans61']) * int(result61[0]) + total_score = csim_cscore[0] + trans32_score + trans64_score + trans61_score + + # Summarize the results + print "\nCache Lab summary:" + print "%-22s%8s%10s%12s" % ("", "Points", "Max pts", "Misses") + print "%-22s%8.1f%10d" % ("Csim correctness", csim_cscore[0], + maxscore['csim']) + + misses = str(miss32) + if miss32 == 2**31-1 : + misses = "invalid" + print "%-22s%8.1f%10d%12s" % ("Trans perf 32x32", trans32_score, + maxscore['trans32'], misses) + + misses = str(miss64) + if miss64 == 2**31-1 : + misses = "invalid" + print "%-22s%8.1f%10d%12s" % ("Trans perf 64x64", trans64_score, + maxscore['trans64'], misses) + + misses = str(miss61) + if miss61 == 2**31-1 : + misses = "invalid" + print "%-22s%8.1f%10d%12s" % ("Trans perf 61x67", trans61_score, + maxscore['trans61'], misses) + + print "%22s%8.1f%10d" % ("Total points", total_score, + maxscore['csim'] + + maxscore['trans32'] + + maxscore['trans64'] + + maxscore['trans61']) + + # Emit autoresult string for Autolab if called with -A option + if autograde: + autoresult="%.1f:%d:%d:%d" % (total_score, miss32, miss64, miss61) + print "\nAUTORESULT_STRING=%s" % autoresult + + +# execute main only if called as a script +if __name__ == "__main__": + main() diff --git a/test-csim b/test-csim new file mode 100755 index 0000000..c7da44d Binary files /dev/null and b/test-csim differ diff --git a/test-trans.c b/test-trans.c new file mode 100644 index 0000000..a5adfce --- /dev/null +++ b/test-trans.c @@ -0,0 +1,261 @@ +/* + * test-trans.c - Checks the correctness and performance of all of the + * student's transpose functions and records the results for their + * official submitted version as well. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "cachelab.h" +#include // fir WEXITSTATUS +#include // for INT_MAX + +/* Maximum array dimension */ +#define MAXN 256 + +/* The description string for the transpose_submit() function that the + student submits for credit */ +#define SUBMIT_DESCRIPTION "Transpose submission" + +/* External function defined in trans.c */ +extern void registerFunctions(); + +/* External variables defined in cachelab-tools.c */ +extern trans_func_t func_list[MAX_TRANS_FUNCS]; +extern int func_counter; + +/* Globals set on the command line */ +static int M = 0; +static int N = 0; + +/* The correctness and performance for the submitted transpose function */ +struct results { + int funcid; + int correct; + int misses; +}; +static struct results results = {-1, 0, INT_MAX}; + +/* + * eval_perf - Evaluate the performance of the registered transpose functions + */ +void eval_perf(unsigned int s, unsigned int E, unsigned int b) +{ + int i,flag; + unsigned int len, hits, misses, evictions; + unsigned long long int marker_start, marker_end, addr; + char buf[1000], cmd[255]; + char filename[128]; + + registerFunctions(); + + /* Open the complete trace file */ + FILE* full_trace_fp; + FILE* part_trace_fp; + + /* Evaluate the performance of each registered transpose function */ + + for (i=0; i trace.tmp", M, N,i); + flag=WEXITSTATUS(system(cmd)); + if (0!=flag) { + printf("Validation error at function %d! Run ./tracegen -M %d -N %d -F %d for details.\nSkipping performance evaluation for this function.\n",flag-1,M,N,i); + continue; + } + + /* Get the start and end marker addresses */ + FILE* marker_fp = fopen(".marker", "r"); + assert(marker_fp); + fscanf(marker_fp, "%llx %llx", &marker_start, &marker_end); + fclose(marker_fp); + + + func_list[i].correct=1; + + /* Save the correctness of the transpose submission */ + if (results.funcid == i ) { + results.correct = 1; + } + + full_trace_fp = fopen("trace.tmp", "r"); + assert(full_trace_fp); + + + /* Filtered trace for each transpose function goes in a separate file */ + sprintf(filename, "trace.f%d", i); + part_trace_fp = fopen(filename, "w"); + assert(part_trace_fp); + + /* Locate trace corresponding to the trans function */ + flag = 0; + while (fgets(buf, 1000, full_trace_fp) != NULL) { + + /* We are only interested in memory access instructions */ + if (buf[0]==' ' && buf[2]==' ' && + (buf[1]=='S' || buf[1]=='M' || buf[1]=='L' )) { + sscanf(buf+3, "%llx,%u", &addr, &len); + + /* If start marker found, set flag */ + if (addr == marker_start) + flag = 1; + + /* Valgrind creates many spurious accesses to the + stack that have nothing to do with the students + code. At the moment, we are ignoring all stack + accesses by using the simple filter of recording + accesses to only the low 32-bit portion of the + address space. At some point it would be nice to + try to do more informed filtering so that would + eliminate the valgrind stack references while + include the student stack references. */ + if (flag && addr < 0xffffffff) { + fputs(buf, part_trace_fp); + } + + /* if end marker found, close trace file */ + if (addr == marker_end) { + flag = 0; + fclose(part_trace_fp); + break; + } + } + } + fclose(full_trace_fp); + + /* Run the reference simulator */ + printf("Step 2: Evaluating performance (s=%d, E=%d, b=%d)\n", s, E, b); + char cmd[255]; + sprintf(cmd, "./csim-ref -s %u -E %u -b %u -t trace.f%d > /dev/null", + s, E, b, i); + system(cmd); + + /* Collect results from the reference simulator */ + FILE* in_fp = fopen(".csim_results","r"); + assert(in_fp); + fscanf(in_fp, "%u %u %u", &hits, &misses, &evictions); + fclose(in_fp); + func_list[i].num_hits = hits; + func_list[i].num_misses = misses; + func_list[i].num_evictions = evictions; + printf("func %u (%s): hits:%u, misses:%u, evictions:%u\n", + i, func_list[i].description, hits, misses, evictions); + + /* If it is transpose_submit(), record number of misses */ + if (results.funcid == i) { + results.misses = misses; + } + } + +} + +/* + * usage - Print usage info + */ +void usage(char *argv[]){ + printf("Usage: %s [-h] -M -N \n", argv[0]); + printf("Options:\n"); + printf(" -h Print this help message.\n"); + printf(" -M Number of matrix rows (max %d)\n", MAXN); + printf(" -N Number of matrix columns (max %d)\n", MAXN); + printf("Example: %s -M 8 -N 8\n", argv[0]); +} + +/* + * sigsegv_handler - SIGSEGV handler + */ +void sigsegv_handler(int signum){ + printf("Error: Segmentation Fault.\n"); + printf("TEST_TRANS_RESULTS=0:0\n"); + fflush(stdout); + exit(1); +} + +/* + * sigalrm_handler - SIGALRM handler + */ +void sigalrm_handler(int signum){ + printf("Error: Program timed out.\n"); + printf("TEST_TRANS_RESULTS=0:0\n"); + fflush(stdout); + exit(1); +} + +/* + * main - Main routine + */ +int main(int argc, char* argv[]) +{ + char c; + + while ((c = getopt(argc,argv,"M:N:h")) != -1) { + switch(c) { + case 'M': + M = atoi(optarg); + break; + case 'N': + N = atoi(optarg); + break; + case 'h': + usage(argv); + exit(0); + default: + usage(argv); + exit(1); + } + } + + if (M == 0 || N == 0) { + printf("Error: Missing required argument\n"); + usage(argv); + exit(1); + } + + if (M > MAXN || N > MAXN) { + printf("Error: M or N exceeds %d\n", MAXN); + usage(argv); + exit(1); + } + + /* Install SIGSEGV and SIGALRM handlers */ + if (signal(SIGSEGV, sigsegv_handler) == SIG_ERR) { + fprintf(stderr, "Unable to install SIGALRM handler\n"); + exit(1); + } + + if (signal(SIGALRM, sigalrm_handler) == SIG_ERR) { + fprintf(stderr, "Unable to install SIGALRM handler\n"); + exit(1); + } + + /* Time out and give up after a while */ + alarm(120); + + /* Check the performance of the student's transpose function */ + eval_perf(5, 1, 5); + + /* Emit the results for this particular test */ + if (results.funcid == -1) { + printf("\nError: We could not find your transpose_submit() function\n"); + printf("Error: Please ensure that description field is exactly \"%s\"\n", + SUBMIT_DESCRIPTION); + printf("\nTEST_TRANS_RESULTS=0:0\n"); + } + else { + printf("\nSummary for official submission (func %d): correctness=%d misses=%d\n", + results.funcid, results.correct, results.misses); + printf("\nTEST_TRANS_RESULTS=%d:%d\n", results.correct, results.misses); + } + return 0; +} diff --git a/tracegen.c b/tracegen.c new file mode 100644 index 0000000..33d3d21 --- /dev/null +++ b/tracegen.c @@ -0,0 +1,107 @@ +/* + * tracegen.c - Running the binary tracegen with valgrind produces + * a memory trace of all of the registered transpose functions. + * + * The beginning and end of each registered transpose function's trace + * is indicated by reading from "marker" addresses. These two marker + * addresses are recorded in file for later use. + */ + +#include +#include +#include +#include +#include +#include "cachelab.h" +#include + +/* External variables declared in cachelab.c */ +extern trans_func_t func_list[MAX_TRANS_FUNCS]; +extern int func_counter; + +/* External function from trans.c */ +extern void registerFunctions(); + +/* Markers used to bound trace regions of interest */ +volatile char MARKER_START, MARKER_END; + +static int A[256][256]; +static int B[256][256]; +static int M; +static int N; + + +int validate(int fn,int M, int N, int A[N][M], int B[M][N]) { + int C[M][N]; + memset(C,0,sizeof(C)); + correctTrans(M,N,A,C); + for(int i=0;i +#include "cachelab.h" + +int is_transpose(int M, int N, int A[N][M], int B[M][N]); + +/* + * transpose_submit - This is the solution transpose function that you + * will be graded on for Part B of the assignment. Do not change + * the description string "Transpose submission", as the driver + * searches for that string to identify the transpose function to + * be graded. + */ +char transpose_submit_desc[] = "Transpose submission"; +void transpose_submit(int M, int N, int A[N][M], int B[M][N]) +{ +} + +/* + * You can define additional transpose functions below. We've defined + * a simple one below to help you get started. + */ + +/* + * trans - A simple baseline transpose function, not optimized for the cache. + */ +char trans_desc[] = "Simple row-wise scan transpose"; +void trans(int M, int N, int A[N][M], int B[M][N]) +{ + int i, j, tmp; + + for (i = 0; i < N; i++) { + for (j = 0; j < M; j++) { + tmp = A[i][j]; + B[j][i] = tmp; + } + } + +} + +/* + * registerFunctions - This function registers your transpose + * functions with the driver. At runtime, the driver will + * evaluate each of the registered functions and summarize their + * performance. This is a handy way to experiment with different + * transpose strategies. + */ +void registerFunctions() +{ + /* Register your solution function */ + registerTransFunction(transpose_submit, transpose_submit_desc); + + /* Register any additional transpose functions */ + registerTransFunction(trans, trans_desc); + +} + +/* + * is_transpose - This helper function checks if B is the transpose of + * A. You can check the correctness of your transpose by calling + * it before returning from the transpose function. + */ +int is_transpose(int M, int N, int A[N][M], int B[M][N]) +{ + int i, j; + + for (i = 0; i < N; i++) { + for (j = 0; j < M; ++j) { + if (A[i][j] != B[j][i]) { + return 0; + } + } + } + return 1; +} +