Simulation.py revision 8724:7b4d80b26e35
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            if not buildEnv['FULL_SYSTEM']:
128                switch_cpus[i].workload = testsys.cpu[i].workload
129            switch_cpus[i].clock = testsys.cpu[0].clock
130            # simulation period
131            if options.maxinsts:
132                switch_cpus[i].max_insts_any_thread = options.maxinsts
133
134        testsys.switch_cpus = switch_cpus
135        switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
136
137    if options.standard_switch:
138        if not options.caches:
139            # O3 CPU must have a cache to work.
140            print "O3 CPU must be used with caches"
141            sys.exit(1)
142
143        switch_cpus = [TimingSimpleCPU(defer_registration=True, cpu_id=(np+i))
144                       for i in xrange(np)]
145        switch_cpus_1 = [DerivO3CPU(defer_registration=True, cpu_id=(2*np+i))
146                        for i in xrange(np)]
147
148        for i in xrange(np):
149            switch_cpus[i].system =  testsys
150            switch_cpus_1[i].system =  testsys
151            if not buildEnv['FULL_SYSTEM']:
152                switch_cpus[i].workload = testsys.cpu[i].workload
153                switch_cpus_1[i].workload = testsys.cpu[i].workload
154            switch_cpus[i].clock = testsys.cpu[0].clock
155            switch_cpus_1[i].clock = testsys.cpu[0].clock
156
157            # if restoring, make atomic cpu simulate only a few instructions
158            if options.checkpoint_restore != None:
159                testsys.cpu[i].max_insts_any_thread = 1
160            # Fast forward to specified location if we are not restoring
161            elif options.fast_forward:
162                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
163            # Fast forward to a simpoint (warning: time consuming)
164            elif options.simpoint:
165                if testsys.cpu[i].workload[0].simpoint == 0:
166                    fatal('simpoint not found')
167                testsys.cpu[i].max_insts_any_thread = \
168                    testsys.cpu[i].workload[0].simpoint
169            # No distance specified, just switch
170            else:
171                testsys.cpu[i].max_insts_any_thread = 1
172
173            # warmup period
174            if options.warmup_insts:
175                switch_cpus[i].max_insts_any_thread =  options.warmup_insts
176
177            # simulation period
178            if options.maxinsts:
179                switch_cpus_1[i].max_insts_any_thread = options.maxinsts
180
181        testsys.switch_cpus = switch_cpus
182        testsys.switch_cpus_1 = switch_cpus_1
183        switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
184        switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)]
185
186    # set the checkpoint in the cpu before m5.instantiate is called
187    if options.take_checkpoints != None and \
188           (options.simpoint or options.at_instruction):
189        offset = int(options.take_checkpoints)
190        # Set an instruction break point
191        if options.simpoint:
192            for i in xrange(np):
193                if testsys.cpu[i].workload[0].simpoint == 0:
194                    fatal('no simpoint for testsys.cpu[%d].workload[0]', i)
195                checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset
196                testsys.cpu[i].max_insts_any_thread = checkpoint_inst
197                # used for output below
198                options.take_checkpoints = checkpoint_inst
199        else:
200            options.take_checkpoints = offset
201            # Set all test cpus with the right number of instructions
202            # for the upcoming simulation
203            for i in xrange(np):
204                testsys.cpu[i].max_insts_any_thread = offset
205
206    checkpoint_dir = None
207    if options.checkpoint_restore != None:
208        from os.path import isdir, exists
209        from os import listdir
210        import re
211
212        if not isdir(cptdir):
213            fatal("checkpoint dir %s does not exist!", cptdir)
214
215        if options.at_instruction or options.simpoint:
216            inst = options.checkpoint_restore
217            if options.simpoint:
218                # assume workload 0 has the simpoint
219                if testsys.cpu[0].workload[0].simpoint == 0:
220                    fatal('Unable to find simpoint')
221                inst += int(testsys.cpu[0].workload[0].simpoint)
222
223            checkpoint_dir = joinpath(cptdir,
224                                      "cpt.%s.%s" % (options.bench, inst))
225            if not exists(checkpoint_dir):
226                fatal("Unable to find checkpoint directory %s", checkpoint_dir)
227        else:
228            dirs = listdir(cptdir)
229            expr = re.compile('cpt\.([0-9]*)')
230            cpts = []
231            for dir in dirs:
232                match = expr.match(dir)
233                if match:
234                    cpts.append(match.group(1))
235
236            cpts.sort(lambda a,b: cmp(long(a), long(b)))
237
238            cpt_num = options.checkpoint_restore
239
240            if cpt_num > len(cpts):
241                fatal('Checkpoint %d not found', cpt_num)
242
243            ## Adjust max tick based on our starting tick
244            maxtick = maxtick - int(cpts[cpt_num - 1])
245            checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1])
246
247    m5.instantiate(checkpoint_dir)
248
249    if options.standard_switch or cpu_class:
250        if options.standard_switch:
251            print "Switch at instruction count:%s" % \
252                    str(testsys.cpu[0].max_insts_any_thread)
253            exit_event = m5.simulate()
254        elif cpu_class and options.fast_forward:
255            print "Switch at instruction count:%s" % \
256                    str(testsys.cpu[0].max_insts_any_thread)
257            exit_event = m5.simulate()
258        else:
259            print "Switch at curTick count:%s" % str(10000)
260            exit_event = m5.simulate(10000)
261        print "Switched CPUS @ tick %s" % (m5.curTick())
262
263        # when you change to Timing (or Atomic), you halt the system
264        # given as argument.  When you are finished with the system
265        # changes (including switchCpus), you must resume the system
266        # manually.  You DON'T need to resume after just switching
267        # CPUs if you haven't changed anything on the system level.
268
269        m5.changeToTiming(testsys)
270        m5.switchCpus(switch_cpu_list)
271        m5.resume(testsys)
272
273        if options.standard_switch:
274            print "Switch at instruction count:%d" % \
275                    (testsys.switch_cpus[0].max_insts_any_thread)
276
277            #warmup instruction count may have already been set
278            if options.warmup_insts:
279                exit_event = m5.simulate()
280            else:
281                exit_event = m5.simulate(options.warmup)
282            print "Switching CPUS @ tick %s" % (m5.curTick())
283            print "Simulation ends instruction count:%d" % \
284                    (testsys.switch_cpus_1[0].max_insts_any_thread)
285            m5.drain(testsys)
286            m5.switchCpus(switch_cpu_list1)
287            m5.resume(testsys)
288
289    num_checkpoints = 0
290    exit_cause = ''
291
292    # If we're taking and restoring checkpoints, use checkpoint_dir
293    # option only for finding the checkpoints to restore from.  This
294    # lets us test checkpointing by restoring from one set of
295    # checkpoints, generating a second set, and then comparing them.
296    if options.take_checkpoints and options.checkpoint_restore:
297        if m5.options.outdir:
298            cptdir = m5.options.outdir
299        else:
300            cptdir = getcwd()
301
302    # Checkpoints being taken via the command line at <when> and at
303    # subsequent periods of <period>.  Checkpoint instructions
304    # received from the benchmark running are ignored and skipped in
305    # favor of command line checkpoint instructions.
306    if options.take_checkpoints != None :
307        if options.at_instruction or options.simpoint:
308            checkpoint_inst = int(options.take_checkpoints)
309
310            # maintain correct offset if we restored from some instruction
311            if options.checkpoint_restore != None:
312                checkpoint_inst += options.checkpoint_restore
313
314            print "Creating checkpoint at inst:%d" % (checkpoint_inst)
315            exit_event = m5.simulate()
316            print "exit cause = %s" % (exit_event.getCause())
317
318            # skip checkpoint instructions should they exist
319            while exit_event.getCause() == "checkpoint":
320                exit_event = m5.simulate()
321
322            if exit_event.getCause() == \
323                   "a thread reached the max instruction count":
324                m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \
325                        (options.bench, checkpoint_inst)))
326                print "Checkpoint written."
327                num_checkpoints += 1
328
329            if exit_event.getCause() == "user interrupt received":
330                exit_cause = exit_event.getCause();
331        else:
332            when, period = options.take_checkpoints.split(",", 1)
333            when = int(when)
334            period = int(period)
335
336            exit_event = m5.simulate(when)
337            while exit_event.getCause() == "checkpoint":
338                exit_event = m5.simulate(when - m5.curTick())
339
340            if exit_event.getCause() == "simulate() limit reached":
341                m5.checkpoint(joinpath(cptdir, "cpt.%d"))
342                num_checkpoints += 1
343
344            sim_ticks = when
345            exit_cause = "maximum %d checkpoints dropped" % max_checkpoints
346            while num_checkpoints < max_checkpoints and \
347                    exit_event.getCause() == "simulate() limit reached":
348                if (sim_ticks + period) > maxtick:
349                    exit_event = m5.simulate(maxtick - sim_ticks)
350                    exit_cause = exit_event.getCause()
351                    break
352                else:
353                    exit_event = m5.simulate(period)
354                    sim_ticks += period
355                    while exit_event.getCause() == "checkpoint":
356                        exit_event = m5.simulate(sim_ticks - m5.curTick())
357                    if exit_event.getCause() == "simulate() limit reached":
358                        m5.checkpoint(joinpath(cptdir, "cpt.%d"))
359                        num_checkpoints += 1
360
361            if exit_event.getCause() != "simulate() limit reached":
362                exit_cause = exit_event.getCause();
363
364    else: # no checkpoints being taken via this script
365        if options.fast_forward:
366            m5.stats.reset()
367        print "**** REAL SIMULATION ****"
368        exit_event = m5.simulate(maxtick)
369
370        while exit_event.getCause() == "checkpoint":
371            m5.checkpoint(joinpath(cptdir, "cpt.%d"))
372            num_checkpoints += 1
373            if num_checkpoints == max_checkpoints:
374                exit_cause = "maximum %d checkpoints dropped" % max_checkpoints
375                break
376
377            exit_event = m5.simulate(maxtick - m5.curTick())
378            exit_cause = exit_event.getCause()
379
380    if exit_cause == '':
381        exit_cause = exit_event.getCause()
382    print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause)
383
384    if options.checkpoint_at_end:
385        m5.checkpoint(joinpath(cptdir, "cpt.%d"))
386
387