Simulation.py revision 5369:9358355117b0
1# Copyright (c) 2006-2008 The Regents of The University of Michigan
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met: redistributions of source code must retain the above copyright
7# notice, this list of conditions and the following disclaimer;
8# redistributions in binary form must reproduce the above copyright
9# notice, this list of conditions and the following disclaimer in the
10# documentation and/or other materials provided with the distribution;
11# neither the name of the copyright holders nor the names of its
12# contributors may be used to endorse or promote products derived from
13# this software without specific prior written permission.
14#
15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26#
27# Authors: Lisa Hsu
28
29from os import getcwd
30from os.path import join as joinpath
31import m5
32from m5.objects import *
33m5.AddToPath('../common')
34from Caches import L1Cache
35
36def setCPUClass(options):
37
38    atomic = False
39    if options.timing:
40        class TmpClass(TimingSimpleCPU): pass
41    elif options.detailed:
42        if not options.caches:
43            print "O3 CPU must be used with caches"
44            sys.exit(1)
45        class TmpClass(DerivO3CPU): pass
46    else:
47        class TmpClass(AtomicSimpleCPU): pass
48        atomic = True
49
50    CPUClass = None
51    test_mem_mode = 'atomic'
52
53    if not atomic:
54        if options.checkpoint_restore != None or options.fast_forward:
55            CPUClass = TmpClass
56            class TmpClass(AtomicSimpleCPU): pass
57        else:
58            test_mem_mode = 'timing'
59
60    return (TmpClass, test_mem_mode, CPUClass)
61
62
63def run(options, root, testsys, cpu_class):
64    if options.maxtick:
65        maxtick = options.maxtick
66    elif options.maxtime:
67        simtime = m5.ticks.seconds(simtime)
68        print "simulating for: ", simtime
69        maxtick = simtime
70    else:
71        maxtick = m5.MaxTick
72
73    if options.checkpoint_dir:
74        cptdir = options.checkpoint_dir
75    elif m5.options.outdir:
76        cptdir = m5.options.outdir
77    else:
78        cptdir = getcwd()
79
80    np = options.num_cpus
81    max_checkpoints = options.max_checkpoints
82    switch_cpus = None
83
84    if cpu_class:
85        switch_cpus = [cpu_class(defer_registration=True, cpu_id=(np+i))
86                       for i in xrange(np)]
87
88        for i in xrange(np):
89            if options.fast_forward:
90                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
91            switch_cpus[i].system =  testsys
92            if not m5.build_env['FULL_SYSTEM']:
93                switch_cpus[i].workload = testsys.cpu[i].workload
94            switch_cpus[i].clock = testsys.cpu[0].clock
95            # simulation period
96            if options.max_inst:
97                switch_cpus[i].max_insts_any_thread = options.max_inst
98
99        testsys.switch_cpus = switch_cpus
100        switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
101
102    if options.standard_switch:
103        switch_cpus = [TimingSimpleCPU(defer_registration=True, cpu_id=(np+i))
104                       for i in xrange(np)]
105        switch_cpus_1 = [DerivO3CPU(defer_registration=True, cpu_id=(2*np+i))
106                        for i in xrange(np)]
107
108        for i in xrange(np):
109            switch_cpus[i].system =  testsys
110            switch_cpus_1[i].system =  testsys
111            if not m5.build_env['FULL_SYSTEM']:
112                switch_cpus[i].workload = testsys.cpu[i].workload
113                switch_cpus_1[i].workload = testsys.cpu[i].workload
114            switch_cpus[i].clock = testsys.cpu[0].clock
115            switch_cpus_1[i].clock = testsys.cpu[0].clock
116
117            # if restoring, make atomic cpu simulate only a few instructions
118            if options.checkpoint_restore != None:
119                testsys.cpu[i].max_insts_any_thread = 1
120            # Fast forward to specified location if we are not restoring
121            elif options.fast_forward:
122                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
123            # Fast forward to a simpoint (warning: time consuming)
124            elif options.simpoint:
125                if testsys.cpu[i].workload[0].simpoint == None:
126                    m5.panic('simpoint not found')
127                testsys.cpu[i].max_insts_any_thread = \
128                    testsys.cpu[i].workload[0].simpoint
129            # No distance specified, just switch
130            else:
131                testsys.cpu[i].max_insts_any_thread = 1
132
133            # warmup period
134            if options.warmup_insts:
135                switch_cpus[i].max_insts_any_thread =  options.warmup_insts
136
137            # simulation period
138            if options.max_inst:
139                switch_cpus_1[i].max_insts_any_thread = options.max_inst
140
141            if not options.caches:
142                # O3 CPU must have a cache to work.
143                switch_cpus_1[i].addPrivateSplitL1Caches(L1Cache(size = '32kB'),
144                                                         L1Cache(size = '64kB'))
145                switch_cpus_1[i].connectMemPorts(testsys.membus)
146
147            testsys.switch_cpus = switch_cpus
148            testsys.switch_cpus_1 = switch_cpus_1
149            switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
150            switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)]
151
152    # set the checkpoint in the cpu before m5.instantiate is called
153    if options.take_checkpoints != None and \
154           (options.simpoint or options.at_instruction):
155        offset = int(options.take_checkpoints)
156        # Set an instruction break point
157        if options.simpoint:
158            for i in xrange(np):
159                if testsys.cpu[i].workload[0].simpoint == None:
160                    m5.panic('no simpoint for testsys.cpu[%d].workload[0]' % i)
161                checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset
162                testsys.cpu[i].max_insts_any_thread = checkpoint_inst
163                # used for output below
164                options.take_checkpoints = checkpoint_inst
165        else:
166            options.take_checkpoints = offset
167            # Set all test cpus with the right number of instructions
168            # for the upcoming simulation
169            for i in xrange(np):
170                testsys.cpu[i].max_insts_any_thread = offset
171
172    m5.instantiate(root)
173
174    if options.checkpoint_restore != None:
175        from os.path import isdir, exists
176        from os import listdir
177        import re
178
179        if not isdir(cptdir):
180            m5.panic("checkpoint dir %s does not exist!" % cptdir)
181
182        if options.at_instruction:
183            checkpoint_dir = joinpath(cptdir, "cpt.%s.%s" % \
184                    (options.bench, options.checkpoint_restore))
185            if not exists(checkpoint_dir):
186                m5.panic("Unable to find checkpoint directory %s" % \
187                         checkpoint_dir)
188
189            print "Restoring checkpoint ..."
190            m5.restoreCheckpoint(root, checkpoint_dir)
191            print "Done."
192        elif options.simpoint:
193            # assume workload 0 has the simpoint
194            if testsys.cpu[0].workload[0].simpoint == None:
195                m5.panic('Unable to find simpoint')
196
197            options.checkpoint_restore += \
198                int(testsys.cpu[0].workload[0].simpoint)
199
200            checkpoint_dir = joinpath(cptdir, "cpt.%s.%d" % \
201                    (options.bench, options.checkpoint_restore))
202            if not exists(checkpoint_dir):
203                m5.panic("Unable to find checkpoint directory %s.%s" % \
204                        (options.bench, options.checkpoint_restore))
205
206            print "Restoring checkpoint ..."
207            m5.restoreCheckpoint(root,checkpoint_dir)
208            print "Done."
209        else:
210            dirs = listdir(cptdir)
211            expr = re.compile('cpt\.([0-9]*)')
212            cpts = []
213            for dir in dirs:
214                match = expr.match(dir)
215                if match:
216                    cpts.append(match.group(1))
217
218            cpts.sort(lambda a,b: cmp(long(a), long(b)))
219
220            cpt_num = options.checkpoint_restore
221
222            if cpt_num > len(cpts):
223                m5.panic('Checkpoint %d not found' % cpt_num)
224
225            ## Adjust max tick based on our starting tick
226            maxtick = maxtick - int(cpts[cpt_num - 1])
227
228            ## Restore the checkpoint
229            m5.restoreCheckpoint(root,
230                    joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1]))
231
232    if options.standard_switch or cpu_class:
233        if options.standard_switch:
234            print "Switch at instruction count:%s" % \
235                    str(testsys.cpu[0].max_insts_any_thread)
236            exit_event = m5.simulate()
237        elif cpu_class and options.fast_forward:
238            print "Switch at instruction count:%s" % \
239                    str(testsys.cpu[0].max_insts_any_thread)
240            exit_event = m5.simulate()
241        else:
242            print "Switch at curTick count:%s" % str(10000)
243            exit_event = m5.simulate(10000)
244        print "Switched CPUS @ cycle = %s" % (m5.curTick())
245
246        # when you change to Timing (or Atomic), you halt the system
247        # given as argument.  When you are finished with the system
248        # changes (including switchCpus), you must resume the system
249        # manually.  You DON'T need to resume after just switching
250        # CPUs if you haven't changed anything on the system level.
251
252        m5.changeToTiming(testsys)
253        m5.switchCpus(switch_cpu_list)
254        m5.resume(testsys)
255
256        if options.standard_switch:
257            print "Switch at instruction count:%d" % \
258                    (testsys.switch_cpus[0].max_insts_any_thread)
259
260            #warmup instruction count may have already been set
261            if options.warmup_insts:
262                exit_event = m5.simulate()
263            else:
264                exit_event = m5.simulate(options.warmup)
265            print "Switching CPUS @ cycle = %s" % (m5.curTick())
266            print "Simulation ends instruction count:%d" % \
267                    (testsys.switch_cpus_1[0].max_insts_any_thread)
268            m5.drain(testsys)
269            m5.switchCpus(switch_cpu_list1)
270            m5.resume(testsys)
271
272    num_checkpoints = 0
273    exit_cause = ''
274
275    # Checkpoints being taken via the command line at <when> and at
276    # subsequent periods of <period>.  Checkpoint instructions
277    # received from the benchmark running are ignored and skipped in
278    # favor of command line checkpoint instructions.
279    if options.take_checkpoints != None :
280        if options.at_instruction or options.simpoint:
281            checkpoint_inst = int(options.take_checkpoints)
282
283            # maintain correct offset if we restored from some instruction
284            if options.checkpoint_restore != None:
285                checkpoint_inst += options.checkpoint_restore
286
287            print "Creating checkpoint at inst:%d" % (checkpoint_inst)
288            exit_event = m5.simulate()
289            print "exit cause = %s" % (exit_event.getCause())
290
291            # skip checkpoint instructions should they exist
292            while exit_event.getCause() == "checkpoint":
293                exit_event = m5.simulate()
294
295            if exit_event.getCause() == \
296                   "a thread reached the max instruction count":
297                m5.checkpoint(root, joinpath(cptdir, "cpt.%s.%d" % \
298                        (options.bench, checkpoint_inst)))
299                print "Checkpoint written."
300                num_checkpoints += 1
301
302            if exit_event.getCause() == "user interrupt received":
303                exit_cause = exit_event.getCause();
304        else:
305            when, period = options.take_checkpoints.split(",", 1)
306            when = int(when)
307            period = int(period)
308
309            exit_event = m5.simulate(when)
310            while exit_event.getCause() == "checkpoint":
311                exit_event = m5.simulate(when - m5.curTick())
312
313            if exit_event.getCause() == "simulate() limit reached":
314                m5.checkpoint(root, joinpath(cptdir, "cpt.%d"))
315                num_checkpoints += 1
316
317            sim_ticks = when
318            exit_cause = "maximum %d checkpoints dropped" % max_checkpoints
319            while num_checkpoints < max_checkpoints and \
320                    exit_event.getCause() == "simulate() limit reached":
321                if (sim_ticks + period) > maxtick:
322                    exit_event = m5.simulate(maxtick - sim_ticks)
323                    exit_cause = exit_event.getCause()
324                    break
325                else:
326                    exit_event = m5.simulate(period)
327                    sim_ticks += period
328                    while exit_event.getCause() == "checkpoint":
329                        exit_event = m5.simulate(sim_ticks - m5.curTick())
330                    if exit_event.getCause() == "simulate() limit reached":
331                        m5.checkpoint(root, joinpath(cptdir, "cpt.%d"))
332                        num_checkpoints += 1
333
334            if exit_event.getCause() != "simulate() limit reached":
335                exit_cause = exit_event.getCause();
336
337    else: # no checkpoints being taken via this script
338        if options.fast_forward:
339            m5.stats.reset()
340        print "**** REAL SIMULATION ****"
341        exit_event = m5.simulate(maxtick)
342
343        while exit_event.getCause() == "checkpoint":
344            m5.checkpoint(root, joinpath(cptdir, "cpt.%d"))
345            num_checkpoints += 1
346            if num_checkpoints == max_checkpoints:
347                exit_cause = "maximum %d checkpoints dropped" % max_checkpoints
348                break
349
350            exit_event = m5.simulate(maxtick - m5.curTick())
351            exit_cause = exit_event.getCause()
352
353    if exit_cause == '':
354        exit_cause = exit_event.getCause()
355    print 'Exiting @ cycle %i because %s' % (m5.curTick(), exit_cause)
356
357