3 # This Source Code Form is subject to the terms of the Mozilla Public
4 # License, v. 2.0. If a copy of the MPL was not distributed with this
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
14 from mozbuild
.base
import MozbuildObject
, BinaryNotFoundException
15 from mozfile
import TemporaryDirectory
16 from mozhttpd
import MozHttpd
17 from mozprofile
import FirefoxProfile
, Preferences
18 from mozprofile
.permissions
import ServerLocations
19 from mozrunner
import FirefoxRunner
, CLI
20 from six
import string_types
25 '/webkit/PerformanceTests': 'third_party/webkit/PerformanceTests',
26 # It is tempting to map to `testing/talos/talos/tests` instead, to avoid
27 # writing `tests/` in every path, but we can't do that because some files
28 # refer to scripts located in `../..`.
29 '/talos': 'testing/talos/talos',
33 def get_crashreports(directory
, name
=None):
35 upload_path
= os
.environ
.get('UPLOAD_PATH')
37 # For automation, log the minidumps with stackwalk and get them moved to
38 # the artifacts directory.
39 fetches_dir
= os
.environ
.get('MOZ_FETCHES_DIR')
41 raise Exception("Unable to process minidump in automation because "
42 "$MOZ_FETCHES_DIR is not set in the environment")
43 stackwalk_binary
= os
.path
.join(fetches_dir
, 'minidump_stackwalk', 'minidump_stackwalk')
44 if sys
.platform
== 'win32':
45 stackwalk_binary
+= '.exe'
46 minidump_path
= os
.path
.join(directory
, "minidumps")
47 rc
= mozcrash
.check_for_crashes(
49 symbols_path
=fetches_dir
,
50 stackwalk_binary
=stackwalk_binary
,
51 dump_save_path
=upload_path
,
57 if __name__
== '__main__':
59 debug_args
, interactive
= cli
.debugger_arguments()
60 runner_args
= cli
.runner_args()
62 build
= MozbuildObject
.from_environment()
64 binary
= runner_args
.get('binary')
67 binary
= build
.get_binary_path(where
="staged-package")
68 except BinaryNotFoundException
as e
:
69 print('{}\n\n{}\n'.format(e
, e
.help()))
71 binary
= os
.path
.normpath(os
.path
.abspath(binary
))
74 k
: os
.path
.join(build
.topsrcdir
, v
)
75 for k
, v
in PATH_MAPPINGS
.items()
77 httpd
= MozHttpd(port
=PORT
,
78 docroot
=os
.path
.join(build
.topsrcdir
, "build", "pgo"),
79 path_mappings
=path_mappings
)
80 httpd
.start(block
=False)
82 locations
= ServerLocations()
83 locations
.add_host(host
='127.0.0.1',
85 options
='primary,privileged')
87 old_profraw_files
= glob
.glob('*.profraw')
88 for f
in old_profraw_files
:
91 with
TemporaryDirectory() as profilePath
:
92 # TODO: refactor this into mozprofile
93 profile_data_dir
= os
.path
.join(build
.topsrcdir
, 'testing', 'profiles')
94 with
open(os
.path
.join(profile_data_dir
, 'profiles.json'), 'r') as fh
:
95 base_profiles
= json
.load(fh
)['profileserver']
97 prefpaths
= [os
.path
.join(profile_data_dir
, profile
, 'user.js')
98 for profile
in base_profiles
]
101 for path
in prefpaths
:
102 prefs
.update(Preferences
.read_prefs(path
))
104 interpolation
= {"server": "%s:%d" % httpd
.httpd
.server_address
}
105 for k
, v
in prefs
.items():
106 if isinstance(v
, string_types
):
107 v
= v
.format(**interpolation
)
108 prefs
[k
] = Preferences
.cast(v
)
110 # Enforce e10s. This isn't in one of the user.js files because those
111 # are shared with android, which doesn't want this on. We can't
112 # interpolate because the formatting code only works for strings,
113 # and this is a bool pref.
114 prefs
["browser.tabs.remote.autostart"] = True
116 profile
= FirefoxProfile(profile
=profilePath
,
118 addons
=[os
.path
.join(
119 build
.topsrcdir
, 'tools', 'quitter',
120 'quitter@mozilla.org.xpi')],
123 env
= os
.environ
.copy()
124 env
["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
125 env
["XPCOM_DEBUG_BREAK"] = "warn"
126 # We disable sandboxing to make writing profiling data actually work
127 # Bug 1553850 considers fixing this.
128 env
["MOZ_DISABLE_CONTENT_SANDBOX"] = "1"
129 env
["MOZ_DISABLE_RDD_SANDBOX"] = "1"
131 # Ensure different pids write to different files
132 env
["LLVM_PROFILE_FILE"] = "default_%p_random_%m.profraw"
134 # Write to an output file if we're running in automation
135 process_args
= {'universal_newlines': True}
136 if 'UPLOAD_PATH' in env
:
137 process_args
['logfile'] = os
.path
.join(env
['UPLOAD_PATH'], 'profile-run-1.log')
139 # Run Firefox a first time to initialize its profile
140 runner
= FirefoxRunner(profile
=profile
,
142 cmdargs
=['data:text/html,<script>Quitter.quit()</script>'],
144 process_args
=process_args
)
148 print("Firefox exited with code %d during profile initialization"
150 logfile
= process_args
.get('logfile')
152 print("Firefox output (%s):" % logfile
)
153 with
open(logfile
) as f
:
156 get_crashreports(profilePath
, name
='Profile initialization')
159 jarlog
= os
.getenv("JARLOG_FILE")
161 env
["MOZ_JAR_LOG_FILE"] = os
.path
.abspath(jarlog
)
162 print("jarlog: %s" % env
["MOZ_JAR_LOG_FILE"])
163 if os
.path
.exists(jarlog
):
166 if 'UPLOAD_PATH' in env
:
167 process_args
['logfile'] = os
.path
.join(env
['UPLOAD_PATH'], 'profile-run-2.log')
168 cmdargs
= ["http://localhost:%d/index.html" % PORT
]
169 runner
= FirefoxRunner(profile
=profile
,
173 process_args
=process_args
)
174 runner
.start(debug_args
=debug_args
, interactive
=interactive
)
178 print("Firefox exited with code %d during profiling" % ret
)
179 logfile
= process_args
.get('logfile')
181 print("Firefox output (%s):" % logfile
)
182 with
open(logfile
) as f
:
184 get_crashreports(profilePath
, name
='Profiling run')
187 # Try to move the crash reports to the artifacts even if Firefox appears
188 # to exit successfully, in case there's a crash that doesn't set the
189 # return code to non-zero for some reason.
190 if get_crashreports(profilePath
, name
='Firefox exited successfully?') != 0:
191 print("Firefox exited successfully, but produced a crashreport")
194 llvm_profdata
= env
.get('LLVM_PROFDATA')
196 profraw_files
= glob
.glob('*.profraw')
197 if not profraw_files
:
198 print('Could not find profraw files in the current directory: %s' % os
.getcwd())
206 rc
= subprocess
.call(merge_cmd
)
208 print('INFRA-ERROR: Failed to merge profile data. Corrupt profile?')
209 # exit with TBPL_RETRY