Bug 952397 - Merge |mach valgrind-test| and valgrind_test.py. r=ted.
authorNicholas Nethercote <nnethercote@mozilla.com>
Thu, 19 Dec 2013 21:33:01 -0800
changeset 162101 14ac61461f2a8c4a7a4568c2da66bdf03df53577
parent 162100 cf80c0d4f46e3526d5f80671626f27a984cf4eae
child 162123 a101c9691b1526a5e57107ec3b8923c5c9aef055
push id25933
push usernnethercote@mozilla.com
push dateMon, 06 Jan 2014 01:23:21 +0000
treeherdermozilla-central@14ac61461f2a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs952397
milestone29.0a1
first release with
nightly linux32
14ac61461f2a / 29.0a1 / 20140106030203 / files
nightly linux64
14ac61461f2a / 29.0a1 / 20140106030203 / files
nightly mac
14ac61461f2a / 29.0a1 / 20140106030203 / files
nightly win32
14ac61461f2a / 29.0a1 / 20140106030203 / files
nightly win64
14ac61461f2a / 29.0a1 / 20140106030203 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 952397 - Merge |mach valgrind-test| and valgrind_test.py. r=ted.
build/valgrind/mach_commands.py
build/valgrind/valgrind_test.py
--- a/build/valgrind/mach_commands.py
+++ b/build/valgrind/mach_commands.py
@@ -2,75 +2,128 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import print_function, unicode_literals
 
 import os
 import subprocess
 
+from mach.decorators import (
+    CommandProvider,
+    Command,
+)
 from mozbuild.base import (
     MachCommandBase,
     MachCommandConditions as conditions,
 )
 
-from mach.decorators import (
-    CommandProvider,
-    Command,
-)
+
+def is_valgrind_build(cls):
+    """Must be a build with --enable-valgrind and --disable-jemalloc."""
+    defines = cls.config_environment.defines
+    return 'MOZ_VALGRIND' in defines and 'MOZ_MEMORY' not in defines
 
 
 @CommandProvider
 class MachCommands(MachCommandBase):
     '''
-    Easily run Valgrind tests.
+    Run Valgrind tests.
     '''
     def __init__(self, context):
         MachCommandBase.__init__(self, context)
 
     @Command('valgrind-test', category='testing',
-        conditions=[conditions.is_firefox],
+        conditions=[conditions.is_firefox, is_valgrind_build],
         description='Run the Valgrind test job.')
     def valgrind_test(self):
-        defines = self.config_environment.defines
-        if 'MOZ_VALGRIND' not in defines or 'MOZ_MEMORY' in defines:
-            print("sorry, this command requires a build configured with\n"
-                  "--enable-valgrind and --disable-jemalloc build")
-            return 1
+        import json
+        import sys
+        import tempfile
 
-        debugger_args = [
-            '--error-exitcode=1',
-            '--smc-check=all-non-file',
-            '--vex-iropt-register-updates=allregs-at-each-insn',
-            '--gen-suppressions=all',
-            '--num-callers=20',
-            '--leak-check=full',
-            '--show-possibly-lost=no',
-            '--track-origins=yes'
-        ]
+        from mozbuild.base import MozbuildObject
+        from mozfile import TemporaryDirectory
+        from mozhttpd import MozHttpd
+        from mozprofile import FirefoxProfile, Preferences
+        from mozprofile.permissions import ServerLocations
+        from mozrunner import FirefoxRunner
+        from mozrunner.utils import findInPath
 
         build_dir = os.path.join(self.topsrcdir, 'build')
-        supps_dir = os.path.join(build_dir, 'valgrind')
-        debugger_args.append('--suppressions=' + os.path.join(supps_dir, 'cross-architecture.sup'))
+
+        # XXX: currently we just use the PGO inputs for Valgrind runs.  This may
+        # change in the future.
+        httpd = MozHttpd(docroot=os.path.join(build_dir, 'pgo'))
+        httpd.start(block=False)
+
+        with TemporaryDirectory() as profilePath:
+            #TODO: refactor this into mozprofile
+            prefpath = os.path.join(self.topsrcdir, 'testing', 'profiles', 'prefs_general.js')
+            prefs = {}
+            prefs.update(Preferences.read_prefs(prefpath))
+            interpolation = { 'server': '%s:%d' % httpd.httpd.server_address,
+                              'OOP': 'false'}
+            prefs = json.loads(json.dumps(prefs) % interpolation)
+            for pref in prefs:
+                prefs[pref] = Preferences.cast(prefs[pref])
+
+            quitter = os.path.join(self.distdir, 'xpi-stage', 'quitter')
+
+            locations = ServerLocations()
+            locations.add_host(host='127.0.0.1',
+                               port=httpd.httpd.server_port,
+                               options='primary')
+
+            profile = FirefoxProfile(profile=profilePath,
+                                     preferences=prefs,
+                                     addons=[quitter],
+                                     locations=locations)
+
+            firefox_args = [httpd.get_url()]
+
+            env = os.environ.copy()
+            env['G_SLICE'] = 'always-malloc'
+            env['XPCOM_CC_RUN_DURING_SHUTDOWN'] = '1'
+            env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
+            env['XPCOM_DEBUG_BREAK'] = 'warn'
 
-        # MACHTYPE is an odd bash-only environment variable that doesn't show
-        # up in os.environ, so we have to get it another way.
-        machtype = subprocess.check_output(['bash', '-c', 'echo $MACHTYPE']).rstrip()
-        arch_specific_supps_file = os.path.join(supps_dir, machtype + '.sup')
-        if os.path.isfile(arch_specific_supps_file):
-            debugger_args.append('--suppressions=' + os.path.join(supps_dir, arch_specific_supps_file))
-            print('Using platform-specific suppression file: ',
-                  arch_specific_supps_file + '\n')
-        else:
-            print('Warning: could not find a platform-specific suppression file\n')
+            valgrind = 'valgrind'
+            if not os.path.exists(valgrind):
+                valgrind = findInPath(valgrind)
+
+            valgrind_args = [
+                valgrind,
+                '--error-exitcode=1',
+                '--smc-check=all-non-file',
+                '--vex-iropt-register-updates=allregs-at-each-insn',
+                '--gen-suppressions=all',
+                '--num-callers=20',
+                '--leak-check=full',
+                '--show-possibly-lost=no',
+                '--track-origins=yes'
+            ]
+
+            supps_dir = os.path.join(build_dir, 'valgrind')
+            supps_file1 = os.path.join(supps_dir, 'cross-architecture.sup')
+            valgrind_args.append('--suppressions=' + supps_file1)
 
-        env = os.environ.copy()
-        env['G_SLICE'] = 'always-malloc'
-        env['XPCOM_CC_RUN_DURING_SHUTDOWN'] = '1'
-
-        script = os.path.join(build_dir, 'valgrind', 'valgrind_test.py')
+            # MACHTYPE is an odd bash-only environment variable that doesn't
+            # show up in os.environ, so we have to get it another way.
+            machtype = subprocess.check_output(['bash', '-c', 'echo $MACHTYPE']).rstrip()
+            supps_file2 = os.path.join(supps_dir, machtype + '.sup')
+            if os.path.isfile(supps_file2):
+                valgrind_args.append('--suppressions=' + supps_file2)
 
+            try:
+                runner = FirefoxRunner(profile=profile,
+                                       binary=self.get_binary_path(),
+                                       cmdargs=firefox_args,
+                                       env=env)
+                runner.start(debug_args=valgrind_args)
+                status = runner.wait()
 
-        return subprocess.call([self.virtualenv_manager.python_path, script,
-                                '--debugger=valgrind',
-                                '--debugger-args=' + ' '.join(debugger_args) + ''],
-                                env=env)
+            finally:
+                httpd.stop()
+                if status != 0:
+                    status = 1 # normalize status, in case it's larger than 127
+                    print('TEST-UNEXPECTED-FAIL | valgrind-test | non-zero exit code')
 
+            return status
deleted file mode 100644
--- a/build/valgrind/valgrind_test.py
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/usr/bin/python
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-from mozprofile import FirefoxProfile, Profile, Preferences
-from mozprofile.permissions import ServerLocations
-from mozrunner import FirefoxRunner, CLI
-from mozhttpd import MozHttpd
-import json
-import socket
-import threading
-import os
-import sys
-import shutil
-import tempfile
-from datetime import datetime
-from mozbuild.base import MozbuildObject
-
-PORT = 8888
-
-if __name__ == '__main__':
-  cli = CLI()
-  debug_args, interactive = cli.debugger_arguments()
-
-  build = MozbuildObject.from_environment()
-  # XXX: currently we just use the PGO inputs for Valgrind runs.  This may
-  # change in the future.
-  httpd = MozHttpd(port=PORT,
-                   docroot=os.path.join(build.topsrcdir, "build", "pgo"))
-  httpd.start(block=False)
-
-  locations = ServerLocations()
-  locations.add_host(host='127.0.0.1',
-                     port=PORT,
-                     options='primary,privileged')
-
-  #TODO: mozfile.TemporaryDirectory
-  profilePath = tempfile.mkdtemp()
-  try:
-    #TODO: refactor this into mozprofile
-    prefpath = os.path.join(build.topsrcdir, "testing", "profiles", "prefs_general.js")
-    prefs = {}
-    prefs.update(Preferences.read_prefs(prefpath))
-    interpolation = { "server": "%s:%d" % httpd.httpd.server_address,
-                      "OOP": "false"}
-    prefs = json.loads(json.dumps(prefs) % interpolation)
-    for pref in prefs:
-      prefs[pref] = Preferences.cast(prefs[pref])
-    profile = FirefoxProfile(profile=profilePath,
-                             preferences=prefs,
-                             addons=[os.path.join(build.distdir, 'xpi-stage', 'quitter')],
-                             locations=locations)
-
-    env = os.environ.copy()
-    env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
-    env["XPCOM_DEBUG_BREAK"] = "warn"
-    jarlog = os.getenv("JARLOG_FILE")
-    if jarlog:
-      env["MOZ_JAR_LOG_FILE"] = os.path.abspath(jarlog)
-      print "jarlog: %s" % env["MOZ_JAR_LOG_FILE"]
-
-    cmdargs = ["http://localhost:%d/index.html" % PORT]
-    runner = FirefoxRunner(profile=profile,
-                           binary=build.get_binary_path(),
-                           cmdargs=cmdargs,
-                           env=env)
-    runner.start(debug_args=debug_args, interactive=interactive)
-    status = runner.wait()
-    httpd.stop()
-    if status != 0:
-        status = 1      # normalize status, in case it's larger than 127
-
-    sys.exit(status)
-  finally:
-    shutil.rmtree(profilePath)