From: Jacob Lifshay Date: Sun, 3 Dec 2023 07:57:21 +0000 (-0800) Subject: MemMMap/SimState: speed up SimState.get_mem() for large memories X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a1995d29d2a363e0d83cddc518776ec345074e0d;p=openpower-isa.git MemMMap/SimState: speed up SimState.get_mem() for large memories make MemMMap use struct.Struct.unpack_from to read a whole page at once, rather than doing a sequence of loads. This makes an ELF binary statically-linked to glibc able to run many instructions per second rather than one every tens of seconds or so. --- diff --git a/src/openpower/decoder/isa/mem.py b/src/openpower/decoder/isa/mem.py index 2b3ec844..a5867f3d 100644 --- a/src/openpower/decoder/isa/mem.py +++ b/src/openpower/decoder/isa/mem.py @@ -19,6 +19,7 @@ import math import enum from cached_property import cached_property import mmap +import struct from pickle import PicklingError import ctypes from nmutil import plain_data @@ -115,6 +116,19 @@ class MemCommon: raise NotImplementedError yield 0 + def make_sim_state_dict(self): + """ returns a dict equivalent to: + retval = {} + for k in list(self.word_idxs()): + data = self.ld(k*8, 8, False) + retval[k*8] = data + """ + retval = {} + for k in list(self.word_idxs()): + data = self.ld(k*8, 8, False, reason=_ReadReason.Dump) + retval[k*8] = data + return retval + def _get_shifter_mask(self, wid, remainder, do_log=True): shifter = ((self.bytes_per_word - wid) - remainder) * \ 8 # bits per byte @@ -1024,6 +1038,29 @@ class MemMMap(MemCommon): if bytes_ != zeros: yield word_idx + def make_sim_state_dict(self): + """ returns a dict equivalent to: + retval = {} + for k in list(self.word_idxs()): + data = self.ld(k*8, 8, False) + retval[k*8] = data + """ + if self.bytes_per_word != 8: + return super().make_sim_state_dict() + retval = {} + page_struct = struct.Struct("<%dQ" % (MMAP_PAGE_SIZE // 8,)) + assert page_struct.size == MMAP_PAGE_SIZE, "got wrong format" + for page_idx in self.modified_pages: + start = self.mmap_page_idx_to_addr(page_idx) + block, block_addr = self.__access_addr_range( + start, MMAP_PAGE_SIZE, MMapPageFlags.R) + # written this way to avoid unnecessary allocations + words = page_struct.unpack_from(block, block_addr) + for i, v in zip(range(start, start + MMAP_PAGE_SIZE, 8), words): + if v != 0: + retval[i] = v + return retval + @plain_data.plain_data() class LoadedELF: diff --git a/src/openpower/decoder/isa/test_mem.py b/src/openpower/decoder/isa/test_mem.py index 04d3f70c..3180f0fb 100644 --- a/src/openpower/decoder/isa/test_mem.py +++ b/src/openpower/decoder/isa/test_mem.py @@ -80,6 +80,36 @@ Memory: 0x7FFFFEDCBA90: 00 00 00 00 00 00 00 00 89 67 45 23 01 EF CD AB |.........gE#....| """) + def test_make_sim_state_dict(self): + m = self.MemCls(row_bytes=8, initial_mem=(0x58, [ + 0x5DE6DA2A1137745E, 0x6054D17B4C773D2D, + 0x5B66920D9540B825, 0x7753D053D9854A8F, + 0x9F2A58E2B5B79829, 0x974AC142D081CE83, + 0xAA963F95FC566F57, 0xE63A95A3F654A57E, + 0x103709510CBE0EEF, 0, + 0x5053575776376ACD, 0xCFDFF67B7C5096C2, + 0x9F8FC1B06E7868A0, 0x6E7B1D27CCBAF8E7, + 0xEB91B92FAF546BA1, 0x21FB683F34641876, + ])) + + a = m.make_sim_state_dict() + b = m.make_sim_state_dict() + self.assertIsNot(a, b) # must always return a new dict + self.assertEqual(a, b) # should return the same result + expected = { + 0x58: 0x5DE6DA2A1137745E, 0x60: 0x6054D17B4C773D2D, + 0x68: 0x5B66920D9540B825, 0x70: 0x7753D053D9854A8F, + 0x78: 0x9F2A58E2B5B79829, 0x80: 0x974AC142D081CE83, + 0x88: 0xAA963F95FC566F57, 0x90: 0xE63A95A3F654A57E, + 0x98: 0x103709510CBE0EEF, 0xA0: 0, + 0xA8: 0x5053575776376ACD, 0xB0: 0xCFDFF67B7C5096C2, + 0xB8: 0x9F8FC1B06E7868A0, 0xC0: 0x6E7B1D27CCBAF8E7, + 0xC8: 0xEB91B92FAF546BA1, 0xD0: 0x21FB683F34641876, + } + if isinstance(m, MemMMap): + del expected[0xA0] # MemMMap doesn't list zero entries + self.assertEqual(a, expected) + class TestMemMMap(TestMemCommon): MemCls = MemMMap diff --git a/src/openpower/test/state.py b/src/openpower/test/state.py index 50a01520..a8bec472 100644 --- a/src/openpower/test/state.py +++ b/src/openpower/test/state.py @@ -425,13 +425,7 @@ class SimState(State): mem = self.sim.mem if isinstance(mem, RADIX): mem = mem.mem - keys = list(mem.word_idxs()) - self.mem = {} - # from each address in the underlying mem-simulated dictionary - # issue a 64-bit LD (with no byte-swapping) - for k in keys: - data = mem.ld(k*8, 8, False) - self.mem[k*8] = data + self.mem = mem.make_sim_state_dict() class ExpectedState(State):