/* Sources: http://www.gnu.org/software/libc/manual/html_node/Getopt.html https://en.wikipedia.org/wiki/C_dynamic_memory_allocation Computer Systems A Programmers Perspective */ #include <stdlib.h> #include <stdio.h> #include <getopt.h> #include "cachelab.h" #include <math.h> #include <strings.h> typedef unsigned long long int address; typedef int bool; #define true 1 #define false 0 typedef struct // Structure for holding command line parameters given when calling the program { int S, s, E, b, B; } parameter; typedef struct // Structure for holding hits misses evictions { int e, m, h; } cachingResult; typedef struct // Structure representing a line within the cache { address line_Tag; bool is_Valid; int used; char* block; } line_Struct; typedef struct // Structure to nest within virtual cache, representing a set of lines { line_Struct* line; } set_Struct; typedef struct // Structure representing a cache of sets { set_Struct* cache_Sets; }virtualCache; line_Struct structInit(); int indexReturn(int* used, int line_n, set_Struct temp_Set, bool emptyFlag); virtualCache cacheInit(int line_n, long long block_Sz, long long set_n, virtualCache initCache); cachingResult cacheRun(virtualCache cache, cachingResult result, address memAdd, int line_n, int temp, int b); void printUse(); int main(int argc, char **argv) // http://www.gnu.org/software/libc/manual/html_node/Getopt.html was used { cachingResult result, resultS, resultM, resultL, resultBuff; // holds results from caching for easier passing result.e = 0; result.h = 0; result.m = 0; virtualCache cache_t; // cache struct address memAdd; // memory address var parameter para; // parameters from command line FILE *trace_In; // input trace file char szBuff, accessType; // buffer, variable for holding I, M, L, S int verbosity = 0; int sz = 0; int temp = 0; long long set_n = 0; long long block_Sz = 0; printf("first while"); while((szBuff=getopt(argc, argv, "s:E:b:t:vh")) != -1){ // while szBuff equals command line argument switch(szBuff){ case 's': temp = atoi(optarg); break; case 'E': para.E = atoi(optarg); break; case 'b': para.b = atoi(optarg); break; case 't': trace_In = fopen(optarg, "r"); // sets trace_In to the input trace file, read break; case 'v': verbosity = true; // set verbosity equal to true if flag is set break; default: case 'h': printUse(); // prints use if h is flagged exit(1); } } if (temp == 0 || para.E == 0 || para.b == 0 || trace_In == 0){ printf("Incorrect parameters entered.\n"); // Defaults to no parameters, inform user printUse(); exit(1); } set_n = pow(2.0, (float)temp); // set_n = 2^s temp += para.b; cache_t = cacheInit(para.E, block_Sz, set_n, cache_t); if(trace_In == 0){ printf("\nUnable to load trace.\n"); exit(1); } if (trace_In != NULL) { while (fscanf(trace_In, " %c %llx,%d", &accessType, &memAdd, &sz) == 3){ if(accessType != 'I'){ // if it is not a instruction cache access, per lab guideline if(verbosity == true){ resultBuff = cacheRun(cache_t, resultBuff, memAdd, para.E, temp, para.b); // Increment results correspondingly switch(accessType){ case 'M': resultM += resultBuff; break; case 'S': resultS += resultBuff; break; case 'L': resultL += resultBuff; break; } result += resultBuff; } else{ result = cacheRun(cache_t, result, memAdd, para.E, temp, para.b); // Increment results correspondingly } } } } if(verbosity == true){ printf("Results for M\n"); printSummary(resultM.h, resultM.m, resultM.e); printf("Results for S\n"); printSummary(resultS.h, resultS.m, resultS.e); printf("Results for L\n"); printSummary(resultL.h, resultL.m, resultL.e); } printSummary(result.h, result.m, result.e); // print hits, misses, and evictions from result struct fclose(trace_In); } void printUse() { printf("Usage: ./csim [-hv] -s <num> -E <num> -b <num> -t <file>\n"); printf("-h Print this help message.\n"); printf("-v Optional verbose flag.\n"); printf("-s <num> Number of set index bits.\n"); printf("-E <num> Number of lines per set.\n"); printf("-b <num> Number of block offset bits.\n"); printf("-t <file> Trace file.\n"); } virtualCache cacheInit(int line_n, long long block_Sz, long long set_n, virtualCache initCache){ set_Struct temp_Set; line_Struct temp_Line; int i, j; // i = index of line, j = index of set initCache.cache_Sets = (set_Struct *) malloc(sizeof(set_Struct) * set_n); for (j = 0; j < set_n; j++){ temp_Set.line = (line_Struct *) malloc(sizeof(line_Struct) * line_n); initCache.cache_Sets[j] = temp_Set; for (i = 0; i < line_n; i++){ temp_Line.used = 0; temp_Line.line_Tag = 0; temp_Line.is_Valid = false; temp_Set.line[i] = temp_Line; } } return initCache; } int indexReturn(int* used, int line_n, set_Struct temp_Set, bool emptyFlag){ int i; int most_Freq = temp_Set.line[0].used; // declaring variables here, since if the else statement is taken they are unnecessary int least_Freq = most_Freq; int szBuff, j = 0; for(i = 1; i < line_n; i++){ szBuff = temp_Set.line[i].used; if(most_Freq < szBuff){ most_Freq = szBuff; } if (least_Freq > szBuff){ j = i; least_Freq = szBuff; } } used[1] = most_Freq; used[0] = least_Freq; if(emptyFlag){ return j; } for(i = 0; i < line_n; i++){ if (!temp_Set.line[i].is_Valid){ return i; } } return 0; } cachingResult cacheRun(virtualCache cache, cachingResult result, address memAdd, int line_n, int temp, int b){ int i,j; // used for indexing int tag_Sz = (64-temp); // calculates tag size based off of param s/b and 64 bit int missCheck = result.h; // for comparison to increment misses bool spaceCheck = true; address tag_In = memAdd >> temp; int index = ((memAdd << tag_Sz) >> (tag_Sz + b)); set_Struct temp_Set = cache.cache_Sets[index]; // sets temp_Set equal to the passed cache's cache_Sets set index for (i = 0; i < line_n; i++){// increment thsrough line indexing line_Struct temp_Line = temp_Set.line[i]; if (temp_Line.is_Valid){ if(tag_In == temp_Line.line_Tag){ // if it is valid and the tag is the same temp_Line.used += 1; temp_Set.line[i] = temp_Line; // move used value over to cache result.h++; // increment hit } } else if (!temp_Line.is_Valid && spaceCheck) { spaceCheck = false; // there are empty lines } } if (result.h == missCheck){ // If they are the same, negating will equal 0 and ! on 0 is true; i.e, true equals no change between previous and now result.m++; // miss is found } else{ // a hit was triggered, progress to next cacheRun w/in the while loop return result; } int* used = (int* ) malloc(sizeof(int)*2); // variables are declared here due to the branch - they do not need to be declared unless missed j = indexReturn(used, line_n, temp_Set, spaceCheck); // index of empty line, or least recently used line; determined by branch off of emptyFlag bool temp_Set.line[j].used = used[1]+1; temp_Set.line[j].line_Tag = tag_In; if(spaceCheck){ result.e++; // Since it is full, increment eviction } else{ printf("Space_Check\n"); temp_Set.line[j].is_Valid = true; // if not empty, it is valid } return result; }
/* * trans.c - Matrix transpose B = A^T * * Each transpose function must have a prototype of the form: * void trans(int M, int N, int A[N][M], int B[M][N]); * * A transpose function is evaluated by counting the number of misses * on a 1KB direct mapped cache with a block size of 32 bytes. */ #include <stdio.h> #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]) { int i, j, tmp = 0, vert = 0, hori = 0; // i and j are indexes. Buff is an intermediary value, for use in diagonal int buff = 0; // transposition. Vert and hori both represent movement through corresponding planes if (N == 32){ // 32x32 square for(vert = 0; vert < N; vert += 8){ // Traverses horizontally through blocks via N by size of block for(hori = 0; hori < N; hori += 8){ // Traverse vertically through blocks via M by size of block for(i = hori; i < hori+8; i++){ // Progress by row via i for(j = vert; j < vert+8; j++){ // Progress by column via j if(i != j){ // If the index are not set equal, than the current matrix elements are not diagonal B[j][i] = A[i][j]; // Swap } else{ // If the two index are equal, it is diagonal so... buff = A[i][j]; // Set buff equal to position within A this iteration tmp = i; // Hold index of current diagonal } } if(vert == hori){ B[tmp][tmp] = buff; // Set B[i][i] equal to A[i][j] for diagonal transposition } } } } } if (N == 64 && M == 64){ // 64x64 square for(vert = 0; N > vert; vert += 4){ // Traverses horizontally through blocks via N by size of block for(hori = 0; N > hori; hori += 4){ // Traverse vertically through blocks via M by size of block for(i = hori; hori+4 > i; i++){ // Progress by row via i for(j = vert; vert+4 > j; j++){ // Progress by column via j if(i != j){ // If the index are not set equal, than the current matrix elements are not diagonal B[j][i] = A[i][j]; // Swap } else{ // If the two index are equal, it is diagonal so... buff = A[i][j]; // Set buff equal to position within A this iteration tmp = i; // Hold index of current diagonal } } if(vert == hori){ B[tmp][tmp] = buff; // Set B[i][i] equal to A[i][j] for diagonal transposition } } } } } else{ // all other test cases for(vert = 0; M > vert; vert += 16){ // Traverses horizontally through blocks via N by size of block for(hori = 0; N > hori; hori += 16){ // Traverse vertically through blocks via M by size of block for(i = hori; (N>i) && hori+16 > i; i++){ // Progress by row via i for(j = vert; (M>j) && vert+16 > j; j++){ // Progress by column via j if(i != j){ // If the index are not set equal, than the current matrix elements are not diagonal B[j][i] = A[i][j]; // Swap } else{ // If the two index are equal, it is diagonal so... buff = A[i][j]; // Set buff equal to position within A this iteration tmp = i; // Hold index of current diagonal } } if(vert == hori){ B[tmp][tmp] = buff; // Set B[i][i] equal to A[i][j] for diagonal transposition } } } } } } /* * 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; }