1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
11 from mach
.decorators
import Command
, CommandArgument
12 from mozbuild
.base
import BinaryNotFoundException
13 from mozbuild
.base
import MachCommandConditions
as conditions
16 def is_valgrind_build(cls
):
17 """Must be a build with --enable-valgrind and --disable-jemalloc."""
18 defines
= cls
.config_environment
.defines
19 return "MOZ_VALGRIND" in defines
and "MOZ_MEMORY" not in defines
25 conditions
=[conditions
.is_firefox_or_thunderbird
, is_valgrind_build
],
26 description
="Run the Valgrind test job (memory-related errors).",
33 help="Specify a suppression file for Valgrind to use. Use "
34 "--suppression multiple times to specify multiple suppression "
37 def valgrind_test(command_context
, suppressions
):
42 from mozfile
import TemporaryDirectory
43 from mozhttpd
import MozHttpd
44 from mozprofile
import FirefoxProfile
, Preferences
45 from mozprofile
.permissions
import ServerLocations
46 from mozrunner
import FirefoxRunner
47 from mozrunner
.utils
import findInPath
48 from valgrind
.output_handler
import OutputHandler
50 build_dir
= os
.path
.join(command_context
.topsrcdir
, "build")
52 # XXX: currently we just use the PGO inputs for Valgrind runs. This may
53 # change in the future.
54 httpd
= MozHttpd(docroot
=os
.path
.join(build_dir
, "pgo"))
55 httpd
.start(block
=False)
57 with
TemporaryDirectory() as profilePath
:
58 # TODO: refactor this into mozprofile
59 profile_data_dir
= os
.path
.join(
60 command_context
.topsrcdir
, "testing", "profiles"
62 with
open(os
.path
.join(profile_data_dir
, "profiles.json"), "r") as fh
:
63 base_profiles
= json
.load(fh
)["valgrind"]
66 os
.path
.join(profile_data_dir
, profile
, "user.js")
67 for profile
in base_profiles
70 for path
in prefpaths
:
71 prefs
.update(Preferences
.read_prefs(path
))
74 "server": "%s:%d" % httpd
.httpd
.server_address
,
76 for k
, v
in prefs
.items():
77 if isinstance(v
, str):
78 v
= v
.format(**interpolation
)
79 prefs
[k
] = Preferences
.cast(v
)
81 quitter
= os
.path
.join(
82 command_context
.topsrcdir
, "tools", "quitter", "quitter@mozilla.org.xpi"
85 locations
= ServerLocations()
87 host
="127.0.0.1", port
=httpd
.httpd
.server_port
, options
="primary"
90 profile
= FirefoxProfile(
97 firefox_args
= [httpd
.get_url()]
99 env
= os
.environ
.copy()
100 env
["G_SLICE"] = "always-malloc"
101 env
["MOZ_FORCE_DISABLE_E10S"] = "1"
102 env
["MOZ_CC_RUN_DURING_SHUTDOWN"] = "1"
103 env
["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
104 env
["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"
105 env
["XPCOM_DEBUG_BREAK"] = "warn"
107 outputHandler
= OutputHandler(command_context
.log
)
109 "processOutputLine": [outputHandler
],
110 "universal_newlines": True,
113 valgrind
= "valgrind"
114 if not os
.path
.exists(valgrind
):
115 valgrind
= findInPath(valgrind
)
120 "--smc-check=all-non-file",
121 "--vex-iropt-register-updates=allregs-at-mem-access",
122 "--gen-suppressions=all",
125 "--show-possibly-lost=no",
126 "--track-origins=yes",
127 "--trace-children=yes",
128 "--trace-children-skip=*/dbus-launch",
129 "-v", # Enable verbosity to get the list of used suppressions
130 # Avoid excessive delays in the presence of spinlocks.
133 # Keep debuginfo after library unmap. See bug 1382280.
134 "--keep-debuginfo=yes",
135 # Reduce noise level on rustc and/or LLVM compiled code.
137 "--expensive-definedness-checks=yes",
138 # Compensate for the compiler inlining `new` but not `delete`
140 "--show-mismatched-frees=no",
143 for s
in suppressions
:
144 valgrind_args
.append("--suppressions=" + s
)
146 supps_dir
= os
.path
.join(build_dir
, "valgrind")
147 supps_file1
= os
.path
.join(supps_dir
, "cross-architecture.sup")
148 valgrind_args
.append("--suppressions=" + supps_file1
)
150 if mozinfo
.os
== "linux":
152 "x86_64": "x86_64-pc-linux-gnu",
153 "x86": "i386-pc-linux-gnu",
154 }.get(mozinfo
.processor
)
156 supps_file2
= os
.path
.join(supps_dir
, machtype
+ ".sup")
157 if os
.path
.isfile(supps_file2
):
158 valgrind_args
.append("--suppressions=" + supps_file2
)
162 binary_not_found_exception
= None
164 runner
= FirefoxRunner(
166 binary
=command_context
.get_binary_path(),
167 cmdargs
=firefox_args
,
169 process_args
=kp_kwargs
,
171 start_time
= time
.monotonic()
172 runner
.start(debug_args
=valgrind_args
)
173 exitcode
= runner
.wait(timeout
=timeout
)
174 end_time
= time
.monotonic()
175 if "MOZ_AUTOMATION" in os
.environ
:
177 "framework": {"name": "build_metrics"},
181 "value": end_time
- start_time
,
182 "lowerIsBetter": True,
183 "shouldAlert": False,
188 if "TASKCLUSTER_INSTANCE_TYPE" in os
.environ
:
189 # Include the instance type so results can be grouped.
190 data
["suites"][0]["extraOptions"] = [
191 "taskcluster-%s" % os
.environ
["TASKCLUSTER_INSTANCE_TYPE"],
195 "valgrind-perfherder",
196 {"data": json
.dumps(data
)},
197 "PERFHERDER_DATA: {data}",
199 except BinaryNotFoundException
as e
:
200 binary_not_found_exception
= e
202 errs
= outputHandler
.error_count
203 supps
= outputHandler
.suppression_count
205 status
= 1 # turns the TBPL job orange
208 "valgrind-fail-parsing",
209 {"errs": errs
, "supps": supps
},
210 "TEST-UNEXPECTED-FAIL | valgrind-test | error parsing: {errs} errors "
211 "seen, but {supps} generated suppressions seen",
220 "TEST-PASS | valgrind-test | valgrind found no errors",
223 status
= 1 # turns the TBPL job orange
224 # We've already printed details of the errors.
226 if binary_not_found_exception
:
227 status
= 2 # turns the TBPL job red
230 "valgrind-fail-errors",
231 {"error": str(binary_not_found_exception
)},
232 "TEST-UNEXPECTED-FAIL | valgrind-test | {error}",
236 "valgrind-fail-errors",
237 {"help": binary_not_found_exception
.help()},
240 elif exitcode
is None:
241 status
= 2 # turns the TBPL job red
244 "valgrind-fail-timeout",
245 {"timeout": timeout
},
246 "TEST-UNEXPECTED-FAIL | valgrind-test | Valgrind timed out "
247 "(reached {timeout} second limit)",
250 status
= 2 # turns the TBPL job red
253 "valgrind-fail-errors",
254 {"exitcode": exitcode
},
255 "TEST-UNEXPECTED-FAIL | valgrind-test | non-zero exit code "
256 "from Valgrind: {exitcode}",