pdb: Try to make pdb work better.
[gem5.git] / src / python / m5 / main.py
1 # Copyright (c) 2005 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: Nathan Binkert
28
29 import code
30 import datetime
31 import os
32 import socket
33 import sys
34
35 from util import attrdict
36 import config
37 from options import OptionParser
38
39 __all__ = [ 'options', 'arguments', 'main' ]
40
41 def print_list(items, indent=4):
42 line = ' ' * indent
43 for i,item in enumerate(items):
44 if len(line) + len(item) > 76:
45 print line
46 line = ' ' * indent
47
48 if i < len(items) - 1:
49 line += '%s, ' % item
50 else:
51 line += item
52 print line
53
54 usage="%prog [m5 options] script.py [script options]"
55 version="%prog 2.0"
56 brief_copyright='''
57 Copyright (c) 2001-2008
58 The Regents of The University of Michigan
59 All Rights Reserved
60 '''
61
62 options = OptionParser(usage=usage, version=version,
63 description=brief_copyright)
64 add_option = options.add_option
65 set_group = options.set_group
66 usage = options.usage
67
68 # Help options
69 add_option('-A', "--authors", action="store_true", default=False,
70 help="Show author information")
71 add_option('-B', "--build-info", action="store_true", default=False,
72 help="Show build information")
73 add_option('-C', "--copyright", action="store_true", default=False,
74 help="Show full copyright information")
75 add_option('-R', "--readme", action="store_true", default=False,
76 help="Show the readme")
77 add_option('-N', "--release-notes", action="store_true", default=False,
78 help="Show the release notes")
79
80 # Options for configuring the base simulator
81 add_option('-d', "--outdir", metavar="DIR", default=".",
82 help="Set the output directory to DIR [Default: %default]")
83 add_option('-r', "--redirect-stdout", action="store_true", default=False,
84 help="Redirect stdout (& stderr, without -e) to file")
85 add_option('-e', "--redirect-stderr", action="store_true", default=False,
86 help="Redirect stderr to file")
87 add_option("--stdout-file", metavar="FILE", default="simout",
88 help="Filename for -r redirection [Default: %default]")
89 add_option("--stderr-file", metavar="FILE", default="simerr",
90 help="Filename for -e redirection [Default: %default]")
91 add_option('-i', "--interactive", action="store_true", default=False,
92 help="Invoke the interactive interpreter after running the script")
93 add_option("--pdb", action="store_true", default=False,
94 help="Invoke the python debugger before running the script")
95 add_option('-p', "--path", metavar="PATH[:PATH]", action='append', split=':',
96 help="Prepend PATH to the system path when invoking the script")
97 add_option('-q', "--quiet", action="count", default=0,
98 help="Reduce verbosity")
99 add_option('-v', "--verbose", action="count", default=0,
100 help="Increase verbosity")
101
102 # Statistics options
103 set_group("Statistics Options")
104 add_option("--stats-file", metavar="FILE", default="m5stats.txt",
105 help="Sets the output file for statistics [Default: %default]")
106
107 # Debugging options
108 set_group("Debugging Options")
109 add_option("--debug-break", metavar="TIME[,TIME]", action='append', split=',',
110 help="Cycle to create a breakpoint")
111 add_option("--remote-gdb-port", type='int', default=7000,
112 help="Remote gdb base port")
113
114 # Tracing options
115 set_group("Trace Options")
116 add_option("--trace-help", action='store_true',
117 help="Print help on trace flags")
118 add_option("--trace-flags", metavar="FLAG[,FLAG]", action='append', split=',',
119 help="Sets the flags for tracing (-FLAG disables a flag)")
120 add_option("--trace-start", metavar="TIME", type='int',
121 help="Start tracing at TIME (must be in ticks)")
122 add_option("--trace-file", metavar="FILE", default="cout",
123 help="Sets the output file for tracing [Default: %default]")
124 add_option("--trace-ignore", metavar="EXPR", action='append', split=':',
125 help="Ignore EXPR sim objects")
126
127 # Help options
128 set_group("Help Options")
129 add_option("--list-sim-objects", action='store_true', default=False,
130 help="List all built-in SimObjects, their parameters and default values")
131
132 def main():
133 import event
134 import info
135 import internal
136
137 # load the options.py config file to allow people to set their own
138 # default options
139 options_file = config.get('options.py')
140 if options_file:
141 scope = { 'options' : options }
142 execfile(options_file, scope)
143
144 arguments = options.parse_args()
145
146 if not os.path.isdir(options.outdir):
147 os.makedirs(options.outdir)
148
149 # These filenames are used only if the redirect_std* options are set
150 stdout_file = os.path.join(options.outdir, options.stdout_file)
151 stderr_file = os.path.join(options.outdir, options.stderr_file)
152
153 # Print redirection notices here before doing any redirection
154 if options.redirect_stdout and not options.redirect_stderr:
155 print "Redirecting stdout and stderr to", stdout_file
156 else:
157 if options.redirect_stdout:
158 print "Redirecting stdout to", stdout_file
159 if options.redirect_stderr:
160 print "Redirecting stderr to", stderr_file
161
162 # Now redirect stdout/stderr as desired
163 if options.redirect_stdout:
164 redir_fd = os.open(stdout_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
165 os.dup2(redir_fd, sys.stdout.fileno())
166 if not options.redirect_stderr:
167 os.dup2(redir_fd, sys.stderr.fileno())
168
169 if options.redirect_stderr:
170 redir_fd = os.open(stderr_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
171 os.dup2(redir_fd, sys.stderr.fileno())
172
173 done = False
174
175 if options.build_info:
176 import defines
177
178 done = True
179 print 'Build information:'
180 print
181 print 'compiled %s' % internal.core.cvar.compileDate;
182 print "revision %s" % internal.core.cvar.hgRev
183 print "commit date %s" % internal.core.cvar.hgDate
184 print 'build options:'
185 keys = defines.m5_build_env.keys()
186 keys.sort()
187 for key in keys:
188 val = defines.m5_build_env[key]
189 print ' %s = %s' % (key, val)
190 print
191
192 if options.copyright:
193 done = True
194 print info.LICENSE
195 print
196
197 if options.authors:
198 done = True
199 print 'Author information:'
200 print
201 print info.AUTHORS
202 print
203
204 if options.readme:
205 done = True
206 print 'Readme:'
207 print
208 print info.README
209 print
210
211 if options.release_notes:
212 done = True
213 print 'Release Notes:'
214 print
215 print info.RELEASE_NOTES
216 print
217
218 if options.trace_help:
219 import traceflags
220
221 done = True
222 print "Base Flags:"
223 print_list(traceflags.baseFlags, indent=4)
224 print
225 print "Compound Flags:"
226 for flag in traceflags.compoundFlags:
227 if flag == 'All':
228 continue
229 print " %s:" % flag
230 print_list(traceflags.compoundFlagMap[flag], indent=8)
231 print
232
233 if options.list_sim_objects:
234 import SimObject
235 done = True
236 print "SimObjects:"
237 objects = SimObject.allClasses.keys()
238 objects.sort()
239 for name in objects:
240 obj = SimObject.allClasses[name]
241 print " %s" % obj
242 params = obj._params.keys()
243 params.sort()
244 for pname in params:
245 param = obj._params[pname]
246 default = getattr(param, 'default', '')
247 print " %s" % pname
248 if default:
249 print " default: %s" % default
250 print " desc: %s" % param.desc
251 print
252 print
253
254 if done:
255 sys.exit(0)
256
257 # setting verbose and quiet at the same time doesn't make sense
258 if options.verbose > 0 and options.quiet > 0:
259 options.usage(2)
260
261 verbose = options.verbose - options.quiet
262 if options.verbose >= 0:
263 print "M5 Simulator System"
264 print brief_copyright
265 print
266 print "M5 compiled %s" % internal.core.cvar.compileDate;
267 print "M5 revision %s" % internal.core.cvar.hgRev
268 print "M5 commit date %s" % internal.core.cvar.hgDate
269
270 print "M5 started %s" % datetime.datetime.now().strftime("%b %e %Y %X")
271 print "M5 executing on %s" % socket.gethostname()
272
273 print "command line:",
274 for argv in sys.argv:
275 print argv,
276 print
277
278 # check to make sure we can find the listed script
279 if not arguments or not os.path.isfile(arguments[0]):
280 if arguments and not os.path.isfile(arguments[0]):
281 print "Script %s not found" % arguments[0]
282
283 options.usage(2)
284
285 # tell C++ about output directory
286 internal.core.setOutputDir(options.outdir)
287
288 # update the system path with elements from the -p option
289 sys.path[0:0] = options.path
290
291 import objects
292
293 # set stats options
294 internal.stats.initText(options.stats_file)
295
296 # set debugging options
297 internal.debug.setRemoteGDBPort(options.remote_gdb_port)
298 for when in options.debug_break:
299 internal.debug.schedBreakCycle(int(when))
300
301 if options.trace_flags:
302 import traceflags
303
304 on_flags = []
305 off_flags = []
306 for flag in options.trace_flags:
307 off = False
308 if flag.startswith('-'):
309 flag = flag[1:]
310 off = True
311 if flag not in traceflags.allFlags:
312 print >>sys.stderr, "invalid trace flag '%s'" % flag
313 sys.exit(1)
314
315 if off:
316 off_flags.append(flag)
317 else:
318 on_flags.append(flag)
319
320 for flag in on_flags:
321 internal.trace.set(flag)
322
323 for flag in off_flags:
324 internal.trace.clear(flag)
325
326 if options.trace_start:
327 def enable_trace():
328 internal.trace.cvar.enabled = True
329 event.create(enable_trace, int(options.trace_start))
330 else:
331 internal.trace.cvar.enabled = True
332
333 internal.trace.output(options.trace_file)
334
335 for ignore in options.trace_ignore:
336 internal.trace.ignore(ignore)
337
338 sys.argv = arguments
339 sys.path = [ os.path.dirname(sys.argv[0]) ] + sys.path
340
341 filename = sys.argv[0]
342 filedata = file(filename, 'r').read()
343 filecode = compile(filedata, filename, 'exec')
344 scope = { '__file__' : filename,
345 '__name__' : '__m5_main__' }
346
347 # we want readline if we're doing anything interactive
348 if options.interactive or options.pdb:
349 exec "import readline" in scope
350
351 # if pdb was requested, execfile the thing under pdb, otherwise,
352 # just do the execfile normally
353 if options.pdb:
354 import pdb
355 import traceback
356
357 pdb = pdb.Pdb()
358 try:
359 pdb.run(filecode, scope)
360 except SystemExit:
361 print "The program exited via sys.exit(). Exit status: ",
362 print sys.exc_info()[1]
363 except:
364 traceback.print_exc()
365 print "Uncaught exception. Entering post mortem debugging"
366 t = sys.exc_info()[2]
367 while t.tb_next is not None:
368 t = t.tb_next
369 pdb.interaction(t.tb_frame,t)
370 else:
371 exec filecode in scope
372
373 # once the script is done
374 if options.interactive:
375 interact = code.InteractiveConsole(scope)
376 interact.interact("M5 Interactive Console")
377
378 if __name__ == '__main__':
379 from pprint import pprint
380
381 # load the options.py config file to allow people to set their own
382 # default options
383 options_file = config.get('options.py')
384 if options_file:
385 scope = { 'options' : options }
386 execfile(options_file, scope)
387
388 arguments = options.parse_args()
389
390 print 'opts:'
391 pprint(options, indent=4)
392 print
393
394 print 'args:'
395 pprint(arguments, indent=4)