def test_tso_write_latency(self): """Tests the measurements of write-latency in a TSO cache. Write latency is complicated in TSO: writes normally do not add to the cache latency, unless they are involved in a write buffer drain. Additionally, any write executing when a write buffer drain happens contributes the remainder of its cycles to the latency.""" # Cache with 16 lines, 8 words/line, 4-write buffer with retire-at-2. cache = TSOCache(1, 16, 8, self.fake_bus, self.fake_tracker, 4, 2, False) # Single write: should be buffered. cache.write(5) self.assertEqual(cache.latency, 0) # A second write: should trip retire at N, but no effect on latency. cache.write(10) self.assertEqual(cache.latency, 0) self.assertEqual(len(cache.write_buffer), 1) # Force a drain. cache.write(15) # 2 writes in buffer cache.write(20) # 3 writes in buffer cache.write(25) # 4 writes in buffer; buffer should be full. cache.write(30) # Should force a drain. # Latency will be 4 writes in buffer, plus the one that was processing. self.assertEqual(cache.latency, 222 * 5) self.assertEqual(len(cache.write_buffer), 1)
def test_tso_write_latency(self): """Tests the measurements of write-latency in a TSO cache. Write latency is complicated in TSO: writes normally do not add to the cache latency, unless they are involved in a write buffer drain. Additionally, any write executing when a write buffer drain happens contributes the remainder of its cycles to the latency.""" # Cache with 16 lines, 8 words/line, 4-write buffer with retire-at-2. cache = TSOCache(1, 16, 8, self.fake_bus, self.fake_tracker, 4, 2, False) # Single write: should be buffered. cache.write(5) self.assertEqual(cache.latency, 0) # A second write: should trip retire at N, but no effect on latency. cache.write(10) self.assertEqual(cache.latency, 0) self.assertEqual(len(cache.write_buffer), 1) # Force a drain. cache.write(15) # 2 writes in buffer cache.write(20) # 3 writes in buffer cache.write(25) # 4 writes in buffer; buffer should be full. cache.write(30) # Should force a drain. # Latency will be 4 writes in buffer, plus the one that was processing. self.assertEqual(cache.latency, 222*5) self.assertEqual(len(cache.write_buffer), 1)
def test_tso_post_program_drain(self): """Test the post-program drain of the write buffer.""" # Cache with 16 lines, 8 words/line, 4-write buffer with retire-at-2. cache = TSOCache(1, 16, 8, self.fake_bus, self.fake_tracker, 4, 2, False) # Test that nothing changes if theres nothing in the write buffer. cache.latency = 500 cache.notify_finished() self.assertEqual(cache.latency, 500) self.assertEqual(cache.write_buffer, []) self.assertEqual(cache.write_finishes_at, None) # Test that the write buffer is properly cleared if there is something in it. cache.latency = 500 cache.write_buffer = [10, 20] cache.write_finishes_at = 505 cache.notify_finished() self.assertEqual(cache.latency, 505 + (2 * 222)) self.assertEqual(cache.write_buffer, []) self.assertEqual(cache.write_finishes_at, None)
def test_tso_drain_buffer(self): """Tests that the drain buffer logic in the TSO cache is correct.""" # Cache with 16 lines, 8 words/line, 4-write buffer with retire-at-2. cache = TSOCache(1, 16, 8, self.fake_bus, self.fake_tracker, 4, 2, False) # Check that draining a cache always clears it completely. cache.write_buffer = [1] cache._drain_write_buffer() self.assertEqual(cache.write_buffer, []) cache.write_buffer = [1, 2] cache._drain_write_buffer() self.assertEqual(cache.write_buffer, []) cache.write_buffer = [3, 4, 5, 6, 7] cache._drain_write_buffer() self.assertEqual(cache.write_buffer, []) cache.write_buffer = [] cache._drain_write_buffer() self.assertEqual(cache.write_buffer, []) # Check that when the buffer is drained, any ongoing writes are counted as latency. cache.write_buffer = [] cache.latency = 20 cache.write_finishes_at = 126 cache._drain_write_buffer() self.assertEqual(cache.latency, 126) self.assertEqual(cache.write_finishes_at, None) cache.write_buffer = [10, 20] cache.latency = 20 cache.write_finishes_at = 126 cache._drain_write_buffer() self.assertEqual(cache.latency, 126 + (2 * 222)) self.assertEqual(cache.write_finishes_at, None) # Check that when the buffer is drained, all writes are counted. cache.write_buffer = [10, 20, 30, 40] cache.latency = 0 cache.write_finishes_at = None cache._drain_write_buffer() self.assertEqual(cache.latency, 4 * 222) self.assertEqual(cache.write_finishes_at, None) # Check that when drained, writes execute in the correct order. cache.write_buffer = [10, 138] # Same slot (1), different tag (0 and 1). cache.latency = 0 cache.write_finishes_at = None cache._drain_write_buffer() self.assertEqual(cache.latency, 2 * 222) self.assertEqual(cache.get_cache_line(1).tag, 1) self.assertEqual(cache.get_cache_line(1).state, SlotState.MODIFIED)
def test_tso_check_write_buffer(self): """Tests that the check-buffer logic in the TSO cache is correct.""" # Cache with 16 lines, 8 words/line, 4-write buffer with retire-at-2. cache = TSOCache(1, 16, 8, self.fake_bus, self.fake_tracker, 4, 2, False) # First, check that the method does nothing if a write is still processing. cache.write_finishes_at = 15 # Fake a write in progress. cache.write_buffer = [10, 5, 20] # Fake some writes. cache._check_write_buffer() self.assertEqual(cache.write_finishes_at, 15) self.assertEqual(cache.latency, 0) self.assertEqual(cache.write_buffer, [10, 5, 20]) # Check that if a write is not in process but there are less than N (here, # 2) writes in the buffer, it still does nothing. cache.write_finishes_at = None cache.write_buffer = [10] cache._check_write_buffer() self.assertEqual(cache.write_finishes_at, None) self.assertEqual(cache.latency, 0) self.assertEqual(cache.write_buffer, [10]) # Check that if a write is finished and there are less than N (here, 2) # writes in the buffer, the write is cleared but thats it. cache.write_finishes_at = 10 cache.latency = 15 cache.write_buffer = [10] cache._check_write_buffer() self.assertEqual(cache.write_finishes_at, None) self.assertEqual(cache.latency, 15) self.assertEqual(cache.write_buffer, [10]) # Check that if a write is finished and there are N writes in the buffer, # another write is retired, from the correct end of the line. cache.write_finishes_at = 10 cache.latency = 15 cache.write_buffer = [10, 5] cache._check_write_buffer() self.assertEqual(cache.write_finishes_at, 237) self.assertEqual(cache.latency, 15) self.assertEqual(cache.write_buffer, [5]) # Check that if a write is not in progress and there are N writes in the # buffer, another write is retired, from the correct end of the line. cache.write_finishes_at = None cache.latency = 25 cache.write_buffer = [5, 10] cache._check_write_buffer() self.assertEqual(cache.write_finishes_at, 247) self.assertEqual(cache.latency, 25) self.assertEqual(cache.write_buffer, [10])
def test_tso_read_latency(self): """Tests the measurements of read-latency in a TSO cache.""" # Cache with 16 lines, 8 words/line, 4-write buffer with retire-at-2. cache = TSOCache(1, 16, 8, self.fake_bus, self.fake_tracker, 4, 2, False) # First test that write buffers are snooped correctly. cache.write(5) cache.read(5) self.assertEqual(cache.latency, 1) cache.latency = 0 # Test value that is in the L1 cache. cache.read(4) # Prime the cache. cache.latency = 0 cache.read(4) self.assertEqual(cache.latency, 3) cache.latency = 0 # Test value returned by other processor. cache.read(19) self.assertEqual(cache.latency, 23) cache.latency = 0 # Test value returned by main memory. # Duck-punch the fake bus to claim that it read from memory. # (Don't you love Python? Such abuse! :D) old_read_miss = FakeBus.read_miss def new_read_miss(self, cache_id, address): return True FakeBus.read_miss = new_read_miss cache.read(26) self.assertEqual(cache.latency, 223) # Restore the FakeBus class. FakeBus.read_miss = old_read_miss