24.22.4.2.2. TimingSimpleCPU analysis #1

Backtrace:

EventManager::schedule
DRAMCtrl::Rank::startup
DRAMCtrl::startup

Snippets:

void
DRAMCtrl::startup()
{
    // remember the memory system mode of operation
    isTimingMode = system()->isTimingMode();

    if (isTimingMode) {
        // timestamp offset should be in clock cycles for DRAMPower
        timeStampOffset = divCeil(curTick(), tCK);

        // update the start tick for the precharge accounting to the
        // current tick
        for (auto r : ranks) {
            r->startup(curTick() + tREFI - tRP);
        }

        // shift the bus busy time sufficiently far ahead that we never
        // have to worry about negative values when computing the time for
        // the next request, this will add an insignificant bubble at the
        // start of simulation
        nextBurstAt = curTick() + tRP + tRCD;
    }
}

which then calls:

void
DRAMCtrl::Rank::startup(Tick ref_tick)
{
    assert(ref_tick > curTick());

    pwrStateTick = curTick();

    // kick off the refresh, and give ourselves enough time to
    // precharge
    schedule(refreshEvent, ref_tick);
}

DRAMCtrl::startup is itself a SimObject method exposed to Python and called from simulate in src/python/m5/simulate.py:

def simulate(*args, **kwargs):
    global need_startup

    if need_startup:
        root = objects.Root.getInstance()
        for obj in root.descendants(): obj.startup()

where simulate happens after m5.instantiate, and both are called directly from the toplevel scripts, e.g. for se.py in configs/common/Simulation.py:

def run(options, root, testsys, cpu_class):
    ...
            exit_event = m5.simulate()

By looking up some variable definitions in the source, we now we see some memory parameters clearly:

  • ranks: std::vector<DRAMCtrl::Rank*> with 2 elements. TODO why do we have 2? What does it represent? Likely linked to config.ini at system.mem_ctrls.ranks_per_channel=2: https://en.wikipedia.org/wiki/Memory_rank

  • tCK=1250, tREFI=7800000, tRP=13750, tRCD=13750: all defined in a single code location with a comment:

         /**
         * Basic memory timing parameters initialized based on parameter
         * values.
         */

    Their values can be seen under config.ini and they are documented in src/mem/DRAMCtrl.py e.g.:

        # the base clock period of the DRAM
        tCK = Param.Latency("Clock period")
    
        # minimum time between a precharge and subsequent activate
        tRP = Param.Latency("Row precharge time")
    
        # the amount of time in nanoseconds from issuing an activate command
        # to the data being available in the row buffer for a read/write
        tRCD = Param.Latency("RAS to CAS delay")
    
        # refresh command interval, how often a "ref" command needs
        # to be sent. It is 7.8 us for a 64ms refresh requirement
        tREFI = Param.Latency("Refresh command interval")

So we realize that we are going into deep DRAM modelling, more detail that a mere mortal should ever need to know.

curTick() + tREFI - tRP = 0 + 7800000 - 13750 = 7786250 which is when that refreshEvent was scheduled. Our simulation ends way before that point however, so we will never know what it did thank God.