NMRU tutorial

Overview

Here we will discuss how to add a new replacement policy, which is encapsulated in a SimObject. Our basic strategy will be to copy one of the existing policies in: /src/mem/cache/replacement_policies/

Step 1: Copy an existing policy.

Copy any of the existing replacement policies to use as a starting point for NMRU.

cp lru_rp.cc nmru_rp.cc
cp lru_rp.hh nmru_rp.hh

Within each file, rename any LRU specific prefixes to NMRU.

Step 2

Each SimObject has a Python class which is associated with it. This Python class describes the parameters of your SimObject that can be controlled from the Python configuration files. For our NMRU replacement policy, we are just going to inherit all of the parameters from the BaseReplacementPolicy. Thus, we simply need to declare a new class for our SimObject and set it’s name and the C++ header that will define the C++ class for the SimObject.

We edit the file, ReplacementPolicies.py, in /src/mem/cache/replacement_policies

class NMRURP(BaseReplacementPolicy):
    type = 'NMRURP'
    cxx_class = 'gem5::replacement_policy::NMRU'
    cxx_header = "mem/cache/replacement_policies/nmru_rp.hh"

Step 3: Register the C++ file

Each SimObject must be registered with SCons so that its Params object and Python wrapper is created. Additionally, we also have to tell SCons which C++ files to compile. To do this, modify the SConscipt file in the directory that your SimObject is in. For each SimObject, add a call to SimObject and for each source file add a call to Source. In this example, you need to add the following to src/mem/cache/replacement_policies/SConscript:

Source('nmru_rp.cc')

Also add NMRURP to the SimObject array in src/mem/cache/replacement_policies/SConscript.

At this point, you should be able to compile the code.

Step 4: Modify the source code to implement NMRU

Implement the functionality of NMRU – i.e. replace any line that’s not the most recently used line. The key function is getVictim in nmru_rp.cc.

Also, looking at the random replacement policy may help.

Step 5: Make it configurable in se.py

Supposing you would like to use se.py, you should add an addtional paramter to the cache-of-interest. In particular, you would add: dcache_class(size= ... , replacement_policy=NMRURP()).

If you want to get fancier, you can make the replacement policy easy to change as a paramter.

To do that, first add this line to configs/common/ObjectList after cpu_list is defined:

repl_list = ObjectList(getattr(m5.objects, 'BaseReplacementPolicy', None))

Then, add some new options in configs/common/Options.py:

    parser.add_option("--l1d_repl", type="choice", default="LRURP",
                      choices=ObjectList.repl_list.get_names(),
                      help = "replacement policy for l1")

    parser.add_option("--l2_repl", type="choice", default="LRURP",
                      choices=ObjectList.repl_list.get_names(),
                      help = "replacement policy for l2")

Finally, connect these options up to the dcache, in configs/common/CacheConfig.py

dcache = dcache_class(size=options.l1d_size,
                      assoc=options.l1d_assoc,
                      replacement_policy=ObjectList.repl_list.get(options.l1d_repl)())

The same will work for l2 cache:

system.l2 = l2_cache_class(clk_domain=system.cpu_clk_domain,
                           size=options.l2_size,
                           assoc=options.l2_assoc,
                           replacement_policy=ObjectList.repl_list.get(options.l2_repl)())