-
Notifications
You must be signed in to change notification settings - Fork 1
/
cjunderhill-sccoache-handin.tar
552 lines (465 loc) · 20 KB
/
cjunderhill-sccoache-handin.tar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
csim.c 0000664 0001751 0001751 00000020232 13023604663 013553 0 ustar cjunderhill cjunderhill /*
* Chad Underhill and Sam Coache
* cjunderhill-sccoache
*/
#include <time.h>
#include <getopt.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include "cachelab.h"
#define INPUT_CAP 250
// Structure containing Set data
struct set {
int *valid; // Pointer to valid bit
clock_t *last_accessed; // Track access info for implementation of LRU
long *tag; // Pointer to tag
};
struct set *g_set;
int hits, misses, evicts; // Counters to track cache hits, misses, and evictions
int s = 0, b = 0, E = 0; // Holds parameter input (s = set index, b = block offset, E = # lines/set)
char *trace_file = NULL; // Hold pointer to the input cache trace file
long access_time = 0; // Hold access info for LRU implementation
/*
* get_set - Get set number from the address
* Params:
* *addr - Pointer to the memory address of the set.
* Returns: void
*/
int get_set(void *addr) {
int sbit = (int) ((1 << s) - 1);
return ((long) addr >> b) & sbit;
}
/*
* get_tag - Get tag from the address
* Params:
* *addr - Pointer to the memory address of the tag.
* Returns: void
*/
long get_tag(void *addr) {
int sb_bits = (s + b);
return (long) addr >> sb_bits;
}
/*
* operate_L - handle a LOAD operation passed in from the cache trace
* Params:
* *addr - Pointer to the memory address being accessed.
* size - Number of bytes accessed by the operation.
* Returns: void
*/
void operate_L(void *addr, int size) {
// Initialize pointer to current set in cache
struct set *current_set = &g_set[get_set(addr)];
int i = 0, is_full = 1;
int empty_item = 0; // Track the empty entry
int last_entry = 0; // Track the evict entry
int last_time = current_set->last_accessed[0];
// For each line in the set
for (; i < E; i++) {
// Find and update the access time if entry is valid and has matching tag
if (current_set->valid[i] == 1 && get_tag(addr) == current_set->tag[i]) {
current_set->last_accessed[i] = access_time++;
break;
// Else if entry is not valid, then it's considered empty and the cache is not full
} else if (current_set->valid[i] == 0) {
is_full = 0;
empty_item = i;
// Else the entry is valid but the tag is not equal
} else {
// Track LRU item, which will be evicted
if (current_set->last_accessed[i] < last_time) {
last_entry = i;
last_time = current_set->last_accessed[i];
}
}
}
// If we have a miss
if (i == E) {
misses++;
// If cache is full, evict
if (is_full) {
current_set->last_accessed[last_entry] = access_time++;
current_set->tag[last_entry] = get_tag(addr);
evicts++;
// Otherwise it's simply a miss
} else {
// Set line bit to valid, assign an address to the cache, and set the access time
current_set->last_accessed[empty_item] = access_time++;
current_set->valid[empty_item] = 1;
current_set->tag[empty_item] = get_tag(addr);
}
// Otherwise it's a hit!
} else {
hits++;
}
}
/*
* operate_S - Handle a STORE operation passed in from the cache trace;
* Runs a LOAD operation if miss.
* Params:
* *addr - Pointer to the memory address being accessed.
* size - Number of bytes accessed by the operation.
* Returns: void
*/
void operate_S(void *addr, int size) {
// Initialize pointer to current set in cache
struct set *current_set = &g_set[get_set(addr)];
int i = 0;
// For each line in the set
for (; i < E; i++) {
// Find and update the access time if entry is valid and has matching tag
if (current_set->valid[i] == 1 && get_tag(addr) == current_set->tag[i]) {
current_set->last_accessed[i] = access_time++;
break;
}
}
// If we have a miss, load the data
if (i == E) {
operate_L(addr, size);
// Otherwise it's a hit!
} else {
hits++;
}
}
/*
* operate_M - Handle a MODIFY operation passed in from the cache trace;
* Simply a LOAD operation followed by a STORE operation.
* Params:
* *addr - Pointer to the memory address being accessed.
* size - Number of bytes accessed by the operation.
* Returns: void
*/
void operate_M(void *addr, int size) {
operate_L(addr, size);
operate_S(addr, size);
}
/*
* get_operator - Processes input program parameters.
* Utilizes getopt library for core functionality.
* Params:
* argc - Argument count
* **argv - Pointer to argument array
* Returns: void
*/
//function to find the program parameters
void get_operator(int argc, char **argv) {
int toggle; // Holds input parameter character for comparison
// Process while there are still remaining unhandled parameters (where getopt then returns -1)
while ((toggle = getopt(argc, argv, "s:E:b:t:")) != -1) {
// Process input argument
if(toggle == 's') {
s = atoi(optarg);
} else if(toggle == 'E') {
E = atoi(optarg);
} else if(toggle == 'b') {
b = atoi(optarg);
} else if(toggle == 't') {
trace_file = optarg;
} else { // Error case
printf("Error: Illegal operation!\n");
exit(0); // Terminate
}
}
}
/*
* initialize - Initialize cache data structure in memory
* Returns: void
*/
void initialize() {
int S = (1 << s); // Calc number of sets (2^s)
// Handle nonpositive set counts with error
if (S <= 0) {
fprintf(stderr, "Error: Attempted to initialize cache with nonpositive number of sets!\n");
exit(0); // Terminate
}
// Allocate memory for all sets in cache
g_set = (struct set*) malloc(sizeof(struct set) * S);
// Allocate memory for data in each set
for (int i = 0; i < S; i++) {
g_set[i].last_accessed = (clock_t *) malloc(sizeof(clock_t) * E);
g_set[i].valid = (int *) malloc(sizeof(int) * E);
g_set[i].tag = (long *) malloc(sizeof(long) * E);
// Initialize all blocks on each line to empty
for(int j = 0 ; j < E; j++) {
g_set[i].last_accessed[j] = 0;
g_set[i].valid[j] = 0;
g_set[i].tag[j] = 0;
}
}
}
/*
* deinitialize - Free cache data structure in memory
* Returns: void
*/
void deinitialize() {
int S = (1 << s); // Calc number of sets (2^s)
g_set = (struct set*) malloc(sizeof(struct set) * S);
// Sequentially free memory for each set in the cache
for (int i = 0; i < S; i++) {
free(g_set[i].last_accessed);
free(g_set[i].valid);
free(g_set[i].tag);
}
// Free memory for entire cache
free(g_set);
}
/*
* main - Entry point for the program
* Params:
* argc - Argument count
* **argv - Pointer to argument array
* Returns: 0 if success
*/
int main(int argc, char **argv) {
// Process input parameters
get_operator(argc, argv);
// Initialize cache data structure
initialize();
char operation[INPUT_CAP]; // Cache operation
void *addr; // Operation memory address
int size; // Size (in bytes) accessed by operation
char buf[INPUT_CAP]; // Hold line currently read from the file
FILE *fp = fopen(trace_file, "r"); // Hold pointer to the specified trace file
// Throw error if trace file is invalid
if (fp == NULL) {
fprintf(stderr, "Error 404: trace file not found!\n");
exit(0); // Terminate
}
// For each line in the cache file
while (fgets(buf, INPUT_CAP, fp) != NULL) {
// Parse the line, store operation, address, and size
sscanf(buf, "%s %p,%d", operation, &addr, &size);
// Perform relevant operation based on specified operation
if (*operation == 'S') {
operate_S(addr, size);
}
else if (*operation == 'M') {
operate_M(addr, size);
}
else if (*operation == 'L') {
operate_L(addr, size);
}
}
// Free cache data structure
deinitialize();
// Print summary of cache simulation instructions
printSummary(hits, misses, evicts);
return 0; // Indicate successful run
} trans.c 0002666 0001751 0001751 00000020127 13024001421 013736 0 ustar cjunderhill cjunderhill /*
* Chad Underhill and Sam Coache
* cjunderhill-sccoache
*/
/*
* 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]);
void transpose_32(int M, int N, int A[N][M], int B[M][N]);
void transpose_64(int M, int N, int A[N][M], int B[M][N]);
void transpose_other(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]){
// Determine variation of transpose function to run based on dimensions of input matrix
switch(N) {
case 32: // 32x32 matrix
transpose_32(M, N, A, B);
break;
case 64: // 64x64 matrix
transpose_64(M, N, A, B);
break;
default: // all matrices not 32x32 or 64x64
transpose_other(M, N, A, B);
break;
}
}
/*
* You can define additional transpose functions below. We've defined
* a simple one below to help you get started.
*/
/*
* transpose_32 - Matrix transposition function optimized for a 32x32 matrix
Fairly optimal solution - # of misses is ~290
* Params:
* M - Number of columns in the matrix
* N - Number of rows in the matrix
* A[N][M] - Input matrix - the one transposed from
* B[N][M] - Input matrix - the one transposed to
* Returns: void
*/
char transpose_32_desc[] = "Transpose a 32x32 matrix";
void transpose_32(int M, int N, int A[N][M], int B[M][N]){
int n, m; // Indecies for rows and columns in matrix
int row, col; // Track current row and column in matrix
int d_val = 0; // Hold value of diagonal element found in matrix (detailed in below code)
int diag = 0; // Hold position of diagonal element found in matrix (detailed in below code)
// Iterates through each column and row
for (col = 0; col < N; col += 8) {
for (row = 0; row < N; row += 8) {
// For each row and column in the designated block, until end of matrix
for (n = row; n < (row + 8); n++) {
for (m = col; m < (col + 8); m++) {
// If row and column do not match, transposition will occur
if (n != m) {
B[m][n] = A[n][m];
// Else, row and column are same and element in matrix is defined as a diagonal
} else {
// Assign diagonal element to a temporary variable
// This saves an individual cache miss on each run through the matrix where the columns and rows still match up
diag = n;
d_val = A[n][m];
}
}
// If row and column are same, element is defined as a diagonal and our temporarily saved element is assigned
if (row == col) {
B[diag][diag] = d_val;
}
}
}
}
}
/*
* transpose_64 - Matrix transposition function optimized for a 64x64 matrix
Not the most optimal solution - couldn't determine a way to reduce # of misses below ~1750 =(
* Params:
* M - Number of columns in the matrix
* N - Number of rows in the matrix
* A[N][M] - Input matrix - the one transposed from
* B[N][M] - Input matrix - the one transposed to
* Returns: void
*/
char transpose_64_desc[] = "Transpose a 64x64 matrix";
void transpose_64(int M, int N, int A[N][M], int B[M][N]){
int n, m; // Indecies for rows and columns in matrix
int row, col; // Track current row and column in matrix
int d_val = 0; // Hold value of diagonal element found in matrix (detailed in below code)
int diag = 0; // Hold position of diagonal element found in matrix (detailed in below code)
// Iterates through each column and row
for (col = 0; col < N; col += 4) {
for (row = 0; row < N; row += 4) {
// For each row and column in the designated block, until end of matrix
for (n = row; n < (row + 4); n++) {
for (m = col; m < (col + 4); m++) {
// If row and column number do not match, transposition will occur
if (n != m) {
B[m][n] = A[n][m];
// Else, row and column number are same and element in matrix is defined as a diagonal
} else {
// Assign diagonal element to a temporary variable
// This saves an individual cache miss on each run through the matrix where the columns and rows still match up
diag = n;
d_val = A[n][m];
}
}
// If row and column are same, element is defined as a diagonal and our temporarily saved element is assigned
if (row == col) {
B[diag][diag] = d_val;
}
}
}
}
}
/*
* transpose_other - Matrix transposition function optimized for matricies that aren't 32x32 or 64x64
Appears to be a fairly optimal solution - # of misses for a 61x67 matrix is ~1800
* Params:
* M - Number of columns in the matrix
* N - Number of rows in the matrix
* A[N][M] - Input matrix - the one transposed from
* B[N][M] - Input matrix - the one transposed to
* Returns: void
*/
char transpose_other_desc[] = "Transpose any matrix that isn't 32x32 or 64x64";
void transpose_other(int M, int N, int A[N][M], int B[M][N]){
int n, m; // Indecies for rows and columns in matrix
int row, col; // Track current row and column in matrix
int d_val = 0; // Hold value of diagonal element found in matrix (detailed in below code)
int diag = 0; // Hold position of diagonal element found in matrix (detailed in below code)
// Iterates through each column and row
for (col = 0; col < M; col += 16) {
for (row = 0; row < N; row += 16) {
// For each row and column after current one, until end of matrix
for (n = row; (n < row + 16) && (n < N); n++) {
for (m = col; (m < col + 16) && (m < M); m++) {
// If row and column number do not match, transposition will occur
if (n != m) {
B[m][n] = A[n][m];
// Else, row and column number are same and element in matrix is defined as a diagonal
} else {
// Assign diagonal element to a temporary variable
// This saves an individual cache miss on each run through the matrix where the columns and rows still match up
diag = n;
d_val = A[n][m];
}
}
// If row and column are same, element is defined as a diagonal and our temporarily saved element is assigned
if (row == col) {
B[diag][diag] = d_val;
}
}
}
}
}
/*
* 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);
// Register custom transpose functions
registerTransFunction(transpose_32, transpose_32_desc);
registerTransFunction(transpose_64, transpose_64_desc);
registerTransFunction(transpose_other, transpose_other_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;
}