# HG changeset patch # User Christian Wimmer # Date 1325981107 28800 # Node ID b019b2ebe03ef795ab49a727f6297955f2ae1df5 # Parent 75c620f90ab9f2add893e550f4b839d8ae500dc3# Parent a69889e5a8a57d9d54c1c1c30d3c2a5446fa9b4d Merge diff -r 75c620f90ab9 -r b019b2ebe03e mx/commands.py --- a/mx/commands.py Sat Jan 07 16:04:22 2012 -0800 +++ b/mx/commands.py Sat Jan 07 16:05:07 2012 -0800 @@ -139,7 +139,7 @@ def dacapo(args): """run one or all DaCapo benchmarks - DaCapo options are distinguised from VM options by a '@' prefix. + DaCapo options are distinguished from VM options by a '@' prefix. For example, '@--iterations @5' will pass '--iterations 5' to the DaCapo harness.""" @@ -219,7 +219,7 @@ if build == 'product': return jdk - elif build in ['debug', 'fastdebug', 'optimized']: + elif build in ['debug', 'fastdebug']: res = join(jdk, build) if not exists(res): if not create: @@ -580,11 +580,11 @@ unittest([]) t.stop() - t = Task('DaCapoBenchmarks:' + vmbuild) - for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate): + for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild): + t = Task(str(test) + ':' + vmbuild) if not test.test('-graal'): t.abort(test.group + ' ' + test.name + ' Failed') - t.stop() + t.stop() except Exception as e: total.abort(str(e)) @@ -628,11 +628,10 @@ mx.add_argument('--product', action='store_const', dest='vmbuild', const='product', help='select the product VM') mx.add_argument('--debug', action='store_const', dest='vmbuild', const='debug', help='select the debug VM') mx.add_argument('--fastdebug', action='store_const', dest='vmbuild', const='fastdebug', help='select the fast debug VM') - mx.add_argument('--optimized', action='store_const', dest='vmbuild', const='optimized', help='select the optimized VM') commands.update({ 'export': [export, '[-options] [zipfile]'], - 'build': [build, '[-options] [product|debug|fastdebug|optimized]...'] + 'build': [build, '[-options] [product|debug|fastdebug]...'] }) mx.commands.update(commands) diff -r 75c620f90ab9 -r b019b2ebe03e mx/sanitycheck.py --- a/mx/sanitycheck.py Sat Jan 07 16:04:22 2012 -0800 +++ b/mx/sanitycheck.py Sat Jan 07 16:05:07 2012 -0800 @@ -47,6 +47,23 @@ 'xalan': [0, 0, 5, 10, 15], } +dacapoGateBuildLevels = { + 'avrora': ['product', 'fastdebug', 'debug'], + 'batik': ['product', 'fastdebug', 'debug'], + 'eclipse': ['product'], + 'fop': ['product', 'fastdebug', 'debug'], + 'h2': ['product', 'fastdebug', 'debug'], + 'jython': ['product', 'fastdebug', 'debug'], + 'luindex': ['product', 'fastdebug', 'debug'], + 'lusearch': ['product'], + 'pmd': ['product', 'fastdebug', 'debug'], + 'sunflow': ['product', 'fastdebug', 'debug'], + 'tomcat': ['product', 'fastdebug', 'debug'], + 'tradebeans': ['product', 'fastdebug', 'debug'], + 'tradesoap': ['product', 'fastdebug', 'debug'], + 'xalan': ['product', 'fastdebug', 'debug'], +} + class SanityCheckLevel: Fast, Gate, Normal, Extensive, Benchmark = range(5) @@ -72,19 +89,24 @@ return Test("SPECjvm2008", "SPECjvm2008", ['-jar', 'SPECjvm2008.jar'] + opts, [success], [error], [matcher], vmOpts=['-Xms2g'], defaultCwd=specjvm2008) -def getDacapos(level=SanityCheckLevel.Normal, dacapoArgs=[]): +def getDacapos(level=SanityCheckLevel.Normal, gateBuildLevel=None, dacapoArgs=[]): checks = [] for (bench, ns) in dacapoSanityWarmup.items(): if ns[level] > 0: - checks.append(getDacapo(bench, ns[level], dacapoArgs)) + if gateBuildLevel is None or gateBuildLevel in dacapoGateBuildLevels[bench]: + checks.append(getDacapo(bench, ns[level], dacapoArgs)) return checks def getDacapo(name, n, dacapoArgs=[]): dacapo = mx.get_env('DACAPO_CP') if dacapo is None: - dacapo = commands._graal_home + r'/lib/dacapo-9.12-bach.jar' + l = mx.library('DACAPO', False) + if l is not None: + dacapo = l.get_path(True) + else: + mx.abort('DaCapo 9.12 jar file must be specified with DACAPO_CP environment variable or as DACAPO library') if not isfile(dacapo) or not dacapo.endswith('.jar'): mx.abort('Specified DaCapo jar file does not exist or is not a jar file: ' + dacapo) @@ -118,6 +140,9 @@ self.vmOpts = vmOpts self.cmd = cmd self.defaultCwd = defaultCwd + + def __str__(self): + return self.name def test(self, vm, cwd=None, opts=[], vmbuild=None): """ diff -r 75c620f90ab9 -r b019b2ebe03e mxtool/README --- a/mxtool/README Sat Jan 07 16:04:22 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -This is as a read-only copy of the mxtool (https://hg.kenai.com/hg/maxine~mxtool). -Having a copy makes the GraalVM repo more self-contained so that every revision -will always be built with a specific version of this tool, ensuring repeatability. - -Changes to the tool should be made in a clone of the Kenai repo, pushed back -to Kenai and copied here. diff -r 75c620f90ab9 -r b019b2ebe03e mxtool/mx.py --- a/mxtool/mx.py Sat Jan 07 16:04:22 2012 -0800 +++ b/mxtool/mx.py Sat Jan 07 16:05:07 2012 -0800 @@ -87,7 +87,7 @@ # # Values can use environment variables with Bash syntax (e.g. ${HOME}). -import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile +import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal import shutil, fnmatch, re, xml.dom.minidom from collections import Callable from threading import Thread @@ -295,7 +295,6 @@ urls = pop_list(attrs, 'urls') l = Library(self, name, path, mustExist, urls) l.__dict__.update(attrs) - l.get_path(True) self.libs.append(l) def _load_commands(self, mxDir): @@ -462,7 +461,11 @@ self.add_argument('--Ja', action='append', dest='java_args_sfx', help='suffix Java VM arguments (e.g. --Ja @-dsa)', metavar='@', default=[]) self.add_argument('--user-home', help='users home directory', metavar='', default=os.path.expanduser('~')) self.add_argument('--java-home', help='JDK installation directory (must be JDK 6 or later)', metavar='') - self.add_argument('--timeout', help='Timeout (in seconds) for subprocesses', type=int, default=0, metavar='') + if get_os() != 'windows': + # Time outs are (currently) implemented with Unix specific functionality + self.add_argument('--timeout', help='Timeout (in seconds) for command', type=int, default=0, metavar='') + self.add_argument('--ptimeout', help='Timeout (in seconds) for subprocesses', type=int, default=0, metavar='') + def _parse_cmd_line(self, args=None): if args is None: @@ -507,6 +510,15 @@ def run_java(args, nonZeroIsFatal=True, out=None, err=None, cwd=None): return run(java().format_cmd(args), nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd) +def _kill_process_group(pid): + pgid = os.getpgid(pid) + try: + os.killpg(pgid, signal.SIGKILL) + return True + except: + log('Error killing subprocess ' + str(pgid) + ': ' + str(sys.exc_info()[1])) + return False + def _waitWithTimeout(process, args, timeout): def _waitpid(pid): while True: @@ -534,11 +546,15 @@ return _returncode(status) remaining = end - time.time() if remaining <= 0: - process.kill() abort('Process timed out after {0} seconds: {1}'.format(timeout, ' '.join(args))) + _kill_process_group(process.pid) delay = min(delay * 2, remaining, .05) time.sleep(delay) +# Makes the current subprocess accessible to the abort() function +# This is a tuple of the Popen object and args. +_currentSubprocess = None + def run(args, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None): """ Run a command in a subprocess, wait for it to complete and return the exit status of the process. @@ -555,12 +571,21 @@ if _opts.verbose: log(' '.join(args)) - if timeout is None and _opts.timeout != 0: - timeout = _opts.timeout - + if timeout is None and _opts.ptimeout != 0: + timeout = _opts.ptimeout + + global _currentSubprocess + try: + # On Unix, the new subprocess should be in a separate group so that a timeout alarm + # can use os.killpg() to kill the whole subprocess group + preexec_fn = os.setsid if get_os() != 'windows' else None + if not callable(out) and not callable(err) and timeout is None: - retcode = subprocess.call(args, cwd=cwd) + # The preexec_fn=os.setsid + p = subprocess.Popen(args, cwd=cwd, preexec_fn=preexec_fn) + _currentSubprocess = (p, args) + retcode = p.wait() else: def redirect(stream, f): for line in iter(stream.readline, ''): @@ -568,7 +593,8 @@ stream.close() stdout=out if not callable(out) else subprocess.PIPE stderr=err if not callable(err) else subprocess.PIPE - p = subprocess.Popen(args, cwd=cwd, stdout=stdout, stderr=stderr) + p = subprocess.Popen(args, cwd=cwd, stdout=stdout, stderr=stderr, preexec_fn=preexec_fn) + _currentSubprocess = (p, args) if callable(out): t = Thread(target=redirect, args=(p.stdout, out)) t.daemon = True # thread dies with the program @@ -588,7 +614,10 @@ if _opts.verbose: raise e abort(e.errno) - + except KeyboardInterrupt: + abort(1) + finally: + _currentSubprocess = None if retcode and nonZeroIsFatal: if _opts.verbose: @@ -712,6 +741,14 @@ if it is None, the exit status is zero; if it has another type (such as a string), the object's value is printed and the exit status is one. """ + + #import traceback + #traceback.print_stack() + currentSubprocess = _currentSubprocess + if currentSubprocess is not None: + p, _ = currentSubprocess + _kill_process_group(p.pid) + raise SystemExit(codeOrMessage) def download(path, urls, verbose=False): @@ -1181,7 +1218,7 @@ _argParser = ArgParser() -def main(): +def main(): MX_INCLUDES = os.environ.get('MX_INCLUDES', None) if MX_INCLUDES is not None: for path in MX_INCLUDES.split(os.pathsep): @@ -1214,6 +1251,11 @@ c, _ = commands[command][:2] try: + if opts.timeout != 0: + def alarm_handler(signum, frame): + abort('Command timed out after ' + str(opts.timeout) + ' seconds: ' + ' '.join(commandAndArgs)) + signal.signal(signal.SIGALRM, alarm_handler) + signal.alarm(opts.timeout) retcode = c(command_args) if retcode is not None and retcode != 0: abort(retcode) @@ -1224,5 +1266,5 @@ if __name__ == '__main__': # rename this module as 'mx' so it is not imported twice by the commands.py modules sys.modules['mx'] = sys.modules.pop('__main__') - + main()