Guest CPU Cache ModellingΒΆ

Renode can perform a post-mortem analysis of memory accesses (generated by the execution tracing subsystem) to simulate CPU cache behavior and generate usage statistics.

To generate memory access traces from a simulation, add the following lines to the resc file:

cpu MaximumBlockSize 1
cpu CreateExecutionTracing "tracer" $ORIGIN/trace.log PCAndOpcode
tracer TrackMemoryAccesses

Note

Replace cpu with the core name (from the repl file) that you want to analyse.

You can then pass the generated trace.log file to the Renode Cache Modeling Analyzer. Note that you need to install the dependencies listed in requirements.txt before running the analyzer.

You can use the analyzer with its built-in presets:

./renode_cache_interface.py trace.log presets 'fu740.u74'

The presets are stored in the presets.py file. To create a new preset add a new entry:

'new_preset': {
    'l1d': Cache(
        name='l1i,name',            # Cache name - used in the `printd` debug helpers.
        cache_width=15,             # number of bits used to address the cache
        block_width=6,              # number of bits used in a cache block
        memory_width=64,            # number of bits used to address the main memory
        lines_per_set=2,            # 2 way associativity
        replacement_policy="FIFO"   # replacement policy
        ),
    'flush_opcodes': {
        0x1000: 'd',                # flush `l1d` when after the `0x1000` opcode is executed 
    },
    'invalidate_on_io': True        # flush the data cache when an MemoryMapped I/O operation is performed
}

This will create a preset with data cache only. You can add Instruction cache by adding the l1i object. For more information about cache configuration using presets, please refer to the documentation in the cache.py file. Currently, only Level 1 instruction and data caches are supported.

You can also configure the cache using the CLI parameters:

./renode_cache_interface.py trace.log config            \
                          --memory_width 64             \
                          --l1i_cache_width 15          \
                          --l1i_block_width 6           \
                          --l1i_lines_per_set 4         \
                          --l1i_replacement_policy LRU  \
                          --l1d_cache_width 15          \
                          --l1d_block_width 6           \
                          --l1d_lines_per_set 8         \
                          --l1d_replacement_policy LRU

For more information about cache configuration using CLI, please refer to the output of the ./renode_cache_interface.py trace.log config --help command.

A sample output of the analysis:

$ ./renode_cache_interface.py trace.log presets fu740.u74
l1i,u74 configuration:
Cache size:          32768 bytes
Block size:          64 bytes
Number of lines:     512
Number of sets:      128 (4 lines per set)
Replacement policy:  RAND

l1d,u74 configuration:
Cache size:          32768 bytes
Block size:          64 bytes
Number of lines:     512
Number of sets:      64 (8 lines per set)
Replacement policy:  RAND

Instructions read: 174620452
Total memory operations: 68952483 (read: 50861775, write 18090708)
Total I/O operations: 1875 (read: 181, write 1694)

l1i,u74 results:
Misses: 168
Hits: 174620284
Invalidations: 3
Hit ratio: 100.0%

l1d,u74
Misses: 17320212
Hits: 51632271
Invalidations: 17319700
Hit ratio: 74.88%

It is also possible to generate an output JSON file by passing the --output <filaname> flag:

{
   "l1i,u74":{
      "hit":174620284,
      "miss":168,
      "invalidations":3
   },
   "l1d,u74":{
      "hit":51632271,
      "miss":17320212,
      "invalidations":17319700
   }
}

Last update: 2025-03-06