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