A Simple Cache Simulator
Jeremy Johnson
This worksheet provides a simple cache simulator, which takes three cache design parameters [size, associativity, and block size] and a sequence of addresses and returns the number of cache misses. The simulator only simulates a single level unified cache [the address sequence does not distinguish reads, writes or instructions vs. data]. The least recently used (lru) strategy is used when a cache line needs to be replaced.
Create a data structure for the Cache simulator. An array, indexed by the cache index and set, is returned. Each entry in the array stores the tag and a clock tick, which is used to keep track of the time [index into the address list that is passed to the simulator] that the element is accessed. A zero entry in the clock field indicates that the cache entry is invalid. The clock information is used to implement the lru replacement strategy.
| > | Cache := proc(C,A,B) |
| > | local i, j, cache, slots; |
| > | slots := C/(B*A); |
| > | cache := array(0..slots-1,0..A-1); |
| > | for i from 0 to slots-1 do |
| > | for j from 0 to A-1 do |
| > | cache[i,j] := table([tag=0,clock=0]); |
| > | od; |
| > | od; |
| > | return eval(cache); |
| > | end; |
| > |
| > | cache := Cache(8,1,1); |
CacheSim implements the simulator.
| > | # Cache Simulator |
| > | # Inputs: |
| > | # addr : a list of addresses |
| > | # C : Cache size |
| > | # A : Associativity |
| > | # B : Block size |
| > | # TRACE : boolean flag. If TRACE is true, each address in the trace is printed along |
| > | # with a message indicating whether the cache access was a hit or not. |
| > | # Output: |
| > | # misses : the number of cache misses that would occur using the specified cache design |
| > | # on the given sequence of addresses. |
| > | CacheSim := proc(addr,C,A,B,TRACE) |
| > | local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; |
| > | cache := Cache(C,A,B); slots := C/(A*B); misses := 0; |
| > | printf("Cache size = %d, Associativity = %d, Block size = %d\n",C,A,B); |
| > | printf("Number of slots = %d\n",slots); |
| > | n := nops(addr); |
| > | for i from 1 to n do |
| > | block := floor(addr[i]/B); offset := addr[i] mod B; |
| > | index := block mod slots; found := false; |
| > | if TRACE then printf("%d-th address = %d -> %d\n",i,addr[i],index); fi; |
| > | for j from 0 to A-1 do |
| > | if block = cache[index,j][tag] and cache[index,j][clock] > 0 then |
| > | found := true; cache[index,j][clock] := i; |
| > | if TRACE then printf("hit\n"); fi; |
| > | fi; |
| > | od; |
| > | if not found then |
| > | if TRACE then printf("miss\n"); fi; |
| > | misses := misses + 1; minclock := n+1; |
| > | for j from 0 to A-1 do |
| > | if cache[index,j][clock] < minclock then |
| > | minclock := cache[index,j][clock]; rep := j; |
| > | fi; |
| > | od; |
| > | cache[index,rep][tag] := block; |
| > | cache[index,rep][clock] := i; |
| > | fi; |
| > | od; |
| > | return misses; |
| > | end; |
| > | T1 := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 2, 4, 6, 8, 10, 12, 14, 0, 4, 8, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15, 1, 5, 9, 13, 3, 7, 11, 15]; |
| > | nops(T1); |
| > | CacheSim(T1,8,1,1,false); |
Cache size = 8, Associativity = 1, Block size = 1
Number of slots = 8
| > | CacheSim(T1,8,1,2,false); |
Cache size = 8, Associativity = 1, Block size = 2
Number of slots = 4
| > | CacheSim(T1,8,2,1,false); |
Cache size = 8, Associativity = 2, Block size = 1
Number of slots = 4
| > | T2 := [0, 1, 2, 3, 4, 5, 6, 7, 0, 4, 1, 5, 2, 6, 3, 7, 8, 9, 10, 11, 12, 13, 14, 15, 8, 12, 9, 13, 10, 14, 11, 15, 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15]; |
| > | CacheSim(T2,8,1,1,false); |
Cache size = 8, Associativity = 1, Block size = 1
Number of slots = 8
| > | CacheSim(T2,8,1,2,false); |
Cache size = 8, Associativity = 1, Block size = 2
Number of slots = 4
| > | CacheSim(T2,8,2,1,true); |
Cache size = 8, Associativity = 2, Block size = 1
Number of slots = 4
1-th address = 0 -> 0
miss
2-th address = 1 -> 1
miss
3-th address = 2 -> 2
miss
4-th address = 3 -> 3
miss
5-th address = 4 -> 0
miss
6-th address = 5 -> 1
miss
7-th address = 6 -> 2
miss
8-th address = 7 -> 3
miss
9-th address = 0 -> 0
hit
10-th address = 4 -> 0
hit
11-th address = 1 -> 1
hit
12-th address = 5 -> 1
hit
13-th address = 2 -> 2
hit
14-th address = 6 -> 2
hit
15-th address = 3 -> 3
hit
16-th address = 7 -> 3
hit
17-th address = 8 -> 0
miss
18-th address = 9 -> 1
miss
19-th address = 10 -> 2
miss
20-th address = 11 -> 3
miss
21-th address = 12 -> 0
miss
22-th address = 13 -> 1
miss
23-th address = 14 -> 2
miss
24-th address = 15 -> 3
miss
25-th address = 8 -> 0
hit
26-th address = 12 -> 0
hit
27-th address = 9 -> 1
hit
28-th address = 13 -> 1
hit
29-th address = 10 -> 2
hit
30-th address = 14 -> 2
hit
31-th address = 11 -> 3
hit
32-th address = 15 -> 3
hit
33-th address = 0 -> 0
miss
34-th address = 8 -> 0
miss
35-th address = 1 -> 1
miss
36-th address = 9 -> 1
miss
37-th address = 2 -> 2
miss
38-th address = 10 -> 2
miss
39-th address = 3 -> 3
miss
40-th address = 11 -> 3
miss
41-th address = 4 -> 0
miss
42-th address = 12 -> 0
miss
43-th address = 5 -> 1
miss
44-th address = 13 -> 1
miss
45-th address = 6 -> 2
miss
46-th address = 14 -> 2
miss
47-th address = 7 -> 3
miss
48-th address = 15 -> 3
miss
| > | T3 := [0,8,0,8]; |
| > | CacheSim(T3,8,1,1,true); |
Cache size = 8, Associativity = 1, Block size = 1
Number of slots = 8
1-th address = 0 -> 0
miss
2-th address = 8 -> 0
miss
3-th address = 0 -> 0
miss
4-th address = 8 -> 0
miss
| > | CacheSim(T3,4,2,1,true); |
Cache size = 4, Associativity = 2, Block size = 1
Number of slots = 2
1-th address = 0 -> 0
miss
2-th address = 8 -> 0
miss
3-th address = 0 -> 0
hit
4-th address = 8 -> 0
hit
| > |