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