Bug 1425308 - Automatically view local talos gecko profile in perf-html.io; r?jmaher
When running talos locally with --geckoProfile set, the latest gecko-profile archive will automatically be loaded in perf-html.io using the view-gecko-profile tool. To disable this automatic perf-html.io launching, set TALOS_DISABLE_PROFILE_LAUNCH=1.
MozReview-Commit-ID: 8tpLnsPAXD9
--- a/testing/mozharness/mozharness/mozilla/testing/talos.py
+++ b/testing/mozharness/mozharness/mozilla/testing/talos.py
@@ -597,16 +597,25 @@ class Talos(TestingMixin, MercurialScrip
)
super(Talos, self).create_virtualenv()
# talos in harness requires what else is
# listed in talos requirements.txt file.
self.install_module(
requirements=[os.path.join(self.talos_path,
'requirements.txt')]
)
+ # if running locally and gecko profiing is on, we will be using the
+ # view-gecko-profile tool which has its own requirements too
+ if self.gecko_profile and self.run_local:
+ tools = os.path.join(self.config['repo_path'], 'testing', 'tools')
+ view_gecko_profile_req = os.path.join(tools,
+ 'view_gecko_profile',
+ 'requirements.txt')
+ self.info("installing requirements for the view-gecko-profile tool")
+ self.install_module(requirements=[view_gecko_profile_req])
def _validate_treeherder_data(self, parser):
# late import is required, because install is done in create_virtualenv
import jsonschema
if len(parser.found_perf_data) != 1:
self.critical("PERFHERDER_DATA was seen %d times, expected 1."
% len(parser.found_perf_data))
--- a/testing/talos/talos/cmdline.py
+++ b/testing/talos/talos/cmdline.py
@@ -86,17 +86,20 @@ def create_parser(mach_interface=False):
"run and output the results in $MOZ_UPLOAD_DIR.")
add_arg('--spsProfileInterval', dest='gecko_profile_interval', type=float,
help="(Deprecated - Use --geckoProfileInterval instead.) How "
"frequently to take samples (ms)")
add_arg('--spsProfileEntries', dest="gecko_profile_entries", type=int,
help="(Deprecated - Use --geckoProfileEntries instead.) How "
"many samples to take with the profiler")
add_arg('--geckoProfile', action="store_true", dest="gecko_profile",
- help="Profile the run and output the results in $MOZ_UPLOAD_DIR.")
+ help="Profile the run and output the results in $MOZ_UPLOAD_DIR. "
+ "After talos is finished, perf-html.io will be launched in Firefox so you "
+ "can analyze the local profiles. To disable auto-launching of perf-html.io "
+ "set the TALOS_DISABLE_PROFILE_LAUNCH=1 env var.")
add_arg('--geckoProfileInterval', dest='gecko_profile_interval', type=float,
help="How frequently to take samples (ms)")
add_arg('--geckoProfileEntries', dest="gecko_profile_entries", type=int,
help="How many samples to take with the profiler")
add_arg('--extension', dest='extensions', action='append',
default=['${talos}/talos-powers'],
help="Extension to install while running")
add_arg('--fast', action='store_true',
--- a/testing/talos/talos/gecko_profile.py
+++ b/testing/talos/talos/gecko_profile.py
@@ -199,16 +199,19 @@ class GeckoProfile(object):
arc.write(profile_path, path_in_zip)
except Exception:
LOG.exception(
"Failed to copy profile {0} as {1} to"
" archive {2}".format(profile_path,
path_in_zip,
self.profile_arcname)
)
+ # save the latest gecko profile archive to an env var, so later on
+ # it can be viewed automatically via the view-gecko-profile tool
+ os.environ['TALOS_LATEST_GECKO_PROFILE_ARCHIVE'] = self.profile_arcname
def clean(self):
"""
Clean up temp folders created with the instance creation.
"""
mozfile.remove(self.option('dir'))
if self.cleanup:
for symbol_path in self.symbol_paths.values():
--- a/testing/talos/talos/run_tests.py
+++ b/testing/talos/talos/run_tests.py
@@ -2,16 +2,17 @@
# 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 __future__ import absolute_import, print_function
import copy
import os
+import subprocess
import sys
import time
import traceback
import urllib
import mozhttpd
import mozversion
import utils
@@ -323,21 +324,79 @@ def run_tests(config, browser_config):
# output results
if results_urls and not browser_config['no_upload_results']:
talos_results.output(results_urls)
if browser_config['develop'] or config['gecko_profile']:
print("Thanks for running Talos locally. Results are in %s"
% (results_urls['output_urls']))
+ # when running talos locally with gecko profiling on, use the view-gecko-profile
+ # tool to automatically load the latest gecko profile in perf-html.io
+ if config['gecko_profile'] and browser_config['develop']:
+ if os.environ.get('TALOS_DISABLE_PROFILE_LAUNCH', '0') == '1':
+ LOG.info("Not launching perf-html.io because TALOS_DISABLE_PROFILE_LAUNCH=1")
+ else:
+ view_gecko_profile(config['browser_path'])
+
# we will stop running tests on a failed test, or we will return 0 for
# green
return 0
+def view_gecko_profile(ffox_bin):
+ # automatically load the latest talos gecko-profile archive in perf-html.io
+ if not os.path.exists(ffox_bin):
+ LOG.info("unable to find Firefox bin, cannot launch view-gecko-profile")
+ return
+
+ profile_zip = os.environ.get('TALOS_LATEST_GECKO_PROFILE_ARCHIVE', None)
+ if profile_zip is None or not os.path.exists(profile_zip):
+ LOG.info("No local talos gecko profiles were found so not launching perf-html.io")
+ return
+
+ # need the view-gecko-profile tool, it's in repo/testing/tools
+ repo_dir = os.environ.get('MOZ_DEVELOPER_REPO_DIR', None)
+ if repo_dir is None:
+ LOG.info("unable to find MOZ_DEVELOPER_REPO_DIR, can't launch view-gecko-profile")
+ return
+
+ view_gp = os.path.join(repo_dir, 'testing', 'tools',
+ 'view_gecko_profile', 'view_gecko_profile.py')
+ if not os.path.exists(view_gp):
+ LOG.info("unable to find the view-gecko-profile tool, cannot launch it")
+ return
+
+ command = ['python',
+ view_gp,
+ '-b', ffox_bin,
+ '-p', profile_zip]
+
+ LOG.info('Auto-loading this profile in perfhtml.io: %s' % profile_zip)
+ LOG.info(command)
+
+ # if the view-gecko-profile tool fails to launch for some reason, we don't
+ # want to crash talos! just dump error and finsh up talos as usual
+ try:
+ view_profile = subprocess.Popen(command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ # that will leave it running in own instance and let talos finish up
+ except Exception as e:
+ LOG.info("failed to launch view-gecko-profile tool, exeption: %s" % e)
+ return
+
+ time.sleep(5)
+ ret = view_profile.poll()
+ if ret is None:
+ LOG.info("view-gecko-profile successfully started as pid %d" % view_profile.pid)
+ else:
+ LOG.error('view-gecko-profile process failed to start, poll returned: %s' % ret)
+
+
def make_comparison_result(base_and_reference_results):
''' Receive a test result object meant to be used as a base vs reference test. The result
object will have one test with two subtests; instead of traditional subtests we want to
treat them as separate tests, comparing them together and reporting the comparison results.
Results with multiple pages used as subtests would look like this normally, with the overall
result value being the mean of the pages/subtests: