Automated merge with ssh://hg@m5sim.org/m5
[gem5.git] / configs / common / Simulation.py
index 59cf32303024476869b8bb3e5408e3e36aa5118f..1c9d4ff4ebbf311ee47309d7e02b936466c19541 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2006 The Regents of The University of Michigan
+# Copyright (c) 2006-2008 The Regents of The University of Michigan
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # Authors: Lisa Hsu
 
 from os import getcwd
+from os.path import join as joinpath
+
 import m5
+from m5.defines import buildEnv
 from m5.objects import *
-m5.AddToPath('../common')
-from Caches import *
+from m5.util import *
+
+addToPath('../common')
+
+def setCPUClass(options):
+
+    atomic = False
+    if options.timing:
+        class TmpClass(TimingSimpleCPU): pass
+    elif options.detailed:
+        if not options.caches:
+            print "O3 CPU must be used with caches"
+            sys.exit(1)
+        class TmpClass(DerivO3CPU): pass
+    elif options.inorder:
+        if not options.caches:
+            print "InOrder CPU must be used with caches"
+            sys.exit(1)
+        class TmpClass(InOrderCPU): pass
+    else:
+        class TmpClass(AtomicSimpleCPU): pass
+        atomic = True
+
+    CPUClass = None
+    test_mem_mode = 'atomic'
+
+    if not atomic:
+        if options.checkpoint_restore != None or options.fast_forward:
+            CPUClass = TmpClass
+            class TmpClass(AtomicSimpleCPU): pass
+        else:
+            test_mem_mode = 'timing'
 
-def run(options, root, testsys):
+    return (TmpClass, test_mem_mode, CPUClass)
+
+
+def run(options, root, testsys, cpu_class):
     if options.maxtick:
         maxtick = options.maxtick
     elif options.maxtime:
-        simtime = int(options.maxtime * root.clock.value)
+        simtime = m5.ticks.seconds(simtime)
         print "simulating for: ", simtime
         maxtick = simtime
     else:
-        maxtick = -1
+        maxtick = m5.MaxTick
 
     if options.checkpoint_dir:
         cptdir = options.checkpoint_dir
+    elif m5.options.outdir:
+        cptdir = m5.options.outdir
     else:
         cptdir = getcwd()
 
+    if options.fast_forward and options.checkpoint_restore != None:
+        fatal("Can't specify both --fast-forward and --checkpoint-restore")
+
+    if options.standard_switch and not options.caches:
+        fatal("Must specify --caches when using --standard-switch")
+
     np = options.num_cpus
     max_checkpoints = options.max_checkpoints
+    switch_cpus = None
+
+    if options.prog_intvl:
+        for i in xrange(np):
+            testsys.cpu[i].progress_interval = options.prog_intvl
+
+    if options.maxinsts:
+        for i in xrange(np):
+            testsys.cpu[i].max_insts_any_thread = options.maxinsts
+
+    if cpu_class:
+        switch_cpus = [cpu_class(defer_registration=True, cpu_id=(np+i))
+                       for i in xrange(np)]
+
+        for i in xrange(np):
+            if options.fast_forward:
+                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
+            switch_cpus[i].system =  testsys
+            if not buildEnv['FULL_SYSTEM']:
+                switch_cpus[i].workload = testsys.cpu[i].workload
+            switch_cpus[i].clock = testsys.cpu[0].clock
+            # simulation period
+            if options.max_inst:
+                switch_cpus[i].max_insts_any_thread = options.max_inst
+
+        testsys.switch_cpus = switch_cpus
+        switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
 
     if options.standard_switch:
         switch_cpus = [TimingSimpleCPU(defer_registration=True, cpu_id=(np+i))
                        for i in xrange(np)]
-        switch_cpus1 = [DerivO3CPU(defer_registration=True, cpu_id=(2*np+i))
+        switch_cpus_1 = [DerivO3CPU(defer_registration=True, cpu_id=(2*np+i))
                         for i in xrange(np)]
+
         for i in xrange(np):
             switch_cpus[i].system =  testsys
-            switch_cpus1[i].system =  testsys
-            if not m5.build_env['FULL_SYSTEM']:
+            switch_cpus_1[i].system =  testsys
+            if not buildEnv['FULL_SYSTEM']:
                 switch_cpus[i].workload = testsys.cpu[i].workload
-                switch_cpus1[i].workload = testsys.cpu[i].workload
+                switch_cpus_1[i].workload = testsys.cpu[i].workload
             switch_cpus[i].clock = testsys.cpu[0].clock
-            switch_cpus1[i].clock = testsys.cpu[0].clock
-            if options.caches:
-                switch_cpus[i].addPrivateSplitL1Caches(L1Cache(size = '32kB'),
-                                                       L1Cache(size = '64kB'))
-
-            switch_cpus[i].mem = testsys.physmem
-            switch_cpus1[i].mem = testsys.physmem
-            switch_cpus[i].connectMemPorts(testsys.membus)
-            root.switch_cpus = switch_cpus
-            root.switch_cpus1 = switch_cpus1
+            switch_cpus_1[i].clock = testsys.cpu[0].clock
+
+            # if restoring, make atomic cpu simulate only a few instructions
+            if options.checkpoint_restore != None:
+                testsys.cpu[i].max_insts_any_thread = 1
+            # Fast forward to specified location if we are not restoring
+            elif options.fast_forward:
+                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
+            # Fast forward to a simpoint (warning: time consuming)
+            elif options.simpoint:
+                if testsys.cpu[i].workload[0].simpoint == 0:
+                    fatal('simpoint not found')
+                testsys.cpu[i].max_insts_any_thread = \
+                    testsys.cpu[i].workload[0].simpoint
+            # No distance specified, just switch
+            else:
+                testsys.cpu[i].max_insts_any_thread = 1
+
+            # warmup period
+            if options.warmup_insts:
+                switch_cpus[i].max_insts_any_thread =  options.warmup_insts
+
+            # simulation period
+            if options.max_inst:
+                switch_cpus_1[i].max_insts_any_thread = options.max_inst
+
+            if not options.caches:
+                # O3 CPU must have a cache to work.
+                print "O3 CPU must be used with caches"
+                sys.exit(1)
+
+            testsys.switch_cpus = switch_cpus
+            testsys.switch_cpus_1 = switch_cpus_1
             switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
-            switch_cpu_list1 = [(switch_cpus[i], switch_cpus1[i]) for i in xrange(np)]
+            switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)]
+
+    # set the checkpoint in the cpu before m5.instantiate is called
+    if options.take_checkpoints != None and \
+           (options.simpoint or options.at_instruction):
+        offset = int(options.take_checkpoints)
+        # Set an instruction break point
+        if options.simpoint:
+            for i in xrange(np):
+                if testsys.cpu[i].workload[0].simpoint == 0:
+                    fatal('no simpoint for testsys.cpu[%d].workload[0]', i)
+                checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset
+                testsys.cpu[i].max_insts_any_thread = checkpoint_inst
+                # used for output below
+                options.take_checkpoints = checkpoint_inst
+        else:
+            options.take_checkpoints = offset
+            # Set all test cpus with the right number of instructions
+            # for the upcoming simulation
+            for i in xrange(np):
+                testsys.cpu[i].max_insts_any_thread = offset
 
     m5.instantiate(root)
 
-    if options.checkpoint_restore:
-        from os.path import isdir
+    if options.checkpoint_restore != None:
+        from os.path import isdir, exists
         from os import listdir
         import re
 
         if not isdir(cptdir):
-            m5.panic("checkpoint dir %s does not exist!" % cptdir)
+            fatal("checkpoint dir %s does not exist!", cptdir)
 
-        dirs = listdir(cptdir)
-        expr = re.compile('cpt.([0-9]*)')
-        cpts = []
-        for dir in dirs:
-            match = expr.match(dir)
-            if match:
-                cpts.append(match.group(1))
+        if options.at_instruction:
+            checkpoint_dir = joinpath(cptdir, "cpt.%s.%s" % \
+                    (options.bench, options.checkpoint_restore))
+            if not exists(checkpoint_dir):
+                fatal("Unable to find checkpoint directory %s", checkpoint_dir)
 
-        cpts.sort(lambda a,b: cmp(long(a), long(b)))
+            print "Restoring checkpoint ..."
+            m5.restoreCheckpoint(root, checkpoint_dir)
+            print "Done."
+        elif options.simpoint:
+            # assume workload 0 has the simpoint
+            if testsys.cpu[0].workload[0].simpoint == 0:
+                fatal('Unable to find simpoint')
 
-        cpt_num = options.checkpoint_restore
+            options.checkpoint_restore += \
+                int(testsys.cpu[0].workload[0].simpoint)
 
-        if cpt_num > len(cpts):
-            m5.panic('Checkpoint %d not found' % cpt_num)
+            checkpoint_dir = joinpath(cptdir, "cpt.%s.%d" % \
+                    (options.bench, options.checkpoint_restore))
+            if not exists(checkpoint_dir):
+                fatal("Unable to find checkpoint directory %s.%s",
+                      options.bench, options.checkpoint_restore)
 
-        m5.restoreCheckpoint(root,
-                             "/".join([cptdir, "cpt.%s" % cpts[cpt_num - 1]]))
+            print "Restoring checkpoint ..."
+            m5.restoreCheckpoint(root,checkpoint_dir)
+            print "Done."
+        else:
+            dirs = listdir(cptdir)
+            expr = re.compile('cpt\.([0-9]*)')
+            cpts = []
+            for dir in dirs:
+                match = expr.match(dir)
+                if match:
+                    cpts.append(match.group(1))
 
-    if options.standard_switch:
-        exit_event = m5.simulate(10000)
+            cpts.sort(lambda a,b: cmp(long(a), long(b)))
+
+            cpt_num = options.checkpoint_restore
+
+            if cpt_num > len(cpts):
+                fatal('Checkpoint %d not found', cpt_num)
 
-        ## when you change to Timing (or Atomic), you halt the system given
-        ## as argument.  When you are finished with the system changes
-        ## (including switchCpus), you must resume the system manually.
-        ## You DON'T need to resume after just switching CPUs if you haven't
-        ## changed anything on the system level.
+            ## Adjust max tick based on our starting tick
+            maxtick = maxtick - int(cpts[cpt_num - 1])
+
+            ## Restore the checkpoint
+            m5.restoreCheckpoint(root,
+                    joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1]))
+
+    if options.standard_switch or cpu_class:
+        if options.standard_switch:
+            print "Switch at instruction count:%s" % \
+                    str(testsys.cpu[0].max_insts_any_thread)
+            exit_event = m5.simulate()
+        elif cpu_class and options.fast_forward:
+            print "Switch at instruction count:%s" % \
+                    str(testsys.cpu[0].max_insts_any_thread)
+            exit_event = m5.simulate()
+        else:
+            print "Switch at curTick count:%s" % str(10000)
+            exit_event = m5.simulate(10000)
+        print "Switched CPUS @ cycle = %s" % (m5.curTick())
+
+        # when you change to Timing (or Atomic), you halt the system
+        # given as argument.  When you are finished with the system
+        # changes (including switchCpus), you must resume the system
+        # manually.  You DON'T need to resume after just switching
+        # CPUs if you haven't changed anything on the system level.
 
         m5.changeToTiming(testsys)
         m5.switchCpus(switch_cpu_list)
         m5.resume(testsys)
 
-        exit_event = m5.simulate(options.standard_switch)
-        m5.switchCpus(switch_cpu_list1)
+        if options.standard_switch:
+            print "Switch at instruction count:%d" % \
+                    (testsys.switch_cpus[0].max_insts_any_thread)
+
+            #warmup instruction count may have already been set
+            if options.warmup_insts:
+                exit_event = m5.simulate()
+            else:
+                exit_event = m5.simulate(options.warmup)
+            print "Switching CPUS @ cycle = %s" % (m5.curTick())
+            print "Simulation ends instruction count:%d" % \
+                    (testsys.switch_cpus_1[0].max_insts_any_thread)
+            m5.drain(testsys)
+            m5.switchCpus(switch_cpu_list1)
+            m5.resume(testsys)
 
     num_checkpoints = 0
     exit_cause = ''
 
-    ## Checkpoints being taken via the command line at <when> and at subsequent
-    ## periods of <period>.  Checkpoint instructions received from the benchmark running
-    ## are ignored and skipped in favor of command line checkpoint instructions.
-    if options.take_checkpoints:
-        [when, period] = options.take_checkpoints.split(",", 1)
-        when = int(when)
-        period = int(period)
+    # Checkpoints being taken via the command line at <when> and at
+    # subsequent periods of <period>.  Checkpoint instructions
+    # received from the benchmark running are ignored and skipped in
+    # favor of command line checkpoint instructions.
+    if options.take_checkpoints != None :
+        if options.at_instruction or options.simpoint:
+            checkpoint_inst = int(options.take_checkpoints)
 
-        print "when is ", when, " period is ", period
-        exit_event = m5.simulate(when)
-        while exit_event.getCause() == "checkpoint":
-            exit_event = m5.simulate(when - m5.curTick())
+            # maintain correct offset if we restored from some instruction
+            if options.checkpoint_restore != None:
+                checkpoint_inst += options.checkpoint_restore
 
-        if exit_event.getCause() == "simulate() limit reached":
-            m5.checkpoint(root, cptdir + "cpt.%d")
-            num_checkpoints += 1
+            print "Creating checkpoint at inst:%d" % (checkpoint_inst)
+            exit_event = m5.simulate()
+            print "exit cause = %s" % (exit_event.getCause())
 
-        sim_ticks = when
-        exit_cause = "maximum %d checkpoints dropped" % max_checkpoints
-        while num_checkpoints < max_checkpoints:
-            if (sim_ticks + period) > maxtick and maxtick != -1:
-                exit_event = m5.simulate(maxtick - sim_ticks)
-                exit_cause = exit_event.getCause()
-                break
-            else:
-                exit_event = m5.simulate(period)
-                sim_ticks += period
-                while exit_event.getCause() == "checkpoint":
-                    exit_event = m5.simulate(sim_ticks - m5.curTick())
-                if exit_event.getCause() == "simulate() limit reached":
-                    m5.checkpoint(root, cptdir + "cpt.%d")
-                    num_checkpoints += 1
-
-    else: #no checkpoints being taken via this script
+            # skip checkpoint instructions should they exist
+            while exit_event.getCause() == "checkpoint":
+                exit_event = m5.simulate()
+
+            if exit_event.getCause() == \
+                   "a thread reached the max instruction count":
+                m5.checkpoint(root, joinpath(cptdir, "cpt.%s.%d" % \
+                        (options.bench, checkpoint_inst)))
+                print "Checkpoint written."
+                num_checkpoints += 1
+
+            if exit_event.getCause() == "user interrupt received":
+                exit_cause = exit_event.getCause();
+        else:
+            when, period = options.take_checkpoints.split(",", 1)
+            when = int(when)
+            period = int(period)
+
+            exit_event = m5.simulate(when)
+            while exit_event.getCause() == "checkpoint":
+                exit_event = m5.simulate(when - m5.curTick())
+
+            if exit_event.getCause() == "simulate() limit reached":
+                m5.checkpoint(root, joinpath(cptdir, "cpt.%d"))
+                num_checkpoints += 1
+
+            sim_ticks = when
+            exit_cause = "maximum %d checkpoints dropped" % max_checkpoints
+            while num_checkpoints < max_checkpoints and \
+                    exit_event.getCause() == "simulate() limit reached":
+                if (sim_ticks + period) > maxtick:
+                    exit_event = m5.simulate(maxtick - sim_ticks)
+                    exit_cause = exit_event.getCause()
+                    break
+                else:
+                    exit_event = m5.simulate(period)
+                    sim_ticks += period
+                    while exit_event.getCause() == "checkpoint":
+                        exit_event = m5.simulate(sim_ticks - m5.curTick())
+                    if exit_event.getCause() == "simulate() limit reached":
+                        m5.checkpoint(root, joinpath(cptdir, "cpt.%d"))
+                        num_checkpoints += 1
+
+            if exit_event.getCause() != "simulate() limit reached":
+                exit_cause = exit_event.getCause();
+
+    else: # no checkpoints being taken via this script
+        if options.fast_forward:
+            m5.stats.reset()
+        print "**** REAL SIMULATION ****"
         exit_event = m5.simulate(maxtick)
 
         while exit_event.getCause() == "checkpoint":
-            m5.checkpoint(root, cptdir + "cpt.%d")
+            m5.checkpoint(root, joinpath(cptdir, "cpt.%d"))
             num_checkpoints += 1
             if num_checkpoints == max_checkpoints:
-                exit_cause =  "maximum %d checkpoints dropped" % max_checkpoints
+                exit_cause = "maximum %d checkpoints dropped" % max_checkpoints
                 break
 
-            if maxtick == -1:
-                exit_event = m5.simulate(maxtick)
-            else:
-                exit_event = m5.simulate(maxtick - m5.curTick())
-
+            exit_event = m5.simulate(maxtick - m5.curTick())
             exit_cause = exit_event.getCause()
 
     if exit_cause == '':
         exit_cause = exit_event.getCause()
-    print 'Exiting @ cycle', m5.curTick(), 'because ', exit_cause
+    print 'Exiting @ cycle %i because %s' % (m5.curTick(), exit_cause)
+
+    if options.checkpoint_at_end:
+        m5.checkpoint(root, joinpath(cptdir, "cpt.%d"))