csim.c
實驗一文件,根據存放程序對數據的訪問記錄的輸入文件內容,模擬cache,獲得模擬結果。變量與函數解析如下:
- 變量解析
verbosity
:是否輸出每一行記錄的命中、缺失、替換情況,一般用於bug測試s
:組索引組號位寬b
:cache每一行存放的數據位寬,即塊內偏移位寬E
:關聯度,即每組的行數,每組內是全相聯trace_file
:數據訪問追蹤記錄文件路徑S
:組索引組數,由位寬計算得到cache
:模擬cache的一個二維數組,根據組號以及組內行號確定一行cacheset_index_mask
:用於獲得組號的一個mask
- 函數解析
initCache
:根據S,E創建cache數據,並初始化set_index_maskfreeCache
:回收cache模擬數組空間accessData
:根據傳入地址,模擬訪問一次數據,更新模擬結果replayTrace
:根據trace文件模擬整個數據訪問,有的記錄需要兩次訪問數據printUsage
:打印幫助信息main
:處理傳入的參數,將參數傳入函數,依次調用initCache、replayCache、freeCache、printSummary模擬Cache
csim.c編程要求: .模擬器必須在輸入參數s、E、b設置為任意值時均能正確工作——即:
/* * csim.c - A cache simulator that can replay traces from Valgrind * and output statistics such as number of hits, misses, and * evictions. The replacement policy is LRU. * * Implementation and assumptions: * 1. Each load/store can cause at most one cache miss. (I examined the trace, * the largest request I saw was for 8 bytes). * 2. Instruction loads (I) are ignored, since we are interested in evaluating * trans.c in terms of its data cache performance. * 3. data modify (M) is treated as a load followed by a store to the same * address. Hence, an M operation can result in two cache hits, or a miss and a * hit plus an possible eviction. * * The function printSummary() is given to print output. * Please use this function to print the number of hits, misses and evictions. * This is crucial for the driver to evaluate your work. */ #include <getopt.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <assert.h> #include <math.h> #include <limits.h> #include <string.h> #include <errno.h> #include "cachelab.h" //#define DEBUG_ON #define ADDRESS_LENGTH 64 /* Type: Memory address */ typedef unsigned long long int mem_addr_t; /* Type: Cache line LRU is a counter used to implement LRU replacement policy */ typedef struct cache_line { char valid; mem_addr_t tag; unsigned long long int lru; } cache_line_t; typedef cache_line_t* cache_set_t; typedef cache_set_t* cache_t; /* Globals set by command line args */ int verbosity = 0; /* print trace if set */ int s = 0; /* set index bits */ int b = 0; /* block offset bits */ int E = 0; /* associativity */ char* trace_file = NULL; /* Derived from command line args */ int S; /* number of sets */ int B; /* block size (bytes) */ /* Counters used to record cache statistics */ int miss_count = 0; int hit_count = 0; int eviction_count = 0; unsigned long long int lru_counter = 1; /* The cache we are simulating */ cache_t cache; mem_addr_t set_index_mask; /* * initCache - Allocate memory, write 0's for valid and tag and LRU * also computes the set_index_mask */ void initCache() { int i,j; cache = (cache_set_t*) malloc(sizeof(cache_set_t) * S); for (i=0; i<S; i++){ cache[i]=(cache_line_t*) malloc(sizeof(cache_line_t) * E); for (j=0; j<E; j++){ cache[i][j].valid = 0; cache[i][j].tag = 0; cache[i][j].lru = 0; } } /* Computes set index mask */ set_index_mask = (mem_addr_t) (pow(2, s) - 1); } /* * freeCache - free allocated memory */ void freeCache() { for (int i=0;i<S;i++) free(cache[i]); free(cache); } /* * accessData - Access data at memory address addr. * If it is already in cache, increast hit_count * If it is not in cache, bring it in cache, increase miss count. * Also increase eviction_count if a line is evicted. */ void accessData(mem_addr_t addr) { int i; char hit_flag = 0; unsigned long long int eviction_lru = ULONG_MAX; unsigned int eviction_line = 0; mem_addr_t set_index = (addr >> b) & set_index_mask; mem_addr_t tag = addr >> (s+b); cache_set_t cache_set = cache[set_index]; for (i=0;i<E;i++) { if (cache_set[i].valid) { if (cache_set[i].tag == tag) { ++hit_count; cache_set[i].lru = ULONG_MAX; hit_flag = 1; if (verbosity) printf(" hit"); continue; } if (cache_set[i].lru<eviction_lru) { eviction_line = i; eviction_lru = cache_set[i].lru; } --cache_set[i].lru; } else { if (cache_set[i].lru<eviction_lru) { eviction_line = i; eviction_lru = 0; } } } if (!hit_flag) { if (verbosity) { printf(" miss"); if (cache_set[eviction_line].tag)S printf(" eviction"); } ++miss_count; eviction_count += cache_set[eviction_line].valid; cache_set[eviction_line].valid = 1; cache_set[eviction_line].tag = tag; cache_set[eviction_line].lru = ULONG_MAX; } } /* * replayTrace - replays the given trace file against the cache */ void replayTrace(char* trace_fn) { char buf[1000]; mem_addr_t addr=0; unsigned int len=0; FILE* trace_fp = fopen(trace_fn, "r"); while (fscanf(trace_fp,"%[^\n]%*c",buf)!=EOF) { char op; if (buf[0]==' ') sscanf(buf," %c%llx,%d",&op,&addr,&len); else sscanf(buf,"%c%llx,%d",&op,&addr,&len); if (verbosity) printf("%s",buf); switch (op) { case 'I': break; case 'L': accessData(addr); break; case 'S': accessData(addr); break; case 'M': accessData(addr); accessData(addr); break; default: break; } if (verbosity) printf("\n"); } fclose(trace_fp); } /* * printUsage - Print usage info */ void printUsage(char* argv[]) { printf("Usage: %s [-hv] -s <num> -E <num> -b <num> -t <file>\n", argv[0]); printf("Options:\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"); printf("\nExamples:\n"); printf(" linux> %s -s 4 -E 1 -b 4 -t traces/yi.trace\n", argv[0]); printf(" linux> %s -v -s 8 -E 2 -b 4 -t traces/yi.trace\n", argv[0]); exit(0); } /* * main - Main routine */ int main(int argc, char* argv[]) { char c; while( (c=getopt(argc,argv,"s:E:b:t:vh")) != -1){ switch(c){ case 's': s = atoi(optarg); break; case 'E': E = atoi(optarg); break; case 'b': b = atoi(optarg); break; case 't': trace_file = optarg; break; case 'v': verbosity = 1; break; case 'h': printUsage(argv); exit(0); default: printUsage(argv); exit(1); } } /* Make sure that all required command line args were specified */ if (s == 0 || E == 0 || b == 0 || trace_file == NULL) { printf("%s: Missing required command line argument\n", argv[0]); printUsage(argv); exit(1); } /* Compute S, E and B from command line args */ S = (unsigned int) pow(2, s); B = (unsigned int) pow(2, b); /* Initialize cache */ initCache(); #ifdef DEBUG_ON printf("DEBUG: S:%u E:%u B:%u trace:%s\n", S, E, B, trace_file); printf("DEBUG: set_index_mask: %llu\n", set_index_mask); #endif replayTrace(trace_file); /* Free allocated memory */ freeCache(); /* Output the hit and miss statistics for the autograder */ printSummary(hit_count, miss_count, eviction_count); return 0; }