Cache and Virtual Memory Simulations
Does it really matter if you pull a USB out before it safely ejects?
Data structure: Cache struct Cache { }; Set *sets; int set_count; int line_count; int block_size; int set_bits; int block_bits; Set 0: Set 1: Set S -1: 1 valid bit per line Valid Valid Valid Valid Valid Valid t tag bits per line Tag Tag Tag Tag Tag Tag 0 0 B bytes per cache line 0 0 0 0 1 1 1 1 1 1 B 1 B 1 B 1 B 1 B 1 B 1 E lines per set
Data structure: Cache struct Cache { Set *sets; Memory Address: m-1 t bits set_bits bits block_bits bits 0 int set_count; Tag Set index Block offset int line_count; int block_size; int set_bits; int block_bits; block size = 2 _ set count = 2 _ };
Data structure: Cache struct Cache { Set *sets; Memory Address: m-1 t bits set_bits bits block_bits bits 0 int set_count; Tag Set index Block offset int line_count; int block_size; int set_bits; int block_bits; block size = 2 _ set count = 2 _ };
Data structure: Cache struct Cache { Set *sets; Memory Address: m-1 t bits set_bits bits block_bits bits 0 int set_count; Tag Set index Block offset int line_count; int block_size; int set_bits; int block_bits; block size = 2 _ set count = 2 _ };
Data structure: Cache struct Cache { Set *sets; Memory Address: m-1 t bits set_bits bits block_bits bits 0 int set_count; Tag Set index Block offset int line_count; int block_size; int set_bits; int block_bits; block size = 2 _ set count = 2 _ };
Data structure: Set struct Set { Line *lines; int line_count; LRUNode *lru_queue; }; lines is an array lru_queue is a pointer to the head node of a queue
Data structure: Set struct Set { Line *lines; int line_count; LRUNode *lru_queue; }; lines is an array lru_queue is a pointer to the head node of a queue
Data structure: Line struct Line { char valid; int tag; char *accessed; int block_size; };
Data structure: Line struct Line { char valid; int tag; char *accessed; int block_size; };
i-clicker question If a cache has 4 blocks per line, how many block offset bits in the address do we need? A. 1 B. 2 C. 3 D. 4
i-clicker question If a cache has 256 sets, how many set index bits in the address do we need? A. 2 B. 4 C. 6 D. 8
Create and initialize cache Cache *cache = //allocate memory for a cache
Create and initialize cache Cache *cache = //allocate memory for a cache Set *sets = // allocate memory for a set
Create and initialize cache Cache *cache = //allocate memory for a cache Set *sets = // allocate memory for a set cache->sets = make_sets(..) // allocate memory for and initialize the set array sets[i].lines = make_lines(..) // allocate memory for and initialize the lines array
Create and initialize cache No freeing Cache *cache = //allocate memory for a cache Set *sets = // allocate memory for a set cache->sets = make_sets(..) // allocate memory for and initialize the set array sets[i].lines = make_lines(..) // allocate memory for and initialize the lines array
Create and initialize cache Cache *cache = //allocate memory for a cache Set *sets = // allocate memory for a set cache->sets = make_sets(..) // allocate memory for and initialize the set array sets[i].lines = make_lines(..) // allocate memory for and initialize the lines array line[i].valid = 0; line[i].tag = 0;
Create and initialize cache Cache *cache = //allocate memory for a cache Set *sets = // allocate memory for a set cache->sets = make_sets(..) // allocate memory for and initialize the set array sets[i].lines = make_lines(..) // allocate memory for and initialize the lines array line[i].valid = 0; line[i].tag = 0; cache->set_count = // 2 raised to the power of set_bits cache->block_size = // 2 raised to the power of block_bits
i-clicker question Consider a computer system where each memory address has m address bits. 2 of these bits are block offset bits. What is the correct way to allocate memory for blocks in a single line? Suppose each block has 1 byte. A. char *blocks = (char *)(malloc(2)); B. char *blocks = malloc(2); C. char *blocks = (char *)(malloc(4)); D. char *blocks = malloc(4);
Cache Miss Cold miss: The first reference to a block of memory, starting with an invalid cache line. Conflict miss: Two blocks are mapped to set and there is not enough room to hold both.
LRU algorithm Maintain a linked list Hit pull the used cache line to the front Cold miss fetch data from memory add a new cache line that contains the new data at the head Conflict miss fetch data from memory get the tail of the list and update it with new data, then move this cache line to the head of the list
LRU algorithm Maintain a linked list Hit pull the used cache line to the front Cold miss fetch data from memory add a new cache line that contains the new data at the head Conflict miss fetch data from memory get the tail of the list and update it with new data, then move this cache line to the head of the list What if the cache is a direct-mapped cache?
LRU algorithm in a set Reference tag sequence: 2 6 7 1 2 3 4 5
LRU algorithm in a set Reference tag sequence: 2 6 7 1 2 3 4 5
LRU algorithm in a set Reference tag sequence: 2 6 7 1 2 3 4 5 cache hit
LRU algorithm in a set Reference tag sequence: 2 6 7 2 1 3 4 5 cache hit
LRU algorithm in a set Reference tag sequence: 2 6 7 1 2 3 4 5
LRU algorithm in a set Reference tag sequence: 2 6 7 1 2 3 4 5
LRU algorithm in a set Reference tag sequence: 2 6 7 1 2 3 4 5 cold miss
LRU algorithm in a set Reference tag sequence: 2 6 7 3 1 2 4 5 cold miss
LRU algorithm in a set Reference tag sequence: 2 6 7 6 1 2 4 5 cold miss
LRU algorithm in a set Reference tag sequence: 2 6 7 6 1 2 4 5
LRU algorithm in a set Reference tag sequence: 2 6 7 6 1 2 4 5
LRU algorithm in a set Reference tag sequence: 2 6 7 6 1 2 4 5
LRU algorithm in a set Reference tag sequence: 2 6 7 6 1 2 4 5
LRU algorithm in a set Reference tag sequence: 2 6 7 6 1 2 4 5
LRU algorithm in a set Reference tag sequence: 2 6 7 6 1 2 4 5 conflict miss
LRU algorithm in a set Reference tag sequence: 2 6 7 6 1 2 4 7 conflict miss
LRU algorithm in a set Reference tag sequence: 2 6 7 7 6 1 2 4 conflict miss
LRU algorithm in a set Reference tag sequence: 2 6 7 7 6 1 2 4 conflict miss
LRU algorithm current = set->lru_queue; while current is not NULL: line = current->line if the line is valid and the tag matches: we have a hit, move the lru_node to the front and adjust the linked list return if the line is not valid: we have a cold miss set the line valid to 1, update its tag, move the lru_node to the front and adjust the linked list return go to the next element in the list and loop again if we iterated through all the lines in the set and did not find a cold line or matching tag we have a conflict miss we will resue the last line, update its tag, move this line to the front of the LRU stack/queue. return
LRU algorithm current = set->lru_queue; while current is not NULL: line = current->line if the line is valid and the tag matches: we have a hit, move the lru_node to the front and adjust the linked list return if the line is not valid: we have a cold miss set the line valid to 1, update its tag, move the lru_node to the front and adjust the linked list return go to the next element in the list and loop again if we iterated through all the lines in the set and did not find a cold line or matching tag we have a conflict miss we will resue the last line, update its tag, move this line to the front of the LRU stack/queue. return
i-clicker question Which of the following is not true for LRU caching algorithm? A. When you have a cold miss and you enter a new line (with the new tag and valid bits) you should make sure that you make that line to the top of the queue as it is the most recently accessed line. B. During a conflicting miss, LRU is taking the last element and make it the first with the new tag values. C. During the eviction, LRU discards the least recently used items first. D. During a hit, LRU is taking the last element and make it the first with the new tag values.