run-sniper 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  1. #!/usr/bin/env python
  2. import sys, os, time, getopt, tempfile, subprocess, threading, platform, pprint, Queue, socket, pipes, commands
  3. sys.path.append(os.path.join(os.path.dirname(__file__), 'tools'))
  4. import sniper_lib, sniper_config, gen_simout, debugpin, env_setup, run_sniper
  5. HOME = env_setup.sim_root()
  6. def usage():
  7. print 'Run program under the Sniper simulator'
  8. print 'Usage:'
  9. print ' %s' % sys.argv[0] + \
  10. ' [-n <ncores (1)>]' + \
  11. ' [-d <outputdir (.)>]' + \
  12. ' [-c <sniper-config>]' + \
  13. ' [-c [objname:]<name[.cfg]>,<name2[.cfg]>,...]' + \
  14. ' [-c <sniper-options: section/key=value>]' + \
  15. ' [-s <script>]' + \
  16. ' [--roi]' + \
  17. ' [--roi-script]' + \
  18. ' [--viz]' + \
  19. ' [--viz-aso]' + \
  20. ' [--profile]' + \
  21. ' [--memory-profile]' + \
  22. ' [--cheetah]' + \
  23. ' [--perf]' + \
  24. ' [--gdb]' + \
  25. ' [--gdb-wait]' + \
  26. ' [--gdb-quit]' + \
  27. ' [--appdebug]' + \
  28. ' [--appdebug-manual]' + \
  29. ' [--appdebug-enable]' + \
  30. ' [--follow-execv=1]' + \
  31. ' [--power]' + \
  32. ' [--cache-only]' + \
  33. ' [--fast-forward]' + \
  34. ' [--no-cache-warming]' + \
  35. ' [--save-output]' + \
  36. ' [--save-patch]' + \
  37. ' [--pin-stats]' + \
  38. ' [--wrap-sim=]' + \
  39. ' [--mpi [--mpi-ranks=<ranks>] [--mpi-exec="<mpiexec -mpiarg...>"] ]' + \
  40. ' {--traces=<trace0>,<trace1>,... [--sim-end=<first|last|last-restart (default: first)>]' + \
  41. ' | --pinballs=<pinball-basename>,*' + \
  42. ' | --pid=<process-pid>' + \
  43. ' | [--sift] -- <cmdline> }'
  44. print
  45. print 'Example: $ ./run-sniper -- /bin/ls'
  46. print
  47. print 'Note: To get started quickly with our integrated benchmarks distribution (supports SPLASH-2 and PARSEC 2.1),'
  48. print ' see http://snipersim.org/w/Download_Benchmarks'
  49. print
  50. sys.exit(2)
  51. standalone = False
  52. ncores = 1
  53. outputdir = '.'
  54. configfiles = []
  55. sniperoptions = []
  56. roi_only = False
  57. roi_script = False
  58. sim_end = 'first'
  59. sim_end_valid = ('first', 'last', 'last-restart')
  60. use_viz = False
  61. use_viz_profile = ''
  62. use_viz_aso = ''
  63. use_viz_mcpat = ''
  64. use_profile = False
  65. use_memory_profile = False
  66. use_cheetah = False
  67. use_perf = False
  68. use_wrap_sim = None
  69. use_gdb = False
  70. gdb_wait = False
  71. gdb_quit = False
  72. use_appdebug = False
  73. appdebug_manual = False
  74. appdebug_nowait = False
  75. follow_execv = False
  76. run_power = False
  77. save_output = False
  78. save_patch = False
  79. pin_stats = False
  80. curdir = os.getcwd()
  81. scripts = []
  82. use_mpi = False
  83. mpi_ranks = 0
  84. use_mpiexec = False
  85. mpiexec_cmd = None
  86. traces = []
  87. resptraces = []
  88. trace_manual = False
  89. heteroconfig = None
  90. pinballs = None
  91. pinball_sift = True
  92. pinplay_addrtrans = False
  93. use_sift = False
  94. use_pid = None
  95. tracegen = None
  96. trace_extra_args = []
  97. verbose = False
  98. if not sys.argv[1:]:
  99. usage()
  100. def findfile(filename, extension, paths, subpaths = ('.')):
  101. for dirname in paths:
  102. for subpath in subpaths:
  103. for ext in ('', extension):
  104. fullname = os.path.realpath(os.path.join(dirname, subpath, filename + ext))
  105. if os.path.exists(fullname):
  106. return fullname
  107. return False
  108. def findconfig(filename, extension = '.cfg'):
  109. global curdir
  110. return findfile(filename, extension, (curdir, os.path.join(HOME, 'config')))
  111. def findtrace(trace, suffix = '.sift'):
  112. global curdir
  113. dirnames = (curdir, os.getenv('BENCHMARKS_TRACES', '.'), os.getenv('BENCHMARKS_ROOT', '.'), os.getenv('BENCHMARKS_ROOT_ORIG', '.'))
  114. return findfile(trace, suffix, dirnames, ('.', 'traces'))
  115. def findscript(script):
  116. global curdir
  117. return findfile(script, '.py', (curdir, os.path.join(HOME, 'scripts')))
  118. def add_config_file(filename, extension='.cfg'):
  119. config_files = []
  120. configfile = findconfig(filename, extension)
  121. if not configfile:
  122. print >> sys.stderr, 'Cannot find config file', filename
  123. sys.exit(1)
  124. # Handle #include
  125. for line in file(configfile):
  126. if line.startswith('#include'):
  127. config_files += add_config_file(line.split()[1], extension)
  128. config_files.append(configfile)
  129. return config_files
  130. def make_hetero_config(confignames, objname='core', extension='.cfg'):
  131. configfiles = map(lambda x: findconfig(x), confignames)
  132. if not all(configfiles):
  133. notfound = [ name for name, found in zip(confignames, configfiles) if not found ]
  134. print >> sys.stderr, 'Config file not found:', ', '.join(notfound)
  135. sys.exit(1)
  136. configfiledata = map(lambda x:open(x).read(), configfiles)
  137. configs = map(sniper_config.parse_config, configfiledata)
  138. # Generate a set of all config options
  139. opts = set()
  140. for config in configs:
  141. for key in config.keys():
  142. opts.add(key)
  143. # Combine all of the heterogeneous configurations
  144. newconfig = ''
  145. newconfig += '# Generated from ' + ', '.join(set(configfiles)) + '\n'
  146. for opt in opts:
  147. title, _, key = opt.rpartition('/')
  148. newconfig += '[%s]\n%s=' % (title,key)
  149. heteroopts = []
  150. for config in configs:
  151. if opt in config:
  152. heteroopts.append(config[opt])
  153. else:
  154. heteroopts.append('')
  155. newconfig += ','.join(heteroopts)+'\n'
  156. # Create initial tags for the heterogeneous configurations
  157. # The tags are the basename without the extension.
  158. # config/big.cfg with have the tag 'big'
  159. tags = map(lambda x:os.path.splitext(os.path.split(x)[1])[0], configfiles)
  160. for tag in set(tags):
  161. enabled = map(lambda x:(x == tag) and '1' or '0', tags)
  162. newconfig += '[tags/%s]\n' % objname
  163. newconfig += '%s=%s\n' % (tag,','.join(enabled))
  164. return newconfig
  165. record_trace_passthrough = [ 'pid-continue', 'stop-address=' ]
  166. try:
  167. opts, cmdline = getopt.getopt(
  168. sys.argv[1:],
  169. "hvn:m:d:c:g:s:",
  170. [
  171. "roi", "roi-script",
  172. "viz", "viz-aso",
  173. "profile", "memory-profile", "cheetah",
  174. "perf", "valgrind", "wrap-sim=",
  175. "gdb", "gdb-wait", "gdb-quit",
  176. "appdebug", "appdebug-manual", "appdebug-enable",
  177. "follow-execv=",
  178. "power",
  179. "cache-only", "fast-forward", "no-cache-warming",
  180. "save-output", "save-patch",
  181. "curdir=",
  182. "pin-stats",
  183. "traces=", "response-traces=", "trace-manual", "trace-args=",
  184. "sim-end=",
  185. "mpi", "mpi-ranks=", "mpi-exec=",
  186. "pinballs=", "pinball-non-sift", "pinplay-addr-trans",
  187. "sift",
  188. "pid=",
  189. ] + record_trace_passthrough
  190. )
  191. except getopt.GetoptError, e:
  192. # print help information and exit:
  193. print >> sys.stderr, e
  194. usage()
  195. for o, a in opts:
  196. if o == '-h':
  197. usage()
  198. sys.exit()
  199. if o == '-v':
  200. verbose = True
  201. if o == '-n':
  202. ncores = int(a)
  203. if o == '-d':
  204. outputdir = a
  205. if o == '-c':
  206. if '=' in a:
  207. if not a.startswith('-'):
  208. a = '--'+a
  209. sniperoptions.append(pipes.quote(a))
  210. elif ':' in a or ',' in a:
  211. obj, _, cfg = a.rpartition(':')
  212. if not obj:
  213. obj = 'core'
  214. heteroconfig = make_hetero_config(cfg.split(','), objname=obj)
  215. else:
  216. configfiles.extend(add_config_file(a))
  217. if o == '-g':
  218. if not a.startswith('-'):
  219. a = '--'+a
  220. sniperoptions.append(pipes.quote(a))
  221. if o == '--roi':
  222. roi_only = True
  223. if o == '--roi-script':
  224. roi_script = True
  225. if o == '--sim-end':
  226. if a not in sim_end_valid:
  227. print >> sys.stderr, '--sim-end value', a, 'invalid, need one of', sim_end_valid
  228. sys.exit(1)
  229. sim_end = a
  230. if o == '-s':
  231. scripts.append(a)
  232. if o == '--viz':
  233. use_viz = True
  234. if o == '--viz-aso':
  235. use_viz_aso = '--add-level=aso'
  236. if o == '--profile':
  237. use_profile = True
  238. use_viz_profile = '--add-level=profile'
  239. if o == '--memory-profile':
  240. use_memory_profile = True
  241. if o == '--cheetah':
  242. use_cheetah = True
  243. sniperoptions.append('-g --core/cheetah/enabled=true')
  244. if o == '--perf':
  245. use_perf = True
  246. if o == '--valgrind':
  247. use_wrap_sim = 'valgrind'
  248. if o == '--wrap-sim':
  249. use_wrap_sim = a
  250. if o == '--gdb':
  251. use_gdb = True
  252. if o == '--gdb-wait':
  253. use_gdb = True
  254. gdb_wait = True
  255. if o == '--gdb-quit':
  256. use_gdb = True
  257. gdb_wait = False
  258. gdb_quit = True
  259. if o == '--appdebug':
  260. use_appdebug = True
  261. if o == '--appdebug-manual':
  262. use_appdebug = True
  263. appdebug_manual = True
  264. if o == '--appdebug-enable':
  265. use_appdebug = True
  266. appdebug_nowait = True
  267. if o == '--follow-execv':
  268. if a != '1':
  269. # TODO: implement system where a path through an arbitrary execv() tree can be specified
  270. print >> sys.stderr, 'Please use --follow-execv=1 to ensure future compatibility'
  271. sys.exit(-1)
  272. follow_execv = True
  273. if o == '--power':
  274. run_power = True
  275. use_viz_mcpat = '--mcpat'
  276. if o == '--cache-only':
  277. sniperoptions.append('-g --general/inst_mode_roi=cache_only')
  278. if o == '--fast-forward':
  279. sniperoptions.append('-g --general/inst_mode_init=fast_forward')
  280. sniperoptions.append('-g --general/inst_mode_roi=fast_forward')
  281. if o == '--no-cache-warming':
  282. sniperoptions.append('-g --general/inst_mode_init=fast_forward')
  283. if o == '--save-output':
  284. save_output = True
  285. if o == '--save-patch':
  286. save_patch = True
  287. if o == '--pin-stats':
  288. pin_stats = True
  289. if o == '--curdir':
  290. curdir = a
  291. if o == '--traces':
  292. traces.extend(a.split(','))
  293. if o == '--response-traces':
  294. resptraces.extend(a.split(','))
  295. if o == '--trace-manual':
  296. trace_manual = True
  297. if o == '--trace-args':
  298. trace_extra_args.extend(['-X', a])
  299. if o == '--mpi':
  300. use_mpi = True
  301. if o == '--mpi-ranks':
  302. mpi_ranks = long(a)
  303. if o == '--mpi-exec':
  304. use_mpi = True
  305. mpiexec_cmd = a
  306. if o == '--pinballs':
  307. pinballs = a.split(',')
  308. if o == '--pinball-non-sift':
  309. pinball_sift = False
  310. if o == '--pinplay-addr-trans':
  311. pinplay_addrtrans = True
  312. if o == '--sift':
  313. use_sift = True
  314. if o == '--pid':
  315. use_pid = a
  316. use_sift = True
  317. if o.startswith('--') and o[2:] in record_trace_passthrough:
  318. trace_extra_args.append(o)
  319. if o.startswith('--') and o[2:]+'=' in record_trace_passthrough:
  320. trace_extra_args += [o, a]
  321. if cmdline:
  322. if use_mpi or use_sift:
  323. standalone = True
  324. else:
  325. standalone = False
  326. if traces or trace_manual:
  327. print >> sys.stderr, 'Cannot combine traces with running a benchmark'
  328. usage()
  329. if pinballs:
  330. print >> sys.stderr, 'Cannot combine pinball use with running a benchmark'
  331. usage()
  332. elif pinballs:
  333. if len(pinballs) > 1 and not pinball_sift:
  334. print >> sys.stderr, 'Cannot run multiple non-SIFT pinballs'
  335. usage()
  336. if sim_end.endswith('-restart'):
  337. print >> sys.stderr, 'Restart not supported in PinPlay mode'
  338. usage()
  339. standalone = pinball_sift
  340. if traces or trace_manual:
  341. print >> sys.stderr, 'Cannot combine a pinball with tracing (--traces= or --trace-manual)'
  342. usage()
  343. for idx, pinball in enumerate(pinballs[:]):
  344. pinball_found = findtrace(pinball, suffix='.address')
  345. if not pinball_found:
  346. print >> sys.stderr, 'Unable to locate a pinball at (%s), make sure that (%s.address) exists.' % (pinball, pinball)
  347. usage()
  348. else:
  349. pinballs[idx] = pinball_found.rpartition('.')[0]
  350. else:
  351. standalone = True
  352. opt_count = 0
  353. if traces:
  354. opt_count+=1
  355. if trace_manual:
  356. opt_count+=1
  357. if use_pid:
  358. opt_count+=1
  359. if opt_count == 0:
  360. print >> sys.stderr, 'Need either a set of traces (--traces= or --trace-manual), a pinball, an application pid or a benchmark command line'
  361. usage()
  362. if opt_count > 1:
  363. print >> sys.stderr, 'Can only use one of --traces=, --trace-manual, --pid= or --pinballs= when not using a command line argument'
  364. usage()
  365. if roi_only and roi_script:
  366. print >> sys.stderr, 'Use either --roi or --roi-script but not both'
  367. sys.exit(-1)
  368. if standalone:
  369. if use_appdebug:
  370. print >> sys.stderr, '--appdebug not supported in standalone mode'
  371. sys.exit(-1)
  372. if use_wrap_sim and use_gdb:
  373. print >> sys.stderr, 'Cannot use both --wrap-sim and --gdb at the same time [wrap-cmd="%(use_wrap_sim)s"]' % locals()
  374. sys.exit(-1)
  375. if follow_execv:
  376. print >> sys.stderr, '--follow-execv not supported in standalone mode'
  377. sys.exit(-1)
  378. else:
  379. if use_wrap_sim:
  380. print >> sys.stderr, '--wrap-sim only supported in standalone mode [wrap-cmd="%(use_wrap_sim)s"]' % locals()
  381. sys.exit(-1)
  382. if follow_execv and use_gdb:
  383. print >> sys.stderr, 'Cannot use both --follow-execv and --gdb at the same time'
  384. sys.exit(-1)
  385. if use_profile and use_memory_profile:
  386. print >> sys.stderr, 'Cannot use both --profile and --memory-profile at the same time'
  387. sys.exit(-1)
  388. yama_ptrace_file = '/proc/sys/kernel/yama/ptrace_scope'
  389. if use_gdb and os.path.isfile(yama_ptrace_file):
  390. y_pt = int(open(yama_ptrace_file).readline())
  391. if y_pt != 0:
  392. print >> sys.stderr, '\nError: Unable to enable debugging via gdb when the yama ptrace_scope protection is enabled.'
  393. print >> sys.stderr, ' Disable ptrace_scope by setting /proc/sys/kernel/yama/ptrace_scope to 0'
  394. print >> sys.stderr, ' or by updating the value in /etc/sysctl.d/10-ptrace.conf.'
  395. print >> sys.stderr, ' === GDB permission error ===\n'
  396. sys.exit(-1)
  397. outputdir = os.path.realpath(outputdir)
  398. if not os.path.exists(outputdir):
  399. try:
  400. os.makedirs(outputdir)
  401. except OSError:
  402. print >> sys.stderr, 'Failed to create output directory', outputdir
  403. sys.exit(-1)
  404. if save_output:
  405. prefix_fd = run_sniper.Tee(os.path.join(outputdir, 'sim.stdout'))
  406. os.dup2(prefix_fd, sys.stdout.fileno())
  407. os.dup2(prefix_fd, sys.stderr.fileno())
  408. if heteroconfig:
  409. hcfgfile = os.path.join(outputdir,'sim.hetero.cfg')
  410. fp = open(hcfgfile, 'w')
  411. fp.write(heteroconfig)
  412. fp.close()
  413. configfiles.append(hcfgfile)
  414. if not configfiles:
  415. # No config file(s) specified: prepend default Xeon X5550 Gainestown
  416. configfiles = add_config_file('gainestown')
  417. # Prepend config files to options, so -g options are always later on the command line and override config files
  418. sniperoptions = [ '--config=%s' % cfgfile for cfgfile in configfiles ] + sniperoptions
  419. if roi_only or use_mpi:
  420. sniperoptions.append('-g --general/magic=true')
  421. if roi_script:
  422. sniperoptions.append('-g --general/roi_script=true')
  423. if sim_end == 'first':
  424. sniperoptions.append('-g --traceinput/stop_with_first_app=true')
  425. sniperoptions.append('-g --traceinput/restart_apps=false')
  426. elif sim_end == 'last':
  427. sniperoptions.append('-g --traceinput/stop_with_first_app=false')
  428. sniperoptions.append('-g --traceinput/restart_apps=false')
  429. elif sim_end == 'last-restart':
  430. sniperoptions.append('-g --traceinput/stop_with_first_app=false')
  431. sniperoptions.append('-g --traceinput/restart_apps=true')
  432. if use_viz:
  433. scripts.append('periodic-stats:1000:2000')
  434. scripts.append('markers:markers')
  435. if use_viz_aso or use_profile:
  436. sniperoptions.append('-g --instruction_tracer/type=fpstats')
  437. sniperoptions.append('-g --routine_tracer/type=funcstats')
  438. if use_memory_profile:
  439. sniperoptions.append('-g --routine_tracer/type=memory_tracker')
  440. if scripts:
  441. scriptname = os.path.join(outputdir, 'sim.scripts.py')
  442. scriptfileobj = open(scriptname, 'w')
  443. # Generate a Python script that executes all user scripts with their arguments
  444. scriptfileobj.write('import sys\n')
  445. for i, script in enumerate(scripts):
  446. if ':' in script:
  447. filename, args = script.split(':', 1)
  448. else:
  449. filename, args = script, ''
  450. scriptfile = findscript(filename)
  451. if not scriptfile:
  452. print >> sys.stderr, 'Cannot find script file', filename
  453. sys.exit(-1)
  454. scriptfileobj.write('sys.argv = [ "%s", "%s" ]\n' % (scriptfile, args.replace('"', r'\"')))
  455. scriptfileobj.write('execfile("%s")\n' % scriptfile)
  456. scriptfileobj.close()
  457. # Pass our generated script as a single, argument-less script
  458. sniperoptions.append('-g --hooks/numscripts=1')
  459. sniperoptions.append('-g --hooks/script0name=%s' % scriptname)
  460. sniperoptions.append('-g --hooks/script0args=')
  461. # If using traces via this front-end, support either multi-program workloads or a single multi-threaded application
  462. if traces:
  463. sniperoptions.append('-g --traceinput/enabled=true')
  464. if resptraces:
  465. sniperoptions.append('-g --traceinput/emulate_syscalls=true')
  466. sniperoptions.append('-g --traceinput/num_apps=1')
  467. else:
  468. sniperoptions.append('-g --traceinput/emulate_syscalls=false')
  469. sniperoptions = ['-g --traceinput/mirror_output=true'] + sniperoptions # Stored traces: mirror output by default, overridable on command line
  470. sniperoptions.append('-g --traceinput/num_apps=%u' % len(traces))
  471. for thread_id, trace in enumerate(traces):
  472. filename = findtrace(trace, suffix='.sift')
  473. if filename:
  474. print '[SNIPER] (%u) Using trace file %s' % (thread_id, filename)
  475. sniperoptions.append('-g --traceinput/thread_%u=%s' % (thread_id, filename))
  476. else:
  477. print >> sys.stderr, 'Cannot find trace', trace
  478. sys.exit(-1)
  479. for thread_id, trace in enumerate(resptraces):
  480. filename = findtrace(trace, suffix='.sift')
  481. if filename:
  482. print '[SNIPER] (%u) Using response-trace file %s' % (thread_id, filename)
  483. sniperoptions.append('-g --traceinput/thread_response_%u=%s' % (thread_id, filename))
  484. else:
  485. print >> sys.stderr, 'Cannot find trace', trace
  486. sys.exit(-1)
  487. elif use_mpi:
  488. tracegen = {}
  489. if not mpi_ranks:
  490. mpi_ranks = ncores
  491. tracegen['enabled'] = 'true'
  492. tracegen['emulate_syscalls'] = 'true'
  493. tracegen['num_apps'] = mpi_ranks
  494. tracegen['redirect'] = False
  495. sniperoptions.append('-g --traceinput/stop_with_first_app=false') # Only stop once all MPI ranks have completed
  496. # Set trace recorder options
  497. if mpiexec_cmd:
  498. mpiexec = mpiexec_cmd.split(' ')
  499. else:
  500. mpiexec = ['mpiexec']
  501. mpiexec.extend(['-np', str(mpi_ranks)])
  502. applications = [
  503. (mpiexec, [ roi_only and '--roi' or '--roi-mpi', '-e', '1', '-s', '-1', '-r', '1', '--follow', '--pa', '--routine-tracing', '--' ] + cmdline)
  504. ]
  505. elif use_sift:
  506. tracegen = {}
  507. tracegen['enabled'] = 'true'
  508. tracegen['emulate_syscalls'] = 'true'
  509. tracegen['num_apps'] = 1
  510. tracegen['redirect'] = False
  511. sniperoptions.append('-g --traceinput/stop_with_first_app=false') # Only stop once all processes have completed
  512. # Set trace recorder options
  513. other_options = []
  514. if roi_only:
  515. other_options += [ '--roi' ]
  516. if use_pid:
  517. other_options += [ '--pid', use_pid ]
  518. applications = [
  519. ([], other_options + ['-e', '1', '-s', '0', '-r', '1', '--follow', '--pa', '--routine-tracing', '--' ] + cmdline)
  520. ]
  521. elif pinballs and pinball_sift:
  522. tracegen = {}
  523. tracegen['enabled'] = 'true'
  524. tracegen['emulate_syscalls'] = 'false'
  525. tracegen['num_apps'] = len(pinballs)
  526. tracegen['redirect'] = True
  527. # Set trace recorder options
  528. applications = []
  529. for app_id, pinball in enumerate(pinballs):
  530. applications.append(([], [ '-e', '0', '-s', str(app_id), '-r', '1', '--pinball', pinball, '--outputdir', outputdir ]))
  531. # Setup common generated trace files
  532. tracecmds = []
  533. if tracegen:
  534. tracegen['enabled'] = 'true'
  535. sniperoptions.append('-g --traceinput/enabled=%s' % tracegen['enabled'])
  536. sniperoptions.append('-g --traceinput/emulate_syscalls=%s' % tracegen['emulate_syscalls'])
  537. sniperoptions.append('-g --traceinput/num_apps=%d' % tracegen['num_apps'])
  538. basefname = 'run_benchmarks'
  539. tracegen['tracetempdir'] = tempfile.mkdtemp()
  540. tracegen['tracefiles_created'] = [] # FIFOs to be cleaned up
  541. traceprefix = os.path.join(tracegen['tracetempdir'], basefname)
  542. sniperoptions.append('-g --traceinput/trace_prefix=%s' % traceprefix)
  543. # Create FIFOs for first thread of each application
  544. for r in range(tracegen['num_apps']):
  545. for f in ('','_response'):
  546. filename = '%s%s.app%d.th%d.sift' % (traceprefix, f, r, 0)
  547. os.mkfifo(filename)
  548. tracegen['tracefiles_created'].append(filename)
  549. # Start app(s) with trace recorder in a thread
  550. def run_sift_recorder(tracecmd):
  551. if verbose:
  552. print '[SNIPER] Running', tracecmd
  553. sys.stdout.flush()
  554. sys.stderr.flush()
  555. time.sleep(1)
  556. subprocess.Popen(tracecmd).communicate()
  557. if pinplay_addrtrans:
  558. trace_extra_args += [ '--pinplay-addr-trans' ]
  559. for app_id, (pre_cmd, app_cmd) in enumerate(applications):
  560. tracecmd = pre_cmd + [ os.path.join(HOME, 'record-trace'), '-o', traceprefix ] + (['-v'] if verbose else []) + trace_extra_args + app_cmd
  561. tracecmds.append(tracecmd)
  562. if tracegen['redirect']: # redirect output
  563. threading.Thread(target = run_sniper.run_program_redirect, args = (app_id, run_sift_recorder, tracecmd, outputdir)).start()
  564. else: # inline output
  565. threading.Thread(target = run_sift_recorder, args = (tracecmd,)).start()
  566. sniperoptions = ' '.join(sniperoptions)
  567. configfile = os.path.join(HOME, 'config/sniper.py')
  568. config = {}
  569. execfile(configfile, {}, config)
  570. # convert paths in config to absolute paths
  571. for d in ('pin_home',):
  572. absdir = os.path.join(HOME, config[d])
  573. if not os.path.isdir(absdir):
  574. sys.stderr.write('Cannot find %s %s, please check %s\n' % (d, absdir, configfile))
  575. sys.exit(-1)
  576. exec "%s = '%s'" % (d, absdir)
  577. sim_root = HOME
  578. arch = config.get('target', 'intel64')
  579. env = run_sniper.setup_env(sim_root, pin_home, arch, standalone)
  580. optcmd = ''
  581. pin_version = 'unknown'
  582. pinoptions = ''
  583. if not standalone:
  584. try:
  585. pin_version = subprocess.Popen(['%(HOME)s/tools/pinversion.py' % locals(), pin_home], stdout = subprocess.PIPE).communicate()[0]
  586. pin_version = int(pin_version.split('.')[2])
  587. assert 10000 < pin_version < 1000000
  588. except Exception, e:
  589. print >> sys.stderr, 'Cannot get Pin version'
  590. print >> sys.stderr
  591. print >> sys.stderr, e
  592. print >> sys.stderr, pin_version
  593. sys.exit(-1)
  594. pinoptions = '-mt -injection child'
  595. if pin_version >= 49303:
  596. pinoptions += ' -xyzzy -enable_vsm 0' # TODO: Enable vsm once OpenMP thread exit is solved (Redmine #148)
  597. if arch == 'ia32':
  598. # Running Jikes (which is 32-bit) on Sandy Bridge machines sometimes seem to suffer from data corruption,
  599. # leading to weird application crashes. This problem is gone when disabling AVX support.
  600. # Note that this was on Pin 2.12.55942, later versions (up to 2.12.58423) have even worse problems
  601. # (broken SMC or something, see http://groups.yahoo.com/neo/groups/pinheads/conversations/topics/9147 )
  602. pinoptions += ' -xyzzy -allow_AVX_support 0'
  603. if pin_stats:
  604. pinoptions += ' -xyzzy -profile -statistic -log_inline'
  605. if use_gdb:
  606. pinoptions += ' -pause_tool 1'
  607. if use_appdebug:
  608. if appdebug_nowait:
  609. pinoptions += ' -appdebug_enable -appdebug_silent'
  610. else:
  611. pinoptions += ' -appdebug'
  612. if follow_execv:
  613. pinoptions += ' -follow_execv 1'
  614. if pinballs and not pinball_sift:
  615. optcmd += ' -replay -replay:basename "%s" -pinplay:msgfile "%s" -replay:resultfile "%s" --general/enable_pinplay=true' % (pinballs[0], os.path.join(outputdir,'pinball_replay'), os.path.join(outputdir,'pinball_result'))
  616. if pinplay_addrtrans:
  617. optcmd += " -replay:addr_trans"
  618. else:
  619. pinoptions += ' -xyzzy -reserve_memory "%s.address"' % (pinballs[0])
  620. # Overwrite the cmdline with the nullapp, as the pinball will handle the appropriate processing
  621. nullapp_path = '%(pin_home)s/extras/pinplay/bin/%(arch)s/nullapp' % locals()
  622. if not os.path.exists(nullapp_path):
  623. print >> sys.stderr, "Error: Unable to locate PinPlay's nullapp to play back a pinball"
  624. sys.exit(1)
  625. cmdline = [nullapp_path]
  626. optcmd += ' -c %(sim_root)s/config/base.cfg --general/total_cores=%(ncores)u --general/output_dir=%(outputdir)s %(sniperoptions)s' % locals()
  627. if standalone:
  628. if use_gdb:
  629. fh, fn = tempfile.mkstemp()
  630. f = open(fn, 'w')
  631. # When using GDB in standalone mode, do not set the LD_LIBRARY_PATH for GDB, but instead set the shared library path inside GDB for debugging Sniper-standalone
  632. f.write("set environment LD_LIBRARY_PATH = %s\n" % env['LD_LIBRARY_PATH'])
  633. del env['LD_LIBRARY_PATH']
  634. # Create a GDB command file to handle --gdb, --gdb-wait and --gdb-quit for standalone mode
  635. if not gdb_wait:
  636. f.write('run\n')
  637. # Only quit GDB when we have not seen a signal
  638. if gdb_quit:
  639. f.write('if ($_siginfo)\n')
  640. f.write('else \n')
  641. f.write(' quit\n')
  642. f.write('end\n')
  643. f.close()
  644. gdbcmd = 'gdb -quiet --command=%(fn)s %(HOME)s/lib/sniper --args ' % locals()
  645. elif use_wrap_sim:
  646. gdbcmd = '%(use_wrap_sim)s ' % locals()
  647. else:
  648. gdbcmd = ''
  649. cmd = gdbcmd + '%(HOME)s/lib/sniper' % locals() + optcmd
  650. else:
  651. if follow_execv:
  652. pintool = 'follow_execv'
  653. else:
  654. pintool = 'pin_sim'
  655. cmd = '%(pin_home)s/%(arch)s/bin/pinbin %(pinoptions)s -t %(sim_root)s/lib/%(pintool)s' % locals() + optcmd + ' -- ' + ' '.join(cmdline)
  656. queue = Queue.Queue()
  657. memusage = 0; stopping = False
  658. usage = None
  659. def log_memory(pid):
  660. def do_log_memory():
  661. global memusage
  662. while not stopping:
  663. # find children of all known pid's
  664. pids = sniper_lib.find_children(pid)
  665. # sum memory usage of all children
  666. _memusage = 0
  667. for _pid in pids:
  668. try:
  669. proc = file('/proc/%u/statm' % int(_pid)).read()
  670. _memusage += long(proc.split()[0]) * 4096
  671. except:
  672. # process already dead, or something
  673. pass
  674. memusage = max(memusage, _memusage)
  675. # sleep 10 seconds, in an interruptable way so we delay completion by only 1 second rather than up to 10 seconds
  676. for i in range(10):
  677. time.sleep(1)
  678. if stopping: break
  679. threading.Thread(target = do_log_memory).start()
  680. def execute():
  681. global cmd, usage
  682. cmd = [ 'bash', '-c', cmd ]
  683. if use_perf:
  684. cmd = [ 'perf', 'record', '--force', '--output', os.path.join(outputdir, 'perf.data'), '--' ] + cmd
  685. if verbose:
  686. print '[SNIPER] Running', cmd
  687. sys.stdout.flush()
  688. sys.stderr.flush()
  689. subproc = subprocess.Popen(cmd, env = env)
  690. log_memory(subproc.pid)
  691. try:
  692. try:
  693. pid, rc, usage = os.wait4(subproc.pid, 0)
  694. except AttributeError:
  695. pid, rc = os.waitpid(subproc.pid, 0)
  696. except KeyboardInterrupt:
  697. try:
  698. os.kill(subproc.pid, 9)
  699. except OSError:
  700. # Already dead, never mind
  701. pass
  702. return 9
  703. rc >>= 8
  704. return rc
  705. def execute_appdebug():
  706. if verbose:
  707. print '[SNIPER] Running', cmd
  708. sys.stdout.flush()
  709. sys.stderr.flush()
  710. p_sniper = subprocess.Popen([ 'bash', '-c', cmd ], bufsize = 1, stdout = subprocess.PIPE, env = env)
  711. while True:
  712. line = p_sniper.stdout.readline()
  713. if line.startswith(' target remote :'):
  714. info = file(os.path.join(outputdir, 'appdebug_port.out')).read()
  715. g_pid, g_remote = map(long, info.split())
  716. break
  717. print
  718. print "To interrupt the application, use: kill -INT %s" % g_pid
  719. print
  720. def output_sniper():
  721. while True:
  722. line = p_sniper.stdout.readline()
  723. if not line: break
  724. print line,
  725. threading.Thread(target = output_sniper).start()
  726. fh, fn = tempfile.mkstemp()
  727. f = open(fn, 'w')
  728. f.write('target remote :%s\n' % g_remote)
  729. f.close()
  730. rc = os.system('gdb -quiet -command=%s %s' % (fn, '/proc/%s/exe' % g_pid)) # /proc/<pid>/exe is a symlink to the actual binary
  731. rc >>= 8
  732. return rc
  733. if save_patch:
  734. sniperrootdir = HOME
  735. gitdir = os.path.join(sniperrootdir, '.git')
  736. patchfile = os.path.join(outputdir, 'sim.patch')
  737. os.system("git --work-tree='%(sniperrootdir)s' --git-dir='%(gitdir)s' log --max-count=1 --pretty=%%H > '%(patchfile)s'" % locals())
  738. os.system("git --work-tree='%(sniperrootdir)s' --git-dir='%(gitdir)s' diff >> '%(patchfile)s'" % locals())
  739. backtracefile = os.path.join(outputdir, 'debug_backtrace.out')
  740. for filetodelete in (backtracefile, 'sim.out', 'sim.cfg', 'sim.info', 'sim.stats.sqlite3', 'pin.log'):
  741. filetodelete = os.path.join(outputdir, filetodelete)
  742. try: os.unlink(filetodelete)
  743. except OSError: pass
  744. # Pin creates a pin.log file in os.getcwd() when there is a crash. Delete the old version as to not copy it to the outputdir
  745. try: os.unlink('pin.log')
  746. except OSError: pass
  747. t_start = time.time()
  748. print '[SNIPER] Start'
  749. try:
  750. if use_gdb and not standalone:
  751. rc = debugpin.execute_gdb(cmd = cmd, env = env, pin_home = pin_home, arch = arch, wait = gdb_wait, quit = gdb_quit)
  752. elif use_appdebug and not (appdebug_manual or appdebug_nowait):
  753. rc = execute_appdebug()
  754. else:
  755. rc = execute()
  756. except KeyboardInterrupt:
  757. # Make sure Sniper itself is stopped, even if it didn't respond to the SIGINT
  758. print '\n[SNIPER] Ctrl-C detected: Killing all child processes'
  759. time.sleep(1)
  760. sniper_lib.kill_children()
  761. sys.exit(-1)
  762. stopping = True
  763. t_end = time.time()
  764. t_elapsed = t_end - t_start
  765. print '[SNIPER] End'
  766. print '[SNIPER] Elapsed time:', '%.02f' % t_elapsed, 'seconds'
  767. if tracegen:
  768. # Cleanup the pipes and temporary directory
  769. try:
  770. for f in tracegen['tracefiles_created']:
  771. os.unlink(f)
  772. os.rmdir(tracegen['tracetempdir'])
  773. except OSError:
  774. pass
  775. if os.path.exists(backtracefile) and os.path.getsize(backtracefile) > 0:
  776. os.system('%(sim_root)s/tools/gen_backtrace.py "%(backtracefile)s"' % locals())
  777. elif os.path.exists(os.path.join(outputdir, 'sim.cfg')):
  778. if use_profile:
  779. os.system('%(sim_root)s/tools/gen_profile.py -d %(outputdir)s -o %(outputdir)s' % locals())
  780. if use_memory_profile:
  781. os.system('%(sim_root)s/tools/gen_memory_profile.py -d %(outputdir)s -o %(outputdir)s' % locals())
  782. if use_cheetah:
  783. os.system('%(sim_root)s/tools/gen_cheetah.py -d %(outputdir)s -o %(outputdir)s/cheetah' % locals())
  784. if run_power:
  785. print '[SNIPER] Running McPAT'
  786. os.system('%(sim_root)s/tools/mcpat.py -d %(outputdir)s -o %(outputdir)s/power' % locals())
  787. if use_viz:
  788. print '[SNIPER] Generating visualization in viz/'
  789. os.system('%(sim_root)s/tools/viz/viz.py %(use_viz_mcpat)s %(use_viz_profile)s %(use_viz_aso)s -d %(outputdir)s -o %(outputdir)s/viz >/dev/null' % locals())
  790. if use_viz_aso and not use_viz:
  791. print '[SNIPER] Generating ASO visualization in viz/levels/functionbased/'
  792. os.system('%(sim_root)s/tools/viz/functionbased.py -d %(outputdir)s -o %(outputdir)s/viz >/dev/null' % locals())
  793. gen_simout.generate_simout(resultsdir = outputdir, output = open(os.path.join(outputdir, 'sim.out'), 'w'), silent = True)
  794. stats = dict(
  795. host = platform.node(),
  796. user = os.getenv('USER') or os.getenv('USERNAME'),
  797. git_revision = config.get('git_revision', ''),
  798. pin_version = pin_version,
  799. cmdline = sys.argv,
  800. snipercmd = cmd,
  801. tracecmds = tracecmds,
  802. vmem = memusage,
  803. rusage = usage and tuple(usage) or None,
  804. t_start = t_start,
  805. t_elapsed = t_elapsed,
  806. )
  807. if 'BENCHMARKS_ROOT' in os.environ:
  808. stats['benchmarks_root'] = os.getenv('BENCHMARKS_ROOT'),
  809. stats['benchmarks_revision'] = commands.getoutput('cd $BENCHMARKS_ROOT && (if [ -e .git ]; then git rev-parse HEAD; else cat .gitid; fi)'),
  810. file(os.path.join(outputdir, 'sim.info'), 'w').write(pprint.pformat(stats)+'\n')
  811. if os.path.exists('pin.log') and os.path.realpath(os.getcwd()) != os.path.realpath(outputdir):
  812. os.system('cp pin.log %s' % outputdir)
  813. sys.exit(rc)