changeset 4246:b019b2ebe03e

Merge
author Christian Wimmer <christian.wimmer@oracle.com>
date Sat, 07 Jan 2012 16:05:07 -0800
parents 75c620f90ab9 (current diff) a69889e5a8a5 (diff)
children 3f6c6e61614e 1aaf3592e516 e53926b0a6cb
files mxtool/README
diffstat 4 files changed, 88 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- 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)
--- 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):
         """
--- 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.
--- 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='@<args>', default=[])
         self.add_argument('--user-home', help='users home directory', metavar='<path>', default=os.path.expanduser('~'))
         self.add_argument('--java-home', help='JDK installation directory (must be JDK 6 or later)', metavar='<path>')
-        self.add_argument('--timeout', help='Timeout (in seconds) for subprocesses', type=int, default=0, metavar='<secs>')
+        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='<secs>')
+            self.add_argument('--ptimeout', help='Timeout (in seconds) for subprocesses', type=int, default=0, metavar='<secs>')
+        
         
     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()