simulate.py revision 10436:bdb307e8be54
112837Sgabeblack@google.com# Copyright (c) 2012 ARM Limited
212837Sgabeblack@google.com# All rights reserved.
312837Sgabeblack@google.com#
412837Sgabeblack@google.com# The license below extends only to copyright in the software and shall
512837Sgabeblack@google.com# not be construed as granting a license to any other intellectual
612837Sgabeblack@google.com# property including but not limited to intellectual property relating
712837Sgabeblack@google.com# to a hardware implementation of the functionality of the software
812837Sgabeblack@google.com# licensed hereunder.  You may use the software subject to the license
912837Sgabeblack@google.com# terms below provided that you ensure that this notice is replicated
1012837Sgabeblack@google.com# unmodified and in its entirety in all distributions of the software,
1112837Sgabeblack@google.com# modified or unmodified, in source code or in binary form.
1212837Sgabeblack@google.com#
1312837Sgabeblack@google.com# Copyright (c) 2005 The Regents of The University of Michigan
1412837Sgabeblack@google.com# Copyright (c) 2010 Advanced Micro Devices, Inc.
1512837Sgabeblack@google.com# All rights reserved.
1612837Sgabeblack@google.com#
1712837Sgabeblack@google.com# Redistribution and use in source and binary forms, with or without
1812837Sgabeblack@google.com# modification, are permitted provided that the following conditions are
1912837Sgabeblack@google.com# met: redistributions of source code must retain the above copyright
2012837Sgabeblack@google.com# notice, this list of conditions and the following disclaimer;
2112837Sgabeblack@google.com# redistributions in binary form must reproduce the above copyright
2212837Sgabeblack@google.com# notice, this list of conditions and the following disclaimer in the
2312837Sgabeblack@google.com# documentation and/or other materials provided with the distribution;
2412837Sgabeblack@google.com# neither the name of the copyright holders nor the names of its
2512837Sgabeblack@google.com# contributors may be used to endorse or promote products derived from
2612837Sgabeblack@google.com# this software without specific prior written permission.
2712837Sgabeblack@google.com#
2812837Sgabeblack@google.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2912837Sgabeblack@google.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3012901Sgabeblack@google.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3113135Sgabeblack@google.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3212901Sgabeblack@google.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3312901Sgabeblack@google.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3412837Sgabeblack@google.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3513280Sgabeblack@google.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3612982Sgabeblack@google.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3712951Sgabeblack@google.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3813280Sgabeblack@google.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3913288Sgabeblack@google.com#
4012953Sgabeblack@google.com# Authors: Nathan Binkert
4113260Sgabeblack@google.com#          Steve Reinhardt
4213288Sgabeblack@google.com
4313288Sgabeblack@google.comimport atexit
4413288Sgabeblack@google.comimport os
4513155Sgabeblack@google.comimport sys
4612837Sgabeblack@google.com
4712951Sgabeblack@google.com# import the SWIG-wrapped main C++ functions
4813155Sgabeblack@google.comimport internal
4913135Sgabeblack@google.comimport core
5012837Sgabeblack@google.comimport stats
5112952Sgabeblack@google.comimport SimObject
5212952Sgabeblack@google.comimport ticks
5312952Sgabeblack@google.comimport objects
5412952Sgabeblack@google.comfrom m5.util.dot_writer import do_dot
5512952Sgabeblack@google.comfrom m5.internal.stats import updateEvents as updateStatEvents
5612952Sgabeblack@google.com
5713135Sgabeblack@google.comfrom util import fatal
5813135Sgabeblack@google.comfrom util import attrdict
5913135Sgabeblack@google.com
6013135Sgabeblack@google.com# define a MaxTick parameter, unsigned 64 bit
6113135Sgabeblack@google.comMaxTick = 2**64 - 1
6213135Sgabeblack@google.com
6313135Sgabeblack@google.com_memory_modes = {
6413135Sgabeblack@google.com    "atomic" : objects.params.atomic,
6512993Sgabeblack@google.com    "timing" : objects.params.timing,
6612993Sgabeblack@google.com    "atomic_noncaching" : objects.params.atomic_noncaching,
6712952Sgabeblack@google.com    }
6812952Sgabeblack@google.com
6912952Sgabeblack@google.com# The final hook to generate .ini files.  Called from the user script
7012952Sgabeblack@google.com# once the config is built.
7112952Sgabeblack@google.comdef instantiate(ckpt_dir=None):
7213135Sgabeblack@google.com    from m5 import options
7313135Sgabeblack@google.com
7413135Sgabeblack@google.com    root = objects.Root.getInstance()
7513135Sgabeblack@google.com
7613135Sgabeblack@google.com    if not root:
7713135Sgabeblack@google.com        fatal("Need to instantiate Root() before calling instantiate()")
7813135Sgabeblack@google.com
7913135Sgabeblack@google.com    # we need to fix the global frequency
8012993Sgabeblack@google.com    ticks.fixGlobalFrequency()
8112993Sgabeblack@google.com
8212952Sgabeblack@google.com    # Make sure SimObject-valued params are in the configuration
8312952Sgabeblack@google.com    # hierarchy so we catch them with future descendants() walks
8412952Sgabeblack@google.com    for obj in root.descendants(): obj.adoptOrphanParams()
8512952Sgabeblack@google.com
8612952Sgabeblack@google.com    # Unproxy in sorted order for determinism
8713135Sgabeblack@google.com    for obj in root.descendants(): obj.unproxyParams()
8813135Sgabeblack@google.com
8913135Sgabeblack@google.com    if options.dump_config:
9013135Sgabeblack@google.com        ini_file = file(os.path.join(options.outdir, options.dump_config), 'w')
9113135Sgabeblack@google.com        # Print ini sections in sorted order for easier diffing
9213135Sgabeblack@google.com        for obj in sorted(root.descendants(), key=lambda o: o.path()):
9313135Sgabeblack@google.com            obj.print_ini(ini_file)
9413135Sgabeblack@google.com        ini_file.close()
9512993Sgabeblack@google.com
9613194Sgabeblack@google.com    if options.json_config:
9712993Sgabeblack@google.com        try:
9812952Sgabeblack@google.com            import json
9912952Sgabeblack@google.com            json_file = file(os.path.join(options.outdir, options.json_config), 'w')
10012952Sgabeblack@google.com            d = root.get_config_as_dict()
10112952Sgabeblack@google.com            json.dump(d, json_file, indent=4)
10212837Sgabeblack@google.com            json_file.close()
10312837Sgabeblack@google.com        except ImportError:
10412837Sgabeblack@google.com            pass
10513091Sgabeblack@google.com
10612951Sgabeblack@google.com    do_dot(root, options.outdir, options.dot_config)
10712951Sgabeblack@google.com
10812837Sgabeblack@google.com    # Initialize the global statistics
10913091Sgabeblack@google.com    stats.initSimStats()
11012951Sgabeblack@google.com
11112951Sgabeblack@google.com    # Create the C++ sim objects and connect ports
11212837Sgabeblack@google.com    for obj in root.descendants(): obj.createCCObject()
11313091Sgabeblack@google.com    for obj in root.descendants(): obj.connectPorts()
11412837Sgabeblack@google.com
11512982Sgabeblack@google.com    # Do a second pass to finish initializing the sim objects
11612837Sgabeblack@google.com    for obj in root.descendants(): obj.init()
11713091Sgabeblack@google.com
11812837Sgabeblack@google.com    # Do a third pass to initialize statistics
11912837Sgabeblack@google.com    for obj in root.descendants(): obj.regStats()
12012837Sgabeblack@google.com
12112837Sgabeblack@google.com    # Do a fourth pass to initialize probe points
12212837Sgabeblack@google.com    for obj in root.descendants(): obj.regProbePoints()
12312837Sgabeblack@google.com
12412837Sgabeblack@google.com    # Do a fifth pass to connect probe listeners
12512837Sgabeblack@google.com    for obj in root.descendants(): obj.regProbeListeners()
12612837Sgabeblack@google.com
12712837Sgabeblack@google.com    # We're done registering statistics.  Enable the stats package now.
12812837Sgabeblack@google.com    stats.enable()
12912837Sgabeblack@google.com
13012837Sgabeblack@google.com    # Restore checkpoint (if any)
13112837Sgabeblack@google.com    if ckpt_dir:
13212837Sgabeblack@google.com        ckpt = internal.core.getCheckpoint(ckpt_dir)
13312837Sgabeblack@google.com        internal.core.unserializeGlobals(ckpt);
13412837Sgabeblack@google.com        for obj in root.descendants(): obj.loadState(ckpt)
13512837Sgabeblack@google.com        need_resume.append(root)
13612837Sgabeblack@google.com    else:
13712837Sgabeblack@google.com        for obj in root.descendants(): obj.initState()
13812837Sgabeblack@google.com
13912837Sgabeblack@google.com    # Check to see if any of the stat events are in the past after resuming from
14012837Sgabeblack@google.com    # a checkpoint, If so, this call will shift them to be at a valid time.
14112837Sgabeblack@google.com    updateStatEvents()
14212837Sgabeblack@google.com
14312837Sgabeblack@google.comneed_resume = []
14412837Sgabeblack@google.comneed_startup = True
14512837Sgabeblack@google.comdef simulate(*args, **kwargs):
14612837Sgabeblack@google.com    global need_resume, need_startup
14712837Sgabeblack@google.com
14812837Sgabeblack@google.com    if need_startup:
14912837Sgabeblack@google.com        root = objects.Root.getInstance()
15012837Sgabeblack@google.com        for obj in root.descendants(): obj.startup()
15112837Sgabeblack@google.com        need_startup = False
15212837Sgabeblack@google.com
15312837Sgabeblack@google.com        # Python exit handlers happen in reverse order.
15412837Sgabeblack@google.com        # We want to dump stats last.
15512837Sgabeblack@google.com        atexit.register(stats.dump)
15612837Sgabeblack@google.com
15712837Sgabeblack@google.com        # register our C++ exit callback function with Python
15812837Sgabeblack@google.com        atexit.register(internal.core.doExitCleanup)
15912837Sgabeblack@google.com
16012837Sgabeblack@google.com        # Reset to put the stats in a consistent state.
16112837Sgabeblack@google.com        stats.reset()
16212837Sgabeblack@google.com
16312837Sgabeblack@google.com    for root in need_resume:
16412837Sgabeblack@google.com        resume(root)
16512837Sgabeblack@google.com    need_resume = []
16612837Sgabeblack@google.com
16712837Sgabeblack@google.com    return internal.event.simulate(*args, **kwargs)
16812837Sgabeblack@google.com
16912837Sgabeblack@google.com# Export curTick to user script.
17012837Sgabeblack@google.comdef curTick():
17112837Sgabeblack@google.com    return internal.core.curTick()
17212837Sgabeblack@google.com
17312837Sgabeblack@google.com# Drain the system in preparation of a checkpoint or memory mode
17412837Sgabeblack@google.com# switch.
17512837Sgabeblack@google.comdef drain(root):
17612837Sgabeblack@google.com    # Try to drain all objects. Draining might not be completed unless
17712837Sgabeblack@google.com    # all objects return that they are drained on the first call. This
17812837Sgabeblack@google.com    # is because as objects drain they may cause other objects to no
17912837Sgabeblack@google.com    # longer be drained.
18012837Sgabeblack@google.com    def _drain():
18112837Sgabeblack@google.com        all_drained = False
18212837Sgabeblack@google.com        dm = internal.drain.createDrainManager()
18312837Sgabeblack@google.com        unready_objs = sum(obj.drain(dm) for obj in root.descendants())
18412837Sgabeblack@google.com        # If we've got some objects that can't drain immediately, then simulate
18513091Sgabeblack@google.com        if unready_objs > 0:
18613091Sgabeblack@google.com            dm.setCount(unready_objs)
18713091Sgabeblack@google.com            #WARNING: if a valid exit event occurs while draining, it will not
18813091Sgabeblack@google.com            # get returned to the user script
18913091Sgabeblack@google.com            exit_event = simulate()
19013091Sgabeblack@google.com            while exit_event.getCause() != 'Finished drain':
19113091Sgabeblack@google.com                exit_event = simulate()
19213091Sgabeblack@google.com        else:
19313091Sgabeblack@google.com            all_drained = True
19413091Sgabeblack@google.com        internal.drain.cleanupDrainManager(dm)
19513091Sgabeblack@google.com        return all_drained
19613091Sgabeblack@google.com
19713091Sgabeblack@google.com    all_drained = _drain()
19813091Sgabeblack@google.com    while (not all_drained):
19913091Sgabeblack@google.com        all_drained = _drain()
20013091Sgabeblack@google.com
20113091Sgabeblack@google.comdef memWriteback(root):
20213091Sgabeblack@google.com    for obj in root.descendants():
20313091Sgabeblack@google.com        obj.memWriteback()
20413091Sgabeblack@google.com
20513091Sgabeblack@google.comdef memInvalidate(root):
20613091Sgabeblack@google.com    for obj in root.descendants():
20713091Sgabeblack@google.com        obj.memInvalidate()
20813091Sgabeblack@google.com
20912837Sgabeblack@google.comdef resume(root):
21012837Sgabeblack@google.com    for obj in root.descendants(): obj.drainResume()
21113292Sgabeblack@google.com
21213292Sgabeblack@google.comdef checkpoint(dir):
21313292Sgabeblack@google.com    root = objects.Root.getInstance()
21413292Sgabeblack@google.com    if not isinstance(root, objects.Root):
21513292Sgabeblack@google.com        raise TypeError, "Checkpoint must be called on a root object."
21613292Sgabeblack@google.com    drain(root)
21713292Sgabeblack@google.com    memWriteback(root)
21813292Sgabeblack@google.com    print "Writing checkpoint"
21913292Sgabeblack@google.com    internal.core.serializeAll(dir)
22013292Sgabeblack@google.com    resume(root)
22113292Sgabeblack@google.com
22213292Sgabeblack@google.comdef _changeMemoryMode(system, mode):
22313292Sgabeblack@google.com    if not isinstance(system, (objects.Root, objects.System)):
22413292Sgabeblack@google.com        raise TypeError, "Parameter of type '%s'.  Must be type %s or %s." % \
22513292Sgabeblack@google.com              (type(system), objects.Root, objects.System)
22613292Sgabeblack@google.com    if system.getMemoryMode() != mode:
22713292Sgabeblack@google.com        drain(system)
22813292Sgabeblack@google.com        system.setMemoryMode(mode)
22913292Sgabeblack@google.com    else:
23013292Sgabeblack@google.com        print "System already in target mode. Memory mode unchanged."
23113292Sgabeblack@google.com
23213292Sgabeblack@google.comdef switchCpus(system, cpuList, do_drain=True, verbose=True):
23313292Sgabeblack@google.com    """Switch CPUs in a system.
23413292Sgabeblack@google.com
23513292Sgabeblack@google.com    By default, this method drains and resumes the system. This
23613292Sgabeblack@google.com    behavior can be disabled by setting the keyword argument
23713292Sgabeblack@google.com    'do_drain' to false, which might be desirable if multiple
23813292Sgabeblack@google.com    operations requiring a drained system are going to be performed in
23912837Sgabeblack@google.com    sequence.
24012837Sgabeblack@google.com
24112837Sgabeblack@google.com    Note: This method may switch the memory mode of the system if that
24212951Sgabeblack@google.com    is required by the CPUs. It may also flush all caches in the
24312837Sgabeblack@google.com    system.
24412837Sgabeblack@google.com
24512837Sgabeblack@google.com    Arguments:
24612837Sgabeblack@google.com      system -- Simulated system.
24712837Sgabeblack@google.com      cpuList -- (old_cpu, new_cpu) tuples
24812951Sgabeblack@google.com
24912837Sgabeblack@google.com    Keyword Arguments:
25012837Sgabeblack@google.com      do_drain -- Perform a drain/resume of the system when switching.
25112951Sgabeblack@google.com    """
25213079Sgabeblack@google.com
25312951Sgabeblack@google.com    if verbose:
25413284Sgabeblack@google.com        print "switching cpus"
25513284Sgabeblack@google.com
25613284Sgabeblack@google.com    if not isinstance(cpuList, list):
25713284Sgabeblack@google.com        raise RuntimeError, "Must pass a list to this function"
25813284Sgabeblack@google.com    for item in cpuList:
25913284Sgabeblack@google.com        if not isinstance(item, tuple) or len(item) != 2:
26013284Sgabeblack@google.com            raise RuntimeError, "List must have tuples of (oldCPU,newCPU)"
26113284Sgabeblack@google.com
26213284Sgabeblack@google.com    old_cpus = [old_cpu for old_cpu, new_cpu in cpuList]
26313284Sgabeblack@google.com    new_cpus = [new_cpu for old_cpu, new_cpu in cpuList]
26412837Sgabeblack@google.com    old_cpu_set = set(old_cpus)
26512951Sgabeblack@google.com    memory_mode_name = new_cpus[0].memory_mode()
26613191Sgabeblack@google.com    for old_cpu, new_cpu in cpuList:
26713191Sgabeblack@google.com        if not isinstance(old_cpu, objects.BaseCPU):
26813191Sgabeblack@google.com            raise TypeError, "%s is not of type BaseCPU" % old_cpu
26913191Sgabeblack@google.com        if not isinstance(new_cpu, objects.BaseCPU):
27013191Sgabeblack@google.com            raise TypeError, "%s is not of type BaseCPU" % new_cpu
27113191Sgabeblack@google.com        if new_cpu in old_cpu_set:
27213191Sgabeblack@google.com            raise RuntimeError, \
27312951Sgabeblack@google.com                "New CPU (%s) is in the list of old CPUs." % (old_cpu,)
27412951Sgabeblack@google.com        if not new_cpu.switchedOut():
27513191Sgabeblack@google.com            raise RuntimeError, \
27613191Sgabeblack@google.com                "New CPU (%s) is already active." % (new_cpu,)
27713191Sgabeblack@google.com        if not new_cpu.support_take_over():
27813191Sgabeblack@google.com            raise RuntimeError, \
27913191Sgabeblack@google.com                "New CPU (%s) does not support CPU handover." % (old_cpu,)
28013191Sgabeblack@google.com        if new_cpu.memory_mode() != memory_mode_name:
28113191Sgabeblack@google.com            raise RuntimeError, \
28213191Sgabeblack@google.com                "%s and %s require different memory modes." % (new_cpu,
28313191Sgabeblack@google.com                                                               new_cpus[0])
28413191Sgabeblack@google.com        if old_cpu.switchedOut():
28513191Sgabeblack@google.com            raise RuntimeError, \
28613191Sgabeblack@google.com                "Old CPU (%s) is inactive." % (new_cpu,)
28712928Sgabeblack@google.com        if not old_cpu.support_take_over():
28812837Sgabeblack@google.com            raise RuntimeError, \
28913260Sgabeblack@google.com                "Old CPU (%s) does not support CPU handover." % (old_cpu,)
29012837Sgabeblack@google.com
29113288Sgabeblack@google.com    try:
29212837Sgabeblack@google.com        memory_mode = _memory_modes[memory_mode_name]
29312837Sgabeblack@google.com    except KeyError:
29412837Sgabeblack@google.com        raise RuntimeError, "Invalid memory mode (%s)" % memory_mode_name
29513260Sgabeblack@google.com
29612837Sgabeblack@google.com    if do_drain:
29713288Sgabeblack@google.com        drain(system)
29812837Sgabeblack@google.com
29912837Sgabeblack@google.com    # Now all of the CPUs are ready to be switched out
30012837Sgabeblack@google.com    for old_cpu, new_cpu in cpuList:
30113260Sgabeblack@google.com        old_cpu.switchOut()
30212837Sgabeblack@google.com
30313288Sgabeblack@google.com    # Change the memory mode if required. We check if this is needed
30412837Sgabeblack@google.com    # to avoid printing a warning if no switch was performed.
30512837Sgabeblack@google.com    if system.getMemoryMode() != memory_mode:
30612837Sgabeblack@google.com        # Flush the memory system if we are switching to a memory mode
30713260Sgabeblack@google.com        # that disables caches. This typically happens when switching to a
30812837Sgabeblack@google.com        # hardware virtualized CPU.
30913288Sgabeblack@google.com        if memory_mode == objects.params.atomic_noncaching:
31012837Sgabeblack@google.com            memWriteback(system)
31112837Sgabeblack@google.com            memInvalidate(system)
31212837Sgabeblack@google.com
31312837Sgabeblack@google.com        _changeMemoryMode(system, memory_mode)
31413260Sgabeblack@google.com
31512837Sgabeblack@google.com    for old_cpu, new_cpu in cpuList:
31613288Sgabeblack@google.com        new_cpu.takeOverFrom(old_cpu)
31712837Sgabeblack@google.com
31812837Sgabeblack@google.com    if do_drain:
31912837Sgabeblack@google.com        resume(system)
32013260Sgabeblack@google.com
32112837Sgabeblack@google.comfrom internal.core import disableAllListeners
32213288Sgabeblack@google.com