build/valgrind/mach_commands.py

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 4
michael@0 5 from __future__ import print_function, unicode_literals
michael@0 6
michael@0 7 import os
michael@0 8 import re
michael@0 9 import subprocess
michael@0 10
michael@0 11 from mach.decorators import (
michael@0 12 Command,
michael@0 13 CommandArgument,
michael@0 14 CommandProvider,
michael@0 15 )
michael@0 16 from mozbuild.base import (
michael@0 17 MachCommandBase,
michael@0 18 MachCommandConditions as conditions,
michael@0 19 )
michael@0 20
michael@0 21
michael@0 22 def is_valgrind_build(cls):
michael@0 23 '''Must be a build with --enable-valgrind and --disable-jemalloc.'''
michael@0 24 defines = cls.config_environment.defines
michael@0 25 return 'MOZ_VALGRIND' in defines and 'MOZ_MEMORY' not in defines
michael@0 26
michael@0 27
michael@0 28 @CommandProvider
michael@0 29 class MachCommands(MachCommandBase):
michael@0 30 '''
michael@0 31 Run Valgrind tests.
michael@0 32 '''
michael@0 33 def __init__(self, context):
michael@0 34 MachCommandBase.__init__(self, context)
michael@0 35
michael@0 36 @Command('valgrind-test', category='testing',
michael@0 37 conditions=[conditions.is_firefox, is_valgrind_build],
michael@0 38 description='Run the Valgrind test job.')
michael@0 39 @CommandArgument('--suppressions', default=[], action='append',
michael@0 40 metavar='FILENAME',
michael@0 41 help='Specify a suppression file for Valgrind to use. Use '
michael@0 42 '--suppression multiple times to specify multiple suppression '
michael@0 43 'files.')
michael@0 44 def valgrind_test(self, suppressions):
michael@0 45 import json
michael@0 46 import sys
michael@0 47 import tempfile
michael@0 48
michael@0 49 from mozbuild.base import MozbuildObject
michael@0 50 from mozfile import TemporaryDirectory
michael@0 51 from mozhttpd import MozHttpd
michael@0 52 from mozprofile import FirefoxProfile, Preferences
michael@0 53 from mozprofile.permissions import ServerLocations
michael@0 54 from mozrunner import FirefoxRunner
michael@0 55 from mozrunner.utils import findInPath
michael@0 56 from valgrind.output_handler import OutputHandler
michael@0 57
michael@0 58 build_dir = os.path.join(self.topsrcdir, 'build')
michael@0 59
michael@0 60 # XXX: currently we just use the PGO inputs for Valgrind runs. This may
michael@0 61 # change in the future.
michael@0 62 httpd = MozHttpd(docroot=os.path.join(build_dir, 'pgo'))
michael@0 63 httpd.start(block=False)
michael@0 64
michael@0 65 with TemporaryDirectory() as profilePath:
michael@0 66 #TODO: refactor this into mozprofile
michael@0 67 prefpath = os.path.join(self.topsrcdir, 'testing', 'profiles', 'prefs_general.js')
michael@0 68 prefs = {}
michael@0 69 prefs.update(Preferences.read_prefs(prefpath))
michael@0 70 interpolation = { 'server': '%s:%d' % httpd.httpd.server_address,
michael@0 71 'OOP': 'false'}
michael@0 72 prefs = json.loads(json.dumps(prefs) % interpolation)
michael@0 73 for pref in prefs:
michael@0 74 prefs[pref] = Preferences.cast(prefs[pref])
michael@0 75
michael@0 76 quitter = os.path.join(self.distdir, 'xpi-stage', 'quitter')
michael@0 77
michael@0 78 locations = ServerLocations()
michael@0 79 locations.add_host(host='127.0.0.1',
michael@0 80 port=httpd.httpd.server_port,
michael@0 81 options='primary')
michael@0 82
michael@0 83 profile = FirefoxProfile(profile=profilePath,
michael@0 84 preferences=prefs,
michael@0 85 addons=[quitter],
michael@0 86 locations=locations)
michael@0 87
michael@0 88 firefox_args = [httpd.get_url()]
michael@0 89
michael@0 90 env = os.environ.copy()
michael@0 91 env['G_SLICE'] = 'always-malloc'
michael@0 92 env['MOZ_CC_RUN_DURING_SHUTDOWN'] = '1'
michael@0 93 env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
michael@0 94 env['XPCOM_DEBUG_BREAK'] = 'warn'
michael@0 95
michael@0 96 outputHandler = OutputHandler()
michael@0 97 kp_kwargs = {'processOutputLine': [outputHandler]}
michael@0 98
michael@0 99 valgrind = 'valgrind'
michael@0 100 if not os.path.exists(valgrind):
michael@0 101 valgrind = findInPath(valgrind)
michael@0 102
michael@0 103 valgrind_args = [
michael@0 104 valgrind,
michael@0 105 '--smc-check=all-non-file',
michael@0 106 '--vex-iropt-register-updates=allregs-at-mem-access',
michael@0 107 '--gen-suppressions=all',
michael@0 108 '--num-callers=36',
michael@0 109 '--leak-check=full',
michael@0 110 '--show-possibly-lost=no',
michael@0 111 '--track-origins=yes'
michael@0 112 ]
michael@0 113
michael@0 114 for s in suppressions:
michael@0 115 valgrind_args.append('--suppressions=' + s)
michael@0 116
michael@0 117 supps_dir = os.path.join(build_dir, 'valgrind')
michael@0 118 supps_file1 = os.path.join(supps_dir, 'cross-architecture.sup')
michael@0 119 valgrind_args.append('--suppressions=' + supps_file1)
michael@0 120
michael@0 121 # MACHTYPE is an odd bash-only environment variable that doesn't
michael@0 122 # show up in os.environ, so we have to get it another way.
michael@0 123 machtype = subprocess.check_output(['bash', '-c', 'echo $MACHTYPE']).rstrip()
michael@0 124 supps_file2 = os.path.join(supps_dir, machtype + '.sup')
michael@0 125 if os.path.isfile(supps_file2):
michael@0 126 valgrind_args.append('--suppressions=' + supps_file2)
michael@0 127
michael@0 128 exitcode = None
michael@0 129 try:
michael@0 130 runner = FirefoxRunner(profile=profile,
michael@0 131 binary=self.get_binary_path(),
michael@0 132 cmdargs=firefox_args,
michael@0 133 env=env,
michael@0 134 kp_kwargs=kp_kwargs)
michael@0 135 runner.start(debug_args=valgrind_args)
michael@0 136 exitcode = runner.wait()
michael@0 137
michael@0 138 finally:
michael@0 139 errs = outputHandler.error_count
michael@0 140 supps = outputHandler.suppression_count
michael@0 141 if errs != supps:
michael@0 142 status = 1 # turns the TBPL job orange
michael@0 143 print('TEST-UNEXPECTED-FAILURE | valgrind-test | error parsing:', errs, "errors seen, but", supps, "generated suppressions seen")
michael@0 144
michael@0 145 elif errs == 0:
michael@0 146 status = 0
michael@0 147 print('TEST-PASS | valgrind-test | valgrind found no errors')
michael@0 148 else:
michael@0 149 status = 1 # turns the TBPL job orange
michael@0 150 # We've already printed details of the errors.
michael@0 151
michael@0 152 if exitcode != 0:
michael@0 153 status = 2 # turns the TBPL job red
michael@0 154 print('TEST-UNEXPECTED-FAIL | valgrind-test | non-zero exit code from Valgrind')
michael@0 155
michael@0 156 httpd.stop()
michael@0 157
michael@0 158 return status

mercurial