diff options
author | Torne (Richard Coles) <torne@google.com> | 2014-06-09 12:00:27 +0100 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2014-06-09 12:00:27 +0100 |
commit | 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd (patch) | |
tree | ed52337c337f5fd1db77873d9ff980ca3e334b35 /tools | |
parent | 7ef4c70daab901f557268ad466f62cd2f7896916 (diff) | |
download | chromium_org-46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd.tar.gz |
Merge from Chromium at DEPS revision 275586
This commit was generated by merge_to_master.py.
Change-Id: Ief3a0ffd810858bfddbe0ec5931e3ee90d53f78c
Diffstat (limited to 'tools')
302 files changed, 4241 insertions, 1894 deletions
diff --git a/tools/binary_size/run_binary_size_analysis.py b/tools/binary_size/run_binary_size_analysis.py index aa46f6f675..4168874c86 100755 --- a/tools/binary_size/run_binary_size_analysis.py +++ b/tools/binary_size/run_binary_size_analysis.py @@ -455,26 +455,41 @@ def RunElfSymbolizer(outfile, library, addr2line_binary, nm_binary, jobs): symbolizer = elf_symbolizer.ELFSymbolizer(library, addr2line_binary, map_address_symbol, max_concurrent_jobs=jobs) - for line in nm_output_lines: - match = sNmPattern.match(line) - if match: - location = match.group(5) - if not location: - addr = int(match.group(1), 16) - size = int(match.group(2), 16) - if addr in address_symbol: # Already looked up, shortcut ELFSymbolizer. - map_address_symbol(address_symbol[addr], addr) - continue - elif size == 0: - # Save time by not looking up empty symbols (do they even exist?) - print('Empty symbol: ' + line) - else: - symbolizer.SymbolizeAsync(addr, addr) - continue + user_interrupted = False + try: + for line in nm_output_lines: + match = sNmPattern.match(line) + if match: + location = match.group(5) + if not location: + addr = int(match.group(1), 16) + size = int(match.group(2), 16) + if addr in address_symbol: # Already looked up, shortcut + # ELFSymbolizer. + map_address_symbol(address_symbol[addr], addr) + continue + elif size == 0: + # Save time by not looking up empty symbols (do they even exist?) + print('Empty symbol: ' + line) + else: + symbolizer.SymbolizeAsync(addr, addr) + continue + + progress.skip_count += 1 + except KeyboardInterrupt: + user_interrupted = True + print('Interrupting - killing subprocesses. Please wait.') - progress.skip_count += 1 + try: + symbolizer.Join() + except KeyboardInterrupt: + # Don't want to abort here since we will be finished in a few seconds. + user_interrupted = True + print('Patience you must have my young padawan.') - symbolizer.Join() + if user_interrupted: + print('Skipping the rest of the file mapping. ' + 'Output will not be fully classified.') with open(outfile, 'w') as out: for line in nm_output_lines: @@ -483,15 +498,16 @@ def RunElfSymbolizer(outfile, library, addr2line_binary, nm_binary, jobs): location = match.group(5) if not location: addr = int(match.group(1), 16) - symbol = address_symbol[addr] - path = '??' - if symbol.source_path is not None: - path = symbol.source_path - line_number = 0 - if symbol.source_line is not None: - line_number = symbol.source_line - out.write('%s\t%s:%d\n' % (line, path, line_number)) - continue + symbol = address_symbol.get(addr) + if symbol is not None: + path = '??' + if symbol.source_path is not None: + path = symbol.source_path + line_number = 0 + if symbol.source_line is not None: + line_number = symbol.source_line + out.write('%s\t%s:%d\n' % (line, path, line_number)) + continue out.write('%s\n' % line) @@ -500,7 +516,8 @@ def RunElfSymbolizer(outfile, library, addr2line_binary, nm_binary, jobs): def RunNm(binary, nm_binary): print('Starting nm') - cmd = [nm_binary, '-C', '--print-size', binary] + cmd = [nm_binary, '-C', '--print-size', '--size-sort', '--reverse-sort', + binary] nm_process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -678,12 +695,10 @@ def main(): 'template') shutil.copy(os.path.join(d3_src, 'LICENSE'), d3_out) shutil.copy(os.path.join(d3_src, 'd3.js'), d3_out) - print('Copying index.html') shutil.copy(os.path.join(template_src, 'index.html'), opts.destdir) shutil.copy(os.path.join(template_src, 'D3SymbolTreeMap.js'), opts.destdir) - if opts.verbose: - print 'Report saved to ' + opts.destdir + '/index.html' + print 'Report saved to ' + opts.destdir + '/index.html' if __name__ == '__main__': diff --git a/tools/bisect-perf-regression.py b/tools/bisect-perf-regression.py index 674a782df2..7444d37003 100755 --- a/tools/bisect-perf-regression.py +++ b/tools/bisect-perf-regression.py @@ -54,7 +54,7 @@ import zipfile sys.path.append(os.path.join(os.path.dirname(__file__), 'telemetry')) import bisect_utils -import post_perf_builder_job +import post_perf_builder_job as bisect_builder from telemetry.page import cloud_storage # The additional repositories that might need to be bisected. @@ -522,10 +522,15 @@ def ExtractZip(filename, output_dir, verbose=True): # handle links and file bits (executable), which is much # easier then trying to do that with ZipInfo options. # + # The Mac Version of unzip unfortunately does not support Zip64, whereas + # the python module does, so we have to fallback to the python zip module + # on Mac if the filesize is greater than 4GB. + # # On Windows, try to use 7z if it is installed, otherwise fall back to python # zip module and pray we don't have files larger than 512MB to unzip. unzip_cmd = None - if IsMac() or IsLinux(): + if ((IsMac() and os.path.getsize(filename) < 4 * 1024 * 1024 * 1024) + or IsLinux()): unzip_cmd = ['unzip', '-o'] elif IsWindows() and os.path.exists('C:\\Program Files\\7-Zip\\7z.exe'): unzip_cmd = ['C:\\Program Files\\7-Zip\\7z.exe', 'x', '-y'] @@ -541,12 +546,16 @@ def ExtractZip(filename, output_dir, verbose=True): if result: raise IOError('unzip failed: %s => %s' % (str(command), result)) else: - assert IsWindows() + assert IsWindows() or IsMac() zf = zipfile.ZipFile(filename) for name in zf.namelist(): if verbose: print 'Extracting %s' % name zf.extract(name, output_dir) + if IsMac(): + # Restore permission bits. + os.chmod(os.path.join(output_dir, name), + zf.getinfo(name).external_attr >> 16L) def RunProcess(command): @@ -1429,16 +1438,17 @@ class BisectPerformanceMetrics(object): continue if (depot_data.get('recurse') and depot in depot_data.get('from')): - src_dir = (deps_data.get(depot_data.get('src')) or - deps_data.get(depot_data.get('src_old'))) + depot_data_src = depot_data.get('src') or depot_data.get('src_old') + src_dir = deps_data.get(depot_data_src) if src_dir: - self.depot_cwd[depot_name] = os.path.join(self.src_cwd, src_dir[4:]) - re_results = rxp.search(deps_data.get(src_dir, '')) + self.depot_cwd[depot_name] = os.path.join(self.src_cwd, + depot_data_src[4:]) + re_results = rxp.search(src_dir) if re_results: results[depot_name] = re_results.group('revision') else: warning_text = ('Couldn\'t parse revision for %s while bisecting ' - '%s' % (depot_name, depot)) + '%s' % (depot_name, depot)) if not warning_text in self.warnings: self.warnings.append(warning_text) else: @@ -1574,7 +1584,7 @@ class BisectPerformanceMetrics(object): if not fetch_build_func(): if not self.PostBuildRequestAndWait(revision, - condition=fetch_build_func, + fetch_build=fetch_build_func, patch=patch): raise RuntimeError('Somewthing went wrong while processing build' 'request for: %s' % revision) @@ -1606,7 +1616,59 @@ class BisectPerformanceMetrics(object): os.remove(downloaded_file) return False - def PostBuildRequestAndWait(self, revision, condition, patch=None): + def WaitUntilBuildIsReady(self, fetch_build, bot_name, builder_host, + builder_port, build_request_id, max_timeout): + """Waits until build is produced by bisect builder on tryserver. + + Args: + fetch_build: Function to check and download build from cloud storage. + bot_name: Builder bot name on tryserver. + builder_host Tryserver hostname. + builder_port: Tryserver port. + build_request_id: A unique ID of the build request posted to tryserver. + max_timeout: Maximum time to wait for the build. + + Returns: + True if build exists and download is successful, otherwise throws + RuntimeError exception when time elapse. + """ + # Build number on the tryserver. + build_num = None + # Interval to check build on cloud storage. + poll_interval = 60 + # Interval to check build status on tryserver. + status_check_interval = 600 + last_status_check = time.time() + start_time = time.time() + while True: + # Checks for build on gs://chrome-perf and download if exists. + res = fetch_build() + if res: + return (res, 'Build successfully found') + elapsed_status_check = time.time() - last_status_check + # To avoid overloading tryserver with status check requests, we check + # build status for every 10 mins. + if elapsed_status_check > status_check_interval: + last_status_check = time.time() + if not build_num: + # Get the build number on tryserver for the current build. + build_num = bisect_builder.GetBuildNumFromBuilder( + build_request_id, bot_name, builder_host, builder_port) + # Check the status of build using the build number. + # Note: Build is treated as PENDING if build number is not found + # on the the tryserver. + build_status, status_link = bisect_builder.GetBuildStatus( + build_num, bot_name, builder_host, builder_port) + if build_status == bisect_builder.FAILED: + return (False, 'Failed to produce build, log: %s' % status_link) + elapsed_time = time.time() - start_time + if elapsed_time > max_timeout: + return (False, 'Timed out: %ss without build' % max_timeout) + + print 'Time elapsed: %ss without build.' % elapsed_time + time.sleep(poll_interval) + + def PostBuildRequestAndWait(self, revision, fetch_build, patch=None): """POSTs the build request job to the tryserver instance.""" def GetBuilderNameAndBuildTime(target_arch='ia32'): @@ -1622,19 +1684,20 @@ class BisectPerformanceMetrics(object): if IsMac(): return ('mac_perf_bisect_builder', MAX_MAC_BUILD_TIME) raise NotImplementedError('Unsupported Platform "%s".' % sys.platform) - if not condition: + if not fetch_build: return False bot_name, build_timeout = GetBuilderNameAndBuildTime(self.opts.target_arch) - - # Create a unique ID for each build request posted to try server builders. + builder_host = self.opts.builder_host + builder_port = self.opts.builder_port + # Create a unique ID for each build request posted to tryserver builders. # This ID is added to "Reason" property in build's json. - # TODO: Use this id to track the build status. - build_request_id = GetSHA1HexDigest('%s-%s' % (revision, patch)) + build_request_id = GetSHA1HexDigest( + '%s-%s-%s' % (revision, patch, time.time())) # Creates a try job description. - job_args = {'host': self.opts.builder_host, - 'port': self.opts.builder_port, + job_args = {'host': builder_host, + 'port': builder_port, 'revision': 'src@%s' % revision, 'bot': bot_name, 'name': build_request_id @@ -1643,20 +1706,16 @@ class BisectPerformanceMetrics(object): if patch: job_args['patch'] = patch # Posts job to build the revision on the server. - if post_perf_builder_job.PostTryJob(job_args): - poll_interval = 60 - start_time = time.time() - while True: - res = condition() - if res: - return res - elapsed_time = time.time() - start_time - if elapsed_time > build_timeout: - raise RuntimeError('Timed out while waiting %ds for %s build.' % - (build_timeout, revision)) - print ('Time elapsed: %ss, still waiting for %s build' % - (elapsed_time, revision)) - time.sleep(poll_interval) + if bisect_builder.PostTryJob(job_args): + status, error_msg = self.WaitUntilBuildIsReady(fetch_build, + bot_name, + builder_host, + builder_port, + build_request_id, + build_timeout) + if not status: + raise RuntimeError('%s [revision: %s]' % (error_msg, revision)) + return True return False def IsDownloadable(self, depot): diff --git a/tools/checkdeps/PRESUBMIT.py b/tools/checkdeps/PRESUBMIT.py index 10ef63212f..5880d2647e 100644 --- a/tools/checkdeps/PRESUBMIT.py +++ b/tools/checkdeps/PRESUBMIT.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/checkdeps/builddeps.py b/tools/checkdeps/builddeps.py index 0057f635c2..16dd7f3c17 100755 --- a/tools/checkdeps/builddeps.py +++ b/tools/checkdeps/builddeps.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright 2013 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/checkdeps/checkdeps.py b/tools/checkdeps/checkdeps.py index 5bf7907606..83f59ae4dd 100755 --- a/tools/checkdeps/checkdeps.py +++ b/tools/checkdeps/checkdeps.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright 2012 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/checkdeps/checkdeps_test.py b/tools/checkdeps/checkdeps_test.py index e8835a5ca8..1f93db5389 100755 --- a/tools/checkdeps/checkdeps_test.py +++ b/tools/checkdeps/checkdeps_test.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/checkdeps/cpp_checker.py b/tools/checkdeps/cpp_checker.py index 94fd37a921..ca28e4d4ac 100644 --- a/tools/checkdeps/cpp_checker.py +++ b/tools/checkdeps/cpp_checker.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/checkdeps/graphdeps.py b/tools/checkdeps/graphdeps.py index 208772f057..e6dee8ec6a 100755 --- a/tools/checkdeps/graphdeps.py +++ b/tools/checkdeps/graphdeps.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright 2013 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/checkdeps/java_checker.py b/tools/checkdeps/java_checker.py index 36e46230f4..1d5cecf627 100644 --- a/tools/checkdeps/java_checker.py +++ b/tools/checkdeps/java_checker.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/checkdeps/results.py b/tools/checkdeps/results.py index b52880ccca..6f69514f0d 100644 --- a/tools/checkdeps/results.py +++ b/tools/checkdeps/results.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/checkdeps/rules.py b/tools/checkdeps/rules.py index 199c18f367..9dfdc4a126 100644 --- a/tools/checkdeps/rules.py +++ b/tools/checkdeps/rules.py @@ -1,4 +1,4 @@ -# Copyright 2012 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/checkdeps/testdata/allowed/foo_unittest.cc b/tools/checkdeps/testdata/allowed/foo_unittest.cc index 754f295eb5..027adf856a 100644 --- a/tools/checkdeps/testdata/allowed/foo_unittest.cc +++ b/tools/checkdeps/testdata/allowed/foo_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/tools/checkdeps/testdata/allowed/not_a_test.cc b/tools/checkdeps/testdata/allowed/not_a_test.cc index 7b2a105d53..57fa942831 100644 --- a/tools/checkdeps/testdata/allowed/not_a_test.cc +++ b/tools/checkdeps/testdata/allowed/not_a_test.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/tools/checkdeps/testdata/allowed/test.h b/tools/checkdeps/testdata/allowed/test.h index ea33090050..b78bb2d7c9 100644 --- a/tools/checkdeps/testdata/allowed/test.h +++ b/tools/checkdeps/testdata/allowed/test.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/tools/checkdeps/testdata/checkdeps_test/allowed/foo_unittest.cc b/tools/checkdeps/testdata/checkdeps_test/allowed/foo_unittest.cc index 1a507eca4e..68beabfa9d 100644 --- a/tools/checkdeps/testdata/checkdeps_test/allowed/foo_unittest.cc +++ b/tools/checkdeps/testdata/checkdeps_test/allowed/foo_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/tools/checkdeps/testdata/checkdeps_test/allowed/not_a_test.cc b/tools/checkdeps/testdata/checkdeps_test/allowed/not_a_test.cc index 4278d64763..9e5e0cfd78 100644 --- a/tools/checkdeps/testdata/checkdeps_test/allowed/not_a_test.cc +++ b/tools/checkdeps/testdata/checkdeps_test/allowed/not_a_test.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/tools/checkdeps/testdata/checkdeps_test/allowed/test.h b/tools/checkdeps/testdata/checkdeps_test/allowed/test.h index 2dbd7a38b4..f8e4e65d07 100644 --- a/tools/checkdeps/testdata/checkdeps_test/allowed/test.h +++ b/tools/checkdeps/testdata/checkdeps_test/allowed/test.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/skipped/test.h b/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/skipped/test.h index 80105968e2..96fde19e45 100644 --- a/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/skipped/test.h +++ b/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/skipped/test.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/test.h b/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/test.h index aa5013d25d..54f08c339a 100644 --- a/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/test.h +++ b/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/test.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/tools/checkdeps/testdata/checkdeps_test/disallowed/test.h b/tools/checkdeps/testdata/checkdeps_test/disallowed/test.h index 5520a68c8f..15c4d5e893 100644 --- a/tools/checkdeps/testdata/checkdeps_test/disallowed/test.h +++ b/tools/checkdeps/testdata/checkdeps_test/disallowed/test.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/tools/checkdeps/testdata/disallowed/allowed/skipped/test.h b/tools/checkdeps/testdata/disallowed/allowed/skipped/test.h index 80105968e2..96fde19e45 100644 --- a/tools/checkdeps/testdata/disallowed/allowed/skipped/test.h +++ b/tools/checkdeps/testdata/disallowed/allowed/skipped/test.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/tools/checkdeps/testdata/disallowed/allowed/test.h b/tools/checkdeps/testdata/disallowed/allowed/test.h index f7dc822c4b..3d46a5efcf 100644 --- a/tools/checkdeps/testdata/disallowed/allowed/test.h +++ b/tools/checkdeps/testdata/disallowed/allowed/test.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/tools/checkdeps/testdata/disallowed/foo_unittest.cc b/tools/checkdeps/testdata/disallowed/foo_unittest.cc index 144c05eb36..1186ccfe13 100644 --- a/tools/checkdeps/testdata/disallowed/foo_unittest.cc +++ b/tools/checkdeps/testdata/disallowed/foo_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/tools/checkdeps/testdata/disallowed/test.h b/tools/checkdeps/testdata/disallowed/test.h index d0128e3a96..59d712183e 100644 --- a/tools/checkdeps/testdata/disallowed/test.h +++ b/tools/checkdeps/testdata/disallowed/test.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/tools/checklicenses/checklicenses.py b/tools/checklicenses/checklicenses.py index 3c288d5067..c657efff9b 100755 --- a/tools/checklicenses/checklicenses.py +++ b/tools/checklicenses/checklicenses.py @@ -6,6 +6,7 @@ """Makes sure that all files contain proper licensing information.""" +import json import optparse import os.path import subprocess @@ -261,9 +262,6 @@ PATH_SPECIFIC_WHITELISTED_LICENSES = { 'third_party/ocmock/OCMock': [ # http://crbug.com/98454 'UNKNOWN', ], - 'third_party/pdfium': [ # http://crbug.com/374943 - 'UNKNOWN', - ], 'third_party/ply/__init__.py': [ 'UNKNOWN', ], @@ -425,8 +423,8 @@ def check_licenses(options, args): return 1 used_suppressions = set() + errors = [] - success = True for line in stdout.splitlines(): filename, license = line.split(':', 1) filename = os.path.relpath(filename.strip(), options.base_directory) @@ -455,21 +453,16 @@ def check_licenses(options, args): used_suppressions.update(set(matched_prefixes)) continue - print "'%s' has non-whitelisted license '%s'" % (filename, license) - success = False + errors.append({'filename': filename, 'license': license}) - if success: - print "\nSUCCESS\n" + if options.json: + with open(options.json, 'w') as f: + json.dump(errors, f) - if not len(args): - unused_suppressions = set( - PATH_SPECIFIC_WHITELISTED_LICENSES.keys()).difference(used_suppressions) - if unused_suppressions: - print "\nNOTE: unused suppressions detected:\n" - print '\n'.join(unused_suppressions) - - return 0 - else: + if errors: + for error in errors: + print "'%s' has non-whitelisted license '%s'" % ( + error['filename'], error['license']) print "\nFAILED\n" print "Please read", print "http://www.chromium.org/developers/adding-3rd-party-libraries" @@ -484,6 +477,18 @@ def check_licenses(options, args): return 1 + print "\nSUCCESS\n" + + if not len(args): + unused_suppressions = set( + PATH_SPECIFIC_WHITELISTED_LICENSES.iterkeys()).difference( + used_suppressions) + if unused_suppressions: + print "\nNOTE: unused suppressions detected:\n" + print '\n'.join(unused_suppressions) + + return 0 + def main(): default_root = os.path.abspath( @@ -500,6 +505,7 @@ def main(): action='store_true', default=False, help='Ignore path-specific license whitelist.') + option_parser.add_option('--json', help='Path to JSON output file') options, args = option_parser.parse_args() return check_licenses(options, args) diff --git a/tools/checkperms/checkperms.py b/tools/checkperms/checkperms.py index 9395c00d27..ffb08043c1 100755 --- a/tools/checkperms/checkperms.py +++ b/tools/checkperms/checkperms.py @@ -25,6 +25,7 @@ backslashes. All directories should be relative to the source root and all file paths should be only lowercase. """ +import json import logging import optparse import os @@ -298,9 +299,9 @@ def has_shebang_or_is_elf(full_path): return (data[:3] == '#!/', data == '\x7fELF') -def check_file(root_path, rel_path, bare_output): +def check_file(root_path, rel_path): """Checks the permissions of the file whose path is root_path + rel_path and - returns an error if it is inconsistent. + returns an error if it is inconsistent. Returns None on success. It is assumed that the file is not ignored by is_ignored(). @@ -310,6 +311,12 @@ def check_file(root_path, rel_path, bare_output): shebang or ELF header and compares this with the executable bit on the file. """ full_path = os.path.join(root_path, rel_path) + def result_dict(error): + return { + 'error': error, + 'full_path': full_path, + 'rel_path': rel_path, + } try: bit = has_executable_bit(full_path) except OSError: @@ -320,40 +327,26 @@ def check_file(root_path, rel_path, bare_output): if must_be_executable(rel_path): if not bit: - if bare_output: - return full_path - return '%s: Must have executable bit set' % full_path + return result_dict('Must have executable bit set') return if must_not_be_executable(rel_path): if bit: - if bare_output: - return full_path - return '%s: Must not have executable bit set' % full_path + return result_dict('Must not have executable bit set') return # For the others, it depends on the file header. (shebang, elf) = has_shebang_or_is_elf(full_path) if bit != (shebang or elf): - if bare_output: - return full_path if bit: - return '%s: Has executable bit but not shebang or ELF header' % full_path + return result_dict('Has executable bit but not shebang or ELF header') if shebang: - return '%s: Has shebang but not executable bit' % full_path - return '%s: Has ELF header but not executable bit' % full_path + return result_dict('Has shebang but not executable bit') + return result_dict('Has ELF header but not executable bit') -def check_files(root, files, bare_output): - errors = [] - for rel_path in files: - if is_ignored(rel_path): - continue - - error = check_file(root, rel_path, bare_output) - if error: - errors.append(error) - - return errors +def check_files(root, files): + gen = (check_file(root, f) for f in files if not is_ignored(f)) + return filter(None, gen) class ApiBase(object): @@ -371,7 +364,7 @@ class ApiBase(object): not must_not_be_executable(rel_path)): self.count_read_header += 1 - return check_file(self.root_dir, rel_path, self.bare_output) + return check_file(self.root_dir, rel_path) def check_dir(self, rel_path): return self.check(rel_path) @@ -502,6 +495,7 @@ Examples: '--file', action='append', dest='files', help='Specifics a list of files to check the permissions of. Only these ' 'files will be checked') + parser.add_option('--json', help='Path to JSON output file') options, args = parser.parse_args() levels = [logging.ERROR, logging.INFO, logging.DEBUG] @@ -514,26 +508,29 @@ Examples: options.root = os.path.abspath(options.root) if options.files: - errors = check_files(options.root, options.files, options.bare) - print '\n'.join(errors) - return bool(errors) + # --file implies --bare (for PRESUBMIT.py). + options.bare = True - api = get_scm(options.root, options.bare) - if args: - start_dir = args[0] + errors = check_files(options.root, options.files) else: - start_dir = api.root_dir + api = get_scm(options.root, options.bare) + start_dir = args[0] if args else api.root_dir + errors = api.check(start_dir) - errors = api.check(start_dir) + if not options.bare: + print('Processed %s files, %d files where tested for shebang/ELF ' + 'header' % (api.count, api.count_read_header)) - if not options.bare: - print 'Processed %s files, %d files where tested for shebang/ELF header' % ( - api.count, api.count_read_header) + if options.json: + with open(options.json, 'w') as f: + json.dump(errors, f) if errors: - if not options.bare: + if options.bare: + print '\n'.join(e['full_path'] for e in errors) + else: print '\nFAILED\n' - print '\n'.join(errors) + print '\n'.join('%s: %s' % (e['full_path'], e['error']) for e in errors) return 1 if not options.bare: print '\nSUCCESS\n' diff --git a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp index 0ea8f4cac3..d1d3a468ec 100644 --- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp +++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp @@ -486,7 +486,7 @@ class CheckFieldsVisitor : public RecursiveEdgeVisitor { return !invalid_fields_.empty(); } - void VisitMember(Member* edge) override { + void AtMember(Member* edge) override { if (managed_host_) return; // A member is allowed to appear in the context of a root. @@ -499,7 +499,7 @@ class CheckFieldsVisitor : public RecursiveEdgeVisitor { invalid_fields_.push_back(std::make_pair(current_, kMemberInUnmanaged)); } - void VisitValue(Value* edge) override { + void AtValue(Value* edge) override { // TODO: what should we do to check unions? if (edge->value()->record()->isUnion()) return; @@ -540,6 +540,11 @@ class CheckFieldsVisitor : public RecursiveEdgeVisitor { } } + void AtCollection(Collection* edge) override { + if (edge->on_heap() && Parent() && Parent()->IsOwnPtr()) + invalid_fields_.push_back(std::make_pair(current_, kOwnPtrToGCManaged)); + } + private: Error InvalidSmartPtr(Edge* ptr) { if (ptr->IsRawPtr()) diff --git a/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h b/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h index 52062a1d2d..db6955f7b5 100644 --- a/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h +++ b/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h @@ -22,6 +22,7 @@ public: void trace(Visitor*); private: Vector<OwnPtr<HeapObject> > m_objs; + OwnPtr<HeapVector<Member<HeapObject> > > m_objs2; }; } diff --git a/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.txt b/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.txt index b1dac2c6f1..4102e86b32 100644 --- a/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.txt +++ b/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.txt @@ -11,4 +11,7 @@ class HeapObject : public GarbageCollectedFinalized<HeapObject> { ./own_ptr_to_gc_managed_class.h:24:5: note: [blink-gc] OwnPtr field 'm_objs' to a GC managed class declared here: Vector<OwnPtr<HeapObject> > m_objs; ^ +./own_ptr_to_gc_managed_class.h:25:5: note: [blink-gc] OwnPtr field 'm_objs2' to a GC managed class declared here: + OwnPtr<HeapVector<Member<HeapObject> > > m_objs2; + ^ 2 warnings generated. diff --git a/tools/cr/cr/targets/chrome_shell.py b/tools/cr/cr/targets/chrome_shell.py index 65ff6270c8..016d5b681f 100644 --- a/tools/cr/cr/targets/chrome_shell.py +++ b/tools/cr/cr/targets/chrome_shell.py @@ -20,6 +20,6 @@ class ChromeShellTarget(cr.NamedTarget): class ChromeShellTestTarget(cr.NamedTarget): NAME = 'chrome_shell_test' CONFIG = cr.Config.From( - CR_TARGET_NAME='ChromiumTestShellTest', + CR_TARGET_NAME='ChromeShellTest', ) diff --git a/tools/cygprofile/PRESUBMIT.py b/tools/cygprofile/PRESUBMIT.py new file mode 100644 index 0000000000..dd28746631 --- /dev/null +++ b/tools/cygprofile/PRESUBMIT.py @@ -0,0 +1,34 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Top-level presubmit script for cygprofile. + +See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for +details on the presubmit API built into gcl. +""" + + +def CommonChecks(input_api, output_api): + output = [] + blacklist = [] + output.extend(input_api.canned_checks.RunPylint( + input_api, output_api, black_list=blacklist)) + output.extend(input_api.canned_checks.RunUnitTests( + input_api, + output_api, + [input_api.os_path.join(input_api.PresubmitLocalPath(), 'run_tests')])) + + if input_api.is_committing: + output.extend(input_api.canned_checks.PanProjectChecks(input_api, + output_api, + owners_check=False)) + return output + + +def CheckChangeOnUpload(input_api, output_api): + return CommonChecks(input_api, output_api) + + +def CheckChangeOnCommit(input_api, output_api): + return CommonChecks(input_api, output_api) diff --git a/tools/cygprofile/cygprofile.cc b/tools/cygprofile/cygprofile.cc index 980fa9e070..5d0e370554 100644 --- a/tools/cygprofile/cygprofile.cc +++ b/tools/cygprofile/cygprofile.cc @@ -1,401 +1,373 @@ // Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// -// Tool to log the execution of the process (Chrome). Writes logs containing -// time and address of the callback being called for the first time. -// -// To speed up the logging, buffering logs is implemented. Every thread have its -// own buffer and log file so the contention between threads is minimal. As a -// side-effect, functions called might be mentioned in many thread logs. -// -// Special thread is created in the process to periodically flushes logs for all -// threads for the case the thread has stopped before flushing its logs. -// -// Use this profiler with use_allocator!="none". -// -// Note for the ChromeOS Chrome. Remove renderer process from the sandbox (add -// --no-sandbox option to running Chrome in /sbin/session_manager_setup.sh). -// Otherwise renderer will not be able to write logs (and will assert on that). -// -// Also note that the instrumentation code is self-activated. It begins to -// record the log data when it is called first, including the run-time startup. -// Have it in mind when modifying it, in particular do not use global objects -// with constructors as they are called during startup (too late for us). + +#include "tools/cygprofile/cygprofile.h" #include <fcntl.h> -#include <fstream> #include <pthread.h> -#include <stdarg.h> -#include <string> #include <sys/stat.h> #include <sys/syscall.h> #include <sys/time.h> #include <sys/types.h> + +#include <cstdio> +#include <fstream> +#include <string> #include <vector> +#include "base/bind.h" #include "base/containers/hash_tables.h" +#include "base/files/scoped_file.h" #include "base/lazy_instance.h" #include "base/logging.h" -#include "base/memory/singleton.h" +#include "base/macros.h" +#include "base/stl_util.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" +#include "base/strings/stringprintf.h" #include "base/synchronization/lock.h" namespace cygprofile { +namespace { -extern "C" { +// Allow 8 MBytes of data for each thread log. +const int kMaxBufferSize = 8 * 1024 * 1024 / sizeof(LogEntry); -// Note that these are linked internally by the compiler. Don't call -// them directly! -void __cyg_profile_func_enter(void* this_fn, void* call_site) - __attribute__((no_instrument_function)); -void __cyg_profile_func_exit(void* this_fn, void* call_site) - __attribute__((no_instrument_function)); +// Have the background internal thread do its flush every 15 sec. +const int kFlushThreadIdleTimeSec = 15; -} +const char kLogFileNamePrefix[] = "/data/local/tmp/chrome/cyglog/"; -// Single log entry layout. -struct CygLogEntry { - time_t seconds; - long int usec; - pid_t pid; - pthread_t tid; - const void* this_fn; - CygLogEntry(time_t seconds, long int usec, - pid_t pid, pthread_t tid, const void* this_fn) - : seconds(seconds), usec(usec), - pid(pid), tid(tid), this_fn(this_fn) {} -}; +// "cyglog.PID.LWP.PPID" +const char kLogFilenameFormat[] = "%scyglog.%d.%d-%d"; -// Common data for the process. Singleton. -class CygCommon { - public: - static CygCommon* GetInstance(); - std::string header() const { return header_line_; } - private: - CygCommon(); - std::string header_line_; - friend struct DefaultSingletonTraits<CygCommon>; +// Magic value of above to prevent instrumentation. Used when ThreadLog is being +// constructed (to prevent reentering by malloc, for example) and by the flush +// log thread (to prevent it from being logged0. +ThreadLog* const kMagicBeingConstructed = reinterpret_cast<ThreadLog*>(1); - DISALLOW_COPY_AND_ASSIGN(CygCommon); -}; +// Per-thread pointer to the current log object. +static __thread ThreadLog* g_tls_log = NULL; -// Returns light-weight process ID. On linux, this is a system-wide -// unique thread id. -static pid_t GetLwp() { +// Returns light-weight process ID. On Linux, this is a system-wide unique +// thread id. +pid_t GetTID() { return syscall(__NR_gettid); } -// A per-thread structure representing the log itself. -class CygTlsLog { - public: - CygTlsLog() - : in_use_(false), lwp_(GetLwp()), pthread_self_(pthread_self()) { } +timespec GetCurrentTime() { + timespec timestamp; + clock_gettime(CLOCK_MONOTONIC, ×tamp); + return timestamp; +} - // Enter a log entity. - void LogEnter(void* this_fn); +// Sleeps for |sec| seconds. +void SleepSec(int sec) { + for (int secs_to_sleep = sec; secs_to_sleep != 0;) + secs_to_sleep = sleep(secs_to_sleep); +} - // Add newly created CygTlsLog object to the list of all such objects. - // Needed for the timer callback: it will enumerate each object and flush. - static void AddNewLog(CygTlsLog* newlog); +// Exposes the string header that will appear at the top of every trace file. +// This string contains memory mapping information for the mapped +// library/executable which is used offline during symbolization. Note that +// this class is meant to be instantiated once per process and lazily (during +// the first flush). +struct ImmutableFileHeaderLine { + ImmutableFileHeaderLine() : value(MakeFileHeaderLine()) {} - // Starts a thread in this process that periodically flushes all the threads. - // Must be called once per process. - static void StartFlushLogThread(); + const std::string value; private: - static const int kBufMaxSize; - static const char kLogFilenameFmt[]; - static const char kLogFileNamePrefix[]; - - // Flush the log to file. Create file if needed. - // Must be called with locked log_mutex_. - void FlushLog(); + // Returns whether the integer representation of the hexadecimal address + // stored in |line| at position |start_offset| was successfully stored in + // |result|. + static bool ParseAddress(const std::string& line, + off_t start_offset, + size_t length, + uint64* result) { + if (start_offset >= line.length()) + return false; + + uint64 address; + const bool ret = HexStringToUInt64( + base::StringPiece(line.c_str() + start_offset, length), &address); + if (!ret) + return false; + + *result = address; + return true; + } - // Fork hooks. Needed to keep data in consistent state during fork(). - static void AtForkPrepare(); - static void AtForkParent(); - static void AtForkChild(); + // Parses /proc/self/maps and returns a two line string such as: + // 758c6000-79f4b000 r-xp 00000000 b3:17 309475 libchrome.2009.0.so + // secs usecs pid:threadid func + static std::string MakeFileHeaderLine() { + std::ifstream mapsfile("/proc/self/maps"); + CHECK(mapsfile.good()); + std::string result; + + for (std::string line; std::getline(mapsfile, line); ) { + if (line.find("r-xp") == std::string::npos) + continue; + + const size_t address_length = line.find('-'); + uint64 start_address = 0; + CHECK(ParseAddress(line, 0, address_length, &start_address)); + + uint64 end_address = 0; + CHECK(ParseAddress(line, address_length + 1, address_length, + &end_address)); + + const uintptr_t current_func_addr = reinterpret_cast<uintptr_t>( + &MakeFileHeaderLine); + if (current_func_addr >= start_address && + current_func_addr < end_address) { + result.swap(line); + break; + } + } + CHECK(!result.empty()); + result.append("\nsecs\tusecs\tpid:threadid\tfunc\n"); + return result; + } +}; - // Thread callback to flush all logs periodically. - static void* FlushLogThread(void*); +base::LazyInstance<ThreadLogsManager>::Leaky g_logs_manager = + LAZY_INSTANCE_INITIALIZER; - std::string log_filename_; - std::vector<CygLogEntry> buf_; +base::LazyInstance<ImmutableFileHeaderLine>::Leaky g_file_header_line = + LAZY_INSTANCE_INITIALIZER; - // A lock that guards buf_ usage between per-thread instrumentation - // routine and timer flush callback. So the contention could happen - // only during the flush, every 30 secs. - base::Lock log_mutex_; +} // namespace - // Current thread is inside the instrumentation routine. - bool in_use_; +// Custom thread implementation that joins on destruction. Note that +// base::Thread has non-trivial dependencies on e.g. AtExitManager which makes +// it hard to use it early. +class Thread { + public: + Thread(const base::Closure& thread_callback) + : thread_callback_(thread_callback) { + CHECK_EQ(0, pthread_create(&handle_, NULL, &Thread::EntryPoint, this)); + } - // Keeps track of all functions that have been logged on this thread - // so we do not record dublicates. - std::hash_set<void*> functions_called_; + ~Thread() { + CHECK_EQ(0, pthread_join(handle_, NULL)); + } - // Thread identifier as Linux kernel shows it. For debugging purposes. - // LWP (light-weight process) is a unique ID of the thread in the system, - // unlike pthread_self() which is the same for fork()-ed threads. - pid_t lwp_; - pthread_t pthread_self_; + private: + static void* EntryPoint(void* data) { + // Disable logging on this thread. Although this routine is not instrumented + // (cygprofile.gyp provides that), the called routines are and thus will + // call instrumentation. + CHECK(g_tls_log == NULL); // Must be 0 as this is a new thread. + g_tls_log = kMagicBeingConstructed; + + Thread* const instance = reinterpret_cast<Thread*>(data); + instance->thread_callback_.Run(); + return NULL; + } - DISALLOW_COPY_AND_ASSIGN(CygTlsLog); -}; + const base::Closure thread_callback_; + pthread_t handle_; -// Storage for logs for all threads in the process. -// Using std::list may be better, but it fails when used before main(). -struct AllLogs { - std::vector<CygTlsLog*> logs; - base::Lock mutex; + DISALLOW_COPY_AND_ASSIGN(Thread); }; -base::LazyInstance<AllLogs>::Leaky all_logs_ = LAZY_INSTANCE_INITIALIZER; - -// Per-thread pointer to the current log object. -static __thread CygTlsLog* tls_current_log = NULL; - -// Magic value of above to prevent the instrumentation. Used when CygTlsLog is -// being constructed (to prevent reentering by malloc, for example) and by -// the FlushLogThread (to prevent it being logged - see comment in its code). -CygTlsLog* const kMagicBeingConstructed = reinterpret_cast<CygTlsLog*>(1); - -// Number of entries in the per-thread log buffer before we flush. -// Note, that we also flush by timer so not all thread logs may grow up to this. -const int CygTlsLog::kBufMaxSize = 3000; - -#if defined(OS_ANDROID) -const char CygTlsLog::kLogFileNamePrefix[] = - "/data/local/tmp/chrome/cyglog/"; -#else -const char CygTlsLog::kLogFileNamePrefix[] = "/var/log/chrome/"; -#endif +// Single log entry recorded for each function call. +LogEntry::LogEntry(const void* address) + : time(GetCurrentTime()), + pid(getpid()), + tid(GetTID()), + address(address) { +} -// "cyglog.PID.LWP.pthread_self.PPID" -const char CygTlsLog::kLogFilenameFmt[] = "%scyglog.%d.%d.%ld-%d"; +ThreadLog::ThreadLog() + : tid_(GetTID()), + in_use_(false), + flush_callback_( + base::Bind(&ThreadLog::FlushInternal, base::Unretained(this))) { +} -CygCommon* CygCommon::GetInstance() { - return Singleton<CygCommon>::get(); +ThreadLog::ThreadLog(const FlushCallback& flush_callback) + : tid_(GetTID()), + in_use_(false), + flush_callback_(flush_callback) { } -CygCommon::CygCommon() { - // Determine our module addresses. - std::ifstream mapsfile("/proc/self/maps"); - CHECK(mapsfile.good()); - static const int kMaxLineSize = 512; - char line[kMaxLineSize]; - void (*this_fn)(void) = - reinterpret_cast<void(*)()>(__cyg_profile_func_enter); - while (mapsfile.getline(line, kMaxLineSize)) { - const std::string str_line = line; - size_t permindex = str_line.find("r-xp"); - if (permindex != std::string::npos) { - int dashindex = str_line.find("-"); - int spaceindex = str_line.find(" "); - char* p; - void* start = reinterpret_cast<void*> - (strtol((str_line.substr(0, dashindex)).c_str(), - &p, 16)); - CHECK(*p == 0); // Could not determine start address. - void* end = reinterpret_cast<void*> - (strtol((str_line.substr(dashindex + 1, - spaceindex - dashindex - 1)).c_str(), - &p, 16)); - CHECK(*p == 0); // Could not determine end address. - - if (this_fn >= start && this_fn < end) - header_line_ = str_line; - } - } - mapsfile.close(); - header_line_.append("\nsecs\tusecs\tpid:threadid\tfunc\n"); +ThreadLog::~ThreadLog() { + g_tls_log = NULL; } -void CygTlsLog::LogEnter(void* this_fn) { +void ThreadLog::AddEntry(void* address) { if (in_use_) return; in_use_ = true; - if (functions_called_.find(this_fn) == - functions_called_.end()) { - functions_called_.insert(this_fn); - base::AutoLock lock(log_mutex_); - if (buf_.capacity() < kBufMaxSize) - buf_.reserve(kBufMaxSize); - struct timespec timestamp; - clock_gettime(CLOCK_MONOTONIC, ×tamp); - buf_.push_back(CygLogEntry(timestamp.tv_sec, timestamp.tv_nsec / 1000, - getpid(), pthread_self(), this_fn)); - if (buf_.size() == kBufMaxSize) { - FlushLog(); - } + CHECK_EQ(tid_, GetTID()); + const std::pair<std::hash_set<void*>::iterator, bool> pair = + called_functions_.insert(address); + const bool did_insert = pair.second; + + if (did_insert) { + base::AutoLock auto_lock(lock_); + entries_.push_back(LogEntry(address)); + // Crash in a quickly understandable way instead of crashing (or maybe not + // though) due to OOM. + CHECK_LE(entries_.size(), kMaxBufferSize); } in_use_ = false; } -void CygTlsLog::AtForkPrepare() { - CHECK(tls_current_log); - CHECK(tls_current_log->lwp_ == GetLwp()); - CHECK(tls_current_log->pthread_self_ == pthread_self()); - all_logs_.Get().mutex.Acquire(); +void ThreadLog::TakeEntries(std::vector<LogEntry>* destination) { + base::AutoLock auto_lock(lock_); + destination->swap(entries_); + STLClearObject(&entries_); } -void CygTlsLog::AtForkParent() { - CHECK(tls_current_log); - CHECK(tls_current_log->lwp_ == GetLwp()); - CHECK(tls_current_log->pthread_self_ == pthread_self()); - all_logs_.Get().mutex.Release(); +void ThreadLog::Flush(std::vector<LogEntry>* entries) const { + flush_callback_.Run(entries); } -void CygTlsLog::AtForkChild() { - CHECK(tls_current_log); +void ThreadLog::FlushInternal(std::vector<LogEntry>* entries) const { + const std::string log_filename( + base::StringPrintf( + kLogFilenameFormat, kLogFileNamePrefix, getpid(), tid_, getppid())); + const base::ScopedFILE file(fopen(log_filename.c_str(), "a")); + CHECK(file.get()); + + const long offset = ftell(file.get()); + if (offset == 0) + fprintf(file.get(), "%s", g_file_header_line.Get().value.c_str()); + + for (std::vector<LogEntry>::const_iterator it = entries->begin(); + it != entries->end(); ++it) { + fprintf(file.get(), "%ld %ld\t%d:%ld\t%p\n", it->time.tv_sec, + it->time.tv_nsec / 1000, it->pid, it->tid, it->address); + } - // Update the IDs of this new thread of the new process. - // Note that the process may (and Chrome main process forks zygote this way) - // call exec(self) after we return (to launch new shiny self). If done like - // that, PID and LWP will remain the same, but pthread_self() changes. - pid_t lwp = GetLwp(); - CHECK(tls_current_log->lwp_ != lwp); // LWP is system-wide unique thread ID. - tls_current_log->lwp_ = lwp; + STLClearObject(entries); +} - CHECK(tls_current_log->pthread_self_ == pthread_self()); +ThreadLogsManager::ThreadLogsManager() + : wait_callback_(base::Bind(&SleepSec, kFlushThreadIdleTimeSec)) { +} - // Leave the only current thread tls object because fork() clones only the - // current thread (the one that called fork) to the child process. - AllLogs& all_logs = all_logs_.Get(); - all_logs.logs.clear(); - all_logs.logs.push_back(tls_current_log); - CHECK(all_logs.logs.size() == 1); +ThreadLogsManager::ThreadLogsManager(const base::Closure& wait_callback, + const base::Closure& notify_callback) - // Clear log filename so it will be re-calculated with the new PIDs. - tls_current_log->log_filename_.clear(); + : wait_callback_(wait_callback), + notify_callback_(notify_callback) { +} - // Create the thread that will periodically flush all logs for this process. - StartFlushLogThread(); +ThreadLogsManager::~ThreadLogsManager() { + // Note that the internal thread does some work until it sees |flush_thread_| + // = NULL. + scoped_ptr<Thread> flush_thread; + { + base::AutoLock auto_lock(lock_); + flush_thread_.swap(flush_thread); + } + flush_thread.reset(); // Joins the flush thread. - // We do not update log header line (CygCommon data) as it will be the same - // because the new process is just a forked copy. - all_logs.mutex.Release(); + STLDeleteContainerPointers(logs_.begin(), logs_.end()); } -void CygTlsLog::StartFlushLogThread() { - pthread_t tid; - CHECK(!pthread_create(&tid, NULL, &CygTlsLog::FlushLogThread, NULL)); +void ThreadLogsManager::AddLog(scoped_ptr<ThreadLog> new_log) { + base::AutoLock auto_lock(lock_); + + if (logs_.empty()) + StartInternalFlushThread_Locked(); + + logs_.push_back(new_log.release()); } -void CygTlsLog::AddNewLog(CygTlsLog* newlog) { - CHECK(tls_current_log == kMagicBeingConstructed); - AllLogs& all_logs = all_logs_.Get(); - base::AutoLock lock(all_logs.mutex); - if (all_logs.logs.empty()) { - - // An Android app never fork, it always starts with a pre-defined number of - // process descibed by the android manifest file. In fact, there is not - // support for pthread_atfork at the android system libraries. All chrome - // for android processes will start as independent processs and each one - // will generate its own logs that will later have to be merged as usual. -#if !defined(OS_ANDROID) - CHECK(!pthread_atfork(CygTlsLog::AtForkPrepare, - CygTlsLog::AtForkParent, - CygTlsLog::AtForkChild)); -#endif - - // The very first process starts its flush thread here. Forked processes - // will do it in AtForkChild(). - StartFlushLogThread(); - } - all_logs.logs.push_back(newlog); +void ThreadLogsManager::StartInternalFlushThread_Locked() { + lock_.AssertAcquired(); + CHECK(!flush_thread_); + // Note that the |flush_thread_| joins at destruction which guarantees that it + // will never outlive |this|, i.e. it's safe not to use ref-counting. + flush_thread_.reset( + new Thread(base::Bind(&ThreadLogsManager::FlushAllLogsOnFlushThread, + base::Unretained(this)))); } -// Printf-style routine to write to open file. -static void WriteLogLine(int fd, const char* fmt, ...) { - va_list arg_ptr; - va_start(arg_ptr, fmt); - char msg[160]; - int len = vsnprintf(msg, sizeof(msg), fmt, arg_ptr); - int rc = write(fd, msg, (len > sizeof(msg))? sizeof(msg): len); - va_end(arg_ptr); +// Type used below for flushing. +struct LogData { + LogData(ThreadLog* thread_log) : thread_log(thread_log) {} + + ThreadLog* const thread_log; + std::vector<LogEntry> entries; }; -void CygTlsLog::FlushLog() { - bool first_log_write = false; - if (log_filename_.empty()) { - first_log_write = true; - char buf[80]; - snprintf(buf, sizeof(buf), kLogFilenameFmt, - kLogFileNamePrefix, getpid(), lwp_, pthread_self_, getppid()); - log_filename_ = buf; - unlink(log_filename_.c_str()); - } +void ThreadLogsManager::FlushAllLogsOnFlushThread() { + while (true) { + { + base::AutoLock auto_lock(lock_); + // The |flush_thread_| field is reset during destruction. + if (!flush_thread_) + return; + } + // Sleep for a few secs and then flush all thread's buffers. There is a + // danger that, when quitting Chrome, this thread may see unallocated data + // and segfault. We do not care because we need logs when Chrome is working. + wait_callback_.Run(); + + // Copy the ThreadLog pointers to avoid acquiring both the logs manager's + // lock and the one for individual thread logs. + std::vector<ThreadLog*> thread_logs_copy; + { + base::AutoLock auto_lock(lock_); + thread_logs_copy = logs_; + } - int file = open(log_filename_.c_str(), O_CREAT | O_WRONLY | O_APPEND, 00600); - CHECK(file != -1); + // Move the logs' data before flushing them so that the mutexes are not + // acquired for too long. + std::vector<LogData> logs; + for (std::vector<ThreadLog*>::const_iterator it = + thread_logs_copy.begin(); + it != thread_logs_copy.end(); ++it) { + ThreadLog* const thread_log = *it; + LogData log_data(thread_log); + logs.push_back(log_data); + thread_log->TakeEntries(&logs.back().entries); + } - if (first_log_write) - WriteLogLine(file, "%s", CygCommon::GetInstance()->header().c_str()); + for (std::vector<LogData>::iterator it = logs.begin(); + it != logs.end(); ++it) { + if (!it->entries.empty()) + it->thread_log->Flush(&it->entries); + } - for (int i = 0; i != buf_.size(); ++i) { - const CygLogEntry& p = buf_[i]; - WriteLogLine(file, "%ld %ld\t%d:%ld\t%p\n", - p.seconds, p.usec, p.pid, p.tid, p.this_fn); + if (!notify_callback_.is_null()) + notify_callback_.Run(); } - - close(file); - buf_.clear(); } -void* CygTlsLog::FlushLogThread(void*) { - // Disable logging this thread. Although this routine is not instrumented - // (cygprofile.gyp provides that), the called routines are and thus will - // call instrumentation. - CHECK(tls_current_log == NULL); // Must be 0 as this is a new thread. - tls_current_log = kMagicBeingConstructed; - - // Run this loop infinitely: sleep 30 secs and the flush all thread's - // buffers. There is a danger that, when quitting Chrome, this thread may - // see unallocated data and segfault. We do not care because we need logs - // when Chrome is working. - while (true) { - for(int secs_to_sleep = 30; secs_to_sleep != 0;) - secs_to_sleep = sleep(secs_to_sleep); - - AllLogs& all_logs = all_logs_.Get(); - base::AutoLock lock(all_logs.mutex); - for (int i = 0; i != all_logs.logs.size(); ++i) { - CygTlsLog* current_log = all_logs.logs[i]; - base::AutoLock current_lock(current_log->log_mutex_); - if (current_log->buf_.size()) { - current_log->FlushLog(); - } else { - // The thread's log is still empty. Probably the thread finished prior - // to previous timer fired - deallocate its buffer. Even if the thread - // ever resumes, it will allocate its buffer again in - // std::vector::push_back(). - current_log->buf_.clear(); - } - } - } -} +extern "C" { -// Gcc Compiler callback, called on every function invocation providing +// The GCC compiler callbacks, called on every function invocation providing // addresses of caller and callee codes. +void __cyg_profile_func_enter(void* this_fn, void* call_site) + __attribute__((no_instrument_function)); +void __cyg_profile_func_exit(void* this_fn, void* call_site) + __attribute__((no_instrument_function)); + void __cyg_profile_func_enter(void* this_fn, void* callee_unused) { - if (tls_current_log == NULL) { - tls_current_log = kMagicBeingConstructed; - CygTlsLog* newlog = new CygTlsLog; - CHECK(newlog); - CygTlsLog::AddNewLog(newlog); - tls_current_log = newlog; + if (g_tls_log == NULL) { + g_tls_log = kMagicBeingConstructed; + ThreadLog* new_log = new ThreadLog(); + CHECK(new_log); + g_logs_manager.Pointer()->AddLog(make_scoped_ptr(new_log)); + g_tls_log = new_log; } - if (tls_current_log != kMagicBeingConstructed) { - tls_current_log->LogEnter(this_fn); - } -} -// Gcc Compiler callback, called after every function invocation providing -// addresses of caller and callee codes. -void __cyg_profile_func_exit(void* this_fn, void* call_site) { + if (g_tls_log != kMagicBeingConstructed) + g_tls_log->AddEntry(this_fn); } +void __cyg_profile_func_exit(void* this_fn, void* call_site) {} + +} // extern "C" } // namespace cygprofile diff --git a/tools/cygprofile/cygprofile.gyp b/tools/cygprofile/cygprofile.gyp index 1e7c751ae4..910ef54c3c 100644 --- a/tools/cygprofile/cygprofile.gyp +++ b/tools/cygprofile/cygprofile.gyp @@ -3,8 +3,6 @@ # found in the LICENSE file. { - 'variables': { - }, 'targets': [ { 'target_name': 'cygprofile', @@ -12,8 +10,29 @@ 'include_dirs': [ '../..', ], 'sources': [ 'cygprofile.cc', + 'cygprofile.h', ], 'cflags!': [ '-finstrument-functions' ], + 'dependencies': [ + # This adds uninstrumented symbols to the static library from base. + # These symbols are likely *not* to be used because there are many + # other duplicates in other objects/libraries. + '../../base/base.gyp:base', + ], + }, + { + 'target_name': 'cygprofile_unittests', + 'type': 'executable', + 'include_dirs': [ '../..', ], + 'sources': [ + 'cygprofile_unittest.cc', + ], + 'cflags!': [ '-finstrument-functions' ], + 'dependencies': [ + 'cygprofile', + '../../base/base.gyp:base', + '../../testing/gtest.gyp:gtest', + ], }, ], } diff --git a/tools/cygprofile/cygprofile.h b/tools/cygprofile/cygprofile.h new file mode 100644 index 0000000000..eeb3ffbcdf --- /dev/null +++ b/tools/cygprofile/cygprofile.h @@ -0,0 +1,166 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Tool to log the execution of the process (Chrome). Writes logs containing +// time and address of the callback being called for the first time. +// +// For performance reasons logs are buffered. Every thread has its own buffer +// and log file so the contention between threads is minimal. As a side-effect, +// functions called might be mentioned in many thread logs. +// +// A special thread is created in the process to periodically flush logs for all +// threads in case the thread had stopped before flushing its logs. +// +// Also note that the instrumentation code is self-activated. It begins to +// record the log data when it is called first, including the run-time startup. +// Have it in mind when modifying it, in particular do not use global objects +// with constructors as they are called during startup (too late for us). + +#ifndef TOOLS_CYGPROFILE_CYGPROFILE_H_ +#define TOOLS_CYGPROFILE_CYGPROFILE_H_ + +#include <vector> + +#include <sys/time.h> +#include <sys/types.h> + +#include "base/callback.h" +#include "base/containers/hash_tables.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/synchronization/lock.h" +#include "build/build_config.h" + +#if !defined(OS_ANDROID) +// This is only supported on Android thanks to the fact that on Android +// processes (other than the system's zygote) don't fork. +// +// To make cygprofile truly work (i.e. without any deadlock) on Chrome +// platforms that use fork(), cygprofile.cc should be written in a way that +// guarantees that: +// - No lock is acquired by a foreign thread during fork(). In particular this +// means that cygprofile.cc should not perform any heap allocation (since heap +// allocators, including TCMalloc generally use locks). +// - Only cygprofile.cc uses pthread_atfork() in the whole process. Unlike POSIX +// signals, pthread_atfork() doesn't provide a way to install multiple handlers. +// Calling pthread_atfork() in cygprofile.cc would override any handler that +// could have been installed previously. +// +// Chrome happens to violate the first requirement at least once by having its +// process launcher thread fork. However the child process in that case, when +// it's not instrumented with cygprofile, directly calls exec(). This is safe +// since the child process doesn't try to release a lock acquired by another +// thread in the parent process which would lead to a deadlock. This problem was +// actually observed by trying to port the current version of cygprofile.cc to +// Linux. +#error This is only supported on Android. +#endif + +// The following is only exposed for testing. +namespace cygprofile { + +class Thread; + +// Single log entry recorded for each function call. +struct LogEntry { + LogEntry(const void* address); + + const timespec time; + const pid_t pid; + const pid_t tid; + const void* const address; +}; + +// Per-thread function calls log. +class ThreadLog { + public: + // Callback invoked for flushing that can be provided for testing. + typedef base::Callback<void (std::vector<LogEntry>*)> FlushCallback; + + ThreadLog(); + + // Used for testing. + ThreadLog(const FlushCallback& flush_callback); + + ~ThreadLog(); + + // Must only be called from the thread this ThreadLog instance is watching. + void AddEntry(void* address); + + // Can be called from any thread. + void TakeEntries(std::vector<LogEntry>* output); + + // Flushes the provided vector of entries to a file and clears it. Note that + // this can be called from any thread. + void Flush(std::vector<LogEntry>* entries) const; + + private: + // Default implementation (that can be overridden for testing) of the method + // above. + void FlushInternal(std::vector<LogEntry>* entries) const; + + // Thread identifier as Linux kernel shows it. LWP (light-weight process) is + // a unique ID of the thread in the system, unlike pthread_self() which is the + // same for fork()-ed threads. + const pid_t tid_; + + // Current thread is inside the instrumentation routine. + bool in_use_; + + // Callback used to flush entries. + const FlushCallback flush_callback_; + + // Keeps track of all functions that have been logged on this thread so we do + // not record duplicates. + std::hash_set<void*> called_functions_; + + // A lock that guards |entries_| usage between per-thread instrumentation + // routine and timer flush callback. So the contention could happen only + // during the flush, every 15 secs. + base::Lock lock_; + + std::vector<LogEntry> entries_; + + DISALLOW_COPY_AND_ASSIGN(ThreadLog); +}; + +// Manages a list of per-thread logs. +class ThreadLogsManager { + public: + ThreadLogsManager(); + + // Used for testing. The provided callbacks are used for testing to + // synchronize the internal thread with the unit test running on the main + // thread. + ThreadLogsManager(const base::Closure& wait_callback, + const base::Closure& notify_callback); + + ~ThreadLogsManager(); + + // Can be called from any thread. + void AddLog(scoped_ptr<ThreadLog> new_log); + + private: + void StartInternalFlushThread_Locked(); + + // Flush thread's entry point. + void FlushAllLogsOnFlushThread(); + + // Used to make the internal thread sleep before each flush iteration. + const base::Closure wait_callback_; + // Used to trigger a notification when a flush happened on the internal + // thread. + const base::Closure notify_callback_; + + // Protects the state below. + base::Lock lock_; + scoped_ptr<Thread> flush_thread_; + std::vector<ThreadLog*> logs_; + + DISALLOW_COPY_AND_ASSIGN(ThreadLogsManager); +}; + +} // namespace cygprofile + +#endif // TOOLS_CYGPROFILE_CYGPROFILE_H_ diff --git a/tools/cygprofile/cygprofile_unittest.cc b/tools/cygprofile/cygprofile_unittest.cc new file mode 100644 index 0000000000..7a1a3e2909 --- /dev/null +++ b/tools/cygprofile/cygprofile_unittest.cc @@ -0,0 +1,101 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "tools/cygprofile/cygprofile.h" + +#include <vector> + +#include <sys/time.h> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/logging.h" +#include "base/synchronization/waitable_event.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cygprofile { +namespace { + +void FlushEntries(std::vector<LogEntry>* destination, + std::vector<LogEntry>* entries) { + CHECK_EQ(0U, destination->size()); + // Move the provided |entries| vector to the provided |destination| so that + // the unit test that triggered the flush can check it. + destination->swap(*entries); +} + +// Flush callback that should not be invoked. +void CheckFlushDoesNotHappen(std::vector<LogEntry>* entries) { + NOTREACHED(); +} + +uint64_t GetUsecSecTimeFromTimeSpec(struct timespec timespec) { + return timespec.tv_sec * 1000 * 1000 + timespec.tv_nsec / 1000; +} + +TEST(CygprofileTest, ThreadLogBasic) { + ThreadLog thread_log(base::Bind(&CheckFlushDoesNotHappen)); + + thread_log.AddEntry(reinterpret_cast<void*>(0x2)); + thread_log.AddEntry(reinterpret_cast<void*>(0x1)); + + std::vector<LogEntry> entries; + thread_log.TakeEntries(&entries); + + ASSERT_EQ(2U, entries.size()); + // The entries should appear in their insertion order. + const LogEntry& first_entry = entries[0]; + ASSERT_EQ(reinterpret_cast<int>(first_entry.address), 2); + ASSERT_EQ(getpid(), first_entry.pid); + ASSERT_LT(0, first_entry.tid); + + const LogEntry& second_entry = entries[1]; + ASSERT_EQ(1, reinterpret_cast<int>(second_entry.address)); + ASSERT_EQ(first_entry.pid, second_entry.pid); + ASSERT_EQ(first_entry.tid, second_entry.tid); + + ASSERT_GE(GetUsecSecTimeFromTimeSpec(second_entry.time), + GetUsecSecTimeFromTimeSpec(first_entry.time)); +} + +TEST(CygprofileTest, ManagerBasic) { + base::WaitableEvent wait_event(true, false); + base::WaitableEvent notify_event(true, false); + + ThreadLogsManager manager( + base::Bind(&base::WaitableEvent::Wait, base::Unretained(&wait_event)), + base::Bind(&base::WaitableEvent::Signal, + base::Unretained(¬ify_event))); + + std::vector<LogEntry> entries; + scoped_ptr<ThreadLog> thread_log( + new ThreadLog(base::Bind(&FlushEntries, base::Unretained(&entries)))); + + thread_log->AddEntry(reinterpret_cast<void*>(0x2)); + thread_log->AddEntry(reinterpret_cast<void*>(0x3)); + + // This should make the manager spawn its internal flush thread which will + // wait for a notification before it starts doing some work. + manager.AddLog(thread_log.Pass()); + + EXPECT_EQ(0U, entries.size()); + // This will wake up the internal thread. + wait_event.Signal(); + // Now it's our turn to wait until it performed the flush. + notify_event.Wait(); + + // The flush should have moved the data to the local vector of entries. + EXPECT_EQ(2U, entries.size()); + ASSERT_EQ(2, reinterpret_cast<int>(entries[0].address)); + ASSERT_EQ(3, reinterpret_cast<int>(entries[1].address)); +} + +} // namespace +} // namespace cygprofile + +// Custom runner implementation since base's one requires JNI on Android. +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tools/cygprofile/mergetraces.py b/tools/cygprofile/mergetraces.py index 1c7627a8df..93a00cacef 100755 --- a/tools/cygprofile/mergetraces.py +++ b/tools/cygprofile/mergetraces.py @@ -13,9 +13,7 @@ create a single log that is an ordered trace of calls by both processes. """ import optparse -import os import string -import subprocess import sys def ParseLogLines(lines): @@ -55,7 +53,7 @@ def ParseLogLines(lines): return (call_lines, vm_start, vm_end) def HasDuplicates(calls): - """Funcition is a sanity check to make sure that calls are only logged once. + """Makes sure that calls are only logged once. Args: calls: list of calls logged @@ -63,12 +61,12 @@ def HasDuplicates(calls): Returns: boolean indicating if calls has duplicate calls """ - seen = [] + seen = set([]) for call in calls: if call[3] in seen: - return true - else: - seen.append(call[3]) + return True + seen.add(call[3]) + return False def CheckTimestamps(calls): """Prints warning to stderr if the call timestamps are not in order. @@ -137,6 +135,55 @@ def AddTrace (tracemap, trace): Timestamp(tracemap[call]) > Timestamp(trace_entry)): tracemap[call] = trace_entry +def GroupByProcessAndThreadId(input_trace): + """Returns an array of traces grouped by pid and tid. + + This is used to make the order of functions not depend on thread scheduling + which can be greatly impacted when profiling is done with cygprofile. As a + result each thread has its own contiguous segment of code (ordered by + timestamp) and processes also have their code isolated (i.e. not interleaved). + """ + def MakeTimestamp(sec, usec): + return sec * 1000000 + usec + + def PidAndTidFromString(pid_and_tid): + strings = pid_and_tid.split(':') + return (int(strings[0]), int(strings[1])) + + tid_to_pid_map = {} + pid_first_seen = {} + tid_first_seen = {} + + for (sec, usec, pid_and_tid, _) in input_trace: + (pid, tid) = PidAndTidFromString(pid_and_tid) + + # Make sure that thread IDs are unique since this is a property we rely on. + if tid_to_pid_map.setdefault(tid, pid) != pid: + raise Exception( + 'Seen PIDs %d and %d for TID=%d. Thread-IDs must be unique' % ( + tid_to_pid_map[tid], pid, tid)) + + if not pid in pid_first_seen: + pid_first_seen[pid] = MakeTimestamp(sec, usec) + if not tid in tid_first_seen: + tid_first_seen[tid] = MakeTimestamp(sec, usec) + + def CompareEvents(event1, event2): + (sec1, usec1, pid_and_tid, _) = event1 + (pid1, tid1) = PidAndTidFromString(pid_and_tid) + (sec2, usec2, pid_and_tid, _) = event2 + (pid2, tid2) = PidAndTidFromString(pid_and_tid) + + pid_cmp = cmp(pid_first_seen[pid1], pid_first_seen[pid2]) + if pid_cmp != 0: + return pid_cmp + tid_cmp = cmp(tid_first_seen[tid1], tid_first_seen[tid2]) + if tid_cmp != 0: + return tid_cmp + return cmp(MakeTimestamp(sec1, usec1), MakeTimestamp(sec2, usec2)) + + return sorted(input_trace, cmp=CompareEvents) + def main(): """Merge two traces for code in specified library and write to stdout. @@ -151,7 +198,10 @@ def main(): parser.error('expected at least the following args: trace1 trace2') step = 0 + + # Maps function addresses to their corresponding trace entry. tracemap = dict() + for trace_file in args: step += 1 sys.stderr.write(" " + str(step) + "/" + str(len(args)) + @@ -176,9 +226,11 @@ def main(): merged_trace.append(tracemap[call]) merged_trace.sort(key=Timestamp) + grouped_trace = GroupByProcessAndThreadId(merged_trace) + print "0-ffffffff r-xp 00000000 xx:00 00000 ./" print "secs\tusecs\tpid:threadid\tfunc" - for call in merged_trace: + for call in grouped_trace: print (str(call[0]) + "\t" + str(call[1]) + "\t" + call[2] + "\t" + hex(call[3])) diff --git a/tools/cygprofile/mergetraces_unittest.py b/tools/cygprofile/mergetraces_unittest.py new file mode 100644 index 0000000000..de881379d6 --- /dev/null +++ b/tools/cygprofile/mergetraces_unittest.py @@ -0,0 +1,51 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import unittest + +import mergetraces + +class GroupByProcessAndThreadIdTestBasic(unittest.TestCase): + def runTest(self): + # (sec, usec, 'pid:tid', function address). + input_trace = [ + (100, 10, '2000:2001', 0x5), + (100, 11, '2000:2001', 0x3), + (100, 13, '2000:1999', 0x8), + (100, 14, '2000:2000', 0x7), + (120, 13, '2001:2003', 0x9), + (150, 12, '2001:2004', 0x6), + (180, 11, '2000:2000', 0x1), + ] + + # Functions should be grouped by thread-id and PIDs should not be + # interleaved. + expected_trace = [ + (100, 10, '2000:2001', 0x5), + (100, 11, '2000:2001', 0x3), + (100, 13, '2000:1999', 0x8), + (100, 14, '2000:2000', 0x7), + (180, 11, '2000:2000', 0x1), + (120, 13, '2001:2003', 0x9), + (150, 12, '2001:2004', 0x6), + ] + + grouped_trace = mergetraces.GroupByProcessAndThreadId(input_trace) + + self.assertEqual(grouped_trace, expected_trace) + +class GroupByProcessAndThreadIdFailsWithNonUniqueTIDs(unittest.TestCase): + def runTest(self): + # (sec, usec, 'pid:tid', function address). + input_trace = [ + (100, 10, '1999:2001', 0x5), + (100, 10, '1988:2001', 0x5), + ] + + try: + mergetraces.GroupByProcessAndThreadId(input_trace) + except Exception: + return + + self.fail('Multiple processes should not have a same thread-ID.') diff --git a/tools/cygprofile/run_tests b/tools/cygprofile/run_tests new file mode 100755 index 0000000000..70eb64981a --- /dev/null +++ b/tools/cygprofile/run_tests @@ -0,0 +1,25 @@ +#!/usr/bin/env python +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import logging +import os +import sys +import unittest + + +if __name__ == '__main__': + logging.basicConfig( + level=logging.DEBUG if '-v' in sys.argv else logging.WARNING, + format='%(levelname)5s %(filename)15s(%(lineno)3d): %(message)s') + + suite = unittest.TestSuite() + loader = unittest.TestLoader() + suite.addTests(loader.discover(start_dir=os.path.dirname(__file__), + pattern='*_unittest.py')) + res = unittest.TextTestRunner(verbosity=2).run(suite) + if res.wasSuccessful(): + sys.exit(0) + else: + sys.exit(1) diff --git a/tools/gen_keyboard_overlay_data/gen_keyboard_overlay_data.py b/tools/gen_keyboard_overlay_data/gen_keyboard_overlay_data.py index 8531241f28..67b5bebd1e 100755 --- a/tools/gen_keyboard_overlay_data/gen_keyboard_overlay_data.py +++ b/tools/gen_keyboard_overlay_data/gen_keyboard_overlay_data.py @@ -84,25 +84,6 @@ LABEL_MAP = { }; INPUT_METHOD_ID_TO_OVERLAY_ID = { - 'm17n:ar:kbd': 'ar', - 'm17n:fa:isiri': 'ar', - 'm17n:hi:itrans': 'hi', - 'm17n:th:kesmanee': 'th', - 'm17n:th:pattachote': 'th', - 'm17n:th:tis820': 'th', - 'm17n:vi:tcvn': 'vi', - 'm17n:vi:telex': 'vi', - 'm17n:vi:viqr': 'vi', - 'm17n:vi:vni': 'vi', - 'm17n:zh:cangjie': 'zh_TW', - 'm17n:zh:quick': 'zh_TW', - 'mozc': 'en_US', - 'mozc-chewing': 'zh_TW', - 'mozc-dv': 'en_US_dvorak', - 'mozc-hangul': 'ko', - 'mozc-jp': 'ja', - 'pinyin': 'zh_CN', - 'pinyin-dv': 'en_US_dvorak', 'xkb:be::fra': 'fr', 'xkb:be::ger': 'de', 'xkb:be::nld': 'nl', @@ -130,7 +111,6 @@ INPUT_METHOD_ID_TO_OVERLAY_ID = { 'xkb:il::heb': 'iw', 'xkb:it::ita': 'it', 'xkb:jp::jpn': 'ja', - 'xkb:kr:kr104:kor': 'ko', 'xkb:latam::spa': 'es_419', 'xkb:lt::lit': 'lt', 'xkb:lv:apostrophe:lav': 'lv', @@ -147,11 +127,15 @@ INPUT_METHOD_ID_TO_OVERLAY_ID = { 'xkb:tr::tur': 'tr', 'xkb:ua::ukr': 'uk', 'xkb:us::eng': 'en_US', + 'xkb:us::fil': 'en_US', + 'xkb:us::ind': 'en_US', + 'xkb:us::msa': 'en_US', 'xkb:us:altgr-intl:eng': 'en_US_altgr_intl', 'xkb:us:colemak:eng': 'en_US_colemak', 'xkb:us:dvorak:eng': 'en_US_dvorak', 'xkb:us:intl:eng': 'en_US_intl', - 'zinnia-japanese': 'ja', + 'xkb:us:intl:nld': 'en_US_intl', + 'xkb:us:intl:por': 'en_US_intl' } # The file was first generated in 2012 and we have a policy of not updating diff --git a/tools/gn/BUILD.gn b/tools/gn/BUILD.gn index 39dc92ba10..87ec6c664d 100644 --- a/tools/gn/BUILD.gn +++ b/tools/gn/BUILD.gn @@ -54,6 +54,7 @@ static_library("gn_lib") { "function_exec_script.cc", "function_foreach.cc", "function_get_label_info.cc", + "function_get_path_info.cc", "function_get_target_outputs.cc", "function_process_file_template.cc", "function_read_file.cc", @@ -182,6 +183,7 @@ test("gn_unittests") { "file_template_unittest.cc", "function_foreach_unittest.cc", "function_get_label_info_unittest.cc", + "function_get_path_info_unittest.cc", "function_get_target_outputs_unittest.cc", "function_rebase_path_unittest.cc", "function_write_file_unittest.cc", @@ -200,6 +202,7 @@ test("gn_unittests") { "parser_unittest.cc", "path_output_unittest.cc", "pattern_unittest.cc", + "run_all_unittests.cc", "scope_per_file_provider_unittest.cc", "scope_unittest.cc", "source_dir_unittest.cc", @@ -215,7 +218,6 @@ test("gn_unittests") { ] deps = [ ":gn_lib", - "//base/test:run_all_unittests", "//base/test:test_support", "//testing/gtest", ] diff --git a/tools/gn/bin/linux/gn.sha1 b/tools/gn/bin/linux/gn.sha1 index b2e67f6345..7a3cec8803 100644 --- a/tools/gn/bin/linux/gn.sha1 +++ b/tools/gn/bin/linux/gn.sha1 @@ -1 +1 @@ -8b2de69dd544188ae7813d4e08b5b1b04f9aa9f1
\ No newline at end of file +224b6fd62d2187c3dfad190e998187f6ee20b727
\ No newline at end of file diff --git a/tools/gn/bin/linux/gn32.sha1 b/tools/gn/bin/linux/gn32.sha1 index 2640fac329..d4183faf74 100644 --- a/tools/gn/bin/linux/gn32.sha1 +++ b/tools/gn/bin/linux/gn32.sha1 @@ -1 +1 @@ -1d1659f5d656746c5be525ce2b924faae4e237db
\ No newline at end of file +ca1b68df96b5b9013258d30d078354e9bf81d407
\ No newline at end of file diff --git a/tools/gn/bin/mac/gn.sha1 b/tools/gn/bin/mac/gn.sha1 index a479b665cb..22ffdf7d64 100644 --- a/tools/gn/bin/mac/gn.sha1 +++ b/tools/gn/bin/mac/gn.sha1 @@ -1 +1 @@ -34f931d05f6f0d949911c48d223d3af282feb393 +6d7917d003a4776641b6ba19bfcef618e6daf3a9 diff --git a/tools/gn/bin/win/gn.exe.sha1 b/tools/gn/bin/win/gn.exe.sha1 index 8e1e546919..80dfd638d2 100644 --- a/tools/gn/bin/win/gn.exe.sha1 +++ b/tools/gn/bin/win/gn.exe.sha1 @@ -1,2 +1,2 @@ -753fae83cdf54ffdc241a3206d0f27e07ac4ad8c +f8c407945b6af5ae2742a5ba59ee848a21e506ae diff --git a/tools/gn/builder_unittest.cc b/tools/gn/builder_unittest.cc index 75e01e5efb..9bf4bf52c3 100644 --- a/tools/gn/builder_unittest.cc +++ b/tools/gn/builder_unittest.cc @@ -45,7 +45,7 @@ class MockLoader : public Loader { bool match = ( (files_[0] == a && files_[1] == b) || - (files_[0] == b && files_[0] == a)); + (files_[0] == b && files_[1] == a)); files_.clear(); return match; } diff --git a/tools/gn/command_desc.cc b/tools/gn/command_desc.cc index 4fea269b58..f4e97bfae7 100644 --- a/tools/gn/command_desc.cc +++ b/tools/gn/command_desc.cc @@ -69,6 +69,17 @@ void RecursivePrintDeps(const Target* target, std::string indent(indent_level * 2, ' '); for (size_t i = 0; i < sorted_deps.size(); i++) { + // Don't print groups. Groups are flattened such that the deps of the + // group are added directly to the target that depended on the group. + // Printing and recursing into groups here will cause such targets to be + // duplicated. + // + // It would be much more intuitive to do the opposite and not display the + // deps that were copied from the group to the target and instead display + // the group, but the source of those dependencies is not tracked. + if (sorted_deps[i].ptr->output_type() == Target::GROUP) + continue; + OutputString(indent + sorted_deps[i].label.GetUserVisibleName(default_toolchain) + "\n"); RecursivePrintDeps(sorted_deps[i].ptr, default_toolchain, indent_level + 1); @@ -145,6 +156,28 @@ void PrintLibs(const Target* target, bool display_header) { OutputString(" " + libs[i] + "\n"); } +void PrintPublic(const Target* target, bool display_header) { + if (display_header) + OutputString("\npublic\n"); + + if (target->all_headers_public()) { + OutputString(" [All headers listed in the sources are public.]\n"); + return; + } + + Target::FileList public_headers = target->public_headers(); + std::sort(public_headers.begin(), public_headers.end()); + for (size_t i = 0; i < public_headers.size(); i++) + OutputString(" " + public_headers[i].value() + "\n"); +} + +void PrintVisibility(const Target* target, bool display_header) { + if (display_header) + OutputString("\nvisibility\n"); + + OutputString(target->visibility().Describe(2, false)); +} + void PrintConfigs(const Target* target, bool display_header) { // Configs (don't sort since the order determines how things are processed). if (display_header) @@ -247,6 +280,12 @@ const char kDesc_Help[] = " sources\n" " Source files.\n" "\n" + " public\n" + " Public header files.\n" + "\n" + " visibility\n" + " Prints which targets can depend on this one.\n" + "\n" " configs\n" " Shows configs applied to the given target, sorted in the order\n" " they're specified. This includes both configs specified in the\n" @@ -320,6 +359,10 @@ int RunDesc(const std::vector<std::string>& args) { PrintConfigs(target, false); } else if (what == "sources") { PrintSources(target, false); + } else if (what == "public") { + PrintPublic(target, false); + } else if (what == "visibility") { + PrintVisibility(target, false); } else if (what == "deps") { PrintDeps(target, false); } else if (what == "lib_dirs") { @@ -362,6 +405,8 @@ int RunDesc(const std::vector<std::string>& args) { OutputString(target_toolchain.GetUserVisibleName(false) + "\n"); PrintSources(target, true); + PrintPublic(target, true); + PrintVisibility(target, true); PrintConfigs(target, true); OUTPUT_CONFIG_VALUE(defines, std::string) diff --git a/tools/gn/escape.cc b/tools/gn/escape.cc index 1658a8ad1e..7028a38b0b 100644 --- a/tools/gn/escape.cc +++ b/tools/gn/escape.cc @@ -5,10 +5,11 @@ #include "tools/gn/escape.h" #include "base/containers/stack_container.h" +#include "base/logging.h" namespace { -// A "1" in this lookup table means that char is valid in the shell. +// A "1" in this lookup table means that char is valid in the Posix shell. const char kShellValid[0x80] = { // 00-1f: all are invalid 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -26,70 +27,150 @@ const char kShellValid[0x80] = { // p q r s t u v w x y z { | } ~ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0 }; +// Append one character to the given string, escaping it for Ninja. +// +// Ninja's escaping rules are very simple. We always escape colons even +// though they're OK in many places, in case the resulting string is used on +// the left-hand-side of a rule. template<typename DestString> -void EscapeStringToString(const base::StringPiece& str, - const EscapeOptions& options, - DestString* dest, - bool* needed_quoting) { - bool used_quotes = false; +inline void NinjaEscapeChar(char ch, DestString* dest) { + if (ch == '$' || ch == ' ' || ch == ':') + dest->push_back('$'); + dest->push_back(ch); +} - for (size_t i = 0; i < str.size(); i++) { - if (str[i] == '$' && (options.mode & ESCAPE_NINJA)) { - // Escape dollars signs since ninja treats these specially. If we're also - // escaping for the shell, we need to backslash-escape that again. - if (options.mode & ESCAPE_SHELL) - dest->push_back('\\'); - dest->push_back('$'); - dest->push_back('$'); - } else if (str[i] == ' ') { - if (options.mode & ESCAPE_NINJA) { - // For Ninja just escape spaces with $. - dest->push_back('$'); +template<typename DestString> +void EscapeStringToString_Ninja(const base::StringPiece& str, + const EscapeOptions& options, + DestString* dest, + bool* needed_quoting) { + for (size_t i = 0; i < str.size(); i++) + NinjaEscapeChar(str[i], dest); + if (needed_quoting) + *needed_quoting = false; +} + +// Escape for CommandLineToArgvW and additionally escape Ninja characters. +// +// The basic algorithm is if the string doesn't contain any parse-affecting +// characters, don't do anything (other than the Ninja processing). If it does, +// quote the string, and backslash-escape all quotes and backslashes. +// See: +// http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx +// http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx +template<typename DestString> +void EscapeStringToString_WindowsNinjaFork(const base::StringPiece& str, + const EscapeOptions& options, + DestString* dest, + bool* needed_quoting) { + // We assume we don't have any whitespace chars that aren't spaces. + DCHECK(str.find_first_of("\r\n\v\t") == std::string::npos); + + if (str.find_first_of(" \"") == std::string::npos) { + // Simple case, don't quote. + EscapeStringToString_Ninja(str, options, dest, needed_quoting); + } else { + if (!options.inhibit_quoting) + dest->push_back('"'); + + for (size_t i = 0; i < str.size(); i++) { + // Count backslashes in case they're followed by a quote. + size_t backslash_count = 0; + while (i < str.size() && str[i] == '\\') { + i++; + backslash_count++; } - if (options.mode & ESCAPE_SHELL) { - // For the shell, quote the whole string. - if (needed_quoting) - *needed_quoting = true; - if (!options.inhibit_quoting) { - if (!used_quotes) { - used_quotes = true; - dest->insert(dest->begin(), '"'); - } - } + if (i == str.size()) { + // Backslashes at end of string. Backslash-escape all of them since + // they'll be followed by a quote. + dest->append(backslash_count * 2, '\\'); + } else if (str[i] == '"') { + // 0 or more backslashes followed by a quote. Backslash-escape the + // backslashes, then backslash-escape the quote. + dest->append(backslash_count * 2 + 1, '\\'); + dest->push_back('"'); + } else { + // Non-special Windows character, just escape for Ninja. Also, add any + // backslashes we read previously, these are literals. + dest->append(backslash_count, '\\'); + NinjaEscapeChar(str[i], dest); } - dest->push_back(' '); - } else if (str[i] == '\'' && (options.mode & ESCAPE_JSON)) { - dest->push_back('\\'); - dest->push_back('\''); -#if defined(OS_WIN) - } else if (str[i] == '/' && options.convert_slashes) { - // Convert slashes on Windows if requested. - dest->push_back('\\'); -#else - } else if (str[i] == '\\' && (options.mode & ESCAPE_SHELL)) { - // For non-Windows shell, escape backslashes. - dest->push_back('\\'); - dest->push_back('\\'); -#endif - } else if (str[i] == '\\' && (options.mode & ESCAPE_JSON)) { - dest->push_back('\\'); + } + + if (!options.inhibit_quoting) + dest->push_back('"'); + if (needed_quoting) + *needed_quoting = true; + } +} + +template<typename DestString> +void EscapeStringToString_PosixNinjaFork(const base::StringPiece& str, + const EscapeOptions& options, + DestString* dest, + bool* needed_quoting) { + for (size_t i = 0; i < str.size(); i++) { + if (str[i] == '$' || str[i] == ' ') { + // Space and $ are special to both Ninja and the shell. '$' escape for + // Ninja, then backslash-escape for the shell. dest->push_back('\\'); - } else if (str[i] == ':' && (options.mode & ESCAPE_NINJA)) { + dest->push_back('$'); + dest->push_back(str[i]); + } else if (str[i] == ':') { + // Colon is the only other Ninja special char, which is not special to + // the shell. dest->push_back('$'); dest->push_back(':'); - } else if ((options.mode & ESCAPE_SHELL) && - (static_cast<unsigned>(str[i]) >= 0x80 || - !kShellValid[static_cast<int>(str[i])])) { + } else if (static_cast<unsigned>(str[i]) >= 0x80 || + !kShellValid[static_cast<int>(str[i])]) { // All other invalid shell chars get backslash-escaped. dest->push_back('\\'); dest->push_back(str[i]); } else { + // Everything else is a literal. dest->push_back(str[i]); } } +} - if (used_quotes) - dest->push_back('"'); +template<typename DestString> +void EscapeStringToString(const base::StringPiece& str, + const EscapeOptions& options, + DestString* dest, + bool* needed_quoting) { + switch (options.mode) { + case ESCAPE_NONE: + dest->append(str.data(), str.size()); + break; + case ESCAPE_NINJA: + EscapeStringToString_Ninja(str, options, dest, needed_quoting); + break; + case ESCAPE_NINJA_COMMAND: + switch (options.platform) { + case ESCAPE_PLATFORM_CURRENT: +#if defined(OS_WIN) + EscapeStringToString_WindowsNinjaFork(str, options, dest, + needed_quoting); +#else + EscapeStringToString_PosixNinjaFork(str, options, dest, + needed_quoting); +#endif + break; + case ESCAPE_PLATFORM_WIN: + EscapeStringToString_WindowsNinjaFork(str, options, dest, + needed_quoting); + break; + case ESCAPE_PLATFORM_POSIX: + EscapeStringToString_PosixNinjaFork(str, options, dest, + needed_quoting); + break; + default: + NOTREACHED(); + } + break; + default: + NOTREACHED(); + } } } // namespace @@ -106,10 +187,8 @@ std::string EscapeString(const base::StringPiece& str, void EscapeStringToStream(std::ostream& out, const base::StringPiece& str, const EscapeOptions& options) { - // Escape to a stack buffer and then write out to the stream. - base::StackVector<char, 256> result; - result->reserve(str.size() + 4); // Guess we'll add a couple of extra chars. - EscapeStringToString(str, options, &result.container(), NULL); - if (!result->empty()) - out.write(&result[0], result->size()); + base::StackString<256> escaped; + EscapeStringToString(str, options, &escaped.container(), NULL); + if (!escaped->empty()) + out.write(escaped->data(), escaped->size()); } diff --git a/tools/gn/escape.h b/tools/gn/escape.h index 1e4fa68977..6f8cf9cc3b 100644 --- a/tools/gn/escape.h +++ b/tools/gn/escape.h @@ -14,35 +14,42 @@ enum EscapingMode { ESCAPE_NONE, // Ninja string escaping. - ESCAPE_NINJA = 1, + ESCAPE_NINJA, - // Shell string escaping. - ESCAPE_SHELL = 2, + // For writing commands to ninja files. + ESCAPE_NINJA_COMMAND, +}; - // For writing shell commands to ninja files. - ESCAPE_NINJA_SHELL = ESCAPE_NINJA | ESCAPE_SHELL, +enum EscapingPlatform { + // Do escaping for the current platform. + ESCAPE_PLATFORM_CURRENT, - ESCAPE_JSON = 4, + // Force escaping for the given platform. + ESCAPE_PLATFORM_POSIX, + ESCAPE_PLATFORM_WIN, }; struct EscapeOptions { EscapeOptions() : mode(ESCAPE_NONE), - convert_slashes(false), + platform(ESCAPE_PLATFORM_CURRENT), inhibit_quoting(false) { } EscapingMode mode; - // When set, converts forward-slashes to system-specific path separators. - bool convert_slashes; + // Controls how "fork" escaping is done. You will generally want to keep the + // default "current" platform. + EscapingPlatform platform; // When the escaping mode is ESCAPE_SHELL, the escaper will normally put // quotes around things with spaces. If this value is set to true, we'll // disable the quoting feature and just add the spaces. // // This mode is for when quoting is done at some higher-level. Defaults to - // false. + // false. Note that Windows has strange behavior where the meaning of the + // backslashes changes according to if it is followed by a quote. The + // escaping rules assume that a double-quote will be appended to the result. bool inhibit_quoting; }; diff --git a/tools/gn/escape_unittest.cc b/tools/gn/escape_unittest.cc index 9d0cf7a900..1a79a78b67 100644 --- a/tools/gn/escape_unittest.cc +++ b/tools/gn/escape_unittest.cc @@ -12,69 +12,41 @@ TEST(Escape, Ninja) { EXPECT_EQ("asdf$:$ \"$$\\bar", result); } -TEST(Escape, Shell) { +TEST(Escape, WindowsCommand) { EscapeOptions opts; - opts.mode = ESCAPE_SHELL; - std::string result = EscapeString("asdf: \"$\\bar", opts, NULL); -#if defined(OS_WIN) - // Windows shell doesn't escape backslashes, but it does backslash-escape - // quotes. - EXPECT_EQ("\"asdf: \\\"\\$\\bar\"", result); -#else - EXPECT_EQ("\"asdf: \\\"\\$\\\\bar\"", result); -#endif - - // Some more generic shell chars. - result = EscapeString("a_;<*b", opts, NULL); - EXPECT_EQ("a_\\;\\<\\*b", result); -} + opts.mode = ESCAPE_NINJA_COMMAND; + opts.platform = ESCAPE_PLATFORM_WIN; -TEST(Escape, NinjaShell) { - EscapeOptions opts; - opts.mode = ESCAPE_NINJA_SHELL; + // Regular string is passed, even if it has backslashes. + EXPECT_EQ("foo\\bar", EscapeString("foo\\bar", opts, NULL)); - // When escaping for Ninja and the shell, we would escape a $, then escape - // the backslash again. - std::string result = EscapeString("a$b", opts, NULL); - EXPECT_EQ("a\\$$b", result); -} + // Spaces means the string is quoted, normal backslahes untouched. + bool needs_quoting = false; + EXPECT_EQ("\"foo\\$ bar\"", EscapeString("foo\\ bar", opts, &needs_quoting)); + EXPECT_TRUE(needs_quoting); -TEST(Escape, UsedQuotes) { - EscapeOptions shell_options; - shell_options.mode = ESCAPE_SHELL; + // Inhibit quoting. + needs_quoting = false; + opts.inhibit_quoting = true; + EXPECT_EQ("foo\\$ bar", EscapeString("foo\\ bar", opts, &needs_quoting)); + EXPECT_TRUE(needs_quoting); + opts.inhibit_quoting = false; - EscapeOptions ninja_options; - ninja_options.mode = ESCAPE_NINJA; + // Backslashes at the end of the string get escaped. + EXPECT_EQ("\"foo$ bar\\\\\\\\\"", EscapeString("foo bar\\\\", opts, NULL)); - EscapeOptions ninja_shell_options; - ninja_shell_options.mode = ESCAPE_NINJA_SHELL; - - // Shell escaping with quoting inhibited. - bool used_quotes = false; - shell_options.inhibit_quoting = true; - EXPECT_EQ("foo bar", EscapeString("foo bar", shell_options, &used_quotes)); - EXPECT_TRUE(used_quotes); - - // Shell escaping with regular quoting. - used_quotes = false; - shell_options.inhibit_quoting = false; - EXPECT_EQ("\"foo bar\"", - EscapeString("foo bar", shell_options, &used_quotes)); - EXPECT_TRUE(used_quotes); + // Backslashes preceeding quotes are escaped, and the quote is escaped. + EXPECT_EQ("\"foo\\\\\\\"$ bar\"", EscapeString("foo\\\" bar", opts, NULL)); +} - // Ninja shell escaping should be the same. - used_quotes = false; - EXPECT_EQ("\"foo$ bar\"", - EscapeString("foo bar", ninja_shell_options, &used_quotes)); - EXPECT_TRUE(used_quotes); +TEST(Escape, PosixCommand) { + EscapeOptions opts; + opts.mode = ESCAPE_NINJA_COMMAND; + opts.platform = ESCAPE_PLATFORM_POSIX; - // Ninja escaping shouldn't use quoting. - used_quotes = false; - EXPECT_EQ("foo$ bar", EscapeString("foo bar", ninja_options, &used_quotes)); - EXPECT_FALSE(used_quotes); + // : and $ ninja escaped with $. Then Shell-escape backslashes and quotes. + EXPECT_EQ("a$:\\$ \\\"\\$$\\\\b", EscapeString("a: \"$\\b", opts, NULL)); - // Used quotes not reset if it's already true. - used_quotes = true; - EscapeString("foo", ninja_options, &used_quotes); - EXPECT_TRUE(used_quotes); + // Some more generic shell chars. + EXPECT_EQ("a_\\;\\<\\*b", EscapeString("a_;<*b", opts, NULL)); } diff --git a/tools/gn/file_template.cc b/tools/gn/file_template.cc index b6264829e9..b00eb39173 100644 --- a/tools/gn/file_template.cc +++ b/tools/gn/file_template.cc @@ -166,7 +166,7 @@ void FileTemplate::ApplyString(const std::string& str, void FileTemplate::WriteWithNinjaExpansions(std::ostream& out) const { EscapeOptions escape_options; - escape_options.mode = ESCAPE_NINJA_SHELL; + escape_options.mode = ESCAPE_NINJA_COMMAND; escape_options.inhibit_quoting = true; for (size_t template_i = 0; @@ -184,8 +184,10 @@ void FileTemplate::WriteWithNinjaExpansions(std::ostream& out) const { for (size_t subrange_i = 0; subrange_i < t.container().size(); subrange_i++) { if (t[subrange_i].type == Subrange::LITERAL) { + bool cur_needs_quoting = false; item_str.append(EscapeString(t[subrange_i].literal, escape_options, - &needs_quoting)); + &cur_needs_quoting)); + needs_quoting |= cur_needs_quoting; } else { // Don't escape this since we need to preserve the $. item_str.append("${"); diff --git a/tools/gn/file_template_unittest.cc b/tools/gn/file_template_unittest.cc index cd5611c1df..8e3bf40b90 100644 --- a/tools/gn/file_template_unittest.cc +++ b/tools/gn/file_template_unittest.cc @@ -63,11 +63,19 @@ TEST(FileTemplate, NinjaExpansions) { std::ostringstream out; t.WriteWithNinjaExpansions(out); +#if defined(OS_WIN) // The third argument should get quoted since it contains a space, and the // embedded quotes should get shell escaped. EXPECT_EQ( " -i ${source} \"--out=foo$ bar\\\"${source_name_part}\\\".o\" \"\"", out.str()); +#else + // On Posix we don't need to quote the whole thing and can escape all + // individual bad chars. + EXPECT_EQ( + " -i ${source} --out=foo\\$ bar\\\"${source_name_part}\\\".o \"\"", + out.str()); +#endif } TEST(FileTemplate, NinjaVariables) { @@ -80,7 +88,7 @@ TEST(FileTemplate, NinjaVariables) { std::ostringstream out; EscapeOptions options; - options.mode = ESCAPE_NINJA_SHELL; + options.mode = ESCAPE_NINJA_COMMAND; t.WriteNinjaVariablesForSubstitution(out, "../../foo/bar.txt", options); // Just the variables used above should be written. diff --git a/tools/gn/function_get_path_info.cc b/tools/gn/function_get_path_info.cc new file mode 100644 index 0000000000..23f690cfdc --- /dev/null +++ b/tools/gn/function_get_path_info.cc @@ -0,0 +1,197 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "tools/gn/err.h" +#include "tools/gn/filesystem_utils.h" +#include "tools/gn/functions.h" +#include "tools/gn/parse_tree.h" +#include "tools/gn/scope.h" +#include "tools/gn/value.h" + +namespace functions { + +namespace { + +// Corresponds to the various values of "what" in the function call. +enum What { + WHAT_FILE, + WHAT_NAME, + WHAT_EXTENSION, + WHAT_DIR, + WHAT_ABSPATH, +}; + +std::string GetOnePathInfo(const SourceDir& current_dir, + What what, + const Value& input, + Err* err) { + if (!input.VerifyTypeIs(Value::STRING, err)) + return std::string(); + const std::string& input_string = input.string_value(); + if (input_string.empty()) { + *err = Err(input, "Calling get_path_info on an empty string."); + return std::string(); + } + + switch (what) { + case WHAT_FILE: { + return FindFilename(&input_string).as_string(); + } + case WHAT_NAME: { + std::string file = FindFilename(&input_string).as_string(); + size_t extension_offset = FindExtensionOffset(file); + if (extension_offset == std::string::npos) + return file; + // Trim extension and dot. + return file.substr(0, extension_offset - 1); + } + case WHAT_EXTENSION: { + return FindExtension(&input_string).as_string(); + } + case WHAT_DIR: { + base::StringPiece dir_incl_slash = FindDir(&input_string); + if (dir_incl_slash.empty()) + return std::string("."); + // Trim slash since this function doesn't return trailing slashes. The + // times we don't do this are if the result is "/" and "//" since those + // slashes can't be trimmed. + if (dir_incl_slash == "/") + return std::string("/."); + if (dir_incl_slash == "//") + return std::string("//."); + return dir_incl_slash.substr(0, dir_incl_slash.size() - 1).as_string(); + } + case WHAT_ABSPATH: { + if (!input_string.empty() && input_string[input_string.size() - 1] == '/') + return current_dir.ResolveRelativeDir(input_string).value(); + else + return current_dir.ResolveRelativeFile(input_string).value(); + } + default: + NOTREACHED(); + return std::string(); + } +} + +} // namespace + +const char kGetPathInfo[] = "get_path_info"; +const char kGetPathInfo_HelpShort[] = + "get_path_info: Extract parts of a file or directory name."; +const char kGetPathInfo_Help[] = + "get_path_info: Extract parts of a file or directory name.\n" + "\n" + " get_path_info(input, what)\n" + "\n" + " The first argument is either a string representing a file or\n" + " directory name, or a list of such strings. If the input is a list\n" + " the return value will be a list containing the result of applying the\n" + " rule to each item in the input.\n" + "\n" + "Possible values for the \"what\" parameter\n" + "\n" + " \"file\"\n" + " The substring after the last slash in the path, including the name\n" + " and extension. If the input ends in a slash, the empty string will\n" + " be returned.\n" + " \"foo/bar.txt\" => \"bar.txt\"\n" + " \"bar.txt\" => \"bar.txt\"\n" + " \"foo/\" => \"\"\n" + " \"\" => \"\"\n" + "\n" + " \"name\"\n" + " The substring of the file name not including the extension.\n" + " \"foo/bar.txt\" => \"bar\"\n" + " \"foo/bar\" => \"bar\"\n" + " \"foo/\" => \"\"\n" + "\n" + " \"extension\"\n" + " The substring following the last period following the last slash,\n" + " or the empty string if not found. The period is not included.\n" + " \"foo/bar.txt\" => \"txt\"\n" + " \"foo/bar\" => \"\"\n" + "\n" + " \"dir\"\n" + " The directory portion of the name, not including the slash.\n" + " \"foo/bar.txt\" => \"foo\"\n" + " \"//foo/bar\" => \"//foo\"\n" + " \"foo\" => \".\"\n" + "\n" + " The result will never end in a slash, so if the resulting\n" + " is empty, the system (\"/\") or source (\"//\") roots, a \".\"\n" + " will be appended such that it is always legal to append a slash\n" + " and a filename and get a valid path.\n" + "\n" + " \"abspath\"\n" + " The full absolute path name to the file or directory. It will be\n" + " resolved relative to the currebt directory, and then the source-\n" + " absolute version will be returned. If the input is system-\n" + " absolute, the same input will be returned.\n" + " \"foo/bar.txt\" => \"//mydir/foo/bar.txt\"\n" + " \"foo/\" => \"//mydir/foo/\"\n" + " \"//foo/bar\" => \"//foo/bar\" (already absolute)\n" + " \"/usr/include\" => \"/usr/include\" (already absolute)\n" + "\n" + " If you want to make the path relative to another directory, or to\n" + " be system-absolute, see rebase_path().\n" + "\n" + "Examples\n" + " sources = [ \"foo.cc\", \"foo.h\" ]\n" + " result = get_path_info(source, \"abspath\")\n" + " # result will be [ \"//mydir/foo.cc\", \"//mydir/foo.h\" ]\n" + "\n" + " result = get_path_info(\"//foo/bar/baz.cc\", \"dir\")\n" + " # result will be \"//foo/bar\"\n" + "\n" + " # Extract the source-absolute directory name,\n" + " result = get_path_info(get_path_info(path, \"dir\"), \"abspath\")\n"; + +Value RunGetPathInfo(Scope* scope, + const FunctionCallNode* function, + const std::vector<Value>& args, + Err* err) { + if (args.size() != 2) { + *err = Err(function, "Expecting two arguments to get_path_info."); + return Value(); + } + + // Extract the "what". + if (!args[1].VerifyTypeIs(Value::STRING, err)) + return Value(); + What what; + if (args[1].string_value() == "file") { + what = WHAT_FILE; + } else if (args[1].string_value() == "name") { + what = WHAT_NAME; + } else if (args[1].string_value() == "extension") { + what = WHAT_EXTENSION; + } else if (args[1].string_value() == "dir") { + what = WHAT_DIR; + } else if (args[1].string_value() == "abspath") { + what = WHAT_ABSPATH; + } else { + *err = Err(args[1], "Unknown value for 'what'."); + return Value(); + } + + const SourceDir& current_dir = scope->GetSourceDir(); + if (args[0].type() == Value::STRING) { + return Value(function, GetOnePathInfo(current_dir, what, args[0], err)); + } else if (args[0].type() == Value::LIST) { + const std::vector<Value>& input_list = args[0].list_value(); + Value result(function, Value::LIST); + for (size_t i = 0; i < input_list.size(); i++) { + result.list_value().push_back(Value(function, + GetOnePathInfo(current_dir, what, input_list[i], err))); + if (err->has_error()) + return Value(); + } + return result; + } + + *err = Err(args[0], "Path must be a string or a list of strings."); + return Value(); +} + +} // namespace functions diff --git a/tools/gn/function_get_path_info_unittest.cc b/tools/gn/function_get_path_info_unittest.cc new file mode 100644 index 0000000000..12bdc2a5ad --- /dev/null +++ b/tools/gn/function_get_path_info_unittest.cc @@ -0,0 +1,89 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "testing/gtest/include/gtest/gtest.h" +#include "tools/gn/functions.h" +#include "tools/gn/test_with_scope.h" + +namespace { + +class GetPathInfoTest : public testing::Test { + public: + GetPathInfoTest() : testing::Test() { + setup_.scope()->set_source_dir(SourceDir("//src/foo/")); + } + + // Convenience wrapper to call GetLabelInfo. + std::string Call(const std::string& input, const std::string& what) { + FunctionCallNode function; + + std::vector<Value> args; + args.push_back(Value(NULL, input)); + args.push_back(Value(NULL, what)); + + Err err; + Value result = functions::RunGetPathInfo(setup_.scope(), &function, + args, &err); + if (err.has_error()) { + EXPECT_TRUE(result.type() == Value::NONE); + return std::string(); + } + return result.string_value(); + } + + protected: + TestWithScope setup_; +}; + +} // namespace + +TEST_F(GetPathInfoTest, File) { + EXPECT_EQ("bar.txt", Call("foo/bar.txt", "file")); + EXPECT_EQ("bar.txt", Call("bar.txt", "file")); + EXPECT_EQ("bar.txt", Call("/bar.txt", "file")); + EXPECT_EQ("", Call("foo/", "file")); + EXPECT_EQ("", Call("//", "file")); + EXPECT_EQ("", Call("/", "file")); +} + +TEST_F(GetPathInfoTest, Name) { + EXPECT_EQ("bar", Call("foo/bar.txt", "name")); + EXPECT_EQ("bar", Call("bar.", "name")); + EXPECT_EQ("", Call("/.txt", "name")); + EXPECT_EQ("", Call("foo/", "name")); + EXPECT_EQ("", Call("//", "name")); + EXPECT_EQ("", Call("/", "name")); +} + +TEST_F(GetPathInfoTest, Extension) { + EXPECT_EQ("txt", Call("foo/bar.txt", "extension")); + EXPECT_EQ("", Call("bar.", "extension")); + EXPECT_EQ("txt", Call("/.txt", "extension")); + EXPECT_EQ("", Call("f.oo/", "extension")); + EXPECT_EQ("", Call("//", "extension")); + EXPECT_EQ("", Call("/", "extension")); +} + +TEST_F(GetPathInfoTest, Dir) { + EXPECT_EQ("foo", Call("foo/bar.txt", "dir")); + EXPECT_EQ(".", Call("bar.txt", "dir")); + EXPECT_EQ("foo/bar", Call("foo/bar/baz", "dir")); + EXPECT_EQ("//foo", Call("//foo/", "dir")); + EXPECT_EQ("//.", Call("//", "dir")); + EXPECT_EQ("/foo", Call("/foo/", "dir")); + EXPECT_EQ("/.", Call("/", "dir")); +} + +// Note "current dir" is "//src/foo" +TEST_F(GetPathInfoTest, AbsPath) { + EXPECT_EQ("//src/foo/foo/bar.txt", Call("foo/bar.txt", "abspath")); + EXPECT_EQ("//src/foo/bar.txt", Call("bar.txt", "abspath")); + EXPECT_EQ("//src/foo/bar/", Call("bar/", "abspath")); + EXPECT_EQ("//foo", Call("//foo", "abspath")); + EXPECT_EQ("//foo/", Call("//foo/", "abspath")); + EXPECT_EQ("//", Call("//", "abspath")); + EXPECT_EQ("/foo", Call("/foo", "abspath")); + EXPECT_EQ("/foo/", Call("/foo/", "abspath")); + EXPECT_EQ("/", Call("/", "abspath")); +} diff --git a/tools/gn/function_rebase_path.cc b/tools/gn/function_rebase_path.cc index 4f66688e86..dd5e903ec8 100644 --- a/tools/gn/function_rebase_path.cc +++ b/tools/gn/function_rebase_path.cc @@ -131,6 +131,13 @@ const char kRebasePath_Help[] = " current directory to be relative to the build directory (which will\n" " be the current directory when executing scripts).\n" "\n" + " If you want to convert a file path to be source-absolute (that is,\n" + " beginning with a double slash like \"//foo/bar\"), you should use\n" + " the get_path_info() function. This function won't work because it will\n" + " always make relative paths, and it needs to support making paths\n" + " relative to the source root, so can't also generate source-absolute\n" + " paths without more special-cases.\n" + "\n" "Arguments:\n" "\n" " input\n" diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc index 97c2592c46..e973f2ee5c 100644 --- a/tools/gn/functions.cc +++ b/tools/gn/functions.cc @@ -660,6 +660,7 @@ struct FunctionInfoInitializer { INSERT_FUNCTION(ForEach, false) INSERT_FUNCTION(GetEnv, false) INSERT_FUNCTION(GetLabelInfo, false) + INSERT_FUNCTION(GetPathInfo, false) INSERT_FUNCTION(GetTargetOutputs, false) INSERT_FUNCTION(Import, false) INSERT_FUNCTION(Print, false) diff --git a/tools/gn/functions.h b/tools/gn/functions.h index 4b1384ab10..45bb4ded28 100644 --- a/tools/gn/functions.h +++ b/tools/gn/functions.h @@ -163,6 +163,14 @@ Value RunGetLabelInfo(Scope* scope, const std::vector<Value>& args, Err* err); +extern const char kGetPathInfo[]; +extern const char kGetPathInfo_HelpShort[]; +extern const char kGetPathInfo_Help[]; +Value RunGetPathInfo(Scope* scope, + const FunctionCallNode* function, + const std::vector<Value>& args, + Err* err); + extern const char kGetTargetOutputs[]; extern const char kGetTargetOutputs_HelpShort[]; extern const char kGetTargetOutputs_Help[]; diff --git a/tools/gn/gn.gyp b/tools/gn/gn.gyp index b43e700705..d972b5b999 100644 --- a/tools/gn/gn.gyp +++ b/tools/gn/gn.gyp @@ -58,6 +58,7 @@ 'function_exec_script.cc', 'function_foreach.cc', 'function_get_label_info.cc', + 'function_get_path_info.cc', 'function_get_target_outputs.cc', 'function_process_file_template.cc', 'function_read_file.cc', @@ -183,6 +184,7 @@ 'file_template_unittest.cc', 'function_foreach_unittest.cc', 'function_get_label_info_unittest.cc', + 'function_get_path_info_unittest.cc', 'function_get_target_outputs_unittest.cc', 'function_rebase_path_unittest.cc', 'function_write_file_unittest.cc', @@ -201,6 +203,7 @@ 'parser_unittest.cc', 'path_output_unittest.cc', 'pattern_unittest.cc', + 'run_all_unittests.cc', 'scope_per_file_provider_unittest.cc', 'scope_unittest.cc', 'source_dir_unittest.cc', @@ -215,7 +218,6 @@ ], 'dependencies': [ 'gn_lib', - '../../base/base.gyp:run_all_unittests', '../../base/base.gyp:test_support_base', '../../testing/gtest.gyp:gtest', ], diff --git a/tools/gn/ninja_action_target_writer.cc b/tools/gn/ninja_action_target_writer.cc index 1b71fced9c..27bd8a4c58 100644 --- a/tools/gn/ninja_action_target_writer.cc +++ b/tools/gn/ninja_action_target_writer.cc @@ -16,7 +16,7 @@ NinjaActionTargetWriter::NinjaActionTargetWriter(const Target* target, : NinjaTargetWriter(target, toolchain, out), path_output_no_escaping_( target->settings()->build_settings()->build_dir(), - ESCAPE_NONE, false) { + ESCAPE_NONE) { } NinjaActionTargetWriter::~NinjaActionTargetWriter() { @@ -144,8 +144,7 @@ void NinjaActionTargetWriter::WriteArgsSubstitutions( path_output_no_escaping_.WriteFile(source_file_stream, source); EscapeOptions template_escape_options; - template_escape_options.mode = ESCAPE_NINJA_SHELL; - template_escape_options.inhibit_quoting = true; + template_escape_options.mode = ESCAPE_NINJA_COMMAND; args_template.WriteNinjaVariablesForSubstitution( out_, source_file_stream.str(), template_escape_options); diff --git a/tools/gn/ninja_action_target_writer_unittest.cc b/tools/gn/ninja_action_target_writer_unittest.cc index 10b5f81e84..9c6f2f1c3b 100644 --- a/tools/gn/ninja_action_target_writer_unittest.cc +++ b/tools/gn/ninja_action_target_writer_unittest.cc @@ -29,11 +29,7 @@ TEST(NinjaActionTargetWriter, WriteOutputFilesForBuildLine) { std::vector<OutputFile> output_files; writer.WriteOutputFilesForBuildLine(output_template, source, &output_files); - std::string out_str = out.str(); -#if defined(OS_WIN) - std::replace(out_str.begin(), out_str.end(), '\\', '/'); -#endif - EXPECT_EQ(" gen/a$ bbar.h gen/bar.cc", out_str); + EXPECT_EQ(" gen/a$ bbar.h gen/bar.cc", out.str()); } TEST(NinjaActionTargetWriter, WriteOutputFilesForBuildLineWithDepfile) { @@ -57,11 +53,7 @@ TEST(NinjaActionTargetWriter, WriteOutputFilesForBuildLineWithDepfile) { std::vector<OutputFile> output_files; writer.WriteOutputFilesForBuildLine(output_template, source, &output_files); - std::string out_str = out.str(); -#if defined(OS_WIN) - std::replace(out_str.begin(), out_str.end(), '\\', '/'); -#endif - EXPECT_EQ(" gen/bar.d gen/bar.h gen/bar.cc", out_str); + EXPECT_EQ(" gen/bar.d gen/bar.h gen/bar.cc", out.str()); } TEST(NinjaActionTargetWriter, WriteArgsSubstitutions) { @@ -79,13 +71,15 @@ TEST(NinjaActionTargetWriter, WriteArgsSubstitutions) { FileTemplate args_template(args); writer.WriteArgsSubstitutions(SourceFile("//foo/b ar.in"), args_template); - - std::string out_str = out.str(); #if defined(OS_WIN) - std::replace(out_str.begin(), out_str.end(), '\\', '/'); + EXPECT_EQ(" source = \"../../foo/b$ ar.in\"\n" + " source_name_part = \"b$ ar\"\n", + out.str()); +#else + EXPECT_EQ(" source = ../../foo/b\\$ ar.in\n" + " source_name_part = b\\$ ar\n", + out.str()); #endif - EXPECT_EQ(" source = ../../foo/b$ ar.in\n source_name_part = b$ ar\n", - out_str); } // Makes sure that we write sources as input dependencies for actions with @@ -126,11 +120,7 @@ TEST(NinjaActionTargetWriter, ActionWithSources) { "build foo.out: __foo_bar___rule | obj/foo/bar.inputdeps.stamp\n" "\n" "build obj/foo/bar.stamp: stamp foo.out\n"; - std::string out_str = out.str(); -#if defined(OS_WIN) - std::replace(out_str.begin(), out_str.end(), '\\', '/'); -#endif - EXPECT_EQ(expected_linux, out_str); + EXPECT_EQ(expected_linux, out.str()); } // Windows. @@ -145,8 +135,6 @@ TEST(NinjaActionTargetWriter, ActionWithSources) { NinjaActionTargetWriter writer(&target, setup.toolchain(), out); writer.Run(); - // TODO(brettw) I think we'll need to worry about backslashes here - // depending if we're on actual Windows or Linux pretending to be Windows. const char expected_win[] = "rule __foo_bar___rule\n" " command = C$:/python/python.exe gyp-win-tool action-wrapper environment.x86 __foo_bar___rule.$unique_name.rsp\n" @@ -160,11 +148,7 @@ TEST(NinjaActionTargetWriter, ActionWithSources) { "build foo.out: __foo_bar___rule | obj/foo/bar.inputdeps.stamp\n" "\n" "build obj/foo/bar.stamp: stamp foo.out\n"; - std::string out_str = out.str(); -#if defined(OS_WIN) - std::replace(out_str.begin(), out_str.end(), '\\', '/'); -#endif - EXPECT_EQ(expected_win, out_str); + EXPECT_EQ(expected_win, out.str()); } } @@ -214,7 +198,12 @@ TEST(NinjaActionTargetWriter, ForEach) { const char expected_linux[] = "rule __foo_bar___rule\n" " command = /usr/bin/python ../../foo/script.py -i ${source} " + // Escaping is different between Windows and Posix. +#if defined(OS_WIN) "\"--out=foo$ bar${source_name_part}.o\"\n" +#else + "--out=foo\\$ bar${source_name_part}.o\n" +#endif " description = ACTION //foo:bar()\n" " restat = 1\n" "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py " @@ -241,8 +230,6 @@ TEST(NinjaActionTargetWriter, ForEach) { // Windows. { - // Note: we use forward slashes here so that the output will be the same on - // Linux and Windows. setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL( "C:/python/python.exe"))); setup.settings()->set_target_os(Settings::WIN); @@ -251,8 +238,6 @@ TEST(NinjaActionTargetWriter, ForEach) { NinjaActionTargetWriter writer(&target, setup.toolchain(), out); writer.Run(); - // TODO(brettw) I think we'll need to worry about backslashes here - // depending if we're on actual Windows or Linux pretending to be Windows. const char expected_win[] = "rule __foo_bar___rule\n" " command = C$:/python/python.exe gyp-win-tool action-wrapper " @@ -261,7 +246,11 @@ TEST(NinjaActionTargetWriter, ForEach) { " restat = 1\n" " rspfile = __foo_bar___rule.$unique_name.rsp\n" " rspfile_content = C$:/python/python.exe ../../foo/script.py -i " +#if defined(OS_WIN) "${source} \"--out=foo$ bar${source_name_part}.o\"\n" +#else + "${source} --out=foo\\$ bar${source_name_part}.o\n" +#endif "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py " "../../foo/included.txt obj/foo/dep.stamp\n" "\n" @@ -278,11 +267,7 @@ TEST(NinjaActionTargetWriter, ForEach) { "\n" "build obj/foo/bar.stamp: " "stamp input1.out input2.out obj/foo/datadep.stamp\n"; - std::string out_str = out.str(); -#if defined(OS_WIN) - std::replace(out_str.begin(), out_str.end(), '\\', '/'); -#endif - EXPECT_EQ(expected_win, out_str); + EXPECT_EQ(expected_win, out.str()); } } @@ -322,7 +307,11 @@ TEST(NinjaActionTargetWriter, ForEachWithDepfile) { const char expected_linux[] = "rule __foo_bar___rule\n" " command = /usr/bin/python ../../foo/script.py -i ${source} " +#if defined(OS_WIN) "\"--out=foo$ bar${source_name_part}.o\"\n" +#else + "--out=foo\\$ bar${source_name_part}.o\n" +#endif " description = ACTION //foo:bar()\n" " restat = 1\n" "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py " @@ -340,18 +329,11 @@ TEST(NinjaActionTargetWriter, ForEachWithDepfile) { " depfile = gen/input2.d\n" "\n" "build obj/foo/bar.stamp: stamp input1.out input2.out\n"; - - std::string out_str = out.str(); -#if defined(OS_WIN) - std::replace(out_str.begin(), out_str.end(), '\\', '/'); -#endif - EXPECT_EQ(expected_linux, out_str); + EXPECT_EQ(expected_linux, out.str()); } // Windows. { - // Note: we use forward slashes here so that the output will be the same on - // Linux and Windows. setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL( "C:/python/python.exe"))); setup.settings()->set_target_os(Settings::WIN); @@ -360,8 +342,6 @@ TEST(NinjaActionTargetWriter, ForEachWithDepfile) { NinjaActionTargetWriter writer(&target, setup.toolchain(), out); writer.Run(); - // TODO(brettw) I think we'll need to worry about backslashes here - // depending if we're on actual Windows or Linux pretending to be Windows. const char expected_win[] = "rule __foo_bar___rule\n" " command = C$:/python/python.exe gyp-win-tool action-wrapper " @@ -370,7 +350,11 @@ TEST(NinjaActionTargetWriter, ForEachWithDepfile) { " restat = 1\n" " rspfile = __foo_bar___rule.$unique_name.rsp\n" " rspfile_content = C$:/python/python.exe ../../foo/script.py -i " +#if defined(OS_WIN) "${source} \"--out=foo$ bar${source_name_part}.o\"\n" +#else + "${source} --out=foo\\$ bar${source_name_part}.o\n" +#endif "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py " "../../foo/included.txt\n" "\n" @@ -388,10 +372,6 @@ TEST(NinjaActionTargetWriter, ForEachWithDepfile) { " depfile = gen/input2.d\n" "\n" "build obj/foo/bar.stamp: stamp input1.out input2.out\n"; - std::string out_str = out.str(); -#if defined(OS_WIN) - std::replace(out_str.begin(), out_str.end(), '\\', '/'); -#endif - EXPECT_EQ(expected_win, out_str); + EXPECT_EQ(expected_win, out.str()); } } diff --git a/tools/gn/ninja_binary_target_writer.cc b/tools/gn/ninja_binary_target_writer.cc index 1204d4f473..9cfbdfb4fe 100644 --- a/tools/gn/ninja_binary_target_writer.cc +++ b/tools/gn/ninja_binary_target_writer.cc @@ -17,7 +17,7 @@ namespace { // Returns the proper escape options for writing compiler and linker flags. EscapeOptions GetFlagOptions() { EscapeOptions opts; - opts.mode = ESCAPE_NINJA; + opts.mode = ESCAPE_NINJA_COMMAND; // Some flag strings are actually multiple flags that expect to be just // added to the command line. We assume that quoting is done by the @@ -29,7 +29,7 @@ EscapeOptions GetFlagOptions() { struct DefineWriter { DefineWriter() { - options.mode = ESCAPE_SHELL; + options.mode = ESCAPE_NINJA_COMMAND; } void operator()(const std::string& s, std::ostream& out) const { @@ -41,33 +41,20 @@ struct DefineWriter { }; struct IncludeWriter { - IncludeWriter(PathOutput& path_output, - const NinjaHelper& h) + IncludeWriter(PathOutput& path_output, const NinjaHelper& h) : helper(h), - path_output_(path_output), - old_inhibit_quoting_(path_output.inhibit_quoting()) { - // Inhibit quoting since we'll put quotes around the whole thing ourselves. - // Since we're writing in NINJA escaping mode, this won't actually do - // anything, but I think we may need to change to shell-and-then-ninja - // escaping for this in the future. - path_output_.set_inhibit_quoting(true); + path_output_(path_output) { } ~IncludeWriter() { - path_output_.set_inhibit_quoting(old_inhibit_quoting_); } void operator()(const SourceDir& d, std::ostream& out) const { - out << " \"-I"; - // It's important not to include the trailing slash on directories or on - // Windows it will be a backslash and the compiler might think we're - // escaping the quote! + out << " -I"; path_output_.WriteDir(out, d, PathOutput::DIR_NO_LAST_SLASH); - out << "\""; } const NinjaHelper& helper; PathOutput& path_output_; - bool old_inhibit_quoting_; // So we can put the PathOutput back. }; Toolchain::ToolType GetToolTypeForTarget(const Target* target) { @@ -268,8 +255,8 @@ void NinjaBinaryTargetWriter::WriteLinkerFlags( if (!all_lib_dirs.empty()) { // Since we're passing these on the command line to the linker and not // to Ninja, we need to do shell escaping. - PathOutput lib_path_output( - path_output_.current_dir(), ESCAPE_NINJA_SHELL, false); + PathOutput lib_path_output(path_output_.current_dir(), + ESCAPE_NINJA_COMMAND); for (size_t i = 0; i < all_lib_dirs.size(); i++) { out_ << " " << tool.lib_dir_prefix; lib_path_output.WriteDir(out_, all_lib_dirs[i], @@ -291,7 +278,7 @@ void NinjaBinaryTargetWriter::WriteLibs(const Toolchain::Tool& tool) { // Libraries that have been recursively pushed through the dependency tree. EscapeOptions lib_escape_opts; - lib_escape_opts.mode = ESCAPE_NINJA_SHELL; + lib_escape_opts.mode = ESCAPE_NINJA_COMMAND; const OrderedSet<std::string> all_libs = target_->all_libs(); const std::string framework_ending(".framework"); for (size_t i = 0; i < all_libs.size(); i++) { @@ -426,14 +413,19 @@ void NinjaBinaryTargetWriter::ClassifyDependency( target_->output_type() == Target::SHARED_LIBRARY); if (dep->output_type() == Target::SOURCE_SET) { - if (target_->output_type() == Target::SOURCE_SET) { - // When a source set depends on another source set, add it as a data - // dependency so if the user says "ninja second_source_set" it will - // also compile the first (what you would expect) even though we'll - // never do anything with the first one's files. - non_linkable_deps->push_back(dep); - } else { - // Linking in a source set, copy its object files. + // Source sets have their object files linked into final targets (shared + // libraries and executables). Intermediate static libraries and other + // source sets just forward the dependency, otherwise the files in the + // source set can easily get linked more than once which will cause + // multiple definition errors. + // + // In the future, we may need a way to specify a "complete" static library + // for cases where you want a static library that includes all source sets + // (like if you're shipping that to customers to link against). + if (target_->output_type() != Target::SOURCE_SET && + target_->output_type() != Target::STATIC_LIBRARY) { + // Linking in a source set to an executable or shared library, copy its + // object files. for (size_t i = 0; i < dep->sources().size(); i++) { SourceFileType input_file_type = GetSourceFileType(dep->sources()[i]); if (input_file_type != SOURCE_UNKNOWN && diff --git a/tools/gn/ninja_binary_target_writer_unittest.cc b/tools/gn/ninja_binary_target_writer_unittest.cc index 4f120c285f..bcaeae720f 100644 --- a/tools/gn/ninja_binary_target_writer_unittest.cc +++ b/tools/gn/ninja_binary_target_writer_unittest.cc @@ -94,6 +94,42 @@ TEST(NinjaBinaryTargetWriter, SourceSet) { #endif EXPECT_EQ(expected_win, out_str); } + + // A static library that depends on the source set (should not link it). + Target stlib_target(setup.settings(), Label(SourceDir("//foo/"), "stlib")); + stlib_target.set_output_type(Target::STATIC_LIBRARY); + stlib_target.deps().push_back(LabelTargetPair(&target)); + stlib_target.OnResolved(); + + { + std::ostringstream out; + NinjaBinaryTargetWriter writer(&stlib_target, setup.toolchain(), out); + writer.Run(); + + // TODO(brettw) I think we'll need to worry about backslashes here + // depending if we're on actual Windows or Linux pretending to be Windows. + const char expected_win[] = + "defines =\n" + "includes =\n" + "cflags =\n" + "cflags_c =\n" + "cflags_cc =\n" + "cflags_objc =\n" + "cflags_objcc =\n" + "\n" + "\n" + "manifests = obj/foo/stlib.intermediate.manifest\n" + "ldflags = /MANIFEST /ManifestFile:obj/foo/stlib.intermediate.manifest\n" + "libs =\n" + // There are no sources so there are no params to alink. + "build obj/foo/stlib.lib: alink\n\n"; + std::string out_str = out.str(); +#if defined(OS_WIN) + std::replace(out_str.begin(), out_str.end(), '\\', '/'); +#endif + EXPECT_EQ(expected_win, out_str); + } + } TEST(NinjaBinaryTargetWriter, ProductExtension) { diff --git a/tools/gn/ninja_build_writer.cc b/tools/gn/ninja_build_writer.cc index f9039046a7..007089ddf2 100644 --- a/tools/gn/ninja_build_writer.cc +++ b/tools/gn/ninja_build_writer.cc @@ -39,7 +39,7 @@ std::string GetSelfInvocationCommand(const BuildSettings* build_settings) { cmdline.AppendSwitch("-q"); // Don't write output. EscapeOptions escape_shell; - escape_shell.mode = ESCAPE_SHELL; + escape_shell.mode = ESCAPE_NINJA_COMMAND; #if defined(OS_WIN) // The command line code quoting varies by platform. We have one string, // possibly with spaces, that we want to quote. The Windows command line @@ -82,7 +82,7 @@ NinjaBuildWriter::NinjaBuildWriter( default_toolchain_targets_(default_toolchain_targets), out_(out), dep_out_(dep_out), - path_output_(build_settings->build_dir(), ESCAPE_NINJA, false), + path_output_(build_settings->build_dir(), ESCAPE_NINJA), helper_(build_settings) { } diff --git a/tools/gn/ninja_target_writer.cc b/tools/gn/ninja_target_writer.cc index 778e9832b6..d59582e6b9 100644 --- a/tools/gn/ninja_target_writer.cc +++ b/tools/gn/ninja_target_writer.cc @@ -26,9 +26,7 @@ NinjaTargetWriter::NinjaTargetWriter(const Target* target, target_(target), toolchain_(toolchain), out_(out), - path_output_(settings_->build_settings()->build_dir(), - ESCAPE_NINJA, - false), + path_output_(settings_->build_settings()->build_dir(), ESCAPE_NINJA), helper_(settings_->build_settings()) { } @@ -116,7 +114,8 @@ std::string NinjaTargetWriter::WriteInputDepsStampAndGetDep( path_output_.WriteFile(stamp_file_stream, input_stamp_file); std::string stamp_file_string = stamp_file_stream.str(); - out_ << "build " << stamp_file_string << ": stamp"; + out_ << "build " << stamp_file_string << ": " + + helper_.GetRulePrefix(settings_) + "stamp"; // Script file (if applicable). if (add_script_source_as_dep) { diff --git a/tools/gn/ninja_toolchain_writer.cc b/tools/gn/ninja_toolchain_writer.cc index 44d2586241..99087c68f2 100644 --- a/tools/gn/ninja_toolchain_writer.cc +++ b/tools/gn/ninja_toolchain_writer.cc @@ -23,9 +23,7 @@ NinjaToolchainWriter::NinjaToolchainWriter( toolchain_(toolchain), targets_(targets), out_(out), - path_output_(settings_->build_settings()->build_dir(), - ESCAPE_NINJA, - false), + path_output_(settings_->build_settings()->build_dir(), ESCAPE_NINJA), helper_(settings->build_settings()) { } diff --git a/tools/gn/path_output.cc b/tools/gn/path_output.cc index 4e71f9bdc9..7e739b6edc 100644 --- a/tools/gn/path_output.cc +++ b/tools/gn/path_output.cc @@ -9,9 +9,7 @@ #include "tools/gn/output_file.h" #include "tools/gn/string_utils.h" -PathOutput::PathOutput(const SourceDir& current_dir, - EscapingMode escaping, - bool convert_slashes) +PathOutput::PathOutput(const SourceDir& current_dir, EscapingMode escaping) : current_dir_(current_dir) { CHECK(current_dir.is_source_absolute()) << "Currently this only supports writing to output directories inside " @@ -20,11 +18,6 @@ PathOutput::PathOutput(const SourceDir& current_dir, inverse_current_dir_ = InvertDir(current_dir_); options_.mode = escaping; - options_.convert_slashes = convert_slashes; - options_.inhibit_quoting = false; - - if (convert_slashes) - ConvertPathToSystem(&inverse_current_dir_); } PathOutput::~PathOutput() { @@ -91,12 +84,9 @@ void PathOutput::WriteFile(std::ostream& out, void PathOutput::WriteSourceRelativeString( std::ostream& out, const base::StringPiece& str) const { - if (options_.mode == ESCAPE_SHELL) { + if (options_.mode == ESCAPE_NINJA_COMMAND) { // Shell escaping needs an intermediate string since it may end up - // quoting the whole thing. On Windows, the slashes may already be - // converted to backslashes in inverse_current_dir_, but we assume that on - // Windows the escaper won't try to then escape the preconverted - // backslashes and will just pass them, so this is fine. + // quoting the whole thing. std::string intermediate; intermediate.reserve(inverse_current_dir_.size() + str.size()); intermediate.assign(inverse_current_dir_.c_str(), diff --git a/tools/gn/path_output.h b/tools/gn/path_output.h index 33227d4864..ba4a5f6073 100644 --- a/tools/gn/path_output.h +++ b/tools/gn/path_output.h @@ -33,9 +33,7 @@ class PathOutput { DIR_NO_LAST_SLASH, }; - PathOutput(const SourceDir& current_dir, - EscapingMode escaping, - bool convert_slashes); + PathOutput(const SourceDir& current_dir, EscapingMode escaping); ~PathOutput(); // Read-only since inverse_current_dir_ is computed depending on this. @@ -43,19 +41,10 @@ class PathOutput { const SourceDir& current_dir() const { return current_dir_; } - // When true, converts slashes to the system-type path separators (on - // Windows, this is a backslash, this is a NOP otherwise). - // - // Read-only since inverse_current_dir_ is computed depending on this. - bool convert_slashes_to_system() const { return options_.convert_slashes; } - - // When the output escaping is ESCAPE_SHELL, the escaper will normally put - // quotes around suspect things. If this value is set to true, we'll disable - // the quoting feature. This means that in ESCAPE_SHELL mode, strings with - // spaces in them qon't be quoted. This mode is for when quoting is done at - // some higher-level. Defaults to false. + // Getter/setters for flags inside the escape options. bool inhibit_quoting() const { return options_.inhibit_quoting; } void set_inhibit_quoting(bool iq) { options_.inhibit_quoting = iq; } + void set_escape_platform(EscapingPlatform p) { options_.platform = p; } void WriteFile(std::ostream& out, const SourceFile& file) const; void WriteFile(std::ostream& out, const OutputFile& file) const; diff --git a/tools/gn/path_output_unittest.cc b/tools/gn/path_output_unittest.cc index 49f29c9a55..389f96a404 100644 --- a/tools/gn/path_output_unittest.cc +++ b/tools/gn/path_output_unittest.cc @@ -11,7 +11,7 @@ TEST(PathOutput, Basic) { SourceDir build_dir("//out/Debug/"); - PathOutput writer(build_dir, ESCAPE_NONE, false); + PathOutput writer(build_dir, ESCAPE_NONE); { // Normal source-root path. std::ostringstream out; @@ -52,7 +52,7 @@ TEST(PathOutput, Basic) { // Same as basic but the output dir is the root. TEST(PathOutput, BasicInRoot) { SourceDir build_dir("//"); - PathOutput writer(build_dir, ESCAPE_NONE, false); + PathOutput writer(build_dir, ESCAPE_NONE); { // Normal source-root path. std::ostringstream out; @@ -69,7 +69,7 @@ TEST(PathOutput, BasicInRoot) { TEST(PathOutput, NinjaEscaping) { SourceDir build_dir("//out/Debug/"); - PathOutput writer(build_dir, ESCAPE_NINJA, false); + PathOutput writer(build_dir, ESCAPE_NINJA); { // Spaces and $ in filenames. std::ostringstream out; @@ -84,63 +84,85 @@ TEST(PathOutput, NinjaEscaping) { } } -TEST(PathOutput, ShellEscaping) { +TEST(PathOutput, NinjaForkEscaping) { SourceDir build_dir("//out/Debug/"); - PathOutput writer(build_dir, ESCAPE_SHELL, false); + PathOutput writer(build_dir, ESCAPE_NINJA_COMMAND); + + // Spaces in filenames should get quoted on Windows. + writer.set_escape_platform(ESCAPE_PLATFORM_WIN); { - // Spaces in filenames should get quoted. std::ostringstream out; writer.WriteFile(out, SourceFile("//foo/foo bar.cc")); - EXPECT_EQ("\"../../foo/foo bar.cc\"", out.str()); + EXPECT_EQ("\"../../foo/foo$ bar.cc\"", out.str()); + } + + // Spaces in filenames should get escaped on Posix. + writer.set_escape_platform(ESCAPE_PLATFORM_POSIX); + { + std::ostringstream out; + writer.WriteFile(out, SourceFile("//foo/foo bar.cc")); + EXPECT_EQ("../../foo/foo\\$ bar.cc", out.str()); + } + + // Quotes should get blackslash-escaped on Windows and Posix. + writer.set_escape_platform(ESCAPE_PLATFORM_WIN); + { + std::ostringstream out; + writer.WriteFile(out, SourceFile("//foo/\"foobar\".cc")); + // Our Windows code currently quotes the whole thing in this case for + // code simplicity, even though it's strictly unnecessary. This might + // change in the future. + EXPECT_EQ("\"../../foo/\\\"foobar\\\".cc\"", out.str()); } + writer.set_escape_platform(ESCAPE_PLATFORM_POSIX); { - // Quotes should get blackslash-escaped. std::ostringstream out; writer.WriteFile(out, SourceFile("//foo/\"foobar\".cc")); EXPECT_EQ("../../foo/\\\"foobar\\\".cc", out.str()); } + + + // Backslashes should get escaped on non-Windows and preserved on Windows. + writer.set_escape_platform(ESCAPE_PLATFORM_WIN); { - // Backslashes should get escaped on non-Windows and preserved on Windows. std::ostringstream out; writer.WriteFile(out, SourceFile("//foo\\bar.cc")); -#if defined(OS_WIN) EXPECT_EQ("../../foo\\bar.cc", out.str()); -#else - EXPECT_EQ("../../foo\\\\bar.cc", out.str()); -#endif } -} - -TEST(PathOutput, SlashConversion) { - SourceDir build_dir("//out/Debug/"); - PathOutput writer(build_dir, ESCAPE_NINJA, true); + writer.set_escape_platform(ESCAPE_PLATFORM_POSIX); { std::ostringstream out; - writer.WriteFile(out, SourceFile("//foo/bar.cc")); -#if defined(OS_WIN) - EXPECT_EQ("..\\..\\foo\\bar.cc", out.str()); -#else - EXPECT_EQ("../../foo/bar.cc", out.str()); -#endif + writer.WriteFile(out, SourceFile("//foo\\bar.cc")); + EXPECT_EQ("../../foo\\\\bar.cc", out.str()); } } TEST(PathOutput, InhibitQuoting) { SourceDir build_dir("//out/Debug/"); - PathOutput writer(build_dir, ESCAPE_SHELL, false); + PathOutput writer(build_dir, ESCAPE_NINJA_COMMAND); writer.set_inhibit_quoting(true); + + writer.set_escape_platform(ESCAPE_PLATFORM_WIN); { // We should get unescaped spaces in the output with no quotes. std::ostringstream out; writer.WriteFile(out, SourceFile("//foo/foo bar.cc")); - EXPECT_EQ("../../foo/foo bar.cc", out.str()); + EXPECT_EQ("../../foo/foo$ bar.cc", out.str()); + } + + writer.set_escape_platform(ESCAPE_PLATFORM_POSIX); + { + // Escapes the space. + std::ostringstream out; + writer.WriteFile(out, SourceFile("//foo/foo bar.cc")); + EXPECT_EQ("../../foo/foo\\$ bar.cc", out.str()); } } TEST(PathOutput, WriteDir) { { SourceDir build_dir("//out/Debug/"); - PathOutput writer(build_dir, ESCAPE_NINJA, false); + PathOutput writer(build_dir, ESCAPE_NINJA); { std::ostringstream out; writer.WriteDir(out, SourceDir("//foo/bar/"), @@ -191,6 +213,8 @@ TEST(PathOutput, WriteDir) { // Output inside current dir. { std::ostringstream out; + + writer.WriteDir(out, SourceDir("//out/Debug/"), PathOutput::DIR_INCLUDE_LAST_SLASH); EXPECT_EQ("./", out.str()); @@ -216,7 +240,7 @@ TEST(PathOutput, WriteDir) { } { // Empty build dir writer. - PathOutput root_writer(SourceDir("//"), ESCAPE_NINJA, false); + PathOutput root_writer(SourceDir("//"), ESCAPE_NINJA); { std::ostringstream out; root_writer.WriteDir(out, SourceDir("//"), diff --git a/tools/gn/run_all_unittests.cc b/tools/gn/run_all_unittests.cc new file mode 100644 index 0000000000..edd80fed5d --- /dev/null +++ b/tools/gn/run_all_unittests.cc @@ -0,0 +1,13 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/bind.h" +#include "base/test/test_suite.h" + +// Don't use the multiprocess test harness. This test suite is fast enough and +// it makes the output more difficult to read. +int main(int argc, char** argv) { + base::TestSuite test_suite(argc, argv); + return test_suite.Run(); +} diff --git a/tools/gn/secondary/chrome/BUILD.gn b/tools/gn/secondary/chrome/BUILD.gn index c9a7278956..aaff67facd 100644 --- a/tools/gn/secondary/chrome/BUILD.gn +++ b/tools/gn/secondary/chrome/BUILD.gn @@ -122,6 +122,12 @@ source_set("debugger") { "browser/devtools/devtools_file_helper.h", "browser/devtools/devtools_file_system_indexer.cc", "browser/devtools/devtools_file_system_indexer.h", + "browser/devtools/devtools_network_controller.cpp", + "browser/devtools/devtools_network_controller.h", + "browser/devtools/devtools_network_transaction.cpp", + "browser/devtools/devtools_network_transaction.h", + "browser/devtools/devtools_network_transaction_factory.cpp", + "browser/devtools/devtools_network_transaction_factory.h", "browser/devtools/devtools_protocol.cc", "browser/devtools/devtools_protocol.h", "browser/devtools/devtools_toggle_action.h", diff --git a/tools/gn/secondary/sdch/BUILD.gn b/tools/gn/secondary/sdch/BUILD.gn deleted file mode 100644 index 73f3afb8d7..0000000000 --- a/tools/gn/secondary/sdch/BUILD.gn +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -config("sdch_config") { - include_dirs = [ "open-vcdiff/src" ] -} - -static_library("sdch") { - sources = [ - "open-vcdiff/src/addrcache.cc", - "open-vcdiff/src/blockhash.cc", - "open-vcdiff/src/blockhash.h", - "open-vcdiff/src/checksum.h", - "open-vcdiff/src/codetable.cc", - "open-vcdiff/src/codetable.h", - "open-vcdiff/src/compile_assert.h", - "open-vcdiff/src/decodetable.cc", - "open-vcdiff/src/decodetable.h", - "open-vcdiff/src/encodetable.cc", - "open-vcdiff/src/encodetable.h", - "open-vcdiff/src/google/output_string.h", - "open-vcdiff/src/google/vcdecoder.h", - "open-vcdiff/src/headerparser.cc", - "open-vcdiff/src/headerparser.h", - "open-vcdiff/src/instruction_map.cc", - "open-vcdiff/src/instruction_map.h", - "open-vcdiff/src/logging.cc", - "open-vcdiff/src/logging.h", - "open-vcdiff/src/rolling_hash.h", - "open-vcdiff/src/testing.h", - "open-vcdiff/src/varint_bigendian.cc", - "open-vcdiff/src/varint_bigendian.h", - "open-vcdiff/src/vcdecoder.cc", - "open-vcdiff/src/vcdiff_defs.h", - "open-vcdiff/src/vcdiffengine.cc", - "open-vcdiff/src/vcdiffengine.h", - "open-vcdiff/vsprojects/config.h", - "open-vcdiff/vsprojects/stdint.h", - ] - - direct_dependent_configs = [ ":sdch_config" ] - - if (is_linux || is_android) { - include_dirs = [ "linux" ] - } else if (is_ios) { - include_dirs = [ "ios" ] - } else if (is_mac) { - include_dirs = [ "mac" ] - } else if (is_win) { - include_dirs = [ "win" ] - } - - deps = [ "//third_party/zlib" ] - - if (is_clang) { - cflags = [ - # TODO(mostynb): remove this if open-vcdiff is ever updated for c++11: - "-Wno-deprecated-declarations", - ] - } -} diff --git a/tools/gn/secondary/testing/BUILD.gn b/tools/gn/secondary/testing/BUILD.gn new file mode 100644 index 0000000000..2cafa68a28 --- /dev/null +++ b/tools/gn/secondary/testing/BUILD.gn @@ -0,0 +1,11 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("gmock_mutant") { + sources = [ + "gmock_mutant.h", # gMock helpers + ] + + deps = [ "//base" ] +} diff --git a/tools/gn/secondary/testing/gmock/BUILD.gn b/tools/gn/secondary/testing/gmock/BUILD.gn index 8b5f8dbeb9..e682abf58b 100644 --- a/tools/gn/secondary/testing/gmock/BUILD.gn +++ b/tools/gn/secondary/testing/gmock/BUILD.gn @@ -28,7 +28,6 @@ static_library("gmock") { "src/gmock-matchers.cc", "src/gmock-spec-builders.cc", "src/gmock.cc", - "../gmock_mutant.h", # gMock helpers ] # This project includes some stuff form gtest's guts. @@ -38,8 +37,6 @@ static_library("gmock") { ":gmock_config", "//testing/gtest:gtest_config", ] - - deps = [ "//base" ] } static_library("gmock_main") { diff --git a/tools/gn/secondary/third_party/angle/BUILD.gn b/tools/gn/secondary/third_party/angle/BUILD.gn index ec3fd6b289..651d42f7ae 100644 --- a/tools/gn/secondary/third_party/angle/BUILD.gn +++ b/tools/gn/secondary/third_party/angle/BUILD.gn @@ -568,7 +568,7 @@ if (is_win) { ] if (is_debug) { - defines += [ "ANGLE_ENABLE_PERF" ] + defines = [ "ANGLE_ENABLE_PERF" ] } include_dirs = [ "src/libGLESv2" ] diff --git a/tools/gn/secondary/third_party/icu/BUILD.gn b/tools/gn/secondary/third_party/icu/BUILD.gn index 21c4efa714..df268cb145 100644 --- a/tools/gn/secondary/third_party/icu/BUILD.gn +++ b/tools/gn/secondary/third_party/icu/BUILD.gn @@ -16,6 +16,11 @@ config("icu_config") { defines = [ "U_USING_ICU_NAMESPACE=0", ] + + if (component_mode != "shared_library") { + defines += [ "U_STATIC_IMPLEMENTATION" ] + } + include_dirs = [ "source/common", "source/i18n", @@ -24,10 +29,6 @@ config("icu_config") { # Config used only by ICU code. config("icu_code") { - if (component_mode == "static_library") { - defines = [ "U_STATIC_IMPLEMENTATION" ] - } - if (is_win) { # Disable some compiler warnings. cflags = [ @@ -426,7 +427,7 @@ if (is_win) { outputs = [ "$root_out_dir/icudt.dll" ] } } else { - static_library("icudata") { + source_set("icudata") { sources = [ # These are hand-generated, but will do for now. The linux version is an # identical copy of the (mac) icudt46l_dat.S file, modulo removal of the diff --git a/tools/gn/secondary/third_party/nss/BUILD.gn b/tools/gn/secondary/third_party/nss/BUILD.gn index 6ce1d2fd96..a0c1674585 100644 --- a/tools/gn/secondary/third_party/nss/BUILD.gn +++ b/tools/gn/secondary/third_party/nss/BUILD.gn @@ -356,7 +356,7 @@ if (is_linux) { if (component_mode == "shared_library") { if (is_mac) { - cflags = [ "-all_load" ] + ldflags = [ "-all_load" ] } else if (is_win) { # Pass the def file to the linker. ldflags = [ rebase_path("nss/exports_win.def", root_build_dir) ] @@ -1090,10 +1090,6 @@ if (is_linux) { } if (is_win) { - sources -= [ - "nss/lib/freebl/mpi/mpi_amd64.c", - "nss/lib/freebl/mpi/mpi_x86_asm.c", - ] defines += [ "SHLIB_SUFFIX=\"dll\"", "SHLIB_PREFIX=\"\"", @@ -1104,6 +1100,7 @@ if (is_linux) { ] if (cpu_arch == "x86") { + sources -= [ "nss/lib/freebl/mpi/mpi_amd64.c" ] defines += [ "NSS_X86_OR_X64", "NSS_X86", @@ -1115,6 +1112,7 @@ if (is_linux) { "MP_NO_MP_WORD", ] } else if (cpu_arch == "x64") { + sources -= [ "nss/lib/freebl/mpi/mpi_x86_asm.c" ] defines += [ "NSS_USE_64", "NSS_X86_OR_X64", diff --git a/tools/gn/secondary/tools/grit/grit_rule.gni b/tools/gn/secondary/tools/grit/grit_rule.gni index 31307e4184..c3e0a5c41a 100644 --- a/tools/gn/secondary/tools/grit/grit_rule.gni +++ b/tools/gn/secondary/tools/grit/grit_rule.gni @@ -12,6 +12,28 @@ # # You can also put deps here if the grit source depends on generated # # files. # } +import ("//build/config/ui.gni") + +grit_defines = [] + +if (is_chromeos) { + grit_defines += [ + "-D", "chromeos", + "-D", "scale_factors=2x" + ] +} + +if (is_desktop_linux) { + grit_defines += [ "-D", "desktop_linux" ] +} + +if (is_android) { + grit_defines += [ + "-t", "android", + "-E", "ANDROID_JAVA_TAGGED_ONLY=true", + ] +} + template("grit") { assert(defined(invoker.source), "\"source\" must be defined for the grit template $target_name") @@ -70,12 +92,11 @@ template("grit") { source_prereqs = grit_inputs outputs = grit_outputs - # TODO(brettw) grit_defines. args = [ "-i", source_path, "build", "-f", resource_ids, "-o", output_dir, - ] + grit_flags + ] + grit_defines + grit_flags visibility = target_visibility } diff --git a/tools/gn/target.cc b/tools/gn/target.cc index 9bfae3593c..2ddbde91cf 100644 --- a/tools/gn/target.cc +++ b/tools/gn/target.cc @@ -177,13 +177,8 @@ void Target::PullDependentTargetInfo(std::set<const Config*>* unique_configs) { dep->output_type() != EXECUTABLE) { const std::set<const Target*> inherited = dep->inherited_libraries(); for (std::set<const Target*>::const_iterator i = inherited.begin(); - i != inherited.end(); ++i) { - // Don't copy source sets across static library boundaries. The static - // library will include all the files from the source set. - if (!(dep->output_type() == STATIC_LIBRARY && - (*i)->output_type() == SOURCE_SET)) - inherited_libraries_.insert(*i); - } + i != inherited.end(); ++i) + inherited_libraries_.insert(*i); // Inherited library settings. all_lib_dirs_.append(dep->all_lib_dirs()); diff --git a/tools/gn/target_unittest.cc b/tools/gn/target_unittest.cc index 6219374c94..f9a1f972a4 100644 --- a/tools/gn/target_unittest.cc +++ b/tools/gn/target_unittest.cc @@ -225,15 +225,14 @@ TEST_F(TargetTest, InheritLibs) { EXPECT_EQ(1u, c_inherited.size()); EXPECT_TRUE(c_inherited.find(&d) != c_inherited.end()); - // B should have C in its inherited libs, but not D (the static library will - // include the source sets's code). + // B should have C and D in its inherited libs. const std::set<const Target*>& b_inherited = b.inherited_libraries(); - EXPECT_EQ(1u, b_inherited.size()); + EXPECT_EQ(2u, b_inherited.size()); EXPECT_TRUE(b_inherited.find(&c) != b_inherited.end()); + EXPECT_TRUE(b_inherited.find(&d) != b_inherited.end()); // A should have B in its inherited libs, but not any others (the shared - // library will include the static library, which will include the source - // set). + // library will include the static library and source set). const std::set<const Target*>& a_inherited = a.inherited_libraries(); EXPECT_EQ(1u, a_inherited.size()); EXPECT_TRUE(a_inherited.find(&b) != a_inherited.end()); diff --git a/tools/gn/visibility.cc b/tools/gn/visibility.cc index 41bfc63f41..6fc8fa125d 100644 --- a/tools/gn/visibility.cc +++ b/tools/gn/visibility.cc @@ -97,28 +97,40 @@ bool Visibility::CanSeeMe(const Label& label) const { return false; } -std::string Visibility::Describe() const { +std::string Visibility::Describe(int indent, bool include_brackets) const { + std::string outer_indent_string(indent, ' '); + if (patterns_.empty()) - return std::string("[] (no visibility)"); - std::string result = "[\n"; + return outer_indent_string + "[] (no visibility)\n"; + + std::string result; + + std::string inner_indent_string = outer_indent_string; + if (include_brackets) { + result += outer_indent_string + "[\n"; + // Indent the insides more if brackets are requested. + inner_indent_string += " "; + } for (size_t i = 0; i < patterns_.size(); i++) { switch (patterns_[i].type()) { case VisPattern::MATCH: - result += " " + patterns_[i].dir().value() + ":" + + result += inner_indent_string + + DirectoryWithNoLastSlash(patterns_[i].dir()) + ":" + patterns_[i].name() + "\n"; break; case VisPattern::DIRECTORY: - result += " " + DirectoryWithNoLastSlash(patterns_[i].dir()) + - ":*\n"; + result += inner_indent_string + + DirectoryWithNoLastSlash(patterns_[i].dir()) + ":*\n"; break; case VisPattern::RECURSIVE_DIRECTORY: - result += " " + patterns_[i].dir().value() + "*\n"; + result += inner_indent_string + patterns_[i].dir().value() + "*\n"; break; } } - result += "]"; + if (include_brackets) + result += outer_indent_string + "]\n"; return result; } @@ -244,7 +256,7 @@ bool Visibility::CheckItemVisibility(const Item* from, "The item " + from->label().GetUserVisibleName(false) + "\n" "can not depend on " + to_label + "\n" "because it is not in " + to_label + "'s visibility list: " + - to->visibility().Describe()); + to->visibility().Describe(0, true)); return false; } return true; diff --git a/tools/gn/visibility.h b/tools/gn/visibility.h index 52ec73ca15..7ce2b7845f 100644 --- a/tools/gn/visibility.h +++ b/tools/gn/visibility.h @@ -68,8 +68,11 @@ class Visibility { // current visibility. bool CanSeeMe(const Label& label) const; - // Returns a string listing the visibility. - std::string Describe() const; + // Returns a string listing the visibility. |indent| number of spaces will + // be added on the left side of the output. If |include_brackets| is set, the + // result will be wrapped in "[ ]" and the contents further indented. The + // result will end in a newline. + std::string Describe(int indent, bool include_brackets) const; // Converts the given input string to a pattern. This does special stuff // to treat the pattern as a label. Sets the error on failure. diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids index 45eb5a4d6b..21d8a69685 100644 --- a/tools/gritsettings/resource_ids +++ b/tools/gritsettings/resource_ids @@ -163,10 +163,13 @@ "messages": [26000], }, "chrome/common/extensions_api_resources.grd": { - "includes": [26500], + "includes": [26400], }, "extensions/extensions_resources.grd": { - "includes": [26750], + "includes": [26600], + }, + "extensions/renderer/resources/extensions_renderer_resources.grd": { + "includes": [26800], }, "extensions/extensions_strings.grd": { "messages": [27000], diff --git a/tools/gypv8sh.py b/tools/gypv8sh.py index 5c93e51bf7..b8bd4066ec 100755 --- a/tools/gypv8sh.py +++ b/tools/gypv8sh.py @@ -5,10 +5,6 @@ """This script is used by chrome_tests.gypi's js2webui action to maintain the argument lists and to generate inlinable tests. - -Usage: - python tools/gypv8sh.py v8_shell mock.js test_api.js js2webui.js \ - inputfile inputrelfile cxxoutfile jsoutfile """ import json @@ -22,24 +18,28 @@ import shutil def main (): parser = optparse.OptionParser() parser.set_usage( - "%prog v8_shell mock.js axs_testing.js test_api.js js2webui.js " + "%prog v8_shell mock.js test_api.js js2webui.js " "testtype inputfile inputrelfile cxxoutfile jsoutfile") parser.add_option('-v', '--verbose', action='store_true') parser.add_option('-n', '--impotent', action='store_true', help="don't execute; just print (as if verbose)") + parser.add_option('--deps_js', action="store", + help=("Path to deps.js for dependency resolution, " + + "optional.")) (opts, args) = parser.parse_args() - if len(args) != 10: + if len(args) != 9: parser.error('all arguments are required.') - (v8_shell, mock_js, axs_testing_js, test_api, js2webui, test_type, + (v8_shell, mock_js, test_api, js2webui, test_type, inputfile, inputrelfile, cxxoutfile, jsoutfile) = args cmd = [v8_shell] icudatafile = os.path.join(os.path.dirname(v8_shell), 'icudtl.dat') if os.path.exists(icudatafile): cmd.extend(['--icu-data-file=%s' % icudatafile]) - arguments = [js2webui, inputfile, inputrelfile, cxxoutfile, test_type] + arguments = [js2webui, inputfile, inputrelfile, opts.deps_js, + cxxoutfile, test_type] cmd.extend(['-e', "arguments=" + json.dumps(arguments), mock_js, - axs_testing_js, test_api, js2webui]) + test_api, js2webui]) if opts.verbose or opts.impotent: print cmd if not opts.impotent: diff --git a/tools/ipc_fuzzer/mutate/generate.cc b/tools/ipc_fuzzer/mutate/generate.cc index 9ed43b78dc..d741b7f3ac 100644 --- a/tools/ipc_fuzzer/mutate/generate.cc +++ b/tools/ipc_fuzzer/mutate/generate.cc @@ -515,19 +515,6 @@ struct GenerateTraits<base::TimeTicks> { }; template <> -struct GenerateTraits<base::PlatformFileInfo> { - static bool Generate(base::PlatformFileInfo* p, Generator* generator) { - return - GenerateParam(&p->size, generator) && - GenerateParam(&p->is_directory, generator) && - GenerateParam(&p->last_modified, generator) && - GenerateParam(&p->last_accessed, generator) && - GenerateParam(&p->creation_time, generator); - } -}; - - -template <> struct GenerateTraits<base::ListValue> { static bool Generate(base::ListValue* p, Generator* generator) { ++g_depth; diff --git a/tools/ipc_fuzzer/replay/replay_process.cc b/tools/ipc_fuzzer/replay/replay_process.cc index b141cd0029..1e6f4c28c5 100644 --- a/tools/ipc_fuzzer/replay/replay_process.cc +++ b/tools/ipc_fuzzer/replay/replay_process.cc @@ -55,11 +55,10 @@ void ReplayProcess::OpenChannel() { CommandLine::ForCurrentProcess()->GetSwitchValueASCII( switches::kProcessChannelID); - channel_.reset( - new IPC::ChannelProxy(channel_name, - IPC::Channel::MODE_CLIENT, - this, - io_thread_.message_loop_proxy())); + channel_ = IPC::ChannelProxy::Create(channel_name, + IPC::Channel::MODE_CLIENT, + this, + io_thread_.message_loop_proxy()); } bool ReplayProcess::OpenTestcase() { diff --git a/tools/isolate_driver.py b/tools/isolate_driver.py index 4db823e444..192de2cb83 100755 --- a/tools/isolate_driver.py +++ b/tools/isolate_driver.py @@ -113,8 +113,9 @@ def using_blacklist(item): this list. This is simply an optimization. """ IGNORED = ( - '.a', '.cc', '.css', '.def', '.h', '.html', '.js', '.json', '.manifest', - '.o', '.obj', '.pak', '.png', '.pdb', '.strings', '.txt', + '.a', '.cc', '.css', '.def', '.frag', '.h', '.html', '.js', '.json', + '.manifest', '.o', '.obj', '.pak', '.png', '.pdb', '.strings', '.test', + '.txt', '.vert', ) # ninja files use native path format. ext = os.path.splitext(item)[1] @@ -138,31 +139,26 @@ def raw_build_to_deps(item): return filter(using_blacklist, item.split(' ')[1:]) -def recurse(target, build_steps, rules_seen): - """Recursively returns all the interesting dependencies for root_item.""" - out = [] +def collect_deps(target, build_steps, dependencies_added, rules_seen): + """Recursively adds all the interesting dependencies for |target| + into |dependencies_added|. + """ if rules_seen is None: rules_seen = set() if target in rules_seen: # TODO(maruel): Figure out how it happens. logging.warning('Circular dependency for %s!', target) - return [] + return rules_seen.add(target) try: dependencies = raw_build_to_deps(build_steps[target]) except KeyError: logging.info('Failed to find a build step to generate: %s', target) - return [] - logging.debug('recurse(%s) -> %s', target, dependencies) + return + logging.debug('collect_deps(%s) -> %s', target, dependencies) for dependency in dependencies: - out.append(dependency) - dependency_raw_dependencies = build_steps.get(dependency) - if dependency_raw_dependencies: - for i in raw_build_to_deps(dependency_raw_dependencies): - out.extend(recurse(i, build_steps, rules_seen)) - else: - logging.info('Failed to find a build step to generate: %s', dependency) - return out + dependencies_added.add(dependency) + collect_deps(dependency, build_steps, dependencies_added, rules_seen) def post_process_deps(build_dir, dependencies): @@ -219,7 +215,9 @@ def create_wrapper(args, isolate_index, isolated_index): # complain to maruel@. target = isolate[:-len('.isolate')] + '_run' build_steps = load_ninja(build_dir) - binary_deps = post_process_deps(build_dir, recurse(target, build_steps, None)) + binary_deps = set() + collect_deps(target, build_steps, binary_deps, None) + binary_deps = post_process_deps(build_dir, binary_deps) logging.debug( 'Binary dependencies:%s', ''.join('\n ' + i for i in binary_deps)) diff --git a/tools/json_schema_compiler/api_gen_util.target.darwin-arm.mk b/tools/json_schema_compiler/api_gen_util.target.darwin-arm.mk index 09950a8eab..ab912d72d6 100644 --- a/tools/json_schema_compiler/api_gen_util.target.darwin-arm.mk +++ b/tools/json_schema_compiler/api_gen_util.target.darwin-arm.mk @@ -79,7 +79,6 @@ MY_DEFS_Debug := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ @@ -177,7 +176,6 @@ MY_DEFS_Release := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ diff --git a/tools/json_schema_compiler/api_gen_util.target.darwin-arm64.mk b/tools/json_schema_compiler/api_gen_util.target.darwin-arm64.mk index 02dccb89b6..18cafcd952 100644 --- a/tools/json_schema_compiler/api_gen_util.target.darwin-arm64.mk +++ b/tools/json_schema_compiler/api_gen_util.target.darwin-arm64.mk @@ -69,7 +69,6 @@ MY_DEFS_Debug := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ @@ -156,7 +155,6 @@ MY_DEFS_Release := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ diff --git a/tools/json_schema_compiler/api_gen_util.target.darwin-mips.mk b/tools/json_schema_compiler/api_gen_util.target.darwin-mips.mk index 4270b14a26..80470fd453 100644 --- a/tools/json_schema_compiler/api_gen_util.target.darwin-mips.mk +++ b/tools/json_schema_compiler/api_gen_util.target.darwin-mips.mk @@ -73,7 +73,6 @@ MY_DEFS_Debug := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ @@ -165,7 +164,6 @@ MY_DEFS_Release := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ diff --git a/tools/json_schema_compiler/api_gen_util.target.darwin-x86.mk b/tools/json_schema_compiler/api_gen_util.target.darwin-x86.mk index 8b45aacf61..b6d95e70e9 100644 --- a/tools/json_schema_compiler/api_gen_util.target.darwin-x86.mk +++ b/tools/json_schema_compiler/api_gen_util.target.darwin-x86.mk @@ -74,7 +74,6 @@ MY_DEFS_Debug := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ @@ -166,7 +165,6 @@ MY_DEFS_Release := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ diff --git a/tools/json_schema_compiler/api_gen_util.target.darwin-x86_64.mk b/tools/json_schema_compiler/api_gen_util.target.darwin-x86_64.mk index 6ee3f8c374..d647d70903 100644 --- a/tools/json_schema_compiler/api_gen_util.target.darwin-x86_64.mk +++ b/tools/json_schema_compiler/api_gen_util.target.darwin-x86_64.mk @@ -73,7 +73,6 @@ MY_DEFS_Debug := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ @@ -164,7 +163,6 @@ MY_DEFS_Release := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ diff --git a/tools/json_schema_compiler/api_gen_util.target.linux-arm.mk b/tools/json_schema_compiler/api_gen_util.target.linux-arm.mk index 09950a8eab..ab912d72d6 100644 --- a/tools/json_schema_compiler/api_gen_util.target.linux-arm.mk +++ b/tools/json_schema_compiler/api_gen_util.target.linux-arm.mk @@ -79,7 +79,6 @@ MY_DEFS_Debug := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ @@ -177,7 +176,6 @@ MY_DEFS_Release := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ diff --git a/tools/json_schema_compiler/api_gen_util.target.linux-arm64.mk b/tools/json_schema_compiler/api_gen_util.target.linux-arm64.mk index 02dccb89b6..18cafcd952 100644 --- a/tools/json_schema_compiler/api_gen_util.target.linux-arm64.mk +++ b/tools/json_schema_compiler/api_gen_util.target.linux-arm64.mk @@ -69,7 +69,6 @@ MY_DEFS_Debug := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ @@ -156,7 +155,6 @@ MY_DEFS_Release := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ diff --git a/tools/json_schema_compiler/api_gen_util.target.linux-mips.mk b/tools/json_schema_compiler/api_gen_util.target.linux-mips.mk index 4270b14a26..80470fd453 100644 --- a/tools/json_schema_compiler/api_gen_util.target.linux-mips.mk +++ b/tools/json_schema_compiler/api_gen_util.target.linux-mips.mk @@ -73,7 +73,6 @@ MY_DEFS_Debug := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ @@ -165,7 +164,6 @@ MY_DEFS_Release := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ diff --git a/tools/json_schema_compiler/api_gen_util.target.linux-x86.mk b/tools/json_schema_compiler/api_gen_util.target.linux-x86.mk index 8b45aacf61..b6d95e70e9 100644 --- a/tools/json_schema_compiler/api_gen_util.target.linux-x86.mk +++ b/tools/json_schema_compiler/api_gen_util.target.linux-x86.mk @@ -74,7 +74,6 @@ MY_DEFS_Debug := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ @@ -166,7 +165,6 @@ MY_DEFS_Release := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ diff --git a/tools/json_schema_compiler/api_gen_util.target.linux-x86_64.mk b/tools/json_schema_compiler/api_gen_util.target.linux-x86_64.mk index 6ee3f8c374..d647d70903 100644 --- a/tools/json_schema_compiler/api_gen_util.target.linux-x86_64.mk +++ b/tools/json_schema_compiler/api_gen_util.target.linux-x86_64.mk @@ -73,7 +73,6 @@ MY_DEFS_Debug := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ @@ -164,7 +163,6 @@ MY_DEFS_Release := \ '-DENABLE_WEBRTC=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ - '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ '-DENABLE_EGLIMAGE=1' \ diff --git a/tools/json_schema_compiler/cc_generator.py b/tools/json_schema_compiler/cc_generator.py index 96492ba103..61f5bf1f04 100644 --- a/tools/json_schema_compiler/cc_generator.py +++ b/tools/json_schema_compiler/cc_generator.py @@ -146,11 +146,16 @@ class _Generator(object): def _GenerateInitializersAndBody(self, type_): items = [] for prop in type_.properties.values(): - if prop.optional: - continue - t = prop.type_ - if t.property_type == PropertyType.INTEGER: + + real_t = self._type_helper.FollowRef(t) + if real_t.property_type == PropertyType.ENUM: + items.append('%s(%s)' % ( + prop.unix_name, + self._type_helper.GetEnumNoneValue(t))) + elif prop.optional: + continue + elif t.property_type == PropertyType.INTEGER: items.append('%s(0)' % prop.unix_name) elif t.property_type == PropertyType.DOUBLE: items.append('%s(0.0)' % prop.unix_name) @@ -160,12 +165,11 @@ class _Generator(object): t.property_type == PropertyType.ARRAY or t.property_type == PropertyType.BINARY or # mapped to std::string t.property_type == PropertyType.CHOICES or - t.property_type == PropertyType.ENUM or t.property_type == PropertyType.OBJECT or t.property_type == PropertyType.FUNCTION or t.property_type == PropertyType.REF or t.property_type == PropertyType.STRING): - # TODO(miket): It would be nice to initialize CHOICES and ENUM, but we + # TODO(miket): It would be nice to initialize CHOICES, but we # don't presently have the semantics to indicate which one of a set # should be the default. continue diff --git a/tools/json_schema_compiler/idl_schema.py b/tools/json_schema_compiler/idl_schema.py index 72e4d13b4f..89bb8816b0 100644 --- a/tools/json_schema_compiler/idl_schema.py +++ b/tools/json_schema_compiler/idl_schema.py @@ -469,8 +469,14 @@ def Main(): Dump a json serialization of parse result for the IDL files whose names were passed in on the command line. ''' - for filename in sys.argv[1:]: - schema = Load(filename) + if len(sys.argv) > 1: + for filename in sys.argv[1:]: + schema = Load(filename) + print json.dumps(schema, indent=2) + else: + contents = sys.stdin.read() + idl = idl_parser.IDLParser().ParseData(contents, '<stdin>') + schema = IDLSchema(idl).process() print json.dumps(schema, indent=2) diff --git a/tools/json_schema_compiler/test/enums_unittest.cc b/tools/json_schema_compiler/test/enums_unittest.cc index 0a2d5d1176..9bbadd9192 100644 --- a/tools/json_schema_compiler/test/enums_unittest.cc +++ b/tools/json_schema_compiler/test/enums_unittest.cc @@ -42,6 +42,11 @@ TEST(JsonSchemaCompilerEnumsTest, EnumsAsTypes) { } { HasEnumeration enumeration; + EXPECT_EQ(ENUMERATION_NONE, enumeration.enumeration); + EXPECT_EQ(ENUMERATION_NONE, enumeration.optional_enumeration); + } + { + HasEnumeration enumeration; base::DictionaryValue value; ASSERT_FALSE(HasEnumeration::Populate(value, &enumeration)); diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 96b852964a..c174ad2f48 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -1610,6 +1610,21 @@ Therefore, the affected-histogram name has to have at least one dot in it. <summary>Tracks whether Autofill is enabled when Chrome launches.</summary> </histogram> +<histogram name="Autofill.MacAddressBook" enum="AutofillMacAddressBook"> + <owner>erikchen@chromium.org</owner> + <summary> + When Chrome tries to access the user's Address Book, OSX presents a blocking + dialog which disrupts the user experience. A new Chrome feature has been + introduced wherein Chrome only shows this blocking dialog if the user + explicitly asked Chrome to access the user's Address Book. If a form's field + looks like it might support Autofill suggestions from the user's Address + Book and there are no other suggestions, Chrome shows an Autofill entry that + prompts the user to give Chrome access to the user's Address Book. This + histogram tracks the frequency that this Autofill entry is presented, and + the frequency that this Autofill entry is selected. + </summary> +</histogram> + <histogram name="AutoFill.ProfileCount"> <obsolete> Deprecated as of 3/2011, replaced by Autofill.StoredProfileCount. @@ -6787,7 +6802,21 @@ Therefore, the affected-histogram name has to have at least one dot in it. </histogram> <histogram name="Extensions.Permissions_AutoDisable" enum="ExtensionPermission"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <obsolete> + Deprecated as of 5/2014, replaced by Extensions.Permissions_AutoDisable2. + </obsolete> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> + <summary> + The permissions present in an extension when it is automatically disabled + due to a permission increase (e.g., after an extension upgrade). + </summary> +</histogram> + +<histogram name="Extensions.Permissions_AutoDisable2" + enum="ExtensionPermission2"> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> <summary> The permissions present in an extension when it is automatically disabled due to a permission increase (e.g., after an extension upgrade). @@ -6795,7 +6824,19 @@ Therefore, the affected-histogram name has to have at least one dot in it. </histogram> <histogram name="Extensions.Permissions_Install" enum="ExtensionPermission"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <obsolete> + Deprecated as of 5/2014, replaced by Extensions.Permissions_Install2. + </obsolete> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> + <summary> + The permissions present in an extension when it was installed. + </summary> +</histogram> + +<histogram name="Extensions.Permissions_Install2" enum="ExtensionPermission2"> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> <summary> The permissions present in an extension when it was installed. </summary> @@ -6803,7 +6844,21 @@ Therefore, the affected-histogram name has to have at least one dot in it. <histogram name="Extensions.Permissions_InstallAbort" enum="ExtensionPermission"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <obsolete> + Deprecated as of 5/2014, replaced by Extensions.Permissions_InstallAbort2. + </obsolete> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> + <summary> + The permissions present in an extension when installation was aborted, not + including installation errors and user cancels. + </summary> +</histogram> + +<histogram name="Extensions.Permissions_InstallAbort2" + enum="ExtensionPermission2"> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> <summary> The permissions present in an extension when installation was aborted, not including installation errors and user cancels. @@ -6812,19 +6867,55 @@ Therefore, the affected-histogram name has to have at least one dot in it. <histogram name="Extensions.Permissions_InstallCancel" enum="ExtensionPermission"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <obsolete> + Deprecated as of 5/2014, replaced by Extensions.Permissions_InstallCancel2. + </obsolete> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> + <summary> + The permissions present in an extension when installation was canceled. + </summary> +</histogram> + +<histogram name="Extensions.Permissions_InstallCancel2" + enum="ExtensionPermission2"> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> <summary> The permissions present in an extension when installation was canceled. </summary> </histogram> <histogram name="Extensions.Permissions_Load" enum="ExtensionPermission"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <obsolete> + Deprecated as of 5/2014, replaced by Extensions.Permissions_Load2. + </obsolete> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> + <summary>The permissions present in an extension when it was loaded.</summary> +</histogram> + +<histogram name="Extensions.Permissions_Load2" enum="ExtensionPermission2"> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> <summary>The permissions present in an extension when it was loaded.</summary> </histogram> <histogram name="Extensions.Permissions_ReEnable" enum="ExtensionPermission"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <obsolete> + Deprecated as of 5/2014, replaced by Extensions.Permissions_ReEnable2. + </obsolete> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> + <summary> + The permissions present in an extension when it was re-enabled from a + confirmation prompt. + </summary> +</histogram> + +<histogram name="Extensions.Permissions_ReEnable2" enum="ExtensionPermission2"> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> <summary> The permissions present in an extension when it was re-enabled from a confirmation prompt. @@ -6833,7 +6924,21 @@ Therefore, the affected-histogram name has to have at least one dot in it. <histogram name="Extensions.Permissions_ReEnableAbort" enum="ExtensionPermission"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <obsolete> + Deprecated as of 5/2014, replaced by Extensions.Permissions_ReEnableAbort2. + </obsolete> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> + <summary> + The permissions present in an extension when the re-enable prompt was + aborted, not including installation errors and manual user cancels. + </summary> +</histogram> + +<histogram name="Extensions.Permissions_ReEnableAbort2" + enum="ExtensionPermission2"> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> <summary> The permissions present in an extension when the re-enable prompt was aborted, not including installation errors and manual user cancels. @@ -6842,7 +6947,21 @@ Therefore, the affected-histogram name has to have at least one dot in it. <histogram name="Extensions.Permissions_ReEnableCancel" enum="ExtensionPermission"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <obsolete> + Deprecated as of 5/2014, replaced by Extensions.Permissions_ReEnableCancel2. + </obsolete> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> + <summary> + The permissions present in an extension when the re-enable was canceled from + the confirmation prompt. + </summary> +</histogram> + +<histogram name="Extensions.Permissions_ReEnableCancel2" + enum="ExtensionPermission2"> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> <summary> The permissions present in an extension when the re-enable was canceled from the confirmation prompt. @@ -6850,7 +6969,19 @@ Therefore, the affected-histogram name has to have at least one dot in it. </histogram> <histogram name="Extensions.Permissions_Uninstall" enum="ExtensionPermission"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <obsolete> + Deprecated as of 5/2014, replaced by Extensions.Permissions_Uninstall2. + </obsolete> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> + <summary> + The permissions present in an extension when it was uninstalled. + </summary> +</histogram> + +<histogram name="Extensions.Permissions_Uninstall2" enum="ExtensionPermission2"> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> <summary> The permissions present in an extension when it was uninstalled. </summary> @@ -6858,7 +6989,22 @@ Therefore, the affected-histogram name has to have at least one dot in it. <histogram name="Extensions.Permissions_WebStoreInstall" enum="ExtensionPermission"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <obsolete> + Deprecated as of 5/2014, replaced by + Extensions.Permissions_WebStoreInstall2. + </obsolete> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> + <summary> + The permissions present in an extension when it was installed through the + web store. + </summary> +</histogram> + +<histogram name="Extensions.Permissions_WebStoreInstall2" + enum="ExtensionPermission2"> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> <summary> The permissions present in an extension when it was installed through the web store. @@ -6867,7 +7013,22 @@ Therefore, the affected-histogram name has to have at least one dot in it. <histogram name="Extensions.Permissions_WebStoreInstallAbort" enum="ExtensionPermission"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <obsolete> + Deprecated as of 5/2014, replaced by + Extensions.Permissions_WebStoreInstallAbort2. + </obsolete> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> + <summary> + The permissions present in an extension when installation from the web store + was aborted, not including installation errors and user cancels. + </summary> +</histogram> + +<histogram name="Extensions.Permissions_WebStoreInstallAbort2" + enum="ExtensionPermission2"> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> <summary> The permissions present in an extension when installation from the web store was aborted, not including installation errors and user cancels. @@ -6876,7 +7037,22 @@ Therefore, the affected-histogram name has to have at least one dot in it. <histogram name="Extensions.Permissions_WebStoreInstallCancel" enum="ExtensionPermission"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <obsolete> + Deprecated as of 5/2014, replaced by + Extensions.Permissions_WebStoreInstallCancel2. + </obsolete> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> + <summary> + The permissions present in an extension when installation from the web store + was canceled. + </summary> +</histogram> + +<histogram name="Extensions.Permissions_WebStoreInstallCancel2" + enum="ExtensionPermission2"> + <owner>kalman@chromium.org</owner> + <owner>rpaquay@chromium.org</owner> <summary> The permissions present in an extension when installation from the web store was canceled. @@ -9266,6 +9442,25 @@ Therefore, the affected-histogram name has to have at least one dot in it. <summary>Chrome OS login success reason.</summary> </histogram> +<histogram name="Login.UsersActiveWeekly" units="users"> + <owner>alemate@chromium.org</owner> + <owner>nkostylev@chromium.org</owner> + <summary> + Chrome OS histogram that keeps track of number of users who have logged in + in the last 7 days. Reported on every boot and once a day after that. + </summary> +</histogram> + +<histogram name="Login.UsersActiveWeekly.Percent" units="%"> + <owner>alemate@chromium.org</owner> + <owner>nkostylev@chromium.org</owner> + <summary> + Chrome OS histogram that keeps track of percentage of local users who have + logged in in the last 7 days. Reported on every boot and once a day after + that. + </summary> +</histogram> + <histogram name="Login.UserType" enum="LoginUserType"> <owner>cmasone@chromium.org</owner> <summary> @@ -11302,6 +11497,337 @@ Therefore, the affected-histogram name has to have at least one dot in it. </summary> </histogram> +<histogram name="NCN.CM.FastestRTTOn2G" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Rough estimate of the fastest round-trip-time seen on a 2G connection, + before the NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.FastestRTTOn3G" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Rough estimate of the fastest round-trip-time seen on a 3G connection, + before the NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.FastestRTTOn4G" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Rough estimate of the fastest round-trip-time seen on a 4G connection, + before the NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.FastestRTTOnEthernet" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Rough estimate of the fastest round-trip-time seen on an Ethernet + connection, before the NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.FastestRTTOnNone" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Rough estimate of the fastest round-trip-time seen while the + NetworkChangeNotifier thought there was no network connection, before the + NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.FastestRTTOnUnknown" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Rough estimate of the fastest round-trip-time seen on an unknown connection + type, before the NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.FastestRTTOnWifi" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Rough estimate of the fastest round-trip-time seen on a Wifi connection, + before the NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.FirstReadOn2G" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time between switching to a 2G connection and receiving the first network + data. + </summary> +</histogram> + +<histogram name="NCN.CM.FirstReadOn3G" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time between switching to a 3G connection and receiving the first network + data. + </summary> +</histogram> + +<histogram name="NCN.CM.FirstReadOn4G" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time between switching to a 4G connection and receiving the first network + data. + </summary> +</histogram> + +<histogram name="NCN.CM.FirstReadOnEthernet" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time between switching to an Ethernet connection and receiving the first + network data. + </summary> +</histogram> + +<histogram name="NCN.CM.FirstReadOnNone" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time between disconnecting and receiving the first network data. + </summary> +</histogram> + +<histogram name="NCN.CM.FirstReadOnUnknown" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time between switching to an unknown connection type and receiving the first + network data. + </summary> +</histogram> + +<histogram name="NCN.CM.FirstReadOnWifi" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time between switching to a Wifi connection and receiving the first network + data. + </summary> +</histogram> + +<histogram name="NCN.CM.KBTransferedOn2G" units="KB"> + <owner>pauljensen@chromium.org</owner> + <summary> + How much data was transfered while connected via a 2G connection, before the + NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.KBTransferedOn3G" units="KB"> + <owner>pauljensen@chromium.org</owner> + <summary> + How much data was transfered while connected via a 3G connection, before the + NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.KBTransferedOn4G" units="KB"> + <owner>pauljensen@chromium.org</owner> + <summary> + How much data was transfered while connected via a 4G connection, before the + NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.KBTransferedOnEthernet" units="KB"> + <owner>pauljensen@chromium.org</owner> + <summary> + How much data was transfered while connected via an Ethernet connection, + before the NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.KBTransferedOnNone" units="KB"> + <owner>pauljensen@chromium.org</owner> + <summary> + How much data was transfered while the NetworkChangeNotifier thought there + was no network connection, before the NetworkChangeNotifier detected a + connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.KBTransferedOnUnknown" units="KB"> + <owner>pauljensen@chromium.org</owner> + <summary> + How much data was transfered while connected via an unknown connection type, + before the NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.KBTransferedOnWifi" units="KB"> + <owner>pauljensen@chromium.org</owner> + <summary> + How much data was transfered while connected via a Wifi connection, before + the NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.PeakKbpsOn2G" units="Kbps"> + <owner>pauljensen@chromium.org</owner> + <summary> + Rough estimate of peak throughput seen on a 2G connection, before the + NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.PeakKbpsOn3G" units="Kbps"> + <owner>pauljensen@chromium.org</owner> + <summary> + Rough estimate of peak throughput seen on a 3G connection, before the + NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.PeakKbpsOn4G" units="Kbps"> + <owner>pauljensen@chromium.org</owner> + <summary> + Rough estimate of peak throughput seen on a 4G connection, before the + NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.PeakKbpsOnEthernet" units="Kbps"> + <owner>pauljensen@chromium.org</owner> + <summary> + Rough estimate of peak throughput seen on an Ethernet connection, before the + NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.PeakKbpsOnNone" units="Kbps"> + <owner>pauljensen@chromium.org</owner> + <summary> + Rough estimate of peak throughput seen while the NetworkChangeNotifier + thought there was no network connection, before the NetworkChangeNotifier + detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.PeakKbpsOnUnknown" units="Kbps"> + <owner>pauljensen@chromium.org</owner> + <summary> + Rough estimate of peak throughput seen on an unknown connection type, before + the NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.PeakKbpsOnWifi" units="Kbps"> + <owner>pauljensen@chromium.org</owner> + <summary> + Rough estimate of peak throughput seen on a Wifi connection, before the + NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.TimeOn2G" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + How long was spent connected via a 2G connection, before the + NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.TimeOn3G" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + How long was spent connected via a 3G connection, before the + NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.TimeOn4G" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + How long was spent connected via a 4G connection, before the + NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.TimeOnEthernet" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + How long was spent connected via an Ethernet connection, before the + NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.TimeOnNone" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + How long was spent disconnected, before the NetworkChangeNotifier detected a + connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.TimeOnUnknown" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + How long was spent connected via an unknown connection type, before the + NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.CM.TimeOnWifi" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + How long was spent connected via a Wifi connection, before the + NetworkChangeNotifier detected a connectivity change. + </summary> +</histogram> + +<histogram name="NCN.ConnectionTypeChangeToIPAddressChange" + units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time from ConnectionTypeChanged message until IPAddressChanged message. + </summary> +</histogram> + +<histogram name="NCN.DNSConfigChange" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary>Time between DNS configuration change messages.</summary> +</histogram> + +<histogram name="NCN.GetConnectionTypeTime" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + How long does each call to NetworkChangeNotifier::GetConnectionType() take. + </summary> +</histogram> + +<histogram name="NCN.IPAddressChange" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary>Time between IP address change messages.</summary> +</histogram> + +<histogram name="NCN.IPAddressChangeToConnectionTypeChange" + units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time from IPAddressChanged message until ConnectionTypeChanged message. + </summary> +</histogram> + +<histogram name="NCN.NetworkOfflineChange" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time between going online until we go offline change messages, using new + filtered signal. + </summary> +</histogram> + +<histogram name="NCN.NetworkOnlineChange" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time between going offline until we go online change messages, using new + filtered signal. + </summary> +</histogram> + <histogram name="NCN.NetworkOperatorMCCMNC"> <owner>bolian@chromium.org</owner> <owner>bengr@google.com</owner> @@ -11314,6 +11840,62 @@ Therefore, the affected-histogram name has to have at least one dot in it. </summary> </histogram> +<histogram name="NCN.OfflineChange" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time between going online until we go offline change messages. + </summary> +</histogram> + +<histogram name="NCN.OfflineDataRecv" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time between when we thought we went offline and when we received some + network data (a URLRequest read completed). + </summary> +</histogram> + +<histogram name="NCN.OfflineDataRecvAny5sBeforeOnline"> + <owner>pauljensen@chromium.org</owner> + <summary> + Count of how many times we received network data (a URLRequest read + completed) while offline when some data was received at most five seconds + before going online. + </summary> +</histogram> + +<histogram name="NCN.OfflineDataRecvUntilOnline" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time between when we received the last network data (a URLRequest read + completed) while offline and when we thought we went online. + </summary> +</histogram> + +<histogram name="NCN.OfflinePolls"> + <owner>pauljensen@chromium.org</owner> + <summary> + Count of how many times we polled the online/offline status before detecting + an offline to online transition. + </summary> +</histogram> + +<histogram name="NCN.OnlineChange" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time between going offline until we go online change messages. + </summary> +</histogram> + +<histogram name="NCN.PollingOfflineDataRecv" units="milliseconds"> + <owner>pauljensen@chromium.org</owner> + <summary> + Time between when we thought we went offline and when we received some + network data (a URLRequest read completed), while polling + NetworkChangeNotifier::GetConnectionType() still told us we were offline. + </summary> +</histogram> + <histogram name="Net.AlternateProtocolBrokenLocation" enum="BrokenAlternateProtocolLocation"> <owner>rch@chromium.org</owner> @@ -13506,6 +14088,13 @@ Therefore, the affected-histogram name has to have at least one dot in it. </summary> </histogram> +<histogram name="Net.QuicActiveSessions"> + <owner>rtenneti@chromium.org</owner> + <summary> + The number of active QUIC sessions before we activate a new QUIC session. + </summary> +</histogram> + <histogram name="Net.QuicEphemeralPortsSuggested"> <owner>rch@chromium.org</owner> <summary>The number of ports suggested per server.</summary> @@ -17357,6 +17946,16 @@ Therefore, the affected-histogram name has to have at least one dot in it. </summary> </histogram> +<histogram name="Omnibox.HasLegalDefaultMatchWithoutCompletion" enum="Boolean"> + <owner>mpearson@chromium.org</owner> + <summary> + Whether there was at least one legal default match without an + |inline_autocompletion|. Recorded every time + AutocompleteResult::SortAndCull() is called, which could happen multiple + times on each keystroke. + </summary> +</histogram> + <histogram name="Omnibox.Paste" units="count"> <owner>mpearson@chromium.org</owner> <summary> @@ -21289,6 +21888,15 @@ Therefore, the affected-histogram name has to have at least one dot in it. <summary>The frequency of ways that new user profiles are added.</summary> </histogram> +<histogram name="Profile.AndroidAccountManagementMenu" + enum="ProfileAndroidAccountManagementMenu"> + <owner>aruslan@chromium.org</owner> + <summary> + Track user interactions that can be performed in the Android account + management menu. + </summary> +</histogram> + <histogram name="Profile.AppCount"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary>The number of installed apps when a profile is opened.</summary> @@ -21463,7 +22071,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. <owner>rlp@chromium.org</owner> <summary> Counts the number of signed-in profiles on a user's machine when Chrome - starts up, among cases with at least one profile. + starts up. </summary> </histogram> @@ -21479,6 +22087,15 @@ Therefore, the affected-histogram name has to have at least one dot in it. </summary> </histogram> +<histogram name="Profile.NumberOfSignedInProfilesWithGAIAIcons"> + <owner>mlerman@chromium.org</owner> + <summary> + Counts the number of signed-in profiles that are using the GAIA image as the + avatar icon. This is counted when a profile is loaded, including when Chrome + starts up. + </summary> +</histogram> + <histogram name="Profile.Opening" enum="ProfileOpen"> <obsolete> Deprecated because it did not present the information clearly. @@ -22214,6 +22831,40 @@ Therefore, the affected-histogram name has to have at least one dot in it. </summary> </histogram> +<histogram name="Renderer4.GpuRasterizationEnabled" units="BooleanEnabled"> + <owner>alokp@chromium.org</owner> + <summary> + Whether gpu rasterization is enabled (checked once after the page is painted + for the first time). + </summary> +</histogram> + +<histogram name="Renderer4.GpuRasterizationSuitableContent" + units="BooleanEnabled"> + <owner>alokp@chromium.org</owner> + <summary> + If gpu rasterization is enabled, whether the page contents are suitable for + gpu rasterization (checked once after the page is painted for the first + time). + </summary> +</histogram> + +<histogram name="Renderer4.GpuRasterizationTriggered" units="BooleanEnabled"> + <owner>alokp@chromium.org</owner> + <summary> + If gpu rasterization is enabled, whether it was triggered (checked once + after the page is painted for the first time). + </summary> +</histogram> + +<histogram name="Renderer4.GpuRasterizationUsed" units="BooleanEnabled"> + <owner>alokp@chromium.org</owner> + <summary> + If gpu rasterization is enabled, whether it was actually used for the page + (checked once after the page is painted for the first time). + </summary> +</histogram> + <histogram name="Renderer4.InvalidationRegionApproximateRectCount" units="rects"> <owner>wiltzius@chromium.org</owner> @@ -23384,8 +24035,11 @@ Therefore, the affected-histogram name has to have at least one dot in it. <owner>mattm@chromium.org</owner> <summary> Records the total time it takes for the SafeBrowsing download service to - check whether the content of a download is malicious or not. This histogram - only includes requests that are sent to the SafeBrowsing server. + check whether the content of a download is malicious or not, including file + feature extraction, whitelist checking, and server ping. This histogram only + includes checks that sent a ping to the SafeBrowsing server. It does not + include requests that were cancelled, but does include requests that + received a bad response. </summary> </histogram> @@ -23396,6 +24050,24 @@ Therefore, the affected-histogram name has to have at least one dot in it. </summary> </histogram> +<histogram name="SBClientDownload.DownloadRequestNetworkDuration" + units="milliseconds"> + <owner>mattm@chromium.org</owner> + <summary> + Records the time it takes for the SafeBrowsing download service ping. It is + not recorded for requests that were cancelled. + </summary> +</histogram> + +<histogram name="SBClientDownload.DownloadRequestNetworkStats" + enum="SBClientDownloadCheckDownloadStats"> + <owner>mattm@chromium.org</owner> + <summary> + Records the results of SafeBrowsing binary download checks which caused a + server ping. + </summary> +</histogram> + <histogram name="SBClientDownload.DownloadRequestPayloadSize" units="bytes"> <owner>mattm@chromium.org</owner> <summary> @@ -23411,6 +24083,27 @@ Therefore, the affected-histogram name has to have at least one dot in it. </summary> </histogram> +<histogram name="SBClientDownload.DownloadRequestTimeoutDuration" + units="milliseconds"> + <owner>mattm@chromium.org</owner> + <summary> + Records the portion of the SafeBrowsing download service check starting with + the point CheckClientDownloadRequest::StartTimeout() is called. It is + recorded regardless if a ping was sent or not. It is not recorded for + requests that were cancelled. + </summary> +</histogram> + +<histogram name="SBClientDownload.DownloadRequestTimeoutStats" + enum="SBClientDownloadCheckDownloadStats"> + <owner>mattm@chromium.org</owner> + <summary> + For SafeBrowsing binary download checks which reached the + CheckClientDownloadRequest::StartTimeout() call, records the final result + (once the check finishes or is cancelled). + </summary> +</histogram> + <histogram name="SBClientDownload.ExtractImageHeadersTime" units="milliseconds"> <owner>grt@chromium.org</owner> <summary> @@ -23890,6 +24583,28 @@ Therefore, the affected-histogram name has to have at least one dot in it. </summary> </histogram> +<histogram name="ServiceWorker.Database.OpenResult" + enum="ServiceWorkerDatabaseStatus"> + <owner>nhiroki@chromium.org</owner> + <summary> + Records result of opening a database for ServiceWorkerDatabase. + </summary> +</histogram> + +<histogram name="ServiceWorker.Database.ReadResult" + enum="ServiceWorkerDatabaseStatus"> + <owner>nhiroki@chromium.org</owner> + <summary>Records result of read operations in ServiceWorkerDatabase.</summary> +</histogram> + +<histogram name="ServiceWorker.Database.WriteResult" + enum="ServiceWorkerDatabaseStatus"> + <owner>nhiroki@chromium.org</owner> + <summary> + Records result of write operations in ServiceWorkerDatabase. + </summary> +</histogram> + <histogram name="Settings.DefaultSearchProvider" enum="OmniboxSearchEngine"> <obsolete> Deprecated in Chrome 30. Use Search.DefaultSearchProviderType instead. @@ -31109,6 +31824,34 @@ Therefore, the affected-histogram name has to have at least one dot in it. <summary>The success or failure of web fonts CORS-enabled fetching.</summary> </histogram> +<histogram name="WebFont.DiskCache.ReuseCount.Evict"> + <owner>kenjibaheux@chromium.org</owner> + <owner>ksakamoto@chromium.org</owner> + <summary> + When a cache entry for a font in Google Fonts is evicted, records the reuse + count of the cache entry. + </summary> +</histogram> + +<histogram name="WebFont.DiskCache.ReuseCount.Hit"> + <owner>kenjibaheux@chromium.org</owner> + <owner>ksakamoto@chromium.org</owner> + <summary> + Recorded upon a cache hit for a font in Google Fonts. Records the reuse + count of the cache entry. + </summary> +</histogram> + +<histogram name="WebFont.DiskCacheHit.opensans" enum="WebFontDiskCacheHit"> + <owner>kenjibaheux@chromium.org</owner> + <owner>ksakamoto@chromium.org</owner> + <summary> + Whether the font was in the cache or not. "Previously in the + cache" means there was an evicted entry for the font in the cache. + Recorded upon a disk cache query for a font in Google Fonts. + </summary> +</histogram> + <histogram name="WebFont.DownloadTime.0.Under10KB" units="milliseconds"> <owner>kenjibaheux@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> @@ -32216,6 +32959,11 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="17" label="fp05cc03e1"/> </enum> +<enum name="AutofillMacAddressBook" type="int"> + <int value="0" label="Showed popup entry"/> + <int value="1" label="Selected popup entry"/> +</enum> + <enum name="AutofillQuality" type="int"> <int value="0" label="Submitted"/> <int value="1" label="Autofilled"/> @@ -34106,6 +34854,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. label="Restrict the UDP port range used by the remote access host"/> <int value="265" label="Enables the old web-based signin"/> <int value="266" label="Block developer mode"/> + <int value="267" label="Show the apps shortcut in the bookmark bar"/> </enum> <enum name="EnterprisePolicyInvalidations" type="int"> @@ -34387,8 +35136,8 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="28" label="DELETED_FILEBROWSERPRIVATE_ISFULLSCREEN"/> <int value="29" label="AUTOTESTPRIVATE_LOGOUT"/> <int value="30" label="EXPERIMENTAL_HISTORY_GETMOSTVISITED"/> - <int value="31" label="BLUETOOTH_DISCONNECT"/> - <int value="32" label="BLUETOOTH_SETOUTOFBANDPAIRINGDATA"/> + <int value="31" label="DELETED_BLUETOOTH_DISCONNECT"/> + <int value="32" label="DELETED_BLUETOOTH_SETOUTOFBANDPAIRINGDATA"/> <int value="33" label="BOOKMARKMANAGERPRIVATE_CANPASTE"/> <int value="34" label="AUTOTESTPRIVATE_RESTART"/> <int value="35" label="USB_CLAIMINTERFACE"/> @@ -34494,7 +35243,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="135" label="CONTEXTMENUS_UPDATE"/> <int value="136" label="BOOKMARKS_SEARCH"/> <int value="137" label="EXPERIMENTAL_APP_CLEARALLNOTIFICATIONS"/> - <int value="138" label="BLUETOOTH_GETLOCALOUTOFBANDPAIRINGDATA"/> + <int value="138" label="DELETED_BLUETOOTH_GETLOCALOUTOFBANDPAIRINGDATA"/> <int value="139" label="SYSTEMPRIVATE_GETUPDATESTATUS"/> <int value="140" label="FONTSETTINGS_CLEARMINIMUMFONTSIZE"/> <int value="141" label="DELETED_FILEBROWSERPRIVATE_GETFILELOCATIONS"/> @@ -34632,11 +35381,11 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="272" label="PAGEACTIONS_DISABLEFORTAB"/> <int value="273" label="DEVELOPERPRIVATE_ALLOWFILEACCESS"/> <int value="274" label="FILEBROWSERPRIVATE_REMOVEMOUNT"/> - <int value="275" label="BLUETOOTH_CONNECT"/> + <int value="275" label="DELETED_BLUETOOTH_CONNECT"/> <int value="276" label="TABCAPTURE_CAPTURE"/> <int value="277" label="NOTIFICATIONS_CREATE"/> <int value="278" label="TABS_DUPLICATE"/> - <int value="279" label="BLUETOOTH_WRITE"/> + <int value="279" label="DELETED_BLUETOOTH_WRITE"/> <int value="280" label="PAGEACTION_SHOW"/> <int value="281" label="WALLPAPERPRIVATE_GETTHUMBNAIL"/> <int value="282" label="DOWNLOADS_PAUSE"/> @@ -34702,7 +35451,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="342" label="BROWSERACTION_SETPOPUP"/> <int value="343" label="TABS_GETSELECTED"/> <int value="344" label="FONTSETTINGS_GETFONT"/> - <int value="345" label="BLUETOOTH_READ"/> + <int value="345" label="DELETED_BLUETOOTH_READ"/> <int value="346" label="WEBREQUESTINTERNAL_EVENTHANDLED"/> <int value="347" label="EVENTS_ADDRULES"/> <int value="348" label="CONTEXTMENUS_CREATE"/> @@ -34810,8 +35559,8 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="450" label="NETWORKINGPRIVATE_GETMANAGEDPROPERTIES"/> <int value="451" label="LOCATION_WATCHLOCATION"/> <int value="452" label="LOCATION_CLEARWATCH"/> - <int value="453" label="BLUETOOTH_ADDPROFILE"/> - <int value="454" label="BLUETOOTH_REMOVEPROFILE"/> + <int value="453" label="DELETED_BLUETOOTH_ADDPROFILE"/> + <int value="454" label="DELETED_BLUETOOTH_REMOVEPROFILE"/> <int value="455" label="DELETED_BLUETOOTH_GETPROFILES"/> <int value="456" label="EXPERIMENTAL_IDENTITY_REMOVECACHEDAUTHTOKEN"/> <int value="457" label="AUDIO_GETINFO"/> @@ -35061,7 +35810,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="696" label="WEBVIEW_CONTEXTMENUSUPDATE"/> <int value="697" label="WEBVIEW_CONTEXTMENUSREMOVE"/> <int value="698" label="WEBVIEW_CONTEXTMENUSREMOVEALL"/> - <int value="699" label="AUTOMATIONINTERNAL_ENABLECURRENTTAB"/> + <int value="699" label="AUTOMATIONINTERNAL_ENABLETAB"/> <int value="700" label="APP_CURRENTWINDOWINTERNAL_SETSIZECONSTRAINTS"/> <int value="701" label="BLUETOOTH_GETDEVICE"/> <int value="702" label="GCM_UNREGISTER"/> @@ -35074,10 +35823,10 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="709" label="BLUETOOTHPRIVATE_SETPAIRINGRESPONSE"/> <int value="710" label="NETWORKINGPRIVATE_GETCAPTIVEPORTALSTATUS"/> <int value="711" label="AUTOMATIONINTERNAL_PERFORMACTION"/> - <int value="712" label="BLUETOOTH_UPDATE_SOCKET"/> - <int value="713" label="BLUETOOTH_SET_SOCKET_PAUSED"/> - <int value="714" label="BLUETOOTH_GET_SOCKET"/> - <int value="715" label="BLUETOOTH_GET_SOCKETS"/> + <int value="712" label="DELETED_BLUETOOTH_UPDATE_SOCKET"/> + <int value="713" label="DELETED_BLUETOOTH_SET_SOCKET_PAUSED"/> + <int value="714" label="DELETED_BLUETOOTH_GET_SOCKET"/> + <int value="715" label="DELETED_BLUETOOTH_GET_SOCKETS"/> <int value="716" label="FILESYSTEMPROVIDER_UNMOUNT"/> <int value="717" label="FILESYSTEMPROVIDERINTERNAL_UNMOUNTREQUESTEDSUCCESS"/> <int value="718" label="FILESYSTEMPROVIDERINTERNAL_UNMOUNTREQUESTEDERROR"/> @@ -35152,6 +35901,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="782" label="FILEBROWSERPRIVATE_OPENINSPECTOR"/> <int value="783" label="STREAMSPRIVATE_ABORT"/> <int value="784" label="MANAGEMENT_SETLAUNCHTYPE"/> + <int value="785" label="MANAGEMENT_GENERATEAPPFORLINK"/> </enum> <enum name="ExtensionInstallCause" type="int"> @@ -36908,6 +37658,8 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="23" label="GetDatabaseNames"/> <int value="24" label="ReadBlobJournal"/> <int value="25" label="DecodeBlobJournal"/> + <int value="26" label="GetBlobKeyGeneratorCurrentNumber"/> + <int value="27" label="GetBlobInfoForRecord"/> </enum> <enum name="IDBLevelDBBackingStoreOpenResult" type="int"> @@ -37126,6 +37878,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="1" label="PeerConnection00"/> <int value="2" label="DeprecatedPeerConnection"/> <int value="3" label="RTCPeerConnection"/> + <int value="4" label="GetMediaDevices"/> </enum> <enum name="KeyboardControlEvent" type="int"> @@ -40377,6 +41130,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="286711" label="PPB_FlashFullscreen;0.1"/> <int value="2804066" label="PPB_AudioConfig;1.1"/> <int value="8760108" label="PPB_Testing_Private;1.0"/> + <int value="12033600" label="PPB_Compositor;0.1"/> <int value="13662160" label="PPB_CharSet(Dev);0.4"/> <int value="22816901" label="PPB_FileChooser(Dev);0.5"/> <int value="28187368" label="PPB_IMEInputEvent(Dev);0.2"/> @@ -40390,6 +41144,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="156766028" label="PPB_UMA_Private;0.3"/> <int value="162107265" label="PPB_NetworkMonitor;1.0"/> <int value="180906214" label="PPB_Instance_Private;0.1"/> + <int value="206043276" label="PPB_CompositorLayer;0.1"/> <int value="221802429" label="PPB_URLUtil(Dev);0.7"/> <int value="225125520" label="PPB_Find(Private);0.3"/> <int value="226206264" label="PPB_FileRef;1.1"/> @@ -40466,6 +41221,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="1260990020" label="PPB_Ext_Socket(Dev);0.2"/> <int value="1262240942" label="PPB_FileIO;1.1"/> <int value="1272679676" label="PPB_TCPSocket_Private;0.5"/> + <int value="1296231808" label="PPB_VideoDecoder;0.1"/> <int value="1316246754" label="PPB_KeyboardInputEvent;1.0"/> <int value="1316320941" label="PPB_Graphics2D(Dev);0.1"/> <int value="1321620067" label="PPB_Instance;1.0"/> @@ -41176,6 +41932,33 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="3" label="Add new user from the User Manager"/> </enum> +<enum name="ProfileAndroidAccountManagementMenu" type="int"> + <int value="0" label="Opened Menu"> + User arrived at the Account management screen. + </int> + <int value="1" label="Add Account"> + User arrived at the Account management screen, and clicked Add account. + </int> + <int value="2" label="Go Incognito"> + User arrived at the Account management screen, and clicked Go incognito. + </int> + <int value="3" label="Primary Account"> + User arrived at the Account management screen, and clicked on primary. + </int> + <int value="4" label="Secondary Account"> + User arrived at the Account management screen, and clicked on secondary. + </int> + <int value="5" label="Toggled Signout"> + User arrived at the Account management screen, toggled Chrome signout. + </int> + <int value="6" label="Confirm Signout"> + User toggled Chrome signout, and clicked Signout. + </int> + <int value="7" label="Cancel Signout"> + User toggled Chrome signout, and clicked Cancel. + </int> +</enum> + <enum name="ProfileAuth" type="int"> <int value="0" label="Authentication was unnecessary (profile not locked)"/> <int value="1" label="Authentication performed using local credentials"/> @@ -41688,6 +42471,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="55" label="IDC_CONTENT_CONTEXT_SPELLING_TOGGLE"/> <int value="56" label="IDC_SPELLCHECK_LANGUAGES_FIRST"/> <int value="57" label="IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE"/> + <int value="58" label="IDC_SPELLCHECK_SUGGESTION"/> </enum> <enum name="ResolutionCategory" type="int"> @@ -42122,6 +42906,14 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="10" label="SERVICE_UTILITY_SEMANTIC_CAPS_FAILED"/> </enum> +<enum name="ServiceWorkerDatabaseStatus" type="int"> + <int value="0" label="OK"/> + <int value="1" label="Not Found Error"/> + <int value="2" label="IO Error"/> + <int value="3" label="Corruption Error"/> + <int value="4" label="Operation Error"/> +</enum> + <enum name="SessionStartupPref" type="int"> <int value="0" label="Open home page (unused)"/> <int value="1" label="Continue from last opened pages"/> @@ -44034,6 +44826,12 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="2" label="Served from data URL"/> </enum> +<enum name="WebFontDiskCacheHit" type="int"> + <int value="0" label="Not in the cache"/> + <int value="1" label="In the cache"/> + <int value="2" label="Previously in the cache"/> +</enum> + <enum name="WebFontUsageType" type="int"> <int value="0" label="Styled, and used"/> <int value="1" label="Styled, but not used"/> @@ -45123,6 +45921,9 @@ Therefore, the affected-histogram name has to have at least one dot in it. <suffix name="CONNECTION_4G" label="mobile 4G are tallied."/> <suffix name="CONNECTION_NONE" label="NO(?) network are tallied (should be empty)."/> + <suffix name="CONNECTION_BLUETOOTH" + label="Bluetooth are tallied, but this may include connections to a + mobile hotspot."/> <affected-histogram name="Net.QuicSession.21CumulativePacketsReceived_First21"/> <affected-histogram @@ -46748,7 +47549,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. <affected-histogram name="Prerender.TimeUntilUsed2"/> </histogram_suffixes> -<histogram_suffixes name="Profile.DesktopMenu" separator="."> +<histogram_suffixes name="Profile.AndroidAccountManagementMenu" separator="."> <suffix name="NonGAIA" label="Interaction was not initiated from GAIA"/> <suffix name="GAIASignout" label="GAIA-initiated interaction indicating a service type of Signout"/> @@ -46763,6 +47564,24 @@ Therefore, the affected-histogram name has to have at least one dot in it. Reauthenticate this user"/> <suffix name="GAIADefault" label="GAIA-initiated interaction indicating the default service type"/> + <affected-histogram name="Profile.AndroidAccountManagementMenu"/> +</histogram_suffixes> + +<histogram_suffixes name="Profile.DesktopMenu" separator="."> + <suffix name="NonGAIA" label="Interaction was not initiated from GAIA"/> + <suffix name="GAIASignout" + label="GAIA-initiated interaction indicating a service type of Signout"/> + <suffix name="GAIAIncognito" + label="GAIA-initiated interaction indicating a service type of + Incogntio"/> + <suffix name="GAIAAddSession" + label="GAIA-initiated interaction indicating a service type of Add a + Session"/> + <suffix name="GAIAReAuth" + label="GAIA-initiated interaction indicating a service type of + Reauthenticate this user"/> + <suffix name="GAIADefault" + label="GAIA-initiated interaction indicating the default service type"/> <affected-histogram name="Profile.DesktopMenu"/> </histogram_suffixes> @@ -47183,6 +48002,15 @@ Therefore, the affected-histogram name has to have at least one dot in it. <affected-histogram name="Settings.TrackedSplitPreferenceChanged"/> </histogram_suffixes> +<histogram_suffixes name="WebFontFamily"> + <suffix name="roboto" label="Roboto font"/> + <suffix name="opensans" label="Open Sans font"/> + <suffix name="others" label="Fonts other than Roboto and Open Sans"/> + <affected-histogram name="WebFont.DiskCache.ReuseCount.Evict"/> + <affected-histogram name="WebFont.DiskCache.ReuseCount.Hit"/> + <affected-histogram name="WebFont.DiskCacheHit"/> +</histogram_suffixes> + <histogram_suffixes name="WebStoreLinkExperiment"> <suffix name="Disabled" label="Neither extra webstore link is visible"/> <suffix name="FooterLink" label="Link in bottom right of footer"/> diff --git a/tools/metrics/rappor/rappor.xml b/tools/metrics/rappor/rappor.xml new file mode 100644 index 0000000000..4d2651d62c --- /dev/null +++ b/tools/metrics/rappor/rappor.xml @@ -0,0 +1,39 @@ +<!-- +Copyright 2014 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<!-- +This file is used to generate a comprehensive list of Chrome rappor metrics +along with a detailed description for each histogram. See the design doc at +http://www.chromium.org/developers/design-documents/rappor +for a description of rappor metrics. + +TODO(holte): Add validation and pretty printing scripts. +--> + +<rappor-configuration> + +<!-- Rappor metric definitions --> + +<rappor-metrics> + +<rappor-metric name="Settings.HomePage2" type="ETLD_PLUS_ONE"> + <owner>holte@chromium.org</owner> + <summary> + The eTLD+1 of the prefs::kHomePage setting. Only recorded if the URL is + valid and prefs::kHomePageIsNewTabPage is false. + </summary> +</rappor-metric> + +<rappor-metric name="Extensions.PossibleAdInjection2" type="ETLD_PLUS_ONE"> + <owner>rdevlin.cronin@chromium.org</owner> + <summary> + The eTLD+1 of a URL that might be doing ad injection. + </summary> +</rappor-metric> + +</rappor-metrics> + +</rappor-configuration> diff --git a/tools/msan/blacklist.txt b/tools/msan/blacklist.txt index e38e1ed1f5..0d14c12999 100644 --- a/tools/msan/blacklist.txt +++ b/tools/msan/blacklist.txt @@ -14,12 +14,10 @@ fun:*MOZ_Z_deflate* fun:unpack_RGBA8888 fun:unpack_RGB888 -# http://crbug.com/363487 -fun:*WebCore*RenderLayerCompositor*updateIfNeeded* +# Bug in MSan, fixed in clang r210020. http://crbug.com/378909 +fun:*convolveVertically_SSE2* -# Fixed in clang r207227. -# http://code.google.com/p/memory-sanitizer/issues/detail?id=53 -fun:getc_unlocked - -# http://crbug.com/158510 -fun:_ZN7WebCore11RenderTable6layoutEv +# MSan issue, http://crbug.com/381233 +# (Both functions call __mm_maddubs_epi16()). +fun:*ProcessPixelPairHelper* +fun:*ProcessOnePixel* diff --git a/tools/perf/OWNERS b/tools/perf/OWNERS index 16b912ee91..af60bc01ae 100644 --- a/tools/perf/OWNERS +++ b/tools/perf/OWNERS @@ -5,7 +5,7 @@ ernstm@chromium.org hartmanng@chromium.org marja@chromium.org nduca@chromium.org -nednguyen@chromium.org +nednguyen@google.com qyearsley@chromium.org skyostil@chromium.org tonyg@chromium.org diff --git a/tools/perf/PRESUBMIT.py b/tools/perf/PRESUBMIT.py index 3b20bf6f83..2c269c882a 100644 --- a/tools/perf/PRESUBMIT.py +++ b/tools/perf/PRESUBMIT.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/benchmarks/benchmark_unittest.py b/tools/perf/benchmarks/benchmark_unittest.py index f1e0eef9dd..f1c356e742 100644 --- a/tools/perf/benchmarks/benchmark_unittest.py +++ b/tools/perf/benchmarks/benchmark_unittest.py @@ -22,7 +22,7 @@ def SmokeTestGenerator(benchmark): # In general you should @test.Disabled individual benchmarks that fail, # instead of this entire smoke test suite. # TODO(achuith): Multiple tests failing on CrOS. crbug.com/351114 - @test.Disabled('android', 'chromeos', 'win') + @test.Disabled('chromeos') def BenchmarkSmokeTest(self): # Only measure a single page so that this test cycles reasonably quickly. benchmark.options['pageset_repeat'] = 1 diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py index 2e17ca9eed..ae38e48ca1 100644 --- a/tools/perf/benchmarks/blink_perf.py +++ b/tools/perf/benchmarks/blink_perf.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/benchmarks/chrome_proxy.py b/tools/perf/benchmarks/chrome_proxy.py index 5c58709946..4414d24a97 100644 --- a/tools/perf/benchmarks/chrome_proxy.py +++ b/tools/perf/benchmarks/chrome_proxy.py @@ -4,12 +4,17 @@ from telemetry import test from measurements import chrome_proxy - +from page_sets.chrome_proxy import bypass +from page_sets.chrome_proxy import fallback_viaheader +from page_sets.chrome_proxy import safebrowsing +from page_sets.chrome_proxy import smoke +from page_sets.chrome_proxy import synthetic +from page_sets.chrome_proxy import top_20 class ChromeProxyLatency(test.Test): tag = 'latency' test = chrome_proxy.ChromeProxyLatency - page_set = 'page_sets/chrome_proxy/top_20.py' + page_set = top_20.Top20PageSet() options = {'pageset_repeat_iters': 2} def CustomizeBrowserOptions(self, options): @@ -19,22 +24,22 @@ class ChromeProxyLatency(test.Test): class ChromeProxyLatencyDirect(test.Test): tag = 'latency_direct' test = chrome_proxy.ChromeProxyLatency - page_set = 'page_sets/chrome_proxy/top_20.py' + page_set = top_20.Top20PageSet() options = {'pageset_repeat_iters': 2} class ChromeProxyLatencySynthetic(ChromeProxyLatency): - page_set = 'page_sets/chrome_proxy/synthetic.py' + page_set = synthetic.SyntheticPageSet() class ChromeProxyLatencySyntheticDirect(ChromeProxyLatencyDirect): - page_set = 'page_sets/chrome_proxy/synthetic.py' + page_set = synthetic.SyntheticPageSet() class ChromeProxyDataSaving(test.Test): tag = 'data_saving' test = chrome_proxy.ChromeProxyDataSaving - page_set = 'page_sets/chrome_proxy/top_20.py' + page_set = top_20.Top20PageSet() options = {'pageset_repeat_iters': 1} def CustomizeBrowserOptions(self, options): options.AppendExtraBrowserArgs('--enable-spdy-proxy-auth') @@ -44,48 +49,48 @@ class ChromeProxyDataSavingDirect(test.Test): tag = 'data_saving_direct' test = chrome_proxy.ChromeProxyDataSaving options = {'pageset_repeat_iters': 2} - page_set = 'page_sets/chrome_proxy/top_20.py' + page_set = top_20.Top20PageSet() class ChromeProxyDataSavingSynthetic(ChromeProxyDataSaving): - page_set = 'page_sets/chrome_proxy/synthetic.py' + page_set = synthetic.SyntheticPageSet() class ChromeProxyDataSavingSyntheticDirect(ChromeProxyDataSavingDirect): - page_set = 'page_sets/chrome_proxy/synthetic.py' + page_set = synthetic.SyntheticPageSet() class ChromeProxyHeaderValidation(test.Test): tag = 'header_validation' test = chrome_proxy.ChromeProxyHeaders - page_set = 'page_sets/chrome_proxy/top_20.py' + page_set = top_20.Top20PageSet() class ChromeProxyBypass(test.Test): tag = 'bypass' test = chrome_proxy.ChromeProxyBypass - page_set = 'page_sets/chrome_proxy/bypass.py' + page_set = bypass.BypassPageSet() class ChromeProxySafeBrowsing(test.Test): tag = 'safebrowsing' test = chrome_proxy.ChromeProxySafebrowsing - page_set = 'page_sets/chrome_proxy/safebrowsing.py' + page_set = safebrowsing.SafebrowsingPageSet() class ChromeProxyHTTPFallbackProbeURL(test.Test): tag = 'fallback-probe' test = chrome_proxy.ChromeProxyHTTPFallbackProbeURL - page_set = 'page_sets/chrome_proxy/synthetic.py' + page_set = synthetic.SyntheticPageSet() class ChromeProxyHTTPFallbackViaHeader(test.Test): tag = 'fallback-viaheader' test = chrome_proxy.ChromeProxyHTTPFallbackViaHeader - page_set = 'page_sets/chrome_proxy/fallback_viaheader.py' + page_set = fallback_viaheader.FallbackViaHeaderPageSet() class ChromeProxySmoke(test.Test): tag = 'smoke' test = chrome_proxy.ChromeProxySmoke - page_set = 'page_sets/chrome_proxy/smoke.py' + page_set = smoke.SmokePageSet() diff --git a/tools/perf/benchmarks/dom_perf.py b/tools/perf/benchmarks/dom_perf.py index a20a2542ef..b3d8735509 100644 --- a/tools/perf/benchmarks/dom_perf.py +++ b/tools/perf/benchmarks/dom_perf.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/benchmarks/doyouevenbench.py b/tools/perf/benchmarks/doyouevenbench.py deleted file mode 100644 index a4af53ad75..0000000000 --- a/tools/perf/benchmarks/doyouevenbench.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""DoYouEvenBench performance benchmark . - -DoYouEvenBench performance benchmark UI performance related to DOM using -popular JS frameworks. This benchmark uses http://todomvc.com and emulates user -actions: adding 100 todo items, completing them, and then deleting -them with Ember.js, Backbone.js, jQuery, and plain-old DOM. -""" - -import os - -from telemetry import test -from telemetry.page import page_measurement -from telemetry.page import page_set -from telemetry.value import scalar - - -class DoYouEvenBenchMeasurement(page_measurement.PageMeasurement): - - def MeasurePage(self, _, tab, results): - tab.WaitForDocumentReadyStateToBeComplete() - # Tests are ran 5 iteration, results are displayed in the form of HTML - # table. Each row represents timetaken in that iteration and adds rows for - # Arithmetic Mean and 95th Percentile. Total 7 rows in the results table. - tab.WaitForJavaScriptExpression( - 'document.getElementsByTagName("tr").length >= 7', 200) - # Parse results and result for each run including mean and 95th percentile. - js_results = """ function JsResults() { - var _result = {} - _rows = document.getElementsByTagName("tr"); - for(var i=0; i< _rows.length; i++) { - if (_rows[i].cells[0].innerText.indexOf("95th Percentile") == -1) { - _result[_rows[i].cells[0].innerText] = _rows[i].cells[1].innerText; - } - } - return _result; - }; JsResults();""" - results_log = tab.EvaluateJavaScript(js_results) - for name, value in results_log.iteritems(): - score = float(value.replace('ms', '').strip()) - # Add time taken for each iteration to run tests. - if name != 'Arithmetic Mean': - results.Add(name, 'ms', score, data_type='unimportant') - else: - results.AddSummaryValue(scalar.ScalarValue(None, name, 'ms', score)) - -class DoYouEvenBench(test.Test): - """DoYouEvenBench benchmark related to DOMs using JS frameworks.""" - test = DoYouEvenBenchMeasurement - - def CreatePageSet(self, options): - ps = page_set.PageSet( - file_path=os.path.abspath(__file__), - archive_data_file='../page_sets/data/doyouevenbench.json', - make_javascript_deterministic=False) - ps.AddPageWithDefaultRunNavigate( - 'https://trac.webkit.org/export/164157/trunk/' - 'PerformanceTests/DoYouEvenBench/Full.html') - return ps diff --git a/tools/perf/benchmarks/dromaeo.py b/tools/perf/benchmarks/dromaeo.py index eb47892e20..f608e32485 100644 --- a/tools/perf/benchmarks/dromaeo.py +++ b/tools/perf/benchmarks/dromaeo.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/benchmarks/image_decoding.py b/tools/perf/benchmarks/image_decoding.py index 7611f58631..bb1692a103 100644 --- a/tools/perf/benchmarks/image_decoding.py +++ b/tools/perf/benchmarks/image_decoding.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/benchmarks/jetstream.py b/tools/perf/benchmarks/jetstream.py new file mode 100644 index 0000000000..bd8b2bf9ce --- /dev/null +++ b/tools/perf/benchmarks/jetstream.py @@ -0,0 +1,83 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Runs Apple's JetStream benchmark. + +JetStream combines a variety of JavaScript benchmarks, covering a variety of +advanced workloads and programming techniques, and reports a single score that +balances them using geometric mean. + +Each benchmark measures a distinct workload, and no single optimization +technique is sufficient to speed up all benchmarks. Latency tests measure that +a web application can start up quickly, ramp up to peak performance quickly, +and run smoothly without interruptions. Throughput tests measure the sustained +peak performance of a web application, ignoring ramp-up time and spikes in +smoothness. Some benchmarks demonstrate tradeoffs, and aggressive or +specialized optimization for one benchmark might make another benchmark slower. +""" + +import json +import os + +from telemetry import test +from telemetry.page import page_measurement +from telemetry.page import page_set +from telemetry.util import statistics +from telemetry.value import scalar + + +class _JetstreamMeasurement(page_measurement.PageMeasurement): + def __init__(self): + super(_JetstreamMeasurement, self).__init__() + + def WillNavigateToPage(self, page, tab): + page.script_to_evaluate_on_commit = """ + var __results = []; + var __real_log = window.console.log; + window.console.log = function() { + __results.push(Array.prototype.join.call(arguments, ' ')); + __real_log.apply(this, arguments); + } + """ + + def MeasurePage(self, page, tab, results): + get_results_js = """ + (function() { + for (var i = 0; i < __results.length; i++) { + if (!__results[i].indexOf('Raw results: ')) return __results[i]; + } + return null; + })(); + """ + + tab.WaitForDocumentReadyStateToBeComplete() + tab.EvaluateJavaScript('JetStream.start()') + tab.WaitForJavaScriptExpression(get_results_js, 600) + + result = tab.EvaluateJavaScript(get_results_js) + result = json.loads(result.partition(': ')[2]) + + all_scores = [] + for k, v in result.iteritems(): + results.Add(k.replace('.', '_'), 'score', v['result'], + data_type='unimportant') + # Collect all test scores to compute geometric mean. + all_scores.extend(v['result']) + total = statistics.GeometricMean(all_scores) + results.AddSummaryValue( + scalar.ScalarValue(None, 'Score', 'score', total)) + + +@test.Disabled('android') # Crashes on GN. +@test.Disabled('xp') # Crashes on Win XP. See crbug.com/381742 for an example. +class Jetstream(test.Test): + test = _JetstreamMeasurement + + def CreatePageSet(self, options): + ps = page_set.PageSet( + archive_data_file='../page_sets/data/jetstream.json', + make_javascript_deterministic=False, + file_path=os.path.abspath(__file__)) + ps.AddPageWithDefaultRunNavigate('http://browserbench.org/JetStream/') + return ps diff --git a/tools/perf/benchmarks/jsgamebench.py b/tools/perf/benchmarks/jsgamebench.py index fbb9cbacbb..762e8ba496 100644 --- a/tools/perf/benchmarks/jsgamebench.py +++ b/tools/perf/benchmarks/jsgamebench.py @@ -1,8 +1,14 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -"""Runs Facebook's JSGameBench benchmark.""" +"""Runs Facebook's JSGameBench benchmark. + +As of May 14, 2014, JSGameBench is no longer maintained. See README.md: +https://github.com/facebookarchive/jsgamebench + +The benchmark is kept here for historical purposes but is disabled on the bots. +""" import os @@ -25,7 +31,7 @@ class _JsgamebenchMeasurement(page_measurement.PageMeasurement): results.Add('Score', 'score (bigger is better)', result) -@test.Disabled('linux') # crbug.com/365237 +@test.Disabled class Jsgamebench(test.Test): """Counts how many animating sprites can move around on the screen at once.""" test = _JsgamebenchMeasurement diff --git a/tools/perf/benchmarks/kraken.py b/tools/perf/benchmarks/kraken.py index 0401862cb0..4843115205 100644 --- a/tools/perf/benchmarks/kraken.py +++ b/tools/perf/benchmarks/kraken.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/benchmarks/memory.py b/tools/perf/benchmarks/memory.py index b009305f77..cc5e464f83 100644 --- a/tools/perf/benchmarks/memory.py +++ b/tools/perf/benchmarks/memory.py @@ -1,29 +1,33 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. from telemetry import test from measurements import memory +from page_sets import mobile_memory +from page_sets import top_25 +from page_sets import top_desktop_sites_2012Q3 +from page_sets import tough_dom_memory_cases @test.Disabled('android') # crbug.com/370977 class MemoryMobile(test.Test): test = memory.Memory - page_set = 'page_sets/mobile_memory.py' + page_set = mobile_memory.MobileMemoryPageSet() class MemoryTop25(test.Test): test = memory.Memory - page_set = 'page_sets/top_25.py' + page_set = top_25.Top25PageSet() class Reload2012Q3(test.Test): tag = 'reload' test = memory.Memory - page_set = 'page_sets/top_desktop_sites_2012Q3.py' + page_set = top_desktop_sites_2012Q3.Top2012Q3PageSet() @test.Disabled('android') # crbug.com/371153 class MemoryToughDomMemoryCases(test.Test): test = memory.Memory - page_set = 'page_sets/tough_dom_memory_cases.py' + page_set = tough_dom_memory_cases.ToughDomMemoryCasesPageSet() diff --git a/tools/perf/benchmarks/memory_pressure.py b/tools/perf/benchmarks/memory_pressure.py index e1e21812e1..f8f76bbc6c 100644 --- a/tools/perf/benchmarks/memory_pressure.py +++ b/tools/perf/benchmarks/memory_pressure.py @@ -5,6 +5,8 @@ from telemetry import test from measurements import memory_pressure + +@test.Disabled('android') # crbug.com/379561 class MemoryPressure(test.Test): test = memory_pressure.MemoryPressure page_set = 'page_sets/typical_25.py' diff --git a/tools/perf/benchmarks/octane.py b/tools/perf/benchmarks/octane.py index 4fc6a3e8d0..c53b63bce7 100644 --- a/tools/perf/benchmarks/octane.py +++ b/tools/perf/benchmarks/octane.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/benchmarks/page_cycler.py b/tools/perf/benchmarks/page_cycler.py index 1a62a89613..aafd5e961f 100644 --- a/tools/perf/benchmarks/page_cycler.py +++ b/tools/perf/benchmarks/page_cycler.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -36,7 +36,7 @@ class PageCyclerIntlHiRu(test.Test): options = {'pageset_repeat': 10} -@test.Disabled('win') # crbug.com/330909 +@test.Disabled('android', 'win') # crbug.com/379564, crbug.com/330909 class PageCyclerIntlJaZh(test.Test): test = page_cycler.PageCycler page_set = 'page_sets/intl_ja_zh.py' diff --git a/tools/perf/benchmarks/robohornet_pro.py b/tools/perf/benchmarks/robohornet_pro.py index f8a3e38eab..99f3dc43e7 100644 --- a/tools/perf/benchmarks/robohornet_pro.py +++ b/tools/perf/benchmarks/robohornet_pro.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/benchmarks/session_restore.py b/tools/perf/benchmarks/session_restore.py index a5f2a8ca90..98af7dd25e 100644 --- a/tools/perf/benchmarks/session_restore.py +++ b/tools/perf/benchmarks/session_restore.py @@ -2,13 +2,35 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import os +import tempfile + from measurements import session_restore +from measurements import session_restore_with_url +from profile_creators import small_profile_creator from telemetry import test +from telemetry.page import profile_generator + + +class _SessionRestoreTest(test.Test): + + @classmethod + def ProcessCommandLineArgs(cls, parser, args): + super(_SessionRestoreTest, cls).ProcessCommandLineArgs(parser, args) + profile_type = 'small_profile' + if not args.browser_options.profile_dir: + profile_dir = os.path.join(tempfile.gettempdir(), profile_type) + if not os.path.exists(profile_dir): + new_args = args.Copy() + new_args.pageset_repeat = 1 + new_args.output_dir = profile_dir + profile_generator.GenerateProfiles( + small_profile_creator.SmallProfileCreator, profile_type, new_args) + args.browser_options.profile_dir = os.path.join(profile_dir, profile_type) -# crbug.com/325479: Disabling this test for now since it never ran before. -@test.Disabled('android', 'linux') -class SessionRestoreColdTypical25(test.Test): +@test.Disabled('android') # crbug.com/325479 +class SessionRestoreColdTypical25(_SessionRestoreTest): tag = 'cold' test = session_restore.SessionRestore page_set = 'page_sets/typical_25.py' @@ -16,9 +38,30 @@ class SessionRestoreColdTypical25(test.Test): 'pageset_repeat': 5} -class SessionRestoreWarmTypical25(test.Test): +@test.Disabled('android') # crbug.com/325479 +class SessionRestoreWarmTypical25(_SessionRestoreTest): tag = 'warm' test = session_restore.SessionRestore page_set = 'page_sets/typical_25.py' options = {'warm': True, 'pageset_repeat': 20} + + +@test.Disabled('android') # crbug.com/325479 +class SessionRestoreWithUrlCold(_SessionRestoreTest): + """Measure Chrome cold session restore with startup URLs.""" + tag = 'cold' + test = session_restore_with_url.SessionRestoreWithUrl + page_set = 'page_sets/startup_pages.py' + options = {'cold': True, + 'pageset_repeat': 5} + + +@test.Disabled('android') # crbug.com/325479 +class SessionRestoreWithUrlWarm(_SessionRestoreTest): + """Measure Chrome warm session restore with startup URLs.""" + tag = 'warm' + test = session_restore_with_url.SessionRestoreWithUrl + page_set = 'page_sets/startup_pages.py' + options = {'warm': True, + 'pageset_repeat': 10} diff --git a/tools/perf/benchmarks/session_restore_with_url.py b/tools/perf/benchmarks/session_restore_with_url.py deleted file mode 100644 index d4914e7fca..0000000000 --- a/tools/perf/benchmarks/session_restore_with_url.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -from telemetry import test - -from measurements import session_restore_with_url - - -class SessionRestoreWithUrlCold(test.Test): - """Measure Chrome cold session restore with startup URLs.""" - tag = 'cold' - test = session_restore_with_url.SessionRestoreWithUrl - page_set = 'page_sets/startup_pages.py' - options = {'cold': True, - 'pageset_repeat': 5} - -class SessionRestoreWithUrlWarm(test.Test): - """Measure Chrome warm session restore with startup URLs.""" - tag = 'warm' - test = session_restore_with_url.SessionRestoreWithUrl - page_set = 'page_sets/startup_pages.py' - options = {'warm': True, - 'pageset_repeat': 10} - diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py index e98e6f1e29..078639e386 100644 --- a/tools/perf/benchmarks/smoothness.py +++ b/tools/perf/benchmarks/smoothness.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/benchmarks/spaceport.py b/tools/perf/benchmarks/spaceport.py index fa16a38247..cd4d773d35 100644 --- a/tools/perf/benchmarks/spaceport.py +++ b/tools/perf/benchmarks/spaceport.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/benchmarks/speedometer.py b/tools/perf/benchmarks/speedometer.py new file mode 100644 index 0000000000..260d55e91f --- /dev/null +++ b/tools/perf/benchmarks/speedometer.py @@ -0,0 +1,47 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Apple's Speedometer performance benchmark. + +Speedometer measures simulated user interactions in web applications. + +The current benchmark uses TodoMVC to simulate user actions for adding, +completing, and removing to-do items. Speedometer repeats the same actions using +DOM APIs - a core set of web platform APIs used extensively in web applications- +as well as six popular JavaScript frameworks: Ember.js, Backbone.js, jQuery, +AngularJS, React, and Flight. Many of these frameworks are used on the most +popular websites in the world, such as Facebook and Twitter. The performance of +these types of operations depends on the speed of the DOM APIs, the JavaScript +engine, CSS style resolution, layout, and other technologies. +""" + +import os + +from telemetry import test +from telemetry.page import page_measurement +from telemetry.page import page_set + + +class SpeedometerMeasurement(page_measurement.PageMeasurement): + + def MeasurePage(self, _, tab, results): + tab.WaitForDocumentReadyStateToBeComplete() + tab.ExecuteJavaScript('benchmarkClient.iterationCount = 10; startTest();') + tab.WaitForJavaScriptExpression( + 'benchmarkClient._finishedTestCount == benchmarkClient.testsCount', 600) + results.Add( + 'Total', 'ms', tab.EvaluateJavaScript('benchmarkClient._timeValues')) + + +@test.Disabled('android') # Times out +class Speedometer(test.Test): + test = SpeedometerMeasurement + + def CreatePageSet(self, options): + ps = page_set.PageSet( + file_path=os.path.abspath(__file__), + archive_data_file='../page_sets/data/speedometer.json', + make_javascript_deterministic=False) + ps.AddPageWithDefaultRunNavigate('http://browserbench.org/Speedometer/') + return ps diff --git a/tools/perf/benchmarks/sunspider.py b/tools/perf/benchmarks/sunspider.py index a7ce2b0e87..776eee2bef 100644 --- a/tools/perf/benchmarks/sunspider.py +++ b/tools/perf/benchmarks/sunspider.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import collections diff --git a/tools/perf/benchmarks/tab_switching.py b/tools/perf/benchmarks/tab_switching.py index d04cafe407..0a16fb6be8 100644 --- a/tools/perf/benchmarks/tab_switching.py +++ b/tools/perf/benchmarks/tab_switching.py @@ -11,11 +11,14 @@ class TabSwitchingTop10(test.Test): test = tab_switching.TabSwitching page_set = 'page_sets/top_10.py' + class TabSwitchingFiveBlankTabs(test.Test): test = tab_switching.TabSwitching page_set = 'page_sets/five_blank_pages.py' options = {'pageset_repeat': 10} + +@test.Disabled('android') # crbug.com/379561 class TabSwitchingToughEnergyCases(test.Test): test = tab_switching.TabSwitching page_set = 'page_sets/tough_energy_cases.py' diff --git a/tools/perf/benchmarks/thread_times.py b/tools/perf/benchmarks/thread_times.py index 06fb468b50..a2d97aa34e 100644 --- a/tools/perf/benchmarks/thread_times.py +++ b/tools/perf/benchmarks/thread_times.py @@ -7,7 +7,6 @@ from benchmarks import silk_flags from measurements import thread_times -@test.Disabled('android') # crbug.com/355952 class ThreadTimesKeySilkCases(test.Test): """Measures timeline metrics while performing smoothness action on key silk cases.""" @@ -16,7 +15,6 @@ class ThreadTimesKeySilkCases(test.Test): options = {"report_silk_results": True} -@test.Disabled('android') # crbug.com/355952 class ThreadTimesFastPathKeySilkCases(test.Test): """Measures timeline metrics while performing smoothness action on key silk cases using bleeding edge rendering fast paths.""" diff --git a/tools/perf/measurements/image_decoding.py b/tools/perf/measurements/image_decoding.py index 867459cdc8..7d89c4753c 100644 --- a/tools/perf/measurements/image_decoding.py +++ b/tools/perf/measurements/image_decoding.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/measurements/memory.py b/tools/perf/measurements/memory.py index 0ce01f0e23..cd40199c15 100644 --- a/tools/perf/measurements/memory.py +++ b/tools/perf/measurements/memory.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/measurements/page_cycler.py b/tools/perf/measurements/page_cycler.py index 37f9ab22ea..bb394b089b 100644 --- a/tools/perf/measurements/page_cycler.py +++ b/tools/perf/measurements/page_cycler.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/measurements/rasterize_and_record_micro.py b/tools/perf/measurements/rasterize_and_record_micro.py index 8728d1705c..d1182e1cce 100644 --- a/tools/perf/measurements/rasterize_and_record_micro.py +++ b/tools/perf/measurements/rasterize_and_record_micro.py @@ -11,7 +11,7 @@ from telemetry.page import page_test class RasterizeAndRecordMicro(page_measurement.PageMeasurement): def __init__(self): - super(RasterizeAndRecordMicro, self).__init__('', True) + super(RasterizeAndRecordMicro, self).__init__('') self._chrome_branch_number = None @classmethod diff --git a/tools/perf/measurements/session_restore.py b/tools/perf/measurements/session_restore.py index ff210b4f3b..46d4019da8 100644 --- a/tools/perf/measurements/session_restore.py +++ b/tools/perf/measurements/session_restore.py @@ -1,13 +1,16 @@ # Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. + import collections from measurements import startup from metrics import cpu +from metrics import histogram_util from metrics import startup_metric from telemetry.core import util + class SessionRestore(startup.Startup): """Performs a measurement of Chromium's Session restore performance. @@ -23,14 +26,20 @@ class SessionRestore(startup.Startup): def CustomizeBrowserOptions(self, options): super(SessionRestore, self).CustomizeBrowserOptions(options) + histogram_util.CustomizeBrowserOptions(options) options.AppendExtraBrowserArgs([ '--restore-last-session' ]) def TabForPage(self, page, browser): # Detect that the session restore has completed. - util.WaitFor(lambda: len(browser.tabs), 30) - return browser.tabs[0] + util.WaitFor(lambda: browser.tabs and + histogram_util.GetHistogramCount( + histogram_util.BROWSER_HISTOGRAM, + 'SessionRestore.AllTabsLoaded', + browser.foreground_tab), + 30) + return browser.foreground_tab def CanRunForPage(self, page): # No matter how many pages in the pageset, just perform one test iteration. @@ -59,7 +68,7 @@ class SessionRestore(startup.Startup): self._cpu_metric.Start(None, None) def MeasurePage(self, page, tab, results): - tab.browser.foreground_tab.WaitForDocumentReadyStateToBeComplete() + tab.WaitForDocumentReadyStateToBeComplete() # Record CPU usage from browser start to when the foreground page is loaded. self._cpu_metric.Stop(None, None) diff --git a/tools/perf/measurements/skpicture_printer.py b/tools/perf/measurements/skpicture_printer.py index 152d3ec8d8..de2a761e1d 100644 --- a/tools/perf/measurements/skpicture_printer.py +++ b/tools/perf/measurements/skpicture_printer.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import glob diff --git a/tools/perf/measurements/smoothness.py b/tools/perf/measurements/smoothness.py index 9ca784c733..48ab7b1ea3 100644 --- a/tools/perf/measurements/smoothness.py +++ b/tools/perf/measurements/smoothness.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/measurements/smoothness_controller.py b/tools/perf/measurements/smoothness_controller.py index fd38609fa0..0739a8d177 100644 --- a/tools/perf/measurements/smoothness_controller.py +++ b/tools/perf/measurements/smoothness_controller.py @@ -23,6 +23,7 @@ class SmoothnessController(object): def __init__(self): self._timeline_model = None self._tracing_timeline_data = None + self._interaction = None def Start(self, page, tab): custom_categories = ['webkit.console', 'benchmark'] @@ -32,12 +33,12 @@ class SmoothnessController(object): tab.browser.platform.StartRawDisplayFrameRateMeasurement() # Start the smooth marker for all smooth actions. runner = action_runner.ActionRunner(tab) - runner.BeginInteraction(RUN_SMOOTH_ACTIONS, [tir_module.IS_SMOOTH]) + self._interaction = runner.BeginInteraction( + RUN_SMOOTH_ACTIONS, is_smooth=True) def Stop(self, tab): # End the smooth marker for all smooth actions. - runner = action_runner.ActionRunner(tab) - runner.EndInteraction(RUN_SMOOTH_ACTIONS, [tir_module.IS_SMOOTH]) + self._interaction.End() # Stop tracing for smoothness metric. if tab.browser.platform.IsRawDisplayFrameRateSupported(): tab.browser.platform.StopRawDisplayFrameRateMeasurement() diff --git a/tools/perf/measurements/smoothness_unittest.py b/tools/perf/measurements/smoothness_unittest.py index 0aba865864..55cd39edb9 100644 --- a/tools/perf/measurements/smoothness_unittest.py +++ b/tools/perf/measurements/smoothness_unittest.py @@ -106,19 +106,12 @@ class SmoothnessUnitTest( self.assertEquals(len(mostly_smooth), 1) self.assertGreaterEqual(mostly_smooth[0].GetRepresentativeNumber(), 0) - mean_mouse_wheel_latency = results.FindAllPageSpecificValuesNamed( - 'mean_mouse_wheel_latency') - if mean_mouse_wheel_latency: - self.assertEquals(len(mean_mouse_wheel_latency), 1) + mean_input_event_latency = results.FindAllPageSpecificValuesNamed( + 'mean_input_event_latency') + if mean_input_event_latency: + self.assertEquals(len(mean_input_event_latency), 1) self.assertGreater( - mean_mouse_wheel_latency[0].GetRepresentativeNumber(), 0) - - mean_touch_scroll_latency = results.FindAllPageSpecificValuesNamed( - 'mean_touch_scroll_latency') - if mean_touch_scroll_latency: - self.assertEquals(len(mean_touch_scroll_latency), 1) - self.assertGreater( - mean_touch_scroll_latency[0].GetRepresentativeNumber(), 0) + mean_input_event_latency[0].GetRepresentativeNumber(), 0) def testSmoothnessForPageWithNoGesture(self): ps = self.CreateEmptyPageSet() diff --git a/tools/perf/measurements/timeline_controller.py b/tools/perf/measurements/timeline_controller.py index aa1c6bbab6..b34ec4fa39 100644 --- a/tools/perf/measurements/timeline_controller.py +++ b/tools/perf/measurements/timeline_controller.py @@ -19,6 +19,7 @@ class TimelineController(object): self._model = None self._renderer_process = None self._smooth_records = [] + self._interaction = None def Start(self, page, tab): """Starts gathering timeline data. @@ -37,12 +38,12 @@ class TimelineController(object): tab.browser.StartTracing(','.join(categories)) # Start the smooth marker for all actions. runner = action_runner.ActionRunner(tab) - runner.BeginInteraction(RUN_SMOOTH_ACTIONS, [tir_module.IS_SMOOTH]) + self._interaction = runner.BeginInteraction( + RUN_SMOOTH_ACTIONS, is_smooth=True) def Stop(self, tab): # End the smooth marker for all actions. - runner = action_runner.ActionRunner(tab) - runner.EndInteraction(RUN_SMOOTH_ACTIONS, [tir_module.IS_SMOOTH]) + self._interaction.End() # Stop tracing. timeline_data = tab.browser.StopTracing() self._model = TimelineModel(timeline_data) diff --git a/tools/perf/page_sets/PRESUBMIT.py b/tools/perf/page_sets/PRESUBMIT.py index 98623e7e32..0ad52734a4 100644 --- a/tools/perf/page_sets/PRESUBMIT.py +++ b/tools/perf/page_sets/PRESUBMIT.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/page_sets/__init__.py b/tools/perf/page_sets/__init__.py index 96196cffb2..efcc9c35d2 100644 --- a/tools/perf/page_sets/__init__.py +++ b/tools/perf/page_sets/__init__.py @@ -1,3 +1,3 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/perf/page_sets/calendar_forward_backward.py b/tools/perf/page_sets/calendar_forward_backward.py index 0e369a3b86..f4ca483ef4 100644 --- a/tools/perf/page_sets/calendar_forward_backward.py +++ b/tools/perf/page_sets/calendar_forward_backward.py @@ -32,16 +32,13 @@ class CalendarForwardBackwardPage(page_module.Page): 'condition': 'element', 'selector': 'div[class~="navForward"]' })) - action_runner.RunAction(JavascriptAction( - { - 'expression': ''' - (function() { - var elem = document.createElement('meta'); - elem.name='viewport'; - elem.content='initial-scale=1'; - document.body.appendChild(elem); - })();''' - })) + action_runner.ExecuteJavaScript(''' + (function() { + var elem = document.createElement('meta'); + elem.name='viewport'; + elem.content='initial-scale=1'; + document.body.appendChild(elem); + })();''') def RunEndure(self, action_runner): action_runner.RunAction(ClickElementAction( diff --git a/tools/perf/page_sets/data/doyouevenbench.json b/tools/perf/page_sets/data/jetstream.json index abb6ce3218..cc59cf6dc8 100644 --- a/tools/perf/page_sets/data/doyouevenbench.json +++ b/tools/perf/page_sets/data/jetstream.json @@ -1,8 +1,8 @@ { "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.", "archives": { - "doyouevenbench_000.wpr": [ - "https://trac.webkit.org/export/164157/trunk/PerformanceTests/DoYouEvenBench/Full.html" + "jetstream_000.wpr": [ + "http://browserbench.org/JetStream/" ] } }
\ No newline at end of file diff --git a/tools/perf/page_sets/data/jetstream_000.wpr.sha1 b/tools/perf/page_sets/data/jetstream_000.wpr.sha1 new file mode 100644 index 0000000000..c37a279f9b --- /dev/null +++ b/tools/perf/page_sets/data/jetstream_000.wpr.sha1 @@ -0,0 +1 @@ +1212f1ea3fc3e8e2f2a6694032e86fc036cad108
\ No newline at end of file diff --git a/tools/perf/page_sets/data/speedometer.json b/tools/perf/page_sets/data/speedometer.json new file mode 100644 index 0000000000..676d6ae3c4 --- /dev/null +++ b/tools/perf/page_sets/data/speedometer.json @@ -0,0 +1,8 @@ +{ + "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.", + "archives": { + "speedometer_000.wpr": [ + "http://browserbench.org/Speedometer/" + ] + } +}
\ No newline at end of file diff --git a/tools/perf/page_sets/data/speedometer_000.wpr.sha1 b/tools/perf/page_sets/data/speedometer_000.wpr.sha1 new file mode 100644 index 0000000000..53885253db --- /dev/null +++ b/tools/perf/page_sets/data/speedometer_000.wpr.sha1 @@ -0,0 +1 @@ +d9a5aa1403c33b623aafdcaa3be65a3edc568499
\ No newline at end of file diff --git a/tools/perf/page_sets/data/tough_compositor_cases.json b/tools/perf/page_sets/data/tough_compositor_cases.json index 0eda9eb4f1..f73567c9b6 100644 --- a/tools/perf/page_sets/data/tough_compositor_cases.json +++ b/tools/perf/page_sets/data/tough_compositor_cases.json @@ -1,14 +1,18 @@ { "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.", "archives": { - "tough_compositor_cases_000.wpr": [ + "tough_compositor_cases_001.wpr": [ "http://jsbin.com/pixavefe/1/quiet?CC_SCROLL_TEXT_ONLY", - "http://jsbin.com/wixadinu/1/quiet?JS_SCROLL_TEXT_ONLY", + "http://jsbin.com/wixadinu/2/quiet?JS_SCROLL_TEXT_ONLY", "http://jsbin.com/yakagevo/1/quiet?CC_SCROLL_200_LAYER_GRID", - "http://jsbin.com/jevibahi/1/quiet?JS_SCROLL_200_LAYER_GRID", + "http://jsbin.com/jevibahi/4/quiet?JS_SCROLL_200_LAYER_GRID", "http://jsbin.com/falefice/1/quiet?CC_POSTER_CIRCLE", "http://jsbin.com/giqafofe/1/quiet?JS_POSTER_CIRCLE", "http://jsbin.com/beqojupo/1/quiet?JS_FULL_SCREEN_INVALIDATION" + ], + "tough_compositor_cases_000.wpr": [ + "http://jsbin.com/wixadinu/1/quiet?JS_SCROLL_TEXT_ONLY", + "http://jsbin.com/jevibahi/1/quiet?JS_SCROLL_200_LAYER_GRID" ] } }
\ No newline at end of file diff --git a/tools/perf/page_sets/data/tough_compositor_cases_001.wpr.sha1 b/tools/perf/page_sets/data/tough_compositor_cases_001.wpr.sha1 new file mode 100644 index 0000000000..1b97dc81cb --- /dev/null +++ b/tools/perf/page_sets/data/tough_compositor_cases_001.wpr.sha1 @@ -0,0 +1 @@ +a39aa0f60060145e2a0a70693f6cea18551d7321
\ No newline at end of file diff --git a/tools/perf/page_sets/data/typical_25.json b/tools/perf/page_sets/data/typical_25.json index e038b6573f..4f619983b6 100644 --- a/tools/perf/page_sets/data/typical_25.json +++ b/tools/perf/page_sets/data/typical_25.json @@ -1,6 +1,9 @@ { "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.", "archives": { + "typical_25_001.wpr": [ + "http://www.nationalgeographic.com/" + ], "typical_25_000.wpr": [ "http://www.nick.com/games", "http://www.rei.com/", @@ -17,7 +20,6 @@ "http://www.imdb.com/title/tt0910970/", "http://www.flickr.com/search/?q=monkeys&f=hp", "http://money.cnn.com/", - "http://www.nationalgeographic.com/", "http://premierleague.com", "http://www.osubeavers.com/", "http://walgreens.com", @@ -29,4 +31,4 @@ "http://www.fda.gov" ] } -} +}
\ No newline at end of file diff --git a/tools/perf/page_sets/data/typical_25_001.wpr.sha1 b/tools/perf/page_sets/data/typical_25_001.wpr.sha1 new file mode 100644 index 0000000000..0676eca8f1 --- /dev/null +++ b/tools/perf/page_sets/data/typical_25_001.wpr.sha1 @@ -0,0 +1 @@ +17e3515c9a39dcf343c9fa2d914b3be4827c4254
\ No newline at end of file diff --git a/tools/perf/page_sets/gmail_compose_discard.py b/tools/perf/page_sets/gmail_compose_discard.py index 4bab258d45..264878ba90 100644 --- a/tools/perf/page_sets/gmail_compose_discard.py +++ b/tools/perf/page_sets/gmail_compose_discard.py @@ -29,18 +29,16 @@ class GmailComposeDiscardPage(page_module.Page): })) def ComposeClick(self, action_runner): - action_runner.RunAction(JavascriptAction({ - 'expression': ''' + action_runner.ExecuteJavaScript(''' var button=document.evaluate('//div[text()="COMPOSE"]', - document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null) + document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null) .singleNodeValue; var mousedownevent=new MouseEvent('mousedown',true,true,window,0,0,0,0,0, false,false,false,false,0,null); var mouseupevent=new MouseEvent('mouseup',true,true,window,0,0,0,0,0, false,false,false,false,0,null); button.dispatchEvent(mousedownevent); - button.dispatchEvent(mouseupevent);''' - })) + button.dispatchEvent(mouseupevent);''') def RunEndure(self, action_runner): action_runner.RunAction(WaitAction( diff --git a/tools/perf/page_sets/image_decoding_measurement.py b/tools/perf/page_sets/image_decoding_measurement.py index 7f7c19f129..7b8fe61623 100644 --- a/tools/perf/page_sets/image_decoding_measurement.py +++ b/tools/perf/page_sets/image_decoding_measurement.py @@ -16,10 +16,7 @@ class ImageDecodingMeasurementPage(page_module.Page): def RunNavigateSteps(self, action_runner): action_runner.NavigateToPage(self) - action_runner.RunAction(JavascriptAction( - { - 'expression': 'runBenchmark();' - })) + action_runner.ExecuteJavaScript('runBenchmark();') action_runner.RunAction(WaitAction( { 'javascript': 'isDone' diff --git a/tools/perf/page_sets/key_silk_cases.py b/tools/perf/page_sets/key_silk_cases.py index 4a1482988f..a55bb4de80 100644 --- a/tools/perf/page_sets/key_silk_cases.py +++ b/tools/perf/page_sets/key_silk_cases.py @@ -5,7 +5,6 @@ from telemetry.page.actions.all_page_actions import * from telemetry.page import page as page_module from telemetry.page import page_set as page_set_module -from telemetry.web_perf import timeline_interaction_record as tir_module class KeySilkCasesPage(page_module.Page): @@ -299,11 +298,11 @@ class Page16(KeySilkCasesPage): }''', 'speed': 5000 })) - action_runner.BeginInteraction('Wait', [tir_module.IS_SMOOTH]) + interaction = action_runner.BeginInteraction('Wait', is_smooth=True) action_runner.RunAction(WaitAction({ 'javascript': 'document.getElementsByClassName("message").length < 18' })) - action_runner.EndInteraction('Wait', [tir_module.IS_SMOOTH]) + interaction.End() def RunSmoothness(self, action_runner): self.SwipeToDismiss(action_runner) @@ -391,11 +390,11 @@ class Page19(KeySilkCasesPage): { 'selector': '#menu-button' })) - action_runner.BeginInteraction('Wait', [tir_module.IS_SMOOTH]) + interaction = action_runner.BeginInteraction('Wait', is_smooth=True) action_runner.RunAction(WaitAction({ 'javascript': 'document.getElementById("nav-drawer").active' })) - action_runner.EndInteraction('Wait', [tir_module.IS_SMOOTH]) + interaction.End() def RunNavigateSteps(self, action_runner): @@ -535,9 +534,9 @@ class Page23(KeySilkCasesPage): 'scroll_distance_function': 'function() { return window.innerHeight / 2; }' })) - action_runner.BeginInteraction('Wait', [tir_module.IS_SMOOTH]) + interaction = action_runner.BeginInteraction('Wait', is_smooth=True) action_runner.RunAction(WaitAction({'seconds' : 1})) - action_runner.EndInteraction('Wait', [tir_module.IS_SMOOTH]) + interaction.End() class Page24(KeySilkCasesPage): @@ -600,9 +599,9 @@ class Page25(KeySilkCasesPage): callback(document.getElementById(':f')); }''' })) - action_runner.BeginInteraction('Wait', [tir_module.IS_SMOOTH]) + interaction = action_runner.BeginInteraction('Wait', is_smooth=True) action_runner.RunAction(WaitAction({'seconds' : 1})) - action_runner.EndInteraction('Wait', [tir_module.IS_SMOOTH]) + interaction.End() class Page26(KeySilkCasesPage): diff --git a/tools/perf/page_sets/polymer.py b/tools/perf/page_sets/polymer.py index dc04c15ca6..84b57d330f 100644 --- a/tools/perf/page_sets/polymer.py +++ b/tools/perf/page_sets/polymer.py @@ -92,10 +92,8 @@ class PolymerShadowPage(PolymerPage): self.archive_data_file = 'data/polymer.json' def RunSmoothness(self, action_runner): - action_runner.RunAction(JavascriptAction( - { - 'expression': "document.getElementById('fab').scrollIntoView()" - })) + action_runner.ExecuteJavaScript( + "document.getElementById('fab').scrollIntoView()") action_runner.RunAction(WaitAction( { 'seconds': 5 @@ -105,12 +103,8 @@ class PolymerShadowPage(PolymerPage): def AnimateShadow(self, action_runner, eid): for i in range(1, 6): - action_runner.RunAction(JavascriptAction( - { - 'expression': ''' - document.getElementById("{0}").z = {1} - '''.format(eid, i) - })) + action_runner.ExecuteJavaScript( + 'document.getElementById("{0}").z = {1}'.format(eid, i)) action_runner.RunAction(WaitAction( { 'seconds': 1 diff --git a/tools/perf/page_sets/top_10.py b/tools/perf/page_sets/top_10.py index 34ffd1114b..0668d79116 100644 --- a/tools/perf/page_sets/top_10.py +++ b/tools/perf/page_sets/top_10.py @@ -49,12 +49,12 @@ class GoogleCalendar(SimpleScrollPage): def RunNavigateSteps(self, action_runner): super(GoogleCalendar, self).RunNavigateSteps(action_runner) - action_runner.RunAction(JavascriptAction( - { 'expression' : - '(function() { var elem = document.createElement("meta");' - 'elem.name="viewport";' - 'elem.content="initial-scale=1";' - 'document.body.appendChild(elem); })();'})) + action_runner.ExecuteJavaScript(''' + (function() { var elem = document.createElement("meta"); + elem.name="viewport"; + elem.content="initial-scale=1"; + document.body.appendChild(elem); + })();''') action_runner.RunAction(WaitAction({'seconds' : 2})) action_runner.RunAction(WaitAction({ 'condition' : 'element', 'selector' : 'div[class~="navForward"]'})) diff --git a/tools/perf/page_sets/top_25.py b/tools/perf/page_sets/top_25.py index 9fead4bf2f..a437eb04a0 100644 --- a/tools/perf/page_sets/top_25.py +++ b/tools/perf/page_sets/top_25.py @@ -205,16 +205,13 @@ class GoogleCalendarPage(Top25Page): 'condition': 'element', 'selector': 'div[class~="navForward"]' })) - action_runner.RunAction(JavascriptAction( - { - 'expression': ''' - (function() { - var elem = document.createElement('meta'); - elem.name='viewport'; - elem.content='initial-scale=1'; - document.body.appendChild(elem); - })();''' - })) + action_runner.ExecuteJavaScript(''' + (function() { + var elem = document.createElement('meta'); + elem.name='viewport'; + elem.content='initial-scale=1'; + document.body.appendChild(elem); + })();''') action_runner.RunAction(WaitAction( { 'seconds': 1 @@ -515,37 +512,17 @@ class BlogspotPage(Top25Page): })) def RunStressMemory(self, action_runner): - action_runner.RunAction(ClickElementAction( - { - 'text' : 'accessibility', - 'wait_until': { - 'condition': 'navigate' - } - })) + action_runner.RunAction(ClickElementAction({'text' : 'accessibility'})) + action_runner.WaitForNavigate() action_runner.RunAction(ScrollAction()) - action_runner.RunAction(ClickElementAction( - { - 'text' : 'advanced', - 'wait_until': { - 'condition': 'navigate' - } - })) + action_runner.RunAction(ClickElementAction({'text' : 'advanced'})) + action_runner.WaitForNavigate() action_runner.RunAction(ScrollAction()) - action_runner.RunAction(ClickElementAction( - { - 'text' : 'beginner', - 'wait_until': { - 'condition': 'navigate' - } - })) + action_runner.RunAction(ClickElementAction({'text' : 'beginner'})) + action_runner.WaitForNavigate() action_runner.RunAction(ScrollAction()) - action_runner.RunAction(ClickElementAction( - { - 'text' : 'Home', - 'wait_until': { - 'condition': 'navigate' - } - })) + action_runner.RunAction(ClickElementAction({'text' : 'Home'})) + action_runner.WaitForNavigate() class WordpressPage(Top25Page): @@ -572,30 +549,17 @@ class WordpressPage(Top25Page): def RunStressMemory(self, action_runner): action_runner.RunAction(ScrollAction()) action_runner.RunAction(ClickElementAction( - { - 'wait_until': { - 'condition': 'navigate' - }, - 'selector': + {'selector': # pylint: disable=C0301 'a[href="http://en.blog.wordpress.com/2012/08/30/new-themes-able-and-sight/"]' })) + action_runner.WaitForNavigate() action_runner.RunAction(ScrollAction()) - action_runner.RunAction(ClickElementAction( - { - 'text' : 'Features', - 'wait_until': { - 'condition': 'navigate' - } - })) + action_runner.RunAction(ClickElementAction({'text' : 'Features'})) + action_runner.WaitForNavigate() action_runner.RunAction(ScrollAction()) - action_runner.RunAction(ClickElementAction( - { - 'text' : 'News', - 'wait_until': { - 'condition': 'navigate' - } - })) + action_runner.RunAction(ClickElementAction({'text' : 'News'})) + action_runner.WaitForNavigate() action_runner.RunAction(ScrollAction()) @@ -619,48 +583,33 @@ class FacebookPage(Top25Page): })) def RunStressMemory(self, action_runner): - action_runner.RunAction(ClickElementAction( - { - 'text' : 'About', - 'wait_until': { - 'condition': 'navigate' - } - })) + action_runner.RunAction(ClickElementAction({'text' : 'About'})) + action_runner.WaitForNavigate() action_runner.RunAction(ClickElementAction( { 'text' : 'The Audacity of Hope', - 'wait_until': { - 'condition': 'navigate' - } })) + action_runner.WaitForNavigate() action_runner.RunAction(ClickElementAction( { 'text' : 'Back to Barack Obama\'s Timeline', - 'wait_until': { - 'condition': 'navigate' - } })) + action_runner.WaitForNavigate() action_runner.RunAction(ClickElementAction( { 'text' : 'About', - 'wait_until': { - 'condition': 'navigate' - } })) + action_runner.WaitForNavigate() action_runner.RunAction(ClickElementAction( { 'text' : 'Elected to U.S. Senate', - 'wait_until': { - 'condition': 'navigate' - } })) + action_runner.WaitForNavigate() action_runner.RunAction(ClickElementAction( { 'text' : 'Home', - 'wait_until': { - 'condition': 'navigate' - } })) + action_runner.WaitForNavigate() def RunSmoothness(self, action_runner): action_runner.RunAction(ScrollAction( diff --git a/tools/perf/page_sets/tough_compositor_cases.py b/tools/perf/page_sets/tough_compositor_cases.py index 9c08bafdba..b86e317d6e 100644 --- a/tools/perf/page_sets/tough_compositor_cases.py +++ b/tools/perf/page_sets/tough_compositor_cases.py @@ -39,7 +39,7 @@ class ToughCompositorWaitPage(ToughCompositorPage): def RunSmoothness(self, action_runner): # We scroll back and forth a few times to reduce noise in the tests. - action_runner.RunAction(WaitAction({'seconds': 10})) + action_runner.RunAction(WaitAction({'seconds': 8})) class ToughCompositorCasesPageSet(page_set_module.PageSet): @@ -56,11 +56,11 @@ class ToughCompositorCasesPageSet(page_set_module.PageSet): # Why: Baseline CC scrolling page. A long page with only text. """ 'http://jsbin.com/pixavefe/1/quiet?CC_SCROLL_TEXT_ONLY', # Why: Baseline JS scrolling page. A long page with only text. """ - 'http://jsbin.com/wixadinu/1/quiet?JS_SCROLL_TEXT_ONLY', + 'http://jsbin.com/wixadinu/2/quiet?JS_SCROLL_TEXT_ONLY', # Why: Scroll by a large number of CC layers """ 'http://jsbin.com/yakagevo/1/quiet?CC_SCROLL_200_LAYER_GRID', # Why: Scroll by a large number of JS layers """ - 'http://jsbin.com/jevibahi/1/quiet?JS_SCROLL_200_LAYER_GRID', + 'http://jsbin.com/jevibahi/4/quiet?JS_SCROLL_200_LAYER_GRID', ] wait_urls_list = [ diff --git a/tools/perf/page_sets/webrtc_cases.py b/tools/perf/page_sets/webrtc_cases.py index aac321cc66..54c8f48b4f 100644 --- a/tools/perf/page_sets/webrtc_cases.py +++ b/tools/perf/page_sets/webrtc_cases.py @@ -28,10 +28,7 @@ class Page1(WebrtcCasesPage): { 'seconds': 10 })) - action_runner.RunAction(JavascriptAction( - { - 'expression': 'checkForErrors();' - })) + action_runner.ExecuteJavaScript('checkForErrors();') class Page2(WebrtcCasesPage): diff --git a/tools/perf/profile_creators/__init__.py b/tools/perf/profile_creators/__init__.py index f1e2bf49a7..6220954c33 100644 --- a/tools/perf/profile_creators/__init__.py +++ b/tools/perf/profile_creators/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Generators for Chrome profiles for testing purposes.""" diff --git a/tools/perf/profile_creators/small_profile_creator.py b/tools/perf/profile_creators/small_profile_creator.py index b9c2de8157..90c21bb478 100644 --- a/tools/perf/profile_creators/small_profile_creator.py +++ b/tools/perf/profile_creators/small_profile_creator.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -32,6 +32,4 @@ class SmallProfileCreator(profile_creator.ProfileCreator): return browser.tabs.New() def MeasurePage(self, _, tab, results): - # Can't use WaitForDocumentReadyStateToBeComplete() here due to - # crbug.com/280750 . - tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() + tab.WaitForDocumentReadyStateToBeComplete() diff --git a/tools/perf/unit-info.json b/tools/perf/unit-info.json index 5ace7830ef..57a79a9d30 100644 --- a/tools/perf/unit-info.json +++ b/tools/perf/unit-info.json @@ -59,6 +59,10 @@ "improvement_direction": "up", "why": "Higher frequencies are faster." }, + "janks": { + "improvement_direction": "down", + "why": "Fewer janks is better." + }, "kb": { "improvement_direction": "down", "why": "Synonym for KB, used in memory and io metrics." diff --git a/tools/post_perf_builder_job.py b/tools/post_perf_builder_job.py index b1e4e857e1..00262c95e5 100644 --- a/tools/post_perf_builder_job.py +++ b/tools/post_perf_builder_job.py @@ -26,7 +26,7 @@ TRY_SERVER_URL = 'http://build.chromium.org/p/tryserver.chromium' # for posting build request to tryserver. BISECT_BUILDER_HOST = 'master4.golo.chromium.org' # 'try_job_port' on tryserver to post build request. -BISECT_BUILDER_PORT = '8328' +BISECT_BUILDER_PORT = 8328 # From buildbot.status.builder. @@ -234,25 +234,26 @@ def GetBuildStatus(build_num, bot_name, builder_host, builder_port): A tuple consists of build status (SUCCESS, FAILED or PENDING) and a link to build status page on the waterfall. """ - # Gets the buildbot url for the given host and port. - server_url = _GetBuildBotUrl(builder_host, builder_port) - buildbot_url = BUILDER_JSON_URL % {'server_url': server_url, - 'bot_name': bot_name, - 'build_num': build_num - } - build_data = _GetBuildData(buildbot_url) results_url = None - if build_data: - # Link to build on the buildbot showing status of build steps. - results_url = BUILDER_HTML_URL % {'server_url': server_url, - 'bot_name': bot_name, - 'build_num': build_num - } - if _IsBuildFailed(build_data): - return (FAILED, results_url) - - elif _IsBuildSuccessful(build_data): - return (OK, results_url) + if build_num: + # Gets the buildbot url for the given host and port. + server_url = _GetBuildBotUrl(builder_host, builder_port) + buildbot_url = BUILDER_JSON_URL % {'server_url': server_url, + 'bot_name': bot_name, + 'build_num': build_num + } + build_data = _GetBuildData(buildbot_url) + if build_data: + # Link to build on the buildbot showing status of build steps. + results_url = BUILDER_HTML_URL % {'server_url': server_url, + 'bot_name': bot_name, + 'build_num': build_num + } + if _IsBuildFailed(build_data): + return (FAILED, results_url) + + elif _IsBuildSuccessful(build_data): + return (OK, results_url) return (PENDING, results_url) diff --git a/tools/safely-roll-deps.py b/tools/safely-roll-deps.py index 0e75715c32..e37fde43ee 100755 --- a/tools/safely-roll-deps.py +++ b/tools/safely-roll-deps.py @@ -142,7 +142,7 @@ def main(): prnt_subprocess.check_output(['git', 'commit', '-m', commit_msg, 'DEPS']) prnt_subprocess.check_call(['git', 'diff', '--no-ext-diff', options.upstream]) - upload_cmd = ['git', 'cl', 'upload'] + upload_cmd = ['git', 'cl', 'upload', '--bypass-hooks'] if options.commit: upload_cmd.append('--use-commit-queue') if options.reviewers: diff --git a/tools/telemetry/PRESUBMIT.py b/tools/telemetry/PRESUBMIT.py index e7b66d64c9..52c88064f5 100644 --- a/tools/telemetry/PRESUBMIT.py +++ b/tools/telemetry/PRESUBMIT.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import os diff --git a/tools/telemetry/docs/telemetry.core.browser_finder.html b/tools/telemetry/docs/telemetry.core.browser_finder.html index 7ac001c2b8..f88a87955e 100644 --- a/tools/telemetry/docs/telemetry.core.browser_finder.html +++ b/tools/telemetry/docs/telemetry.core.browser_finder.html @@ -190,6 +190,6 @@ Raises:<br> <font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr> <tr><td bgcolor="#55aa55"><tt> </tt></td><td> </td> -<td width="100%"><strong>ALL_BROWSER_TYPES</strong> = ['exact', 'release', 'release_x64', 'debug', 'debug_x64', 'canary', 'content-shell-debug', 'content-shell-debug_x64', 'content-shell-release', 'content-shell-release_x64', 'system', 'android-chrome-beta', 'android-chrome-dev', 'android-chromium-testshell', 'android-jb-system-chrome', 'android-chrome-canary', 'android-chrome', 'android-webview', 'android-content-shell', 'cros-chrome', ...]<br> +<td width="100%"><strong>ALL_BROWSER_TYPES</strong> = ['exact', 'release', 'release_x64', 'debug', 'debug_x64', 'canary', 'content-shell-debug', 'content-shell-debug_x64', 'content-shell-release', 'content-shell-release_x64', 'system', 'android-chrome-beta', 'android-chrome-dev', 'android-chrome-shell', 'android-chromium-testshell', 'android-jb-system-chrome', 'android-chrome-canary', 'android-chrome', 'android-webview', 'android-content-shell', 'cros-chrome', ...]<br> <strong>BROWSER_FINDERS</strong> = [<module 'telemetry.core.backends.chrome.desktop_...core/backends/chrome/desktop_browser_finder.pyc'>, <module 'telemetry.core.backends.chrome.android_...core/backends/chrome/android_browser_finder.pyc'>, <module 'telemetry.core.backends.chrome.cros_bro...ry/core/backends/chrome/cros_browser_finder.pyc'>, <module 'telemetry.core.backends.webdriver.webdr.../webdriver/webdriver_desktop_browser_finder.pyc'>]</td></tr></table> -</body></html>
\ No newline at end of file +</body></html> diff --git a/tools/telemetry/examples/telemetry_perf_test.py b/tools/telemetry/examples/telemetry_perf_test.py index bb1d21a43b..6321911aef 100755 --- a/tools/telemetry/examples/telemetry_perf_test.py +++ b/tools/telemetry/examples/telemetry_perf_test.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/__init__.py b/tools/telemetry/telemetry/__init__.py index 4d3fdc0101..395ffe2f69 100644 --- a/tools/telemetry/telemetry/__init__.py +++ b/tools/telemetry/telemetry/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/__init__.py b/tools/telemetry/telemetry/core/__init__.py index 96196cffb2..efcc9c35d2 100644 --- a/tools/telemetry/telemetry/core/__init__.py +++ b/tools/telemetry/telemetry/core/__init__.py @@ -1,3 +1,3 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py b/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py index 33fd1fc31b..365a61db9f 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py +++ b/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py @@ -30,6 +30,10 @@ CHROME_PACKAGE_NAMES = { ['org.chromium.chrome.shell', android_browser_backend.ChromeShellBackendSettings, 'ChromeShell.apk'], + 'android-chrome-shell': + ['org.chromium.chrome.shell', + android_browser_backend.ChromeShellBackendSettings, + 'ChromeShell.apk'], 'android-webview': ['com.android.webview.chromium.shell', android_browser_backend.WebviewBackendSettings, @@ -220,13 +224,12 @@ def FindAllAvailableBrowsers(finder_options, logging=real_logging): if ret: logging.warn('Failed to taskset %d (%s)', pid, ret) - if not os.environ.get('BUILDBOT_BUILDERNAME'): - # Killing adbd before running tests has proven to make them less likely to - # flake out during the test. We skip this if Telemetry is running under a - # buildbot because build/android/test_runner.py wrapper already took care - # of it before starting the shards. - adb.RestartAdbdOnDevice() - adb.WaitForDevicePm() + if not os.environ.get('BUILDBOT_BUILDERNAME'): + # Killing adbd before running tests has proven to make them less likely to + # flake out during the test. We skip this if Telemetry is running under a + # buildbot because build/android/test_runner.py wrapper already took care + # of it before starting the shards. + adb.RestartAdbdOnDevice() packages = adb.RunShellCommand('pm list packages') possible_browsers = [] diff --git a/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py b/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py index 497ac73bcf..cc9d437806 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py +++ b/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py @@ -89,6 +89,15 @@ class ChromeBrowserBackend(browser_backend.BrowserBackend): args.append('--no-default-browser-check') args.append('--no-first-run') + # TODO(tonyg): Telemetry runs on release build bots which enable DCHECKs. + # While, we'd really like for Chrome to be DCHECK clean, pragmatically, it + # is far from it and the Telemetry unittests are hitting DCHECKS so often + # that the flakiness is becoming untenable. + # + # We should remove this as soon as we're ready to get serious about the + # DCHECK problem and keep Chrome clean. + args.append('--silent-dump-on-dcheck') + # Turn on GPU benchmarking extension for all runs. The only side effect of # the extension being on is that render stats are tracked. This is believed # to be effectively free. And, by doing so here, it avoids us having to diff --git a/tools/telemetry/telemetry/core/backends/chrome/cros_interface.py b/tools/telemetry/telemetry/core/backends/chrome/cros_interface.py index b5add7d4e9..890e0b15ce 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/cros_interface.py +++ b/tools/telemetry/telemetry/core/backends/chrome/cros_interface.py @@ -297,7 +297,8 @@ class CrOSInterface(object): """Returns the pid of the session_manager process, given the list of processes.""" for pid, process, _, _ in procs: - if process.startswith('/sbin/session_manager '): + argv = process.split() + if argv and os.path.basename(argv[0]) == 'session_manager': return pid return None diff --git a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py index bfbc687314..a9f1fa5186 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py +++ b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py @@ -7,6 +7,7 @@ import glob import heapq import logging import os +import os.path import shutil import subprocess as subprocess import sys @@ -74,6 +75,20 @@ class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend): logging.info("Using profile directory:'%s'." % profile_dir) shutil.rmtree(self._tmp_profile_dir) shutil.copytree(profile_dir, self._tmp_profile_dir) + if self.browser_options.use_devtools_active_port: + # No matter whether we're using an existing profile directory or + # creating a new one, always delete the well-known file containing + # the active DevTools port number. + port_file = self._GetDevToolsActivePortPath() + if os.path.isfile(port_file): + try: + os.remove(port_file) + except Exception as e: + logging.critical('Unable to remove DevToolsActivePort file: %s' % e) + sys.exit(1) + + def _GetDevToolsActivePortPath(self): + return os.path.join(self.profile_directory, 'DevToolsActivePort') def _GetCrashServicePipeName(self): # Ensure a unique pipe name by using the name of the temp dir. @@ -119,11 +134,27 @@ class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend): if not self.IsBrowserRunning(): raise exceptions.ProcessGoneException( "Return code: %d" % self._proc.returncode) + if self.browser_options.use_devtools_active_port: + # The Telemetry user selected the new code path to start DevTools on + # an ephemeral port. Wait for the well-known file containing the port + # number to exist. + port_file = self._GetDevToolsActivePortPath() + if not os.path.isfile(port_file): + # File isn't ready yet. Return false. Will retry. + return False + with open(port_file) as f: + port_string = f.read() + self._port = int(port_string) + logging.info('Discovered ephemeral port %s' % self._port) return super(DesktopBrowserBackend, self).HasBrowserFinishedLaunching() def GetBrowserStartupArgs(self): args = super(DesktopBrowserBackend, self).GetBrowserStartupArgs() - self._port = util.GetUnreservedAvailableLocalPort() + if self.browser_options.use_devtools_active_port: + self._port = 0 + else: + self._port = util.GetUnreservedAvailableLocalPort() + logging.info('Requested remote debugging port: %d' % self._port) args.append('--remote-debugging-port=%i' % self._port) args.append('--enable-crash-reporter-for-testing') args.append('--use-mock-keychain') diff --git a/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py b/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py index bd7680c073..5fe86c2091 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py +++ b/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py @@ -74,15 +74,11 @@ class InspectorBackend(inspector_websocket.InspectorWebsocket): @property def url(self): for c in self._browser_backend.ListInspectableContexts(): - if c['id'] == self.id: + if c['id'] == self._context['id']: return c['url'] return None @property - def id(self): - return self._context['id'] - - @property def debugger_url(self): return self._context['webSocketDebuggerUrl'] @@ -158,8 +154,8 @@ class InspectorBackend(inspector_websocket.InspectorWebsocket): # Page public methods. - def PerformActionAndWaitForNavigate(self, action_function, timeout): - self._page.PerformActionAndWaitForNavigate(action_function, timeout) + def WaitForNavigate(self, timeout): + self._page.WaitForNavigate(timeout) def Navigate(self, url, script_to_evaluate_on_commit, timeout): self._page.Navigate(url, script_to_evaluate_on_commit, timeout) diff --git a/tools/telemetry/telemetry/core/backends/chrome/inspector_page.py b/tools/telemetry/telemetry/core/backends/chrome/inspector_page.py index cd3a529de9..cd5d1a524e 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/inspector_page.py +++ b/tools/telemetry/telemetry/core/backends/chrome/inspector_page.py @@ -30,7 +30,7 @@ class InspectorPage(object): (not url == 'chrome://newtab/' and not url == 'about:blank' and not 'parentId' in msg['params']['frame'])): # Marks the navigation as complete and unblocks the - # PerformActionAndWaitForNavigate call. + # WaitForNavigate call. self._navigation_pending = False def _OnClose(self): @@ -70,16 +70,14 @@ class InspectorPage(object): res = self._inspector_backend.SyncRequest(request, timeout) assert len(res['result'].keys()) == 0 - def PerformActionAndWaitForNavigate(self, action_function, timeout=60): - """Executes action_function, and waits for the navigation to complete. + def WaitForNavigate(self, timeout=60): + """Waits for the navigation to complete. - action_function is expect to result in a navigation. This function returns + The current page is expect to be in a navigation. This function returns when the navigation is complete or when the timeout has been exceeded. """ start_time = time.time() remaining_time = timeout - - action_function() self._navigation_pending = True try: while self._navigation_pending and remaining_time > 0: @@ -99,17 +97,16 @@ class InspectorPage(object): the page exists, but before any script on the page itself has executed. """ - def DoNavigate(): - self._SetScriptToEvaluateOnCommit(script_to_evaluate_on_commit) - request = { - 'method': 'Page.navigate', - 'params': { - 'url': url, - } - } - self._inspector_backend.SyncRequest(request, timeout) + self._SetScriptToEvaluateOnCommit(script_to_evaluate_on_commit) + request = { + 'method': 'Page.navigate', + 'params': { + 'url': url, + } + } + self._inspector_backend.SyncRequest(request, timeout) self._navigation_url = url - self.PerformActionAndWaitForNavigate(DoNavigate, timeout) + self.WaitForNavigate(timeout) def GetCookieByName(self, name, timeout=60): """Returns the value of the cookie by the given |name|.""" diff --git a/tools/telemetry/telemetry/core/backends/chrome/inspector_page_unittest.py b/tools/telemetry/telemetry/core/backends/chrome/inspector_page_unittest.py index 0343920432..7408a092c6 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/inspector_page_unittest.py +++ b/tools/telemetry/telemetry/core/backends/chrome/inspector_page_unittest.py @@ -21,14 +21,9 @@ class InspectorPageTest(tab_test_case.TabTestCase): self._tab.EvaluateJavaScript('document.location.pathname;'), '/page_with_link.html') - custom_action_called = [False] - def CustomAction(): - custom_action_called[0] = True - self._tab.ExecuteJavaScript('document.getElementById("clickme").click();') + self._tab.ExecuteJavaScript('document.getElementById("clickme").click();') + self._tab.WaitForNavigate() - self._tab.PerformActionAndWaitForNavigate(CustomAction) - - self.assertTrue(custom_action_called[0]) self.assertEquals( self._tab.EvaluateJavaScript('document.location.pathname;'), '/blank.html') diff --git a/tools/telemetry/telemetry/core/backends/webdriver/webdriver_tab_backend.py b/tools/telemetry/telemetry/core/backends/webdriver/webdriver_tab_backend.py index c65f70b3cd..07f7d6bbf0 100644 --- a/tools/telemetry/telemetry/core/backends/webdriver/webdriver_tab_backend.py +++ b/tools/telemetry/telemetry/core/backends/webdriver/webdriver_tab_backend.py @@ -66,9 +66,8 @@ class WebDriverTabBackend(object): # Webdriver has no API for DOM status. raise NotImplementedError() - def PerformActionAndWaitForNavigate(self, action_function, _): - # TODO(chrisgao): Double check of navigation. - action_function() + def WaitForNavigate(self): + raise NotImplementedError() def Navigate(self, url, script_to_evaluate_on_commit=None, timeout=None): if script_to_evaluate_on_commit: diff --git a/tools/telemetry/telemetry/core/browser.py b/tools/telemetry/telemetry/core/browser.py index 39a18cfb30..b36c565c41 100644 --- a/tools/telemetry/telemetry/core/browser.py +++ b/tools/telemetry/telemetry/core/browser.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/browser_credentials.py b/tools/telemetry/telemetry/core/browser_credentials.py index 80fb181c54..607cd8a133 100644 --- a/tools/telemetry/telemetry/core/browser_credentials.py +++ b/tools/telemetry/telemetry/core/browser_credentials.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -12,6 +12,10 @@ from telemetry.core.backends import google_credentials_backend from telemetry.unittest import options_for_unittests +class CredentialsError(Exception): + """Error that can be thrown when logging in.""" + + class BrowserCredentials(object): def __init__(self, backends = None): self._credentials = {} @@ -33,19 +37,22 @@ class BrowserCredentials(object): def IsLoggedIn(self, credentials_type): if credentials_type not in self._backends: - raise Exception('Unrecognized credentials type: %s', credentials_type) + raise CredentialsError( + 'Unrecognized credentials type: %s', credentials_type) if credentials_type not in self._credentials: return False return self._backends[credentials_type].IsLoggedIn() def CanLogin(self, credentials_type): if credentials_type not in self._backends: - raise Exception('Unrecognized credentials type: %s', credentials_type) + raise CredentialsError( + 'Unrecognized credentials type: %s', credentials_type) return credentials_type in self._credentials def LoginNeeded(self, tab, credentials_type): if credentials_type not in self._backends: - raise Exception('Unrecognized credentials type: %s', credentials_type) + raise CredentialsError( + 'Unrecognized credentials type: %s', credentials_type) if credentials_type not in self._credentials: return False return self._backends[credentials_type].LoginNeeded( diff --git a/tools/telemetry/telemetry/core/browser_credentials_unittest.py b/tools/telemetry/telemetry/core/browser_credentials_unittest.py index cd77aed5d7..84bc39bcaa 100644 --- a/tools/telemetry/telemetry/core/browser_credentials_unittest.py +++ b/tools/telemetry/telemetry/core/browser_credentials_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import os diff --git a/tools/telemetry/telemetry/core/browser_finder.py b/tools/telemetry/telemetry/core/browser_finder.py index 9e30db2e4f..5103fae8eb 100644 --- a/tools/telemetry/telemetry/core/browser_finder.py +++ b/tools/telemetry/telemetry/core/browser_finder.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/browser_options.py b/tools/telemetry/telemetry/core/browser_options.py index aefaa7fa24..1a4514093e 100644 --- a/tools/telemetry/telemetry/core/browser_options.py +++ b/tools/telemetry/telemetry/core/browser_options.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -204,6 +204,11 @@ class BrowserOptions(object): self.platform = None + # Whether to use the new code path for choosing an ephemeral port for + # DevTools. The bots set this to true. When Chrome 37 reaches stable, + # remove this setting and the old code path. http://crbug.com/379980 + self.use_devtools_active_port = False + def __repr__(self): return str(sorted(self.__dict__.items())) @@ -244,6 +249,11 @@ class BrowserOptions(object): group.add_option('--show-stdout', action='store_true', help='When possible, will display the stdout of the process') + # This hidden option is to be removed, and the older code path deleted, + # once Chrome 37 reaches Stable. http://crbug.com/379980 + group.add_option('--use-devtools-active-port', + action='store_true', + help=optparse.SUPPRESS_HELP) parser.add_option_group(group) group = optparse.OptionGroup(parser, 'Compatibility options') @@ -274,6 +284,7 @@ class BrowserOptions(object): 'profile_type', 'show_stdout', 'synthetic_gesture_source_type', + 'use_devtools_active_port', ] for o in browser_options_list: a = getattr(finder_options, o, None) @@ -297,12 +308,17 @@ class BrowserOptions(object): self.dont_override_profile = True if self.profile_dir and self.profile_type != 'clean': - raise Exception("It's illegal to specify both --profile-type and" - " --profile-dir.") + logging.critical( + "It's illegal to specify both --profile-type and --profile-dir.\n" + "For more information see: http://goo.gl/ngdGD5") + sys.exit(1) if self.profile_dir and not os.path.isdir(self.profile_dir): - raise Exception("Directory specified by --profile-dir (%s) doesn't" - " exist or isn't a directory." % (self.profile_dir)) + logging.critical( + "Directory specified by --profile-dir (%s) doesn't exist " + "or isn't a directory.\n" + "For more information see: http://goo.gl/ngdGD5" % self.profile_dir) + sys.exit(1) if not self.profile_dir: self.profile_dir = profile_types.GetProfileDir(self.profile_type) diff --git a/tools/telemetry/telemetry/core/browser_options_unittest.py b/tools/telemetry/telemetry/core/browser_options_unittest.py index 8e5cb11de9..3d95c3638e 100644 --- a/tools/telemetry/telemetry/core/browser_options_unittest.py +++ b/tools/telemetry/telemetry/core/browser_options_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import optparse @@ -83,6 +83,13 @@ class BrowserOptionsTest(unittest.TestCase): self.assertEquals(options.browser_options.extra_browser_args, set(['--foo','--bar'])) + def testUseDevToolsActivePort(self): + options = browser_options.BrowserFinderOptions() + parser = options.CreateParser() + parser.parse_args(['--use-devtools-active-port']) + + self.assertEquals(options.browser_options.use_devtools_active_port, True) + def testMergeDefaultValues(self): options = browser_options.BrowserFinderOptions() options.already_true = True diff --git a/tools/telemetry/telemetry/core/browser_unittest.py b/tools/telemetry/telemetry/core/browser_unittest.py index 38f061ac3c..5d0fd66228 100644 --- a/tools/telemetry/telemetry/core/browser_unittest.py +++ b/tools/telemetry/telemetry/core/browser_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/discover.py b/tools/telemetry/telemetry/core/discover.py index c68dab81db..d815bdf99c 100644 --- a/tools/telemetry/telemetry/core/discover.py +++ b/tools/telemetry/telemetry/core/discover.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/discover_unittest.py b/tools/telemetry/telemetry/core/discover_unittest.py index 5de88ff19e..6937f20aca 100644 --- a/tools/telemetry/telemetry/core/discover_unittest.py +++ b/tools/telemetry/telemetry/core/discover_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import os diff --git a/tools/telemetry/telemetry/core/environment.py b/tools/telemetry/telemetry/core/environment.py index 284dba7194..04bafc8ed2 100644 --- a/tools/telemetry/telemetry/core/environment.py +++ b/tools/telemetry/telemetry/core/environment.py @@ -1,4 +1,4 @@ -# Copyright (c) 2014 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/exceptions.py b/tools/telemetry/telemetry/core/exceptions.py index 83ac24be60..671e2b8f1d 100644 --- a/tools/telemetry/telemetry/core/exceptions.py +++ b/tools/telemetry/telemetry/core/exceptions.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/extension_dict.py b/tools/telemetry/telemetry/core/extension_dict.py index 53e2d328d9..042651f331 100644 --- a/tools/telemetry/telemetry/core/extension_dict.py +++ b/tools/telemetry/telemetry/core/extension_dict.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/extension_page.py b/tools/telemetry/telemetry/core/extension_page.py index b76d7b8015..2f4c092d5a 100644 --- a/tools/telemetry/telemetry/core/extension_page.py +++ b/tools/telemetry/telemetry/core/extension_page.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/extension_to_load.py b/tools/telemetry/telemetry/core/extension_to_load.py index 85244db5b9..6549e8aa76 100644 --- a/tools/telemetry/telemetry/core/extension_to_load.py +++ b/tools/telemetry/telemetry/core/extension_to_load.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import os diff --git a/tools/telemetry/telemetry/core/extension_unittest.py b/tools/telemetry/telemetry/core/extension_unittest.py index 549836865f..23cac65334 100644 --- a/tools/telemetry/telemetry/core/extension_unittest.py +++ b/tools/telemetry/telemetry/core/extension_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/memory_cache_http_server.py b/tools/telemetry/telemetry/core/memory_cache_http_server.py index 9423a25dad..6aae8fd801 100644 --- a/tools/telemetry/telemetry/core/memory_cache_http_server.py +++ b/tools/telemetry/telemetry/core/memory_cache_http_server.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/platform/__init__.py b/tools/telemetry/telemetry/core/platform/__init__.py index b17abd9a1a..db7e7c299b 100644 --- a/tools/telemetry/telemetry/core/platform/__init__.py +++ b/tools/telemetry/telemetry/core/platform/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/platform/android_platform_backend.py b/tools/telemetry/telemetry/core/platform/android_platform_backend.py index a0e2642300..daef2e1e1b 100644 --- a/tools/telemetry/telemetry/core/platform/android_platform_backend.py +++ b/tools/telemetry/telemetry/core/platform/android_platform_backend.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/platform/cros_platform_backend.py b/tools/telemetry/telemetry/core/platform/cros_platform_backend.py index 81f5b002bd..e64c9f966c 100644 --- a/tools/telemetry/telemetry/core/platform/cros_platform_backend.py +++ b/tools/telemetry/telemetry/core/platform/cros_platform_backend.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/platform/linux_platform_backend.py b/tools/telemetry/telemetry/core/platform/linux_platform_backend.py index 679e56c45a..2be32c8c6c 100644 --- a/tools/telemetry/telemetry/core/platform/linux_platform_backend.py +++ b/tools/telemetry/telemetry/core/platform/linux_platform_backend.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/platform/mac_platform_backend.py b/tools/telemetry/telemetry/core/platform/mac_platform_backend.py index 7990176dac..04ac55fcc9 100644 --- a/tools/telemetry/telemetry/core/platform/mac_platform_backend.py +++ b/tools/telemetry/telemetry/core/platform/mac_platform_backend.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/platform/platform_backend.py b/tools/telemetry/telemetry/core/platform/platform_backend.py index fe68cb7481..e75973d148 100644 --- a/tools/telemetry/telemetry/core/platform/platform_backend.py +++ b/tools/telemetry/telemetry/core/platform/platform_backend.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/platform/profiler/__init__.py b/tools/telemetry/telemetry/core/platform/profiler/__init__.py index 806229e907..4f035a3a1a 100644 --- a/tools/telemetry/telemetry/core/platform/profiler/__init__.py +++ b/tools/telemetry/telemetry/core/platform/profiler/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/platform/profiler/iprofiler_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/iprofiler_profiler.py index f10e1e6eb6..77769f53cc 100644 --- a/tools/telemetry/telemetry/core/platform/profiler/iprofiler_profiler.py +++ b/tools/telemetry/telemetry/core/platform/profiler/iprofiler_profiler.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py index a02e84c2c5..48a46c2edc 100644 --- a/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py +++ b/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py index 53ff8af68d..4e0c9eae9f 100644 --- a/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py +++ b/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/platform/profiler/profiler_finder.py b/tools/telemetry/telemetry/core/platform/profiler/profiler_finder.py index d610fff8ec..ab95dc83de 100644 --- a/tools/telemetry/telemetry/core/platform/profiler/profiler_finder.py +++ b/tools/telemetry/telemetry/core/platform/profiler/profiler_finder.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/platform/profiler/sample_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/sample_profiler.py index a666ca975c..bc09c4f603 100644 --- a/tools/telemetry/telemetry/core/platform/profiler/sample_profiler.py +++ b/tools/telemetry/telemetry/core/platform/profiler/sample_profiler.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py index e04f65580c..ba494ea1e9 100644 --- a/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py +++ b/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/platform/win_platform_backend.py b/tools/telemetry/telemetry/core/platform/win_platform_backend.py index a6d28996c6..4597c40c7c 100644 --- a/tools/telemetry/telemetry/core/platform/win_platform_backend.py +++ b/tools/telemetry/telemetry/core/platform/win_platform_backend.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/possible_browser.py b/tools/telemetry/telemetry/core/possible_browser.py index 817ec9ab84..21d51e8b98 100644 --- a/tools/telemetry/telemetry/core/possible_browser.py +++ b/tools/telemetry/telemetry/core/possible_browser.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/profile_types.py b/tools/telemetry/telemetry/core/profile_types.py index 957fd92a21..f031b4783e 100644 --- a/tools/telemetry/telemetry/core/profile_types.py +++ b/tools/telemetry/telemetry/core/profile_types.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/profile_types_unittest.py b/tools/telemetry/telemetry/core/profile_types_unittest.py index 764e2f229f..9695ed0606 100644 --- a/tools/telemetry/telemetry/core/profile_types_unittest.py +++ b/tools/telemetry/telemetry/core/profile_types_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import unittest diff --git a/tools/telemetry/telemetry/core/tab.py b/tools/telemetry/telemetry/core/tab.py index 5e6138dedf..b6d6371a79 100644 --- a/tools/telemetry/telemetry/core/tab.py +++ b/tools/telemetry/telemetry/core/tab.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -109,7 +109,9 @@ class Tab(web_contents.WebContents): screen.style.zIndex = '2147483638'; document.body.appendChild(screen); requestAnimationFrame(function() { - window.__telemetry_screen_%d = screen; + requestAnimationFrame(function() { + window.__telemetry_screen_%d = screen; + }); }); })(); """ % (color.r, color.g, color.b, color.a, int(color))) @@ -122,7 +124,11 @@ class Tab(web_contents.WebContents): (function() { document.body.removeChild(window.__telemetry_screen_%d); requestAnimationFrame(function() { - window.__telemetry_screen_%d = null; + requestAnimationFrame(function() { + window.__telemetry_screen_%d = null; + console.time('__ClearHighlight.video_capture_start'); + console.timeEnd('__ClearHighlight.video_capture_start'); + }); }); })(); """ % (int(color), int(color))) @@ -231,16 +237,14 @@ class Tab(web_contents.WebContents): for timestamp, bmp in frame_generator: yield timestamp - start_time, bmp.Crop(*content_box) - def PerformActionAndWaitForNavigate( - self, action_function, timeout=DEFAULT_TAB_TIMEOUT): - """Executes action_function, and waits for the navigation to complete. + def WaitForNavigate(self, timeout=DEFAULT_TAB_TIMEOUT): + """Waits for the navigation to complete. - action_function must be a Python function that results in a navigation. + The current page is expect to be in a navigation. This function returns when the navigation is complete or when the timeout has been exceeded. """ - self._inspector_backend.PerformActionAndWaitForNavigate( - action_function, timeout) + self._inspector_backend.WaitForNavigate(timeout) def Navigate(self, url, script_to_evaluate_on_commit=None, timeout=DEFAULT_TAB_TIMEOUT): diff --git a/tools/telemetry/telemetry/core/tab_list.py b/tools/telemetry/telemetry/core/tab_list.py index 3e34bbb216..06cb667e1f 100644 --- a/tools/telemetry/telemetry/core/tab_list.py +++ b/tools/telemetry/telemetry/core/tab_list.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. class TabList(object): diff --git a/tools/telemetry/telemetry/core/tab_unittest.py b/tools/telemetry/telemetry/core/tab_unittest.py index 91bdb51f58..89eaddca0a 100644 --- a/tools/telemetry/telemetry/core/tab_unittest.py +++ b/tools/telemetry/telemetry/core/tab_unittest.py @@ -1,12 +1,15 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import logging from telemetry import test +from telemetry.core import bitmap from telemetry.core import util from telemetry.core import exceptions +from telemetry.core.backends.chrome import tracing_backend +from telemetry.core.timeline import model from telemetry.unittest import tab_test_case @@ -93,6 +96,21 @@ class TabTest(tab_test_case.TabTestCase): self.assertFalse(self._tab.is_video_capture_running) self._tab.browser._platform = original_platform + def testHighlight(self): + self.assertEquals(self._tab.url, 'about:blank') + self._browser.StartTracing(tracing_backend.DEFAULT_TRACE_CATEGORIES) + self._tab.Highlight(bitmap.WEB_PAGE_TEST_ORANGE) + self._tab.ClearHighlight(bitmap.WEB_PAGE_TEST_ORANGE) + trace_data = self._browser.StopTracing() + timeline_model = model.TimelineModel(trace_data) + renderer_thread = timeline_model.GetRendererThreadFromTab(self._tab) + found_video_start_event = False + for event in renderer_thread.async_slices: + if event.name == '__ClearHighlight.video_capture_start': + found_video_start_event = True + break + self.assertTrue(found_video_start_event) + class GpuTabTest(tab_test_case.TabTestCase): def setUp(self): diff --git a/tools/telemetry/telemetry/core/timeline/event.py b/tools/telemetry/telemetry/core/timeline/event.py index 874a89576e..1898c0a6c6 100644 --- a/tools/telemetry/telemetry/core/timeline/event.py +++ b/tools/telemetry/telemetry/core/timeline/event.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/timeline/event_unittest.py b/tools/telemetry/telemetry/core/timeline/event_unittest.py index d336a777b4..44aac65e89 100644 --- a/tools/telemetry/telemetry/core/timeline/event_unittest.py +++ b/tools/telemetry/telemetry/core/timeline/event_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/timeline/importer.py b/tools/telemetry/telemetry/core/timeline/importer.py index 3cb058b0c7..4a82ce53f8 100644 --- a/tools/telemetry/telemetry/core/timeline/importer.py +++ b/tools/telemetry/telemetry/core/timeline/importer.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/timeline/inspector_importer.py b/tools/telemetry/telemetry/core/timeline/inspector_importer.py index b0084113fc..c3f3aab32c 100644 --- a/tools/telemetry/telemetry/core/timeline/inspector_importer.py +++ b/tools/telemetry/telemetry/core/timeline/inspector_importer.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. '''Imports event data obtained from the inspector's timeline.''' diff --git a/tools/telemetry/telemetry/core/timeline/inspector_importer_unittest.py b/tools/telemetry/telemetry/core/timeline/inspector_importer_unittest.py index a9063dbb8d..49789bede7 100644 --- a/tools/telemetry/telemetry/core/timeline/inspector_importer_unittest.py +++ b/tools/telemetry/telemetry/core/timeline/inspector_importer_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import unittest diff --git a/tools/telemetry/telemetry/core/timeline/model.py b/tools/telemetry/telemetry/core/timeline/model.py index 113227b43b..8473a64ad1 100644 --- a/tools/telemetry/telemetry/core/timeline/model.py +++ b/tools/telemetry/telemetry/core/timeline/model.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. '''A container for timeline-based events and traces and can handle importing diff --git a/tools/telemetry/telemetry/core/timeline/model_unittest.py b/tools/telemetry/telemetry/core/timeline/model_unittest.py index 85537be453..009baa3086 100644 --- a/tools/telemetry/telemetry/core/timeline/model_unittest.py +++ b/tools/telemetry/telemetry/core/timeline/model_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2014 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/user_agent.py b/tools/telemetry/telemetry/core/user_agent.py index 811aca2bd7..4fa2f68043 100644 --- a/tools/telemetry/telemetry/core/user_agent.py +++ b/tools/telemetry/telemetry/core/user_agent.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/user_agent_unittest.py b/tools/telemetry/telemetry/core/user_agent_unittest.py index 32cbbb7056..74b662215e 100644 --- a/tools/telemetry/telemetry/core/user_agent_unittest.py +++ b/tools/telemetry/telemetry/core/user_agent_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/util.py b/tools/telemetry/telemetry/core/util.py index b982c16569..efeab5aa7f 100644 --- a/tools/telemetry/telemetry/core/util.py +++ b/tools/telemetry/telemetry/core/util.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import glob diff --git a/tools/telemetry/telemetry/core/util_unittest.py b/tools/telemetry/telemetry/core/util_unittest.py index 767ee43cd7..05df311add 100644 --- a/tools/telemetry/telemetry/core/util_unittest.py +++ b/tools/telemetry/telemetry/core/util_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import os diff --git a/tools/telemetry/telemetry/core/web_contents.py b/tools/telemetry/telemetry/core/web_contents.py index 4af1c8f14b..0b3594b259 100644 --- a/tools/telemetry/telemetry/core/web_contents.py +++ b/tools/telemetry/telemetry/core/web_contents.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/webpagereplay.py b/tools/telemetry/telemetry/core/webpagereplay.py index 71e1f35989..e290e44f32 100644 --- a/tools/telemetry/telemetry/core/webpagereplay.py +++ b/tools/telemetry/telemetry/core/webpagereplay.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/core/wpr_modes.py b/tools/telemetry/telemetry/core/wpr_modes.py index 64ffe08853..85a3dd0826 100644 --- a/tools/telemetry/telemetry/core/wpr_modes.py +++ b/tools/telemetry/telemetry/core/wpr_modes.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. WPR_OFF = 'wpr-off' diff --git a/tools/telemetry/telemetry/core/wpr_server.py b/tools/telemetry/telemetry/core/wpr_server.py index fb52e4c6e6..9e65b53b61 100644 --- a/tools/telemetry/telemetry/core/wpr_server.py +++ b/tools/telemetry/telemetry/core/wpr_server.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/__init__.py b/tools/telemetry/telemetry/page/__init__.py index 96196cffb2..efcc9c35d2 100644 --- a/tools/telemetry/telemetry/page/__init__.py +++ b/tools/telemetry/telemetry/page/__init__.py @@ -1,3 +1,3 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/actions/action_runner.py b/tools/telemetry/telemetry/page/actions/action_runner.py index c0847031ef..084b5ef4c3 100644 --- a/tools/telemetry/telemetry/page/actions/action_runner.py +++ b/tools/telemetry/telemetry/page/actions/action_runner.py @@ -1,49 +1,104 @@ # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. + +from telemetry.page.actions.javascript import JavaScriptAction from telemetry.page.actions.navigate import NavigateAction from telemetry.web_perf import timeline_interaction_record as tir_module class ActionRunner(object): + def __init__(self, tab): self._tab = tab - #TODO(nednguyen): remove this when crbug.com/361809 is marked fixed + # TODO(nednguyen): remove this (or make private) when + # crbug.com/361809 is marked fixed def RunAction(self, action): if not action.WillWaitAfterRun(): action.WillRunAction(self._tab) action.RunActionAndMaybeWait(self._tab) - def BeginInteraction(self, logical_name, flags): - """ Issues the begin of interaction record. - flags contains any flags in web_perf.timeline_interaction_record. - """ - assert self._tab - self._tab.ExecuteJavaScript('console.time("%s");' % - tir_module.TimelineInteractionRecord.GetJavascriptMarker(logical_name, - flags)) - - def EndInteraction(self, logical_name, flags): - """ Issues the begin of interaction record. - flags contains any flags in web_perf.timeline_interaction_record. + def BeginInteraction(self, label, is_smooth=False, is_responsive=False): + """Marks the beginning of an interaction record. + + An interaction record is a labeled time period containing + interaction that developers care about. Each set of metrics + specified in flags will be calculated for this time period.. The + End() method in the returned object must be called once to mark + the end of the timeline. + + Args: + label: A label for this particular interaction. This can be any + user-defined string, but must not contain '/'. + is_smooth: Whether to check for smoothness metrics for this interaction. + is_responsive: Whether to check for responsiveness metrics for + this interaction. """ - assert self._tab - self._tab.ExecuteJavaScript('console.timeEnd("%s");' % - tir_module.TimelineInteractionRecord.GetJavascriptMarker(logical_name, - flags)) + flags = [] + if is_smooth: + flags.append(tir_module.IS_SMOOTH) + if is_responsive: + flags.append(tir_module.IS_RESPONSIVE) + + interaction = Interaction(self._tab, label, flags) + interaction.Begin() + return interaction def NavigateToPage(self, page, timeout_seconds=None): - """ Navigate to page. - page is an instance of page.Page + """ Navigate to the given page. + + Args: + page: page is an instance of page.Page """ if page.is_file: target_side_url = self._tab.browser.http_server.UrlOf(page.file_path_url) else: target_side_url = page.url attributes = { - 'url': target_side_url , - 'script_to_evaluate_on_commit': page.script_to_evaluate_on_commit} + 'url': target_side_url, + 'script_to_evaluate_on_commit': page.script_to_evaluate_on_commit} if timeout_seconds: attributes['timeout_seconds'] = timeout_seconds self.RunAction(NavigateAction(attributes)) + + def WaitForNavigate(self, timeout_seconds=60): + self._tab.WaitForNavigate(timeout_seconds) + self._tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() + + def ExecuteJavaScript(self, js_expression): + """Executes a given JavaScript expression. + + Example: runner.ExecuteJavaScript('var foo = 1;'); + + Args: + js_expression: The expression to execute (provided as string). + """ + self.RunAction(JavaScriptAction({'expression': js_expression})) + + +class Interaction(object): + + def __init__(self, action_runner, label, flags): + assert action_runner + assert label + assert isinstance(flags, list) + + self._action_runner = action_runner + self._label = label + self._flags = flags + self._started = False + + def Begin(self): + assert not self._started + self._started = True + self._action_runner.ExecuteJavaScript('console.time("%s");' % + tir_module.TimelineInteractionRecord.GetJavaScriptMarker( + self._label, self._flags)) + + def End(self): + assert self._started + self._started = False + self._action_runner.ExecuteJavaScript('console.timeEnd("%s");' % + tir_module.TimelineInteractionRecord.GetJavaScriptMarker( + self._label, self._flags)) diff --git a/tools/telemetry/telemetry/page/actions/action_runner_unittest.py b/tools/telemetry/telemetry/page/actions/action_runner_unittest.py index ab33a19893..0920194cf2 100644 --- a/tools/telemetry/telemetry/page/actions/action_runner_unittest.py +++ b/tools/telemetry/telemetry/page/actions/action_runner_unittest.py @@ -1,6 +1,7 @@ # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. + from telemetry.core.backends.chrome import tracing_backend from telemetry.core.timeline import model from telemetry.page.actions import action_runner as action_runner_module @@ -16,8 +17,9 @@ class ActionRunnerTest(tab_test_case.TabTestCase): self.Navigate('interaction_enabled_page.html') action_runner.RunAction(WaitAction({'seconds': 1})) self._browser.StartTracing(tracing_backend.DEFAULT_TRACE_CATEGORIES) - action_runner.BeginInteraction('TestInteraction', [tir_module.IS_SMOOTH]) - action_runner.EndInteraction('TestInteraction', [tir_module.IS_SMOOTH]) + interaction = action_runner.BeginInteraction( + 'TestInteraction', is_smooth=True) + interaction.End() trace_data = self._browser.StopTracing() timeline_model = model.TimelineModel(trace_data) @@ -32,3 +34,22 @@ class ActionRunnerTest(tab_test_case.TabTestCase): ' Trace data:\n%s' % repr(trace_data.EventData())) self.assertEqual('TestInteraction', records[0].logical_name) self.assertTrue(records[0].is_smooth) + + def testExecuteJavaScript(self): + action_runner = action_runner_module.ActionRunner(self._tab) + self.Navigate('blank.html') + action_runner.ExecuteJavaScript('var testing = 42;') + self.assertEqual(42, self._tab.EvaluateJavaScript('testing')) + + def testWaitForNavigate(self): + self.Navigate('page_with_link.html') + action_runner = action_runner_module.ActionRunner(self._tab) + action_runner.RunAction(ClickElementAction({'xpath': 'id("clickme")'})) + action_runner.WaitForNavigate() + + self.assertTrue(self._tab.EvaluateJavaScript( + 'document.readyState == "interactive" || ' + 'document.readyState == "complete"')) + self.assertEquals( + self._tab.EvaluateJavaScript('document.location.pathname;'), + '/blank.html') diff --git a/tools/telemetry/telemetry/page/actions/all_page_actions.py b/tools/telemetry/telemetry/page/actions/all_page_actions.py index 25fd7cfca9..695e769d6b 100644 --- a/tools/telemetry/telemetry/page/actions/all_page_actions.py +++ b/tools/telemetry/telemetry/page/actions/all_page_actions.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import os @@ -11,7 +11,6 @@ from telemetry.page.actions import page_action # TODO(nednguyen): Remove all of these imports when we done porting all actions # to action_runner from telemetry.page.actions.interact import InteractAction -from telemetry.page.actions.javascript import JavascriptAction from telemetry.page.actions.javascript_click import ClickElementAction from telemetry.page.actions.js_collect_garbage import JsCollectGarbageAction from telemetry.page.actions.loop import LoopAction diff --git a/tools/telemetry/telemetry/page/actions/gesture_action.py b/tools/telemetry/telemetry/page/actions/gesture_action.py index 0bbd977a94..04503e5a53 100644 --- a/tools/telemetry/telemetry/page/actions/gesture_action.py +++ b/tools/telemetry/telemetry/page/actions/gesture_action.py @@ -6,7 +6,6 @@ from telemetry.page.actions import page_action from telemetry.page.actions import wait from telemetry import decorators from telemetry.page.actions import action_runner -from telemetry.web_perf import timeline_interaction_record as tir_module class GestureAction(page_action.PageAction): def __init__(self, attributes=None): @@ -29,15 +28,16 @@ class GestureAction(page_action.PageAction): else: interaction_name = 'Gesture_%s' % self.__class__.__name__ + interaction = None if self.automatically_record_interaction: - runner.BeginInteraction(interaction_name, [tir_module.IS_SMOOTH]) + interaction = runner.BeginInteraction(interaction_name, is_smooth=True) self.RunGesture(tab) if self.wait_action: self.wait_action.RunAction(tab) - if self.automatically_record_interaction: - runner.EndInteraction(interaction_name, [tir_module.IS_SMOOTH]) + if interaction is not None: + interaction.End() def RunGesture(self, tab): raise NotImplementedError() diff --git a/tools/telemetry/telemetry/page/actions/javascript.py b/tools/telemetry/telemetry/page/actions/javascript.py index 4bd8d6b367..8a0bb092f3 100644 --- a/tools/telemetry/telemetry/page/actions/javascript.py +++ b/tools/telemetry/telemetry/page/actions/javascript.py @@ -5,9 +5,9 @@ from telemetry.page.actions import page_action -class JavascriptAction(page_action.PageAction): +class JavaScriptAction(page_action.PageAction): def __init__(self, attributes=None): - super(JavascriptAction, self).__init__(attributes) + super(JavaScriptAction, self).__init__(attributes) def RunAction(self, tab): assert hasattr(self, 'expression') diff --git a/tools/telemetry/telemetry/page/actions/js_collect_garbage.py b/tools/telemetry/telemetry/page/actions/js_collect_garbage.py index 43aa72a0ba..bda2d7bed7 100644 --- a/tools/telemetry/telemetry/page/actions/js_collect_garbage.py +++ b/tools/telemetry/telemetry/page/actions/js_collect_garbage.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. from telemetry.page.actions import page_action diff --git a/tools/telemetry/telemetry/page/actions/page_action.py b/tools/telemetry/telemetry/page/actions/page_action.py index e7b95a801f..9388ca2e78 100644 --- a/tools/telemetry/telemetry/page/actions/page_action.py +++ b/tools/telemetry/telemetry/page/actions/page_action.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. from telemetry.page.actions import wait_until diff --git a/tools/telemetry/telemetry/page/actions/play.py b/tools/telemetry/telemetry/page/actions/play.py index c81c4336da..62a2c55a7c 100644 --- a/tools/telemetry/telemetry/page/actions/play.py +++ b/tools/telemetry/telemetry/page/actions/play.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/actions/reload.py b/tools/telemetry/telemetry/page/actions/reload.py index 09d5e4a4c9..fca82d998d 100644 --- a/tools/telemetry/telemetry/page/actions/reload.py +++ b/tools/telemetry/telemetry/page/actions/reload.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/actions/scroll.py b/tools/telemetry/telemetry/page/actions/scroll.py index 1d7aeb83a6..2f6dbd7169 100644 --- a/tools/telemetry/telemetry/page/actions/scroll.py +++ b/tools/telemetry/telemetry/page/actions/scroll.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import os diff --git a/tools/telemetry/telemetry/page/actions/scroll_unittest.py b/tools/telemetry/telemetry/page/actions/scroll_unittest.py index a60b089b60..82478cfc31 100644 --- a/tools/telemetry/telemetry/page/actions/scroll_unittest.py +++ b/tools/telemetry/telemetry/page/actions/scroll_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/actions/wait.py b/tools/telemetry/telemetry/page/actions/wait.py index ce1d86b73a..6ff37d8035 100644 --- a/tools/telemetry/telemetry/page/actions/wait.py +++ b/tools/telemetry/telemetry/page/actions/wait.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/actions/wait_unittest.py b/tools/telemetry/telemetry/page/actions/wait_unittest.py index 7278404c3e..1601bff2ee 100644 --- a/tools/telemetry/telemetry/page/actions/wait_unittest.py +++ b/tools/telemetry/telemetry/page/actions/wait_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/actions/wait_until.py b/tools/telemetry/telemetry/page/actions/wait_until.py index f50a810c66..e7ce56120c 100644 --- a/tools/telemetry/telemetry/page/actions/wait_until.py +++ b/tools/telemetry/telemetry/page/actions/wait_until.py @@ -13,13 +13,7 @@ class WaitUntil(object): self._previous_action = previous_action def RunActionAndWait(self, tab): - if getattr(self, 'condition', None) == 'navigate': - self._previous_action.WillRunAction(tab) - action_to_perform = lambda: self._previous_action.RunAction(tab) - tab.PerformActionAndWaitForNavigate(action_to_perform, self.timeout) - tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() - - elif getattr(self, 'condition', None) == 'href_change': + if getattr(self, 'condition', None) == 'href_change': self._previous_action.WillRunAction(tab) old_url = tab.EvaluateJavaScript('document.location.href') self._previous_action.RunAction(tab) diff --git a/tools/telemetry/telemetry/page/block_page_measurement_results.py b/tools/telemetry/telemetry/page/block_page_measurement_results.py index d92ae86c43..f1f865f5da 100644 --- a/tools/telemetry/telemetry/page/block_page_measurement_results.py +++ b/tools/telemetry/telemetry/page/block_page_measurement_results.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import os diff --git a/tools/telemetry/telemetry/page/block_page_measurement_results_unittest.py b/tools/telemetry/telemetry/page/block_page_measurement_results_unittest.py index 234aa01596..0536dd017c 100644 --- a/tools/telemetry/telemetry/page/block_page_measurement_results_unittest.py +++ b/tools/telemetry/telemetry/page/block_page_measurement_results_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import StringIO diff --git a/tools/telemetry/telemetry/page/buildbot_page_measurement_results.py b/tools/telemetry/telemetry/page/buildbot_page_measurement_results.py index 55147c4db8..f960f6a520 100644 --- a/tools/telemetry/telemetry/page/buildbot_page_measurement_results.py +++ b/tools/telemetry/telemetry/page/buildbot_page_measurement_results.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/buildbot_page_measurement_results_unittest.py b/tools/telemetry/telemetry/page/buildbot_page_measurement_results_unittest.py index 7593805d98..e5feb81757 100644 --- a/tools/telemetry/telemetry/page/buildbot_page_measurement_results_unittest.py +++ b/tools/telemetry/telemetry/page/buildbot_page_measurement_results_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import os diff --git a/tools/telemetry/telemetry/page/cloud_storage.py b/tools/telemetry/telemetry/page/cloud_storage.py index be7db6c70d..2c54785748 100644 --- a/tools/telemetry/telemetry/page/cloud_storage.py +++ b/tools/telemetry/telemetry/page/cloud_storage.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/csv_page_measurement_results.py b/tools/telemetry/telemetry/page/csv_page_measurement_results.py index fdbb812f83..56eac05c9c 100644 --- a/tools/telemetry/telemetry/page/csv_page_measurement_results.py +++ b/tools/telemetry/telemetry/page/csv_page_measurement_results.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import csv diff --git a/tools/telemetry/telemetry/page/csv_page_measurement_results_unittest.py b/tools/telemetry/telemetry/page/csv_page_measurement_results_unittest.py index 3891e57965..023eab4ff6 100644 --- a/tools/telemetry/telemetry/page/csv_page_measurement_results_unittest.py +++ b/tools/telemetry/telemetry/page/csv_page_measurement_results_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import StringIO diff --git a/tools/telemetry/telemetry/page/gtest_test_results.py b/tools/telemetry/telemetry/page/gtest_test_results.py index ada547431f..2bed68449e 100644 --- a/tools/telemetry/telemetry/page/gtest_test_results.py +++ b/tools/telemetry/telemetry/page/gtest_test_results.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/page.py b/tools/telemetry/telemetry/page/page.py index 58ced5e780..5ebce2242f 100644 --- a/tools/telemetry/telemetry/page/page.py +++ b/tools/telemetry/telemetry/page/page.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/page_filter.py b/tools/telemetry/telemetry/page/page_filter.py index c15c313fe3..ea009b5424 100644 --- a/tools/telemetry/telemetry/page/page_filter.py +++ b/tools/telemetry/telemetry/page/page_filter.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/page_measurement.py b/tools/telemetry/telemetry/page/page_measurement.py index 993897e1c2..967ecf5cae 100644 --- a/tools/telemetry/telemetry/page/page_measurement.py +++ b/tools/telemetry/telemetry/page/page_measurement.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/page_measurement_results.py b/tools/telemetry/telemetry/page/page_measurement_results.py index 028e2992e8..ee22b2fc69 100644 --- a/tools/telemetry/telemetry/page/page_measurement_results.py +++ b/tools/telemetry/telemetry/page/page_measurement_results.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/page_measurement_results_unittest.py b/tools/telemetry/telemetry/page/page_measurement_results_unittest.py index b5b35dfdd8..d30763e8e9 100644 --- a/tools/telemetry/telemetry/page/page_measurement_results_unittest.py +++ b/tools/telemetry/telemetry/page/page_measurement_results_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import os diff --git a/tools/telemetry/telemetry/page/page_measurement_unittest.py b/tools/telemetry/telemetry/page/page_measurement_unittest.py index e81f2f49ad..7134c9d683 100644 --- a/tools/telemetry/telemetry/page/page_measurement_unittest.py +++ b/tools/telemetry/telemetry/page/page_measurement_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/page_measurement_unittest_base.py b/tools/telemetry/telemetry/page/page_measurement_unittest_base.py index 76c98d1851..24ac840744 100644 --- a/tools/telemetry/telemetry/page/page_measurement_unittest_base.py +++ b/tools/telemetry/telemetry/page/page_measurement_unittest_base.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/page_runner.py b/tools/telemetry/telemetry/page/page_runner.py index 7a7a943c54..5df0d9ab43 100644 --- a/tools/telemetry/telemetry/page/page_runner.py +++ b/tools/telemetry/telemetry/page/page_runner.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/page_runner_unittest.py b/tools/telemetry/telemetry/page/page_runner_unittest.py index b39a308f32..14ea12f4f1 100644 --- a/tools/telemetry/telemetry/page/page_runner_unittest.py +++ b/tools/telemetry/telemetry/page/page_runner_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/page_set.py b/tools/telemetry/telemetry/page/page_set.py index d58f0aeaf4..2285b2958c 100644 --- a/tools/telemetry/telemetry/page/page_set.py +++ b/tools/telemetry/telemetry/page/page_set.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/page_set_archive_info.py b/tools/telemetry/telemetry/page/page_set_archive_info.py index ee235859e6..575f9e172e 100644 --- a/tools/telemetry/telemetry/page/page_set_archive_info.py +++ b/tools/telemetry/telemetry/page/page_set_archive_info.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/page_set_archive_info_unittest.py b/tools/telemetry/telemetry/page/page_set_archive_info_unittest.py index f94b76bd80..f060c74a85 100644 --- a/tools/telemetry/telemetry/page/page_set_archive_info_unittest.py +++ b/tools/telemetry/telemetry/page/page_set_archive_info_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import os diff --git a/tools/telemetry/telemetry/page/page_set_unittest.py b/tools/telemetry/telemetry/page/page_set_unittest.py index 0b5b4ea83e..cb08bc7644 100644 --- a/tools/telemetry/telemetry/page/page_set_unittest.py +++ b/tools/telemetry/telemetry/page/page_set_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/page_test.py b/tools/telemetry/telemetry/page/page_test.py index 4a8497b6e8..c952df1f34 100644 --- a/tools/telemetry/telemetry/page/page_test.py +++ b/tools/telemetry/telemetry/page/page_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/page_test_results.py b/tools/telemetry/telemetry/page/page_test_results.py index e909e7992b..dc653be582 100644 --- a/tools/telemetry/telemetry/page/page_test_results.py +++ b/tools/telemetry/telemetry/page/page_test_results.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/page_test_unittest.py b/tools/telemetry/telemetry/page/page_test_unittest.py index ff4c7316a4..56b4a6a458 100644 --- a/tools/telemetry/telemetry/page/page_test_unittest.py +++ b/tools/telemetry/telemetry/page/page_test_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/page_unittest.py b/tools/telemetry/telemetry/page/page_unittest.py index 61fabc07bd..fcb9ddcce8 100644 --- a/tools/telemetry/telemetry/page/page_unittest.py +++ b/tools/telemetry/telemetry/page/page_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/page/perf_tests_helper.py b/tools/telemetry/telemetry/page/perf_tests_helper.py index cf5744e32c..9c24287843 100644 --- a/tools/telemetry/telemetry/page/perf_tests_helper.py +++ b/tools/telemetry/telemetry/page/perf_tests_helper.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. from __future__ import absolute_import diff --git a/tools/telemetry/telemetry/page/record_wpr.py b/tools/telemetry/telemetry/page/record_wpr.py index a55b238570..07ab64bd4a 100755 --- a/tools/telemetry/telemetry/page/record_wpr.py +++ b/tools/telemetry/telemetry/page/record_wpr.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import logging @@ -41,6 +41,7 @@ class RecordPage(page_test.PageTest): # pylint: disable=W0223 """Override to ensure all resources are fetched from network.""" tab.ClearCache(force=False) if self.test: + self.test.options = self.options self.test.WillNavigateToPage(page, tab) def DidNavigateToPage(self, page, tab): @@ -49,20 +50,14 @@ class RecordPage(page_test.PageTest): # pylint: disable=W0223 self.test.DidNavigateToPage(page, tab) def RunPage(self, page, tab, results): - # When recording, sleep to catch any resources that load post-onload. tab.WaitForDocumentReadyStateToBeComplete() - if self.test: - dummy_results = page_measurement_results.PageMeasurementResults() - dummy_results.WillMeasurePage(page) - self.test.MeasurePage(page, tab, dummy_results) - dummy_results.DidMeasurePage() - else: - # TODO(tonyg): This should probably monitor resource timing for activity - # and sleep until 2s since the last network event with some timeout like - # 20s. We could wrap this up as WaitForNetworkIdle() and share with the - # speed index metric. - time.sleep(3) + # When recording, sleep to catch any resources that load post-onload. + # TODO(tonyg): This should probably monitor resource timing for activity + # and sleep until 2s since the last network event with some timeout like + # 20s. We could wrap this up as WaitForNetworkIdle() and share with the + # speed index metric. + time.sleep(3) # Run the actions for all measurements. Reload the page between # actions. @@ -80,6 +75,12 @@ class RecordPage(page_test.PageTest): # pylint: disable=W0223 self._RunMethod(page, action_name, action_runner) should_reload = True + # Run the PageTest's validator, so that we capture any additional resources + # that are loaded by the test. + if self.test: + dummy_results = page_measurement_results.PageMeasurementResults() + self.test.ValidatePage(page, tab, dummy_results) + def Main(base_dir): measurements = { diff --git a/tools/telemetry/telemetry/test.py b/tools/telemetry/telemetry/test.py index b23f43503b..5764776064 100644 --- a/tools/telemetry/telemetry/test.py +++ b/tools/telemetry/telemetry/test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -37,8 +37,14 @@ class Test(command_line.Command): name = cls.__module__.split('.')[-1] if hasattr(cls, 'tag'): name += '.' + cls.tag - if hasattr(cls, 'page_set'): - name += '.' + os.path.basename(os.path.splitext(cls.page_set)[0]) + page_set_name = None + if hasattr(cls, 'page_set') and isinstance(cls.page_set, page_set.PageSet): + page_set_name = os.path.basename( + os.path.splitext(cls.page_set.file_path)[0]) + elif hasattr(cls, 'page_set') and isinstance(cls.page_set, str): + page_set_name = os.path.basename(os.path.splitext(cls.page_set)[0]) + if page_set_name: + name += '.' + page_set_name return name @classmethod @@ -172,8 +178,15 @@ class Test(command_line.Command): """ if not hasattr(cls, 'page_set'): raise NotImplementedError('This test has no "page_set" attribute.') - return page_set.PageSet.FromFile( - file_path=os.path.join(util.GetBaseDir(), cls.page_set)) + + if isinstance(cls.page_set, str): + return page_set.PageSet.FromFile( + file_path=os.path.join(util.GetBaseDir(), cls.page_set)) + elif isinstance(cls.page_set, page_set.PageSet): + return cls.page_set + else: + raise TypeError('The page_set field of %s has unsupported type.' % + cls.Name) @classmethod def CreateExpectations(cls, ps): # pylint: disable=W0613 diff --git a/tools/telemetry/telemetry/test_runner.py b/tools/telemetry/telemetry/test_runner.py index 66b923bb19..95437c5b2f 100644 --- a/tools/telemetry/telemetry/test_runner.py +++ b/tools/telemetry/telemetry/test_runner.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -155,8 +155,8 @@ class Run(command_line.OptparseCommand): assert issubclass(test_class, test.Test), 'Trying to run a non-Test?!' - test_class.ProcessCommandLineArgs(parser, args) test.ProcessCommandLineArgs(parser, args) + test_class.ProcessCommandLineArgs(parser, args) cls._test = test_class diff --git a/tools/telemetry/telemetry/unittest/__init__.py b/tools/telemetry/telemetry/unittest/__init__.py index 950282d0c1..4d6aabb953 100644 --- a/tools/telemetry/telemetry/unittest/__init__.py +++ b/tools/telemetry/telemetry/unittest/__init__.py @@ -1,3 +1,3 @@ -# Copyright (c) 2014 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/unittest/gtest_testrunner.py b/tools/telemetry/telemetry/unittest/gtest_testrunner.py index b33bf6ebff..33191762e7 100755 --- a/tools/telemetry/telemetry/unittest/gtest_testrunner.py +++ b/tools/telemetry/telemetry/unittest/gtest_testrunner.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/unittest/options_for_unittests.py b/tools/telemetry/telemetry/unittest/options_for_unittests.py index 766a6413b9..fd87bdaf1f 100644 --- a/tools/telemetry/telemetry/unittest/options_for_unittests.py +++ b/tools/telemetry/telemetry/unittest/options_for_unittests.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/unittest/page_set_smoke_test.py b/tools/telemetry/telemetry/unittest/page_set_smoke_test.py index aa30415223..b5e22aed03 100644 --- a/tools/telemetry/telemetry/unittest/page_set_smoke_test.py +++ b/tools/telemetry/telemetry/unittest/page_set_smoke_test.py @@ -6,6 +6,7 @@ import logging import os import unittest +from telemetry.core import browser_credentials from telemetry.core import discover from telemetry.page import page_set as page_set_module from telemetry.page import page_set_archive_info @@ -13,35 +14,102 @@ from telemetry.page import page_set_archive_info class PageSetSmokeTest(unittest.TestCase): - def RunSmokeTest(self, page_sets_dir): - """ - Run smoke test on all page sets in page_sets_dir. Subclass of - PageSetSmokeTest is supposed to call this in some test method to run smoke - test. - """ - # Instantiate all page sets and verify that all URLs have an associated - # archive. - page_sets = discover.GetAllPageSetFilenames(page_sets_dir) - for page_set_path in page_sets: - page_set = page_set_module.PageSet.FromFile(page_set_path) + def CheckArchive(self, page_set): + """Verify that all URLs of pages in page_set have an associated archive. """ + # TODO: Eventually these should be fatal. + if not page_set.archive_data_file: + logging.warning('Skipping %s: no archive data file', page_set.file_path) + return + + logging.info('Testing %s', page_set.file_path) - # TODO: Eventually these should be fatal. - if not page_set.archive_data_file: - logging.warning('Skipping %s: no archive data file', page_set_path) + archive_data_file_path = os.path.join(page_set.base_dir, + page_set.archive_data_file) + self.assertTrue(os.path.exists(archive_data_file_path), + msg='Archive data file not found for %s' % + page_set.file_path) + + wpr_archive_info = page_set_archive_info.PageSetArchiveInfo.FromFile( + archive_data_file_path, ignore_archive=True) + for page in page_set.pages: + if not page.url.startswith('http'): continue + self.assertTrue(wpr_archive_info.WprFilePathForPage(page), + msg='No archive found for %s in %s' % ( + page.url, page_set.archive_data_file)) + + def CheckCredentials(self, page_set): + """Verify that all pages in page_set use proper credentials""" + credentials = browser_credentials.BrowserCredentials() + if page_set.credentials_path: + credentials.credentials_path = ( + os.path.join(page_set.base_dir, page_set.credentials_path)) + for page in page_set.pages: + fail_message = ('page %s of %s has invalid credentials %s' % + (page.url, page_set.file_path, page.credentials)) + if page.credentials: + try: + self.assertTrue(credentials.CanLogin(page.credentials), fail_message) + except browser_credentials.CredentialsError: + self.fail(fail_message) - logging.info('Testing %s', page_set_path) + def CheckTypes(self, page_set): + """Verify that page_set and its page's base attributes have the right types. + """ + self.CheckTypesOfPageSetBasicAttributes(page_set) + for page in page_set.pages: + self.CheckTypesOfPageBasicAttributes(page) - archive_data_file_path = os.path.join(page_set.base_dir, - page_set.archive_data_file) - self.assertTrue(os.path.exists(archive_data_file_path), - msg='Archive data file not found for %s' % page_set_path) + def CheckTypesOfPageSetBasicAttributes(self, page_set): + if page_set.file_path is not None: + self.assertTrue( + isinstance(page_set.file_path, str), + msg='page_set %\'s file_path must have type string') - wpr_archive_info = page_set_archive_info.PageSetArchiveInfo.FromFile( - archive_data_file_path, ignore_archive=True) - for page in page_set.pages: - if not page.url.startswith('http'): - continue - self.assertTrue(wpr_archive_info.WprFilePathForPage(page), - msg='No archive found for %s in %s' % ( - page.url, page_set.archive_data_file)) + self.assertTrue( + isinstance(page_set.description, str), + msg='page_set\'s description must have type string') + + self.assertTrue( + isinstance(page_set.archive_data_file, str), + msg='page_set\'s archive_data_file path must have type string') + + if page_set.user_agent_type is not None: + self.assertTrue( + isinstance(page_set.user_agent_type, str), + msg='page_set\'s user_agent_type must have type string') + + self.assertTrue( + isinstance(page_set.make_javascript_deterministic, bool), + msg='page_set\'s make_javascript_deterministic must have type bool') + + self.assertTrue( + isinstance(page_set.startup_url, str), + msg='page_set\'s startup_url must have type string') + + def CheckTypesOfPageBasicAttributes(self, page): + self.assertTrue( + isinstance(page.url, str), + msg='page %s \'s url must have type string' % page.display_name) + self.assertTrue( + isinstance(page.page_set, page_set_module.PageSet), + msg='page %s \'s page_set must be an instance of ' + 'telemetry.page.page_set.PageSet' % page.display_name) + self.assertTrue( + isinstance(page.name, str), + msg='page %s \'s name field must have type string' % page.display_name) + + def RunSmokeTest(self, page_sets_dir): + """Run smoke test on all page sets in page_sets_dir. + + Subclass of PageSetSmokeTest is supposed to call this in some test + method to run smoke test. + """ + page_sets = discover.GetAllPageSetFilenames(page_sets_dir) + + for page_set_path in page_sets: + page_set = page_set_module.PageSet.FromFile(page_set_path) + logging.info('Testing %s', page_set.file_path) + self.CheckArchive(page_set) + self.CheckCredentials(page_set) + self.CheckTypes(page_set) diff --git a/tools/telemetry/telemetry/unittest/run_tests.py b/tools/telemetry/telemetry/unittest/run_tests.py index ac5841f8c6..6ca96764cf 100644 --- a/tools/telemetry/telemetry/unittest/run_tests.py +++ b/tools/telemetry/telemetry/unittest/run_tests.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/unittest/simple_mock.py b/tools/telemetry/telemetry/unittest/simple_mock.py index 6d22ffd106..14ecf38bfc 100644 --- a/tools/telemetry/telemetry/unittest/simple_mock.py +++ b/tools/telemetry/telemetry/unittest/simple_mock.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """A very very simple mock object harness.""" diff --git a/tools/telemetry/telemetry/unittest/simple_mock_unittest.py b/tools/telemetry/telemetry/unittest/simple_mock_unittest.py index f62febc690..9102caa1b0 100644 --- a/tools/telemetry/telemetry/unittest/simple_mock_unittest.py +++ b/tools/telemetry/telemetry/unittest/simple_mock_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import unittest diff --git a/tools/telemetry/telemetry/unittest/system_stub.py b/tools/telemetry/telemetry/unittest/system_stub.py index c314bb30f8..879eaf9c09 100644 --- a/tools/telemetry/telemetry/unittest/system_stub.py +++ b/tools/telemetry/telemetry/unittest/system_stub.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/unittest/tab_test_case.py b/tools/telemetry/telemetry/unittest/tab_test_case.py index 1802dbe302..51fc2d1a1f 100644 --- a/tools/telemetry/telemetry/unittest/tab_test_case.py +++ b/tools/telemetry/telemetry/unittest/tab_test_case.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/web_components/__init__.py b/tools/telemetry/telemetry/web_components/__init__.py index db87381f93..31fb645580 100644 --- a/tools/telemetry/telemetry/web_components/__init__.py +++ b/tools/telemetry/telemetry/web_components/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2014 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Web components used by telemetry. diff --git a/tools/telemetry/telemetry/web_components/dev_server.py b/tools/telemetry/telemetry/web_components/dev_server.py index 895df7d126..516c95de59 100644 --- a/tools/telemetry/telemetry/web_components/dev_server.py +++ b/tools/telemetry/telemetry/web_components/dev_server.py @@ -1,4 +1,4 @@ -# Copyright (c) 2014 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/web_components/results_viewer.py b/tools/telemetry/telemetry/web_components/results_viewer.py index 6eddcac12b..3e4c80c1fa 100644 --- a/tools/telemetry/telemetry/web_components/results_viewer.py +++ b/tools/telemetry/telemetry/web_components/results_viewer.py @@ -1,4 +1,4 @@ -# Copyright (c) 2014 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/web_components/tvcm_stub.py b/tools/telemetry/telemetry/web_components/tvcm_stub.py index d19f633e3d..214d0f1c6a 100644 --- a/tools/telemetry/telemetry/web_components/tvcm_stub.py +++ b/tools/telemetry/telemetry/web_components/tvcm_stub.py @@ -1,4 +1,4 @@ -# Copyright (c) 2014 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/web_components/web_components_project.py b/tools/telemetry/telemetry/web_components/web_components_project.py index 572918629c..e7b0079a3b 100644 --- a/tools/telemetry/telemetry/web_components/web_components_project.py +++ b/tools/telemetry/telemetry/web_components/web_components_project.py @@ -1,4 +1,4 @@ -# Copyright (c) 2014 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/web_components/web_components_unittest.py b/tools/telemetry/telemetry/web_components/web_components_unittest.py index a43d5db0e6..52314da2a1 100644 --- a/tools/telemetry/telemetry/web_components/web_components_unittest.py +++ b/tools/telemetry/telemetry/web_components/web_components_unittest.py @@ -1,4 +1,4 @@ -# Copyright (c) 2014 The Chromium Authors. All rights reserved. +# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/telemetry/web_perf/metrics/mainthread_jank_stats.py b/tools/telemetry/telemetry/web_perf/metrics/mainthread_jank_stats.py new file mode 100644 index 0000000000..66a86a7052 --- /dev/null +++ b/tools/telemetry/telemetry/web_perf/metrics/mainthread_jank_stats.py @@ -0,0 +1,91 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + + +# A top level slice of a main thread can cause the webapp to behave +# unresponsively if its thread duration is greater than or equals to +# USER_PERCEIVABLE_DELAY_THRESHOLD_MS. Human eyes can perceive delay at low as +# 100ms, but since we use thread time instead of wall-time, we reduce the +# threshold further to 50ms to make room for other OS's activities. +USER_PERCEIVABLE_DELAY_THRESHOLD_MS = 50 + + +class _MainthreadJankStat(object): + """A small wrapper class for storing mainthread jank stats computed for + single record. + """ + + def __init__(self): + self.sum_big_top_slices_thread_time = 0 + self.biggest_top_slice_thread_time = 0 + + +def _ComputeMainthreadJankStatsForRecord(renderer_thread, record): + """Computes the mainthread jank stat on a record range. + + Returns: + An instance of _MainthreadJankStat, which has: + + sum_big_top_slices_thread_time is the total thread duration of all top + slices whose thread time ranges overlapped with (thread_start, thread_end) + and the overlapped thread duration is greater than or equal + USER_PERCEIVABLE_DELAY_THRESHOLD_MS. + + biggest_top_slice_thread_time is the biggest thread duration of all + top slices whose thread time ranges overlapped with + (thread_start, thread_end). + + Note: thread duration of each slices is computed using overlapped range + with (thread_start, thread_end). + """ + stat = _MainthreadJankStat() + for s in renderer_thread.toplevel_slices: + jank_thread_duration = record.GetOverlappedThreadTimeForSlice(s) + stat.biggest_top_slice_thread_time = max( + stat.biggest_top_slice_thread_time, jank_thread_duration) + if jank_thread_duration >= USER_PERCEIVABLE_DELAY_THRESHOLD_MS: + stat.sum_big_top_slices_thread_time += jank_thread_duration + return stat + + +class MainthreadJankStats(object): + """ + Utility class for extracting main thread jank statistics from the timeline + (or other loggin facilities), and providing them in a common format to + classes that compute benchmark metrics from this data. + + total_big_jank_thread_time is the total thread duration of all top + slices whose thread time ranges overlapped with any thread time ranges of + the records and the overlapped thread duration is greater than or equal + USER_PERCEIVABLE_DELAY_THRESHOLD_MS. + + biggest_jank_thread_time is the biggest thread duration of all + top slices whose thread time ranges overlapped with any of records' thread + time ranges. + """ + + def __init__(self, renderer_thread, interaction_records): + self._renderer_thread = renderer_thread + self._interaction_records = interaction_records + self._total_big_jank_thread_time = 0 + self._biggest_jank_thread_time = 0 + self._ComputeMainthreadJankStats() + + @property + def total_big_jank_thread_time(self): + return self._total_big_jank_thread_time + + @property + def biggest_jank_thread_time(self): + return self._biggest_jank_thread_time + + def _ComputeMainthreadJankStats(self): + for record in self._interaction_records: + record_jank_stat = _ComputeMainthreadJankStatsForRecord( + self._renderer_thread, record) + self._total_big_jank_thread_time += ( + record_jank_stat.sum_big_top_slices_thread_time) + self._biggest_jank_thread_time = ( + max(self._biggest_jank_thread_time, + record_jank_stat.biggest_top_slice_thread_time)) diff --git a/tools/telemetry/telemetry/web_perf/metrics/mainthread_jank_stats_unittest.py b/tools/telemetry/telemetry/web_perf/metrics/mainthread_jank_stats_unittest.py new file mode 100644 index 0000000000..b1cbca0154 --- /dev/null +++ b/tools/telemetry/telemetry/web_perf/metrics/mainthread_jank_stats_unittest.py @@ -0,0 +1,118 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import unittest + +from telemetry.core.timeline import model as model_module +from telemetry.core.timeline import async_slice +from telemetry.web_perf import timeline_interaction_record as tir_module +from telemetry.web_perf.metrics import mainthread_jank_stats + + +class MainthreadJankTests(unittest.TestCase): + + def CreateTestRecord(self, name, start, end, thread_start, thread_end, + parent_thread): + s = async_slice.AsyncSlice( + 'cat', 'Interaction.%s/is_responsive' % name, + timestamp=start, duration=end - start, start_thread=parent_thread, + end_thread=parent_thread, thread_start=thread_start, + thread_duration=thread_end - thread_start) + return tir_module.TimelineInteractionRecord.FromAsyncEvent(s) + + def testComputeMainthreadJankStatsForRecord(self): + # The slice hierarchy should look something like this: + # [ MessageLoop::RunTask ] [MessageLoop::RunTask][ MessagLoop::RunTask ] + # [ foo ] [ bar ] + # | | + # 200ms 800ms + # (thread_start) (thread_end) + # + # Note: all timings mentioned here and in comments below are thread time. + + model = model_module.TimelineModel() + renderer_main = model.GetOrCreateProcess(1).GetOrCreateThread(2) + renderer_main.name = 'CrRendererMain' + + # [ MessageLoop::RunTask ] + # 100ms 300ms + renderer_main.BeginSlice('toplevel', 'MessageLoop::RunTask', 112, 100) + renderer_main.EndSlice(240, 300) + + # [ MessageLoop::RunTask ] + # 450ms [ foo ] 475 ms + # 460ms 470ms + renderer_main.BeginSlice('toplevel', 'MessageLoop::RunTask', 462, 450) + renderer_main.BeginSlice('otherlevel', 'foo', 468, 460) + renderer_main.EndSlice(475, 470) + renderer_main.EndSlice(620, 475) + + # [ MessageLoop::RunTask ] + # 620ms [ bar ] 900ms + # 750ms 850ms + renderer_main.BeginSlice('toplevel', 'MessageLoop::RunTask', 652, 620) + renderer_main.BeginSlice('otherlevel', 'bar', 785, 750) + renderer_main.EndSlice(875, 850) + renderer_main.EndSlice(1040, 900) + + model.FinalizeImport(shift_world_to_zero=False) + + # Make a record that starts at 200ms and ends at 800ms in thread time + record = self.CreateTestRecord('test', 100, 700, 200, 800, renderer_main) + # pylint: disable=W0212 + stat = mainthread_jank_stats._ComputeMainthreadJankStatsForRecord( + renderer_main, record) + + # The overlapped between thread time range(200ms -> 800ms) + # with the first top slice (100ms -> 300ms) is 300 - 200 = 100ms, + # with the second slice (450ms -> 475ms) is 475 - 450 = 25 ms, + # with the third slice (620ms -> 900ms) is 800 - 620 = 180 ms. + # + # Hence we have 2 big top slices which overlapped duration > 50ms, + # the biggest top slice is 180ms, and the total big top slice's thread time + # is 100 + 180 = 280ms. + self.assertEquals(180, stat.biggest_top_slice_thread_time) + self.assertEquals(280, stat.sum_big_top_slices_thread_time) + + def testMainthreadJankStats(self): + # [ MessageLoop::RunTask] [MessageLoop::RunTask] [MessagLoop::RunTask] + # 10 100 120 400 450 750 + # [ record_1 ] [ record_2 ] [ record_3 ] + # 40 70 120 200 220 900 + + model = model_module.TimelineModel() + renderer_main = model.GetOrCreateProcess(1).GetOrCreateThread(2) + renderer_main.name = 'CrRendererMain' + + # [ MessageLoop::RunTask ] + # 10ms 100ms + renderer_main.BeginSlice('toplevel', 'MessageLoop::RunTask', 12, 10) + renderer_main.EndSlice(120, 100) + + # [ MessageLoop::RunTask ] + # 120ms 200ms + renderer_main.BeginSlice('toplevel', 'MessageLoop::RunTask', 115, 120) + renderer_main.EndSlice(410, 400) + + # [ MessageLoop::RunTask ] + # 220ms 900ms + renderer_main.BeginSlice('toplevel', 'MessageLoop::RunTask', 477, 450) + renderer_main.EndSlice(772, 750) + + model.FinalizeImport(shift_world_to_zero=False) + + test_records = [ + self.CreateTestRecord('record_1', 10, 80, 40, 70, renderer_main), + self.CreateTestRecord('record_2', 100, 210, 120, 200, renderer_main), + self.CreateTestRecord('record_3', 215, 920, 220, 900, renderer_main) + ] + + stats = mainthread_jank_stats.MainthreadJankStats( + renderer_main, test_records) + # Main thread janks covered by records' ranges are: + # Record 1: (40ms -> 70ms) + # Record 2: (120ms -> 200ms) + # Record 3: (220ms -> 400ms), (450ms -> 750ms) + self.assertEquals(560, stats.total_big_jank_thread_time) + self.assertEquals(300, stats.biggest_jank_thread_time) diff --git a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py index 1a483b8e4b..e53bf41701 100644 --- a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py +++ b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py @@ -30,76 +30,53 @@ class NotEnoughFramesError(page_measurement.MeasurementFailure): '- Pages that can\'t be scrolled') -def GetScrollInputLatencyEvents(scroll_type, browser_process, timeline_range): - """Get scroll events' LatencyInfo from the browser process's trace buffer - that are within the timeline_range. +def GetInputLatencyEvents(process, timeline_range): + """Get input events' LatencyInfo from the process's trace buffer that are + within the timeline_range. - Scroll events (MouseWheel, GestureScrollUpdate or JS scroll on TouchMove) - dump their LatencyInfo into trace buffer as async trace event with name - "InputLatency". The trace event has a memeber 'step' containing its event - type and a memeber 'data' containing its latency history. + Input events dump their LatencyInfo into trace buffer as async trace event + with name "InputLatency". The trace event has a memeber 'data' containing + its latency history. """ - scroll_events = [] - if not browser_process: - return scroll_events - for event in browser_process.IterAllAsyncSlicesOfName("InputLatency"): + input_events = [] + if not process: + return input_events + for event in process.IterAllAsyncSlicesOfName("InputLatency"): if event.start >= timeline_range.min and event.end <= timeline_range.max: for ss in event.sub_slices: - if 'step' not in ss.args: - continue - if 'data' not in ss.args: - continue - if ss.args['step'] == scroll_type: - scroll_events.append(ss) - return scroll_events - - -def ComputeMouseWheelScrollLatency(mouse_wheel_events): - """ Compute the mouse wheel scroll latency. - - Mouse wheel scroll latency is the time from when mouse wheel event is sent - from browser RWH to renderer (the timestamp of component - 'INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT') to when the scrolled page is - buffer swapped (the timestamp of component - 'INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT') - - """ - mouse_wheel_latency = [] - for event in mouse_wheel_events: - data = event.args['data'] - if BEGIN_COMP_NAME in data and END_COMP_NAME in data: - latency = data[END_COMP_NAME]['time'] - data[BEGIN_COMP_NAME]['time'] - mouse_wheel_latency.append(latency / 1000.0) - return mouse_wheel_latency - - -def ComputeTouchScrollLatency(touch_scroll_events): - """ Compute the touch scroll latency. - - Touch scroll latency is the time from when the touch event is created to - when the scrolled page is buffer swapped. - Touch event on differnt platforms uses different LatencyInfo component to - record its creation timestamp. On Aura, the creation time is kept in - 'INPUT_EVENT_LATENCY_UI_COMPONENT' . On Android, the creation time is kept - in 'INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT'. + if 'data' in ss.args: + input_events.append(ss) + return input_events + +def ComputeInputEventLatency(input_events): + """ Compute the input event latency. + + Input event latency is the time from when the input event is created to + when its resulted page is swap buffered. + Input event on differnt platforms uses different LatencyInfo component to + record its creation timestamp. We go through the following component list + to find the creation timestamp: + 1. INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT -- when event is created in OS + 2. INPUT_EVENT_LATENCY_UI_COMPONENT -- when event reaches Chrome + 3. INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT -- when event reaches RenderWidget """ - touch_scroll_latency = [] - for event in touch_scroll_events: + input_event_latency = [] + for event in input_events: data = event.args['data'] if END_COMP_NAME in data: end_time = data[END_COMP_NAME]['time'] - if UI_COMP_NAME in data and ORIGINAL_COMP_NAME in data: - raise ValueError, 'LatencyInfo has both UI and ORIGINAL component' - if UI_COMP_NAME in data: - latency = end_time - data[UI_COMP_NAME]['time'] - touch_scroll_latency.append(latency / 1000.0) - elif ORIGINAL_COMP_NAME in data: + if ORIGINAL_COMP_NAME in data: latency = end_time - data[ORIGINAL_COMP_NAME]['time'] - touch_scroll_latency.append(latency / 1000.0) - return touch_scroll_latency - + elif UI_COMP_NAME in data: + latency = end_time - data[UI_COMP_NAME]['time'] + elif BEGIN_COMP_NAME in data: + latency = end_time - data[BEGIN_COMP_NAME]['time'] + else: + raise ValueError, 'LatencyInfo has no begin component' + input_event_latency.append(latency / 1000.0) + return input_event_latency def HasRenderingStats(process): """ Returns True if the process contains at least one @@ -146,15 +123,9 @@ class RenderingStats(object): self.rasterize_times = [] self.rasterized_pixel_counts = [] self.approximated_pixel_percentages = [] - # End-to-end latency for MouseWheel scroll - from when mouse wheel event is - # generated to when the scrolled page is buffer swapped. - self.mouse_wheel_scroll_latency = [] - # End-to-end latency for GestureScrollUpdate scroll - from when the touch - # event is generated to the scrolled page is buffer swapped. - self.touch_scroll_latency = [] - # End-to-end latency for JS touch handler scrolling - from when the touch - # event is generated to the scrolled page is buffer swapped. - self.js_touch_scroll_latency = [] + # End-to-end latency for input event - from when input event is + # generated to when the its resulted page is swap buffered. + self.input_event_latency = [] for timeline_range in timeline_ranges: self.frame_timestamps.append([]) @@ -166,9 +137,7 @@ class RenderingStats(object): self.rasterize_times.append([]) self.rasterized_pixel_counts.append([]) self.approximated_pixel_percentages.append([]) - self.mouse_wheel_scroll_latency.append([]) - self.touch_scroll_latency.append([]) - self.js_touch_scroll_latency.append([]) + self.input_event_latency.append([]) if timeline_range.is_empty: continue @@ -177,7 +146,8 @@ class RenderingStats(object): renderer_process, timeline_range) self._InitImplThreadRenderingStatsFromTimeline( renderer_process, timeline_range) - self._InitScrollLatencyStatsFromTimeline(browser_process, timeline_range) + self._InitInputLatencyStatsFromTimeline( + browser_process, renderer_process, timeline_range) # Check if we have collected at least 2 frames in every range. Otherwise we # can't compute any meaningful metrics. @@ -185,21 +155,13 @@ class RenderingStats(object): if len(segment) < 2: raise NotEnoughFramesError(len(segment)) - def _InitScrollLatencyStatsFromTimeline( - self, browser_process, timeline_range): - mouse_wheel_events = GetScrollInputLatencyEvents( - "MouseWheel", browser_process, timeline_range) - self.mouse_wheel_scroll_latency = ComputeMouseWheelScrollLatency( - mouse_wheel_events) - - touch_scroll_events = GetScrollInputLatencyEvents( - "GestureScrollUpdate", browser_process, timeline_range) - self.touch_scroll_latency = ComputeTouchScrollLatency(touch_scroll_events) - - js_touch_scroll_events = GetScrollInputLatencyEvents( - "TouchMove", browser_process, timeline_range) - self.js_touch_scroll_latency = ComputeTouchScrollLatency( - js_touch_scroll_events) + def _InitInputLatencyStatsFromTimeline( + self, browser_process, renderer_process, timeline_range): + latency_events = GetInputLatencyEvents(browser_process, timeline_range) + # Plugin input event's latency slice is generated in renderer process. + latency_events.extend(GetInputLatencyEvents(renderer_process, + timeline_range)) + self.input_event_latency[-1] = ComputeInputEventLatency(latency_events) def _GatherEvents(self, event_name, process, timeline_range): events = [] diff --git a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats_unittest.py b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats_unittest.py index 4ec6644e36..20b0132ac9 100644 --- a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats_unittest.py +++ b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats_unittest.py @@ -6,12 +6,9 @@ import random import unittest from telemetry.web_perf.metrics.rendering_stats import ( - UI_COMP_NAME, BEGIN_COMP_NAME, END_COMP_NAME) -from telemetry.web_perf.metrics.rendering_stats import ( - GetScrollInputLatencyEvents) -from telemetry.web_perf.metrics.rendering_stats import ( - ComputeMouseWheelScrollLatency) -from telemetry.web_perf.metrics.rendering_stats import ComputeTouchScrollLatency + UI_COMP_NAME, BEGIN_COMP_NAME, ORIGINAL_COMP_NAME, END_COMP_NAME) +from telemetry.web_perf.metrics.rendering_stats import ComputeInputEventLatency +from telemetry.web_perf.metrics.rendering_stats import GetInputLatencyEvents from telemetry.web_perf.metrics.rendering_stats import HasRenderingStats from telemetry.web_perf.metrics.rendering_stats import RenderingStats from telemetry.web_perf.metrics.rendering_stats import NotEnoughFramesError @@ -67,12 +64,8 @@ class ReferenceRenderingStats(object): class ReferenceInputLatencyStats(object): """ Stores expected data for comparison with actual input latency stats """ def __init__(self): - self.mouse_wheel_scroll_latency = [] - self.touch_scroll_latency = [] - self.js_touch_scroll_latency = [] - self.mouse_wheel_scroll_events = [] - self.touch_scroll_events = [] - self.js_touch_scroll_events = [] + self.input_event_latency = [] + self.input_event = [] def AddMainThreadRenderingStats(mock_timer, thread, first_frame, ref_stats = None): @@ -155,24 +148,26 @@ def AddImplThreadRenderingStats(mock_timer, thread, first_frame, data['visible_content_area']) * 100.0, 3)) -def AddInputLatencyStats(mock_timer, input_type, start_thread, end_thread, +def AddInputLatencyStats(mock_timer, start_thread, end_thread, ref_latency_stats = None): """ Adds a random input latency stats event. - input_type: The input type for which the latency slice is generated. start_thread: The start thread on which the async slice is added. end_thread: The end thread on which the async slice is ended. ref_latency_stats: A ReferenceInputLatencyStats object for expected values. """ mock_timer.Advance(2, 4) + original_comp_time = mock_timer.Get() * 1000.0 + mock_timer.Advance(2, 4) ui_comp_time = mock_timer.Get() * 1000.0 mock_timer.Advance(2, 4) begin_comp_time = mock_timer.Get() * 1000.0 mock_timer.Advance(10, 20) end_comp_time = mock_timer.Get() * 1000.0 - data = { UI_COMP_NAME: {'time': ui_comp_time}, + data = { ORIGINAL_COMP_NAME: {'time': original_comp_time}, + UI_COMP_NAME: {'time': ui_comp_time}, BEGIN_COMP_NAME: {'time': begin_comp_time}, END_COMP_NAME: {'time': end_comp_time} } @@ -183,7 +178,7 @@ def AddInputLatencyStats(mock_timer, input_type, start_thread, end_thread, async_sub_slice = tracing_async_slice.AsyncSlice( 'benchmark', 'InputLatency', timestamp) - async_sub_slice.args = {'data': data, 'step': input_type} + async_sub_slice.args = {'data': data} async_sub_slice.parent_slice = async_slice async_sub_slice.start_thread = start_thread async_sub_slice.end_thread = end_thread @@ -196,20 +191,9 @@ def AddInputLatencyStats(mock_timer, input_type, start_thread, end_thread, if not ref_latency_stats: return - if input_type == 'MouseWheel': - ref_latency_stats.mouse_wheel_scroll_events.append(async_sub_slice) - ref_latency_stats.mouse_wheel_scroll_latency.append( - (data[END_COMP_NAME]['time'] - data[BEGIN_COMP_NAME]['time']) / 1000.0) - - if input_type == 'GestureScrollUpdate': - ref_latency_stats.touch_scroll_events.append(async_sub_slice) - ref_latency_stats.touch_scroll_latency.append( - (data[END_COMP_NAME]['time'] - data[UI_COMP_NAME]['time']) / 1000.0) - - if input_type == 'TouchMove': - ref_latency_stats.js_touch_scroll_events.append(async_sub_slice) - ref_latency_stats.js_touch_scroll_latency.append( - (data[END_COMP_NAME]['time'] - data[UI_COMP_NAME]['time']) / 1000.0) + ref_latency_stats.input_event.append(async_sub_slice) + ref_latency_stats.input_event_latency.append( + (data[END_COMP_NAME]['time'] - data[ORIGINAL_COMP_NAME]['time']) / 1000.0) class RenderingStatsUnitTest(unittest.TestCase): def testHasRenderingStats(self): @@ -379,7 +363,7 @@ class RenderingStatsUnitTest(unittest.TestCase): self.assertEquals(stats.recorded_pixel_counts, renderer_ref_stats.recorded_pixel_counts) - def testScrollLatencyFromTimeline(self): + def testInputLatencyFromTimeline(self): timeline = model.TimelineModel() # Create a browser process and a renderer process. @@ -389,41 +373,26 @@ class RenderingStatsUnitTest(unittest.TestCase): renderer_main = renderer.GetOrCreateThread(tid = 21) timer = MockTimer() - ref_latency_stats = ReferenceInputLatencyStats() + ref_latency = ReferenceInputLatencyStats() # Create 10 input latency stats events for Action A. timer.Advance(2, 4) renderer_main.BeginSlice('webkit.console', 'ActionA', timer.Get(), '') for _ in xrange(0, 10): - AddInputLatencyStats(timer, 'MouseWheel', browser_main, - renderer_main, ref_latency_stats) - AddInputLatencyStats(timer, 'GestureScrollUpdate', browser_main, - renderer_main, ref_latency_stats) - AddInputLatencyStats(timer, 'TouchMove', browser_main, - renderer_main, ref_latency_stats) + AddInputLatencyStats(timer, browser_main, renderer_main, ref_latency) timer.Advance(2, 4) renderer_main.EndSlice(timer.Get()) # Create 5 input latency stats events not within any action. timer.Advance(2, 4) for _ in xrange(0, 5): - AddInputLatencyStats(timer, 'MouseWheel', browser_main, - renderer_main, None) - AddInputLatencyStats(timer, 'GestureScrollUpdate', browser_main, - renderer_main, None) - AddInputLatencyStats(timer, 'TouchMove', browser_main, - renderer_main, None) + AddInputLatencyStats(timer, browser_main, renderer_main, None) # Create 10 input latency stats events for Action B. timer.Advance(2, 4) renderer_main.BeginSlice('webkit.console', 'ActionB', timer.Get(), '') for _ in xrange(0, 10): - AddInputLatencyStats(timer, 'MouseWheel', browser_main, - renderer_main, ref_latency_stats) - AddInputLatencyStats(timer, 'GestureScrollUpdate', browser_main, - renderer_main, ref_latency_stats) - AddInputLatencyStats(timer, 'TouchMove', browser_main, - renderer_main, ref_latency_stats) + AddInputLatencyStats(timer, browser_main, renderer_main, ref_latency) timer.Advance(2, 4) renderer_main.EndSlice(timer.Get()) @@ -431,21 +400,14 @@ class RenderingStatsUnitTest(unittest.TestCase): timer.Advance(2, 4) renderer_main.BeginSlice('webkit.console', 'ActionA', timer.Get(), '') for _ in xrange(0, 10): - AddInputLatencyStats(timer, 'MouseWheel', browser_main, - renderer_main, ref_latency_stats) - AddInputLatencyStats(timer, 'GestureScrollUpdate', browser_main, - renderer_main, ref_latency_stats) - AddInputLatencyStats(timer, 'TouchMove', browser_main, - renderer_main, ref_latency_stats) + AddInputLatencyStats(timer, browser_main, renderer_main, ref_latency) timer.Advance(2, 4) renderer_main.EndSlice(timer.Get()) browser.FinalizeImport() renderer.FinalizeImport() - mouse_wheel_scroll_events = [] - touch_scroll_events = [] - js_touch_scroll_events = [] + input_events = [] timeline_markers = timeline.FindTimelineMarkers( ['ActionA', 'ActionB', 'ActionA']) @@ -453,25 +415,8 @@ class RenderingStatsUnitTest(unittest.TestCase): for marker in timeline_markers ]: if timeline_range.is_empty: continue - tmp_mouse_events = GetScrollInputLatencyEvents( - 'MouseWheel', browser, timeline_range) - tmp_touch_scroll_events = GetScrollInputLatencyEvents( - 'GestureScrollUpdate', browser, timeline_range) - tmp_js_touch_scroll_events = GetScrollInputLatencyEvents( - 'TouchMove', browser, timeline_range) - mouse_wheel_scroll_events.extend(tmp_mouse_events) - touch_scroll_events.extend(tmp_touch_scroll_events) - js_touch_scroll_events.extend(tmp_js_touch_scroll_events) - - self.assertEquals(mouse_wheel_scroll_events, - ref_latency_stats.mouse_wheel_scroll_events) - self.assertEquals(touch_scroll_events, - ref_latency_stats.touch_scroll_events) - self.assertEquals(js_touch_scroll_events, - ref_latency_stats.js_touch_scroll_events) - self.assertEquals(ComputeMouseWheelScrollLatency(mouse_wheel_scroll_events), - ref_latency_stats.mouse_wheel_scroll_latency) - self.assertEquals(ComputeTouchScrollLatency(touch_scroll_events), - ref_latency_stats.touch_scroll_latency) - self.assertEquals(ComputeTouchScrollLatency(js_touch_scroll_events), - ref_latency_stats.js_touch_scroll_latency) + input_events.extend(GetInputLatencyEvents(browser, timeline_range)) + + self.assertEquals(input_events, ref_latency.input_event) + self.assertEquals(ComputeInputEventLatency(input_events), + ref_latency.input_event_latency) diff --git a/tools/telemetry/telemetry/web_perf/metrics/responsiveness_metric.py b/tools/telemetry/telemetry/web_perf/metrics/responsiveness_metric.py new file mode 100644 index 0000000000..17e765afee --- /dev/null +++ b/tools/telemetry/telemetry/web_perf/metrics/responsiveness_metric.py @@ -0,0 +1,47 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import logging + +from telemetry.web_perf import timeline_interaction_record as tir_module +from telemetry.web_perf.metrics import mainthread_jank_stats +from telemetry.web_perf.metrics import timeline_based_metric + + +class ResponsivenessMetric(timeline_based_metric.TimelineBasedMetric): + """Computes metrics that measure respsonsiveness on the record ranges. + + total_big_jank_thread_time is the total thread duration of all top + slices whose thread time ranges overlapped with any thread time ranges of + the records and the overlapped thread duration is greater than or equal + USER_PERCEIVABLE_DELAY_THRESHOLD_MS. + + biggest_jank_thread_time is the biggest thread duration of all + top slices whose thread time ranges overlapped with any of records' thread + time ranges. + + All *_time values are measured in milliseconds. + """ + + def __init__(self): + super(ResponsivenessMetric, self).__init__() + + def AddResults(self, _, renderer_thread, interaction_records, results): + self.VerifyNonOverlappedRecords(interaction_records) + try: + jank_stats = mainthread_jank_stats.MainthreadJankStats( + renderer_thread, interaction_records) + # TODO(nednguyen): maybe fall back to use wall-time for computing the + # metrics. + except tir_module.NoThreadTimeDataException as e: + #TODO(nednguyen): Report the warning with page_results system. + logging.warning( + 'Main thread jank metrics cannot be computed for records %s since ' + 'trace does not contain thread time data. %s', + repr(interaction_records), repr(e)) + return + + results.Add('responsive-total_big_jank_thread_time', 'ms', + jank_stats.total_big_jank_thread_time) + results.Add('responsive-biggest_jank_thread_time', 'ms', + jank_stats.biggest_jank_thread_time) diff --git a/tools/telemetry/telemetry/web_perf/metrics/smoothness.py b/tools/telemetry/telemetry/web_perf/metrics/smoothness.py index fff1f1ec7a..a8158870f8 100644 --- a/tools/telemetry/telemetry/web_perf/metrics/smoothness.py +++ b/tools/telemetry/telemetry/web_perf/metrics/smoothness.py @@ -18,35 +18,17 @@ class SmoothnessMetric(timeline_based_metric.TimelineBasedMetric): stats = rendering_stats.RenderingStats( renderer_process, model.browser_process, [r.GetBounds() for r in interaction_records]) - if stats.mouse_wheel_scroll_latency: - mean_mouse_wheel_scroll_latency = statistics.ArithmeticMean( - stats.mouse_wheel_scroll_latency) - mouse_wheel_scroll_latency_discrepancy = statistics.DurationsDiscrepancy( - stats.mouse_wheel_scroll_latency) - results.Add('mean_mouse_wheel_scroll_latency', 'ms', - round(mean_mouse_wheel_scroll_latency, 3)) - results.Add('mouse_wheel_scroll_latency_discrepancy', 'ms', - round(mouse_wheel_scroll_latency_discrepancy, 4)) - if stats.touch_scroll_latency: - mean_touch_scroll_latency = statistics.ArithmeticMean( - stats.touch_scroll_latency) - touch_scroll_latency_discrepancy = statistics.DurationsDiscrepancy( - stats.touch_scroll_latency) - results.Add('mean_touch_scroll_latency', 'ms', - round(mean_touch_scroll_latency, 3)) - results.Add('touch_scroll_latency_discrepancy', 'ms', - round(touch_scroll_latency_discrepancy, 4)) - - if stats.js_touch_scroll_latency: - mean_js_touch_scroll_latency = statistics.ArithmeticMean( - stats.js_touch_scroll_latency) - js_touch_scroll_latency_discrepancy = statistics.DurationsDiscrepancy( - stats.js_touch_scroll_latency) - results.Add('mean_js_touch_scroll_latency', 'ms', - round(mean_js_touch_scroll_latency, 3)) - results.Add('js_touch_scroll_latency_discrepancy', 'ms', - round(js_touch_scroll_latency_discrepancy, 4)) + input_event_latency = FlattenList(stats.input_event_latency) + if input_event_latency: + mean_input_event_latency = statistics.ArithmeticMean( + input_event_latency) + input_event_latency_discrepancy = statistics.DurationsDiscrepancy( + input_event_latency) + results.Add('mean_input_event_latency', 'ms', + round(mean_input_event_latency, 3)) + results.Add('input_event_latency_discrepancy', 'ms', + round(input_event_latency_discrepancy, 4)) # List of raw frame times. frame_times = FlattenList(stats.frame_times) diff --git a/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py b/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py index f8266390a3..cdf66bb160 100644 --- a/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py +++ b/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py @@ -10,6 +10,7 @@ from telemetry.core.backends.chrome import tracing_backend from telemetry.core.timeline import model as model_module from telemetry.web_perf import timeline_interaction_record as tir_module from telemetry.web_perf.metrics import smoothness +from telemetry.web_perf.metrics import responsiveness_metric from telemetry.page import page_measurement from telemetry.value import string as string_value_module @@ -58,7 +59,6 @@ class _TimelineBasedMetrics(object): event in self._renderer_thread.async_slices if tir_module.IsTimelineInteractionRecord(event.name)] - def AddResults(self, results): interactions = self.FindTimelineInteractionRecords() if len(interactions) == 0: @@ -101,12 +101,12 @@ class TimelineBasedMeasurement(page_measurement.PageMeasurement): @classmethod def AddCommandLineArgs(cls, parser): parser.add_option( - '--overhead-level', type='choice', + '--overhead-level', dest='overhead_level', type='choice', choices=ALL_OVERHEAD_LEVELS, default=NO_OVERHEAD_LEVEL, help='How much overhead to incur during the measurement.') parser.add_option( - '--trace-dir', type='string', default=None, + '--trace-dir', dest='trace_dir', type='string', default=None, help=('Where to save the trace after the run. If this flag ' 'is not set, the trace will not be saved.')) @@ -131,6 +131,8 @@ class TimelineBasedMeasurement(page_measurement.PageMeasurement): res = [] if interaction.is_smooth: res.append(smoothness.SmoothnessMetric()) + if interaction.is_responsive: + res.append(responsiveness_metric.ResponsivenessMetric()) return res def MeasurePage(self, page, tab, results): diff --git a/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py b/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py index c4eeae9e8f..99444fbd0f 100644 --- a/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py +++ b/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py @@ -12,11 +12,16 @@ from telemetry.core.timeline import async_slice from telemetry.page import page_measurement_results from telemetry.page import page_measurement_unittest_base from telemetry.page import page_set +from telemetry.page import page as page_module +# pylint: disable=W0401,W0614 +from telemetry.page.actions.all_page_actions import * from telemetry.unittest import options_for_unittests from telemetry.web_perf import timeline_based_measurement as tbm_module from telemetry.web_perf.metrics import timeline_based_metric + class TimelineBasedMetricsTests(unittest.TestCase): + def setUp(self): model = model_module.TimelineModel() renderer_thread = model.GetOrCreateProcess(1).GetOrCreateThread(2) @@ -33,7 +38,7 @@ class TimelineBasedMetricsTests(unittest.TestCase): start_thread=renderer_thread, end_thread=renderer_thread, thread_start=5, thread_duration=15)) renderer_thread.async_slices.append(async_slice.AsyncSlice( - 'cat', 'Interaction.LogicalName2/is_loading_resources', + 'cat', 'Interaction.LogicalName2/is_responsive', timestamp=25, duration=5, start_thread=renderer_thread, end_thread=renderer_thread, thread_start=25, thread_duration=5)) @@ -43,26 +48,29 @@ class TimelineBasedMetricsTests(unittest.TestCase): self.renderer_thread = renderer_thread def testFindTimelineInteractionRecords(self): - metric = tbm_module._TimelineBasedMetrics( # pylint: disable=W0212 - self.model, self.renderer_thread, lambda _: [] ) + metric = tbm_module._TimelineBasedMetrics( # pylint: disable=W0212 + self.model, self.renderer_thread, lambda _: []) interactions = metric.FindTimelineInteractionRecords() self.assertEquals(2, len(interactions)) self.assertTrue(interactions[0].is_smooth) self.assertEquals(0, interactions[0].start) self.assertEquals(20, interactions[0].end) - self.assertTrue(interactions[1].is_loading_resources) + self.assertTrue(interactions[1].is_responsive) self.assertEquals(25, interactions[1].start) self.assertEquals(30, interactions[1].end) def testAddResults(self): results = page_measurement_results.PageMeasurementResults() + class FakeSmoothMetric(timeline_based_metric.TimelineBasedMetric): + def AddResults(self, model, renderer_thread, interaction_records, results): results.Add('FakeSmoothMetric', 'ms', 1) class FakeLoadingMetric(timeline_based_metric.TimelineBasedMetric): + def AddResults(self, model, renderer_thread, interaction_records, results): for r in interaction_records: @@ -73,11 +81,11 @@ class TimelineBasedMetricsTests(unittest.TestCase): res = [] if interaction.is_smooth: res.append(FakeSmoothMetric()) - if interaction.is_loading_resources: + if interaction.is_responsive: res.append(FakeLoadingMetric()) return res - metric = tbm_module._TimelineBasedMetrics( # pylint: disable=W0212 + metric = tbm_module._TimelineBasedMetrics( # pylint: disable=W0212 self.model, self.renderer_thread, CreateMetricsForTimelineInteractionRecord) ps = page_set.PageSet(file_path=os.path.dirname(__file__)) @@ -93,19 +101,33 @@ class TimelineBasedMetricsTests(unittest.TestCase): self.assertEquals(len(v), 1) +class TestTimelinebasedMeasurementPage(page_module.Page): + + def __init__(self, ps, base_dir): + super(TestTimelinebasedMeasurementPage, self).__init__( + 'file://interaction_enabled_page.html', ps, base_dir) + + def RunSmoothness(self, action_runner): + action_runner.RunAction(WaitAction({'seconds': 2})) + action_runner.RunAction(TapAction( + {'selector': '#drawer', 'automatically_record_interaction': False})) + action_runner.RunAction(WaitAction({'seconds': 1})) + + class TimelineBasedMeasurementTest( - page_measurement_unittest_base.PageMeasurementUnitTestBase): + page_measurement_unittest_base.PageMeasurementUnitTestBase): + def setUp(self): self._options = options_for_unittests.GetCopy() self._options.browser_options.wpr_mode = wpr_modes.WPR_OFF # Disabled due to flakiness: crbug.com/368386 @test.Disabled - def testTimelineBasedForSmoke(self): + def testSmoothnessTimelineBasedMeasurementForSmoke(self): ps = self.CreatePageSetFromFileInUnittestDataDir( 'interaction_enabled_page.html') - setattr(ps.pages[0], 'RunSmoothness', {'action': 'wait', - 'javascript': 'window.animationDone'}) + setattr(ps.pages[0], 'RunSmoothness', { + 'action': 'wait', 'javascript': 'window.animationDone'}) measurement = tbm_module.TimelineBasedMeasurement() results = self.RunMeasurement(measurement, ps, options=self._options) @@ -115,3 +137,28 @@ class TimelineBasedMeasurementTest( v = results.FindAllPageSpecificValuesNamed('DrawerAnimation-jank') self.assertEquals(len(v), 1) + # Disabled since mainthread_jank metric is not supported on windows platform. + @test.Disabled('win') + def testMainthreadJankTimelineBasedMeasurement(self): + ps = self.CreateEmptyPageSet() + ps.AddPage(TestTimelinebasedMeasurementPage(ps, ps.base_dir)) + + measurement = tbm_module.TimelineBasedMeasurement() + results = self.RunMeasurement(measurement, ps, + options=self._options) + self.assertEquals(0, len(results.failures)) + + # In interaction_enabled_page.html, we create a jank loop based on + # window.performance.now() (basically loop for x milliseconds). + # Since window.performance.now() uses wall-time + # instead of thread time, we set time to looping to 100ms in + # interaction_enabled_page.html and only assert the biggest jank > 50ms here + # to account for the fact that the browser may deschedule during the jank + # loop. + v = results.FindAllPageSpecificValuesNamed( + 'JankThreadJSRun-responsive-biggest_jank_thread_time') + self.assertGreaterEqual(v[0].value, 50) + + v = results.FindAllPageSpecificValuesNamed( + 'JankThreadJSRun-responsive-total_big_jank_thread_time') + self.assertGreaterEqual(v[0].value, 50) diff --git a/tools/telemetry/telemetry/web_perf/timeline_interaction_record.py b/tools/telemetry/telemetry/web_perf/timeline_interaction_record.py index 40ab2c2d3c..45e6a34978 100644 --- a/tools/telemetry/telemetry/web_perf/timeline_interaction_record.py +++ b/tools/telemetry/telemetry/web_perf/timeline_interaction_record.py @@ -9,11 +9,11 @@ import telemetry.core.timeline.bounds as timeline_bounds IS_SMOOTH = 'is_smooth' -IS_LOADING_RESOURCES = 'is_loading_resources' +IS_RESPONSIVE = 'is_responsive' FLAGS = [ IS_SMOOTH, - IS_LOADING_RESOURCES + IS_RESPONSIVE ] @@ -22,6 +22,9 @@ class ThreadTimeRangeOverlappedException(Exception): with other events. """ +class NoThreadTimeDataException(ThreadTimeRangeOverlappedException): + """Exception that can be thrown if there is not sufficient thread time data + to compute the overlapped thread time range.""" def IsTimelineInteractionRecord(event_name): return event_name.startswith('Interaction.') @@ -52,7 +55,7 @@ class TimelineInteractionRecord(object): is currently done by pushing markers into the console.time/timeEnd API: this for instance can be issued in JS: - var str = 'Interaction.SendEmail/is_smooth,is_loading_resources'; + var str = 'Interaction.SendEmail/is_smooth,is_responsive'; console.time(str); setTimeout(function() { console.timeEnd(str); @@ -71,7 +74,7 @@ class TimelineInteractionRecord(object): self.start = start self.end = end self.is_smooth = False - self.is_loading_resources = False + self.is_responsive = False self._async_event = async_event # TODO(nednguyen): After crbug.com/367175 is marked fixed, we should be able @@ -84,6 +87,9 @@ class TimelineInteractionRecord(object): async_event: An instance of telemetry.core.timeline.async_slices.AsyncSlice """ + assert async_event.start_thread == async_event.end_thread, ( + 'Start thread of this record\'s async event is not the same as its ' + 'end thread') m = re.match('Interaction\.(.+)\/(.+)', async_event.name) if m: logical_name = m.group(1) @@ -104,7 +110,7 @@ class TimelineInteractionRecord(object): raise Exception( 'Unrecognized flag in timeline Interaction record: %s' % f) record.is_smooth = IS_SMOOTH in flags - record.is_loading_resources = IS_LOADING_RESOURCES in flags + record.is_responsive = IS_RESPONSIVE in flags return record def GetResultNameFor(self, result_name): @@ -118,7 +124,7 @@ class TimelineInteractionRecord(object): return bounds @staticmethod - def GetJavascriptMarker(logical_name, flags): + def GetJavaScriptMarker(logical_name, flags): """ Get the marker string of an interaction record with logical_name and flags. """ @@ -169,16 +175,12 @@ class TimelineInteractionRecord(object): if not self._async_event: raise ThreadTimeRangeOverlappedException( 'This record was not constructed from async event') - if self._async_event.start_thread != self._async_event.end_thread: - raise ThreadTimeRangeOverlappedException( - 'Start thread of this record\'s async event is not the same as its ' - 'end thread') if not self._async_event.has_thread_timestamps: - raise ThreadTimeRangeOverlappedException( + raise NoThreadTimeDataException( 'This record\'s async_event does not contain thread time data. ' 'Event data: %s' % repr(self._async_event)) if not timeline_slice.has_thread_timestamps: - raise ThreadTimeRangeOverlappedException( + raise NoThreadTimeDataException( 'slice does not contain thread time data') if timeline_slice.parent_thread == self._async_event.start_thread: @@ -210,3 +212,19 @@ class TimelineInteractionRecord(object): self._async_event.thread_duration / float(self._async_event.duration)) return (overlapped_walltime_duration * timeline_slice_scheduled_ratio * record_scheduled_ratio) + + def __repr__(self): + flags = [] + if self.is_smooth: + flags.append(IS_SMOOTH) + elif self.is_responsive: + flags.append(IS_RESPONSIVE) + flags_str = ','.join(flags) + + return ('TimelineInteractionRecord(logical_name=\'%s\', start=%f, end=%f,' + + ' flags=%s, async_event=%s)') % ( + self.logical_name, + self.start, + self.end, + flags_str, + repr(self._async_event)) diff --git a/tools/telemetry/telemetry/web_perf/timeline_interaction_record_unittest.py b/tools/telemetry/telemetry/web_perf/timeline_interaction_record_unittest.py index f2248c5381..8a30d193a8 100644 --- a/tools/telemetry/telemetry/web_perf/timeline_interaction_record_unittest.py +++ b/tools/telemetry/telemetry/web_perf/timeline_interaction_record_unittest.py @@ -40,32 +40,32 @@ class TimelineInteractionRecordTests(unittest.TestCase): r = self.CreateSimpleRecordWithName('Interaction.LogicalName') self.assertEquals('LogicalName', r.logical_name) self.assertEquals(False, r.is_smooth) - self.assertEquals(False, r.is_loading_resources) + self.assertEquals(False, r.is_responsive) r = self.CreateSimpleRecordWithName('Interaction.LogicalName/is_smooth') self.assertEquals('LogicalName', r.logical_name) self.assertEquals(True, r.is_smooth) - self.assertEquals(False, r.is_loading_resources) + self.assertEquals(False, r.is_responsive) r = self.CreateSimpleRecordWithName( 'Interaction.LogicalNameWith/Slash/is_smooth') self.assertEquals('LogicalNameWith/Slash', r.logical_name) self.assertEquals(True, r.is_smooth) - self.assertEquals(False, r.is_loading_resources) + self.assertEquals(False, r.is_responsive) r = self.CreateSimpleRecordWithName( - 'Interaction.LogicalNameWith/Slash/is_smooth,is_loading_resources') + 'Interaction.LogicalNameWith/Slash/is_smooth,is_responsive') self.assertEquals('LogicalNameWith/Slash', r.logical_name) self.assertEquals(True, r.is_smooth) - self.assertEquals(True, r.is_loading_resources) + self.assertEquals(True, r.is_responsive) - def testGetJavascriptMarker(self): - smooth_marker = tir_module.TimelineInteractionRecord.GetJavascriptMarker( + def testGetJavaScriptMarker(self): + smooth_marker = tir_module.TimelineInteractionRecord.GetJavaScriptMarker( 'LogicalName', [tir_module.IS_SMOOTH]) self.assertEquals('Interaction.LogicalName/is_smooth', smooth_marker) - slr_marker = tir_module.TimelineInteractionRecord.GetJavascriptMarker( - 'LogicalName', [tir_module.IS_SMOOTH, tir_module.IS_LOADING_RESOURCES]) - self.assertEquals('Interaction.LogicalName/is_smooth,is_loading_resources', + slr_marker = tir_module.TimelineInteractionRecord.GetJavaScriptMarker( + 'LogicalName', [tir_module.IS_SMOOTH, tir_module.IS_RESPONSIVE]) + self.assertEquals('Interaction.LogicalName/is_smooth,is_responsive', slr_marker) def testGetOverlappedThreadTimeForSliceInSameThread(self): @@ -101,6 +101,25 @@ class TimelineInteractionRecordTests(unittest.TestCase): s5 = self.CreateTestSliceFromTimeRanges(renderer_main, 0, 100, 50, 90) self.assertEquals(10, record.GetOverlappedThreadTimeForSlice(s5)) + def testRepr(self): + # Create a renderer thread. + model = model_module.TimelineModel() + renderer_main = model.GetOrCreateProcess(1).GetOrCreateThread(2) + model.FinalizeImport() + + s = async_slice.AsyncSlice( + 'cat', 'Interaction.Test/is_smooth', + timestamp=0, duration=200, start_thread=renderer_main, + end_thread=renderer_main, thread_start=30, thread_duration=30) + record = tir_module.TimelineInteractionRecord.FromAsyncEvent(s) + expected_repr = ( + 'TimelineInteractionRecord(logical_name=\'Test\', ' + 'start=0.000000, end=200.000000, flags=is_smooth, ' + 'async_event=TimelineEvent(name=\'Interaction.Test/is_smooth\',' + ' start=0.000000, duration=200, thread_start=30, thread_duration=30))') + self.assertEquals(expected_repr, repr(record)) + + def testGetOverlappedThreadTimeForSliceInDifferentThread(self): # Create a renderer thread and another thread. model = model_module.TimelineModel() diff --git a/tools/telemetry/unittest_data/discoverable_classes/__init__.py b/tools/telemetry/unittest_data/discoverable_classes/__init__.py index 4e943c4b36..9228df89b0 100644 --- a/tools/telemetry/unittest_data/discoverable_classes/__init__.py +++ b/tools/telemetry/unittest_data/discoverable_classes/__init__.py @@ -1,3 +1,3 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py b/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py index b25cf9e04d..e41eccc4db 100644 --- a/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py +++ b/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/tools/telemetry/unittest_data/interaction_enabled_page.html b/tools/telemetry/unittest_data/interaction_enabled_page.html index cadb1fa515..d7c7cfa013 100644 --- a/tools/telemetry/unittest_data/interaction_enabled_page.html +++ b/tools/telemetry/unittest_data/interaction_enabled_page.html @@ -53,5 +53,20 @@ <div id="drawer"> This is a drawer. </div> + <script> + 'use strict'; + var jankMs = 100; + function jankThread() { + console.time('Interaction.JankThreadJSRun/is_responsive'); + var startTime = window.performance.now(); + var currTime = startTime; + while (currTime - startTime < jankMs) { + var currTime = window.performance.now(); + } + console.timeEnd('Interaction.JankThreadJSRun/is_responsive'); + } + var drawer = document.getElementById('drawer'); + drawer.addEventListener('click', jankThread); + </script> </body> </html> diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt index 97b3680789..37455b7f52 100644 --- a/tools/valgrind/drmemory/suppressions.txt +++ b/tools/valgrind/drmemory/suppressions.txt @@ -423,20 +423,20 @@ skia.dll!HDCOffscreen::draw skia.dll!SkScalerContext_GDI::generateImage skia.dll!SkScalerContext::getImage skia.dll!SkGlyphCache::findImage -skia.dll!D1G_NoBounder_RectClip +skia.dll!D1G_RectClip skia.dll!SkDraw::drawText HANDLE LEAK name=http://crbug.com/346842 system call NtGdiCreateDIBSection -GDI32.dll!CreateDIBSection -skia.dll!HDCOffscreen::draw -skia.dll!SkScalerContext_GDI::generateImage -skia.dll!SkScalerContext::getImage -skia.dll!SkGlyphCache::findImage -skia.dll!D1G_NoBounder_RectClip -skia.dll!SkDraw::drawPosText -skia.dll!SkBitmapDevice::drawPosText +*!CreateDIBSection +*!HDCOffscreen::draw +*!SkScalerContext_GDI::generateImage +*!SkScalerContext::getImage +*!SkGlyphCache::findImage +*!D1G*RectClip +*!SkDraw::drawPosText +*!SkBitmapDevice::drawPosText HANDLE LEAK name=http://crbug.com/346993 @@ -557,7 +557,20 @@ system call NtCreate* UNADDRESSABLE ACCESS name=http://crbug.com/379204 ... -*!WTF::PlatformCondition::timedWait -*!WTF::ThreadCondition::timedWait *!WTF::MessageQueue<>::waitForMessageWithTimeout *!WebCore::WorkerRunLoop::run +*!WebCore::WorkerRunLoop::run +*!WebCore::WorkerThread::workerThread +*!WTF::threadEntryPoint + +GDI USAGE ERROR +name=379774 +system call NtUserCallOneParam.RELEASEDC +USER32.dll!ReleaseDC +*!std::_Tree<>::_Erase +*!std::_Tree<>::erase +*!DefaultSingletonTraits<>::Delete +*!Singleton<>::OnExit +*!base::AtExitManager::ProcessCallbacksNow +*!base::AtExitManager::~AtExitManager +*!base::TestSuite::~TestSuite diff --git a/tools/valgrind/drmemory/suppressions_full.txt b/tools/valgrind/drmemory/suppressions_full.txt index 10de956faf..998e30d4a4 100644 --- a/tools/valgrind/drmemory/suppressions_full.txt +++ b/tools/valgrind/drmemory/suppressions_full.txt @@ -1455,12 +1455,6 @@ name=bug_145244 *!WebCore::StyleSheetContents::requestImportedStyleSheets UNINITIALIZED READ -name=bug_158510 -*!WebCore::RenderTable::layout -... -*!WebCore::RenderBlock::layout - -UNINITIALIZED READ name=bug_159005 *!WebCore::RenderMarquee::updateMarqueeStyle *!WebCore::RenderLayer::styleChanged @@ -2063,14 +2057,6 @@ blink_web.dll!WebCore::FrameView::updateLayoutAndStyleForPainting blink_web.dll!WebCore::PageAnimator::updateLayoutAndStyleForPainting UNINITIALIZED READ -name=bug_364675 -blink_web.dll!WebCore::AutoTableLayout::layout -blink_web.dll!WebCore::RenderTable::layout -blink_web.dll!... -blink_web.dll!WebCore::RenderBlockFlow::layoutBlockFlow -blink_web.dll!WebCore::RenderBlockFlow::layoutBlock - -UNINITIALIZED READ name=bug_365101 *!device::BluetoothAdapterWin::AdapterStateChanged @@ -2176,10 +2162,6 @@ name=bug_374410 *!ui::NativeThemeWin::PaintDirect UNINITIALIZED READ -name=bug_376814 -*!content::PepperPluginInstanceImpl::UpdateLayer - -UNINITIALIZED READ name=bug_377728 ... *!Hunspell::suggest diff --git a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt index 294f5e019c..5f68c7f1ae 100644 --- a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt +++ b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt @@ -9,59 +9,46 @@ # it takes too long to run all browser_tests with Dr.Memory, # and we only select subset to run # A*: ~70 tests +A* # DrM-i#1052-c#52 # AutofillTest.* # AcceleratedCompositingBlockedTest.* # AppApiTest.* -A* # BrowserAccessibilityStateImplTest.* B* # C*: ~190 tests -C* -# D*: ~210 tests D* -# E*: ~535 tests E* F* G* # H*: ~52 tests -H* # DrM-i#1052-c#53 -# HistoryWebUITest.* +HistoryWebUITest.* # I*: ~10 tests -I* # DrM-i#1052-c#53 -# InfoBarsTest.* +InfoBarsTest.* # DrM-i#1052-c#56 -# InspectUITest.* +InspectUITest.* # J*: 0 tests -J* # K*: 1 tests -K* # L*: 62 tests -L* M* N* O* P* -# Q* -# R* -# S* -# T* +Q* +R* +S* +T* # U*: ~20 tests -U* # DrM-i#1052-c#53 -# UnloadTest.* +UnloadTest.* # V*: 5 tests -V* # W*: ~150 tests -# W* +W* # X*: 0 tests -X* # Y*: 0 tests -Y* # Z*: 0 tests -Z* # http://crbug.com/302993 InstantNTPURLRewriteTest.UberURLHandler_InstantExtendedNewTabPage diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt index 9689e8bf89..b1d438b344 100644 --- a/tools/valgrind/memcheck/suppressions.txt +++ b/tools/valgrind/memcheck/suppressions.txt @@ -4208,13 +4208,6 @@ fun:_ZN7content23AudioInputDeviceManager23EnumerateOnDeviceThread* } { - bug_158510 - Memcheck:Uninitialized - fun:_ZN7WebCore11RenderTable6layoutEv - ... - fun:_ZN7WebCore11RenderBlock6layoutEv -} -{ bug_158514 Memcheck:Uninitialized ... @@ -5447,20 +5440,6 @@ fun:_ZN7content12_GLOBAL__N_121ClearOriginOnIOThreadEjRK4GURLRK13scoped_refptrIN3net23URLRequestContextGetterEERKS4_IN5quota12QuotaManagerEE } { - bug_258466 - Memcheck:Leak - fun:_Znw* - fun:_ZN22ChromeBrowserMainParts25PreMainMessageLoopRunImplEv - fun:_ZN22ChromeBrowserMainParts21PreMainMessageLoopRunEv - fun:_ZN7content15BrowserMainLoop13CreateThreadsEv - fun:_ZN7content21BrowserMainRunnerImpl10InitializeERKNS_18MainFunctionParamsE - fun:_ZN7content11BrowserMainERKNS_18MainFunctionParamsE - fun:_ZN7content23RunNamedProcessTypeMainERKSsRKNS_18MainFunctionParamsEPNS_19ContentMainDelegateE - fun:_ZN7content21ContentMainRunnerImpl3RunEv - fun:_ZN7content11ContentMainEiPPKcPNS_19ContentMainDelegateE - fun:ChromeMain -} -{ bug_258132a Memcheck:Leak fun:_Znw* @@ -5832,21 +5811,19 @@ fun:_ZN12_GLOBAL__N_119test_pm_conversionsEP9GrContextPiS2_ fun:_ZN9GrContext19createPMToUPMEffectEP9GrTexturebRK8SkMatrix fun:_ZN9GrContext22readRenderTargetPixelsEP14GrRenderTargetiiii13GrPixelConfigPvmj - fun:_ZN11SkGpuDevice12onReadPixelsERK8SkBitmapiiN8SkCanvas10Config8888E - fun:_ZN12SkBaseDevice10readPixelsEP8SkBitmapiiN8SkCanvas10Config8888E - fun:_ZN8SkCanvas10readPixelsEP8SkBitmapiiNS_10Config8888E - fun:_ZN14DeferredDevice12onReadPixelsERK8SkBitmapiiN8SkCanvas10Config8888E - fun:_ZN12SkBaseDevice10readPixelsEP8SkBitmapiiN8SkCanvas10Config8888E - fun:_ZN8SkCanvas10readPixelsEP8SkBitmapiiNS_10Config8888E - fun:_ZN7WebCore15GraphicsContext10readPixelsEP8SkBitmapiiN8SkCanvas10Config8888E - fun:_ZN7WebCore12getImageDataILNS_8MultiplyE1EEEN3WTF10PassRefPtrINS2_17Uint8ClampedArrayEEERKNS_7IntRectEPNS_15GraphicsContextERKNS_7IntSizeE - fun:_ZNK7WebCore11ImageBuffer24getUnmultipliedImageDataERKNS_7IntRectENS0_16CoordinateSystemE - fun:_ZNK7WebCore24CanvasRenderingContext2D12getImageDataENS_11ImageBuffer16CoordinateSystemEffffRNS_14ExceptionStateE - fun:_ZNK7WebCore24CanvasRenderingContext2D12getImageDataEffffRNS_14ExceptionStateE + fun:_ZN11SkGpuDevice12onReadPixelsE* + fun:_ZN12SkBaseDevice10readPixelsE* + fun:_ZN8SkCanvas10readPixelsE* + fun:_ZN*DeferredDevice12onReadPixelsE* + fun:_ZN12SkBaseDevice10readPixelsE* + fun:_ZN8SkCanvas10readPixelsE* + fun:_ZN7WebCore15GraphicsContext10readPixelsE* + fun:_ZN7WebCore12getImageDataILNS_8MultiplyE* + fun:_ZNK7WebCore11ImageBuffer24getUnmultipliedImageDataE* + fun:_ZNK7WebCore24CanvasRenderingContext2D12getImageDataE* + ... fun:_ZN7WebCore34CanvasRenderingContext2DV8InternalL18getImageDataMethodERKN2v820FunctionCallbackInfoINS1_5ValueEEE fun:_ZN7WebCore34CanvasRenderingContext2DV8InternalL26getImageDataMethodCallbackERKN2v820FunctionCallbackInfoINS1_5ValueEEE - fun:_ZN2v88internal25FunctionCallbackArguments4CallEPFvRKNS_20FunctionCallbackInfoINS_5ValueEEEE - fun:_ZN2v88internalL19HandleApiCallHelperILb0EEEPNS0_11MaybeObjectENS0_12_GLOBAL__N_116BuiltinArgumentsILNS0_21BuiltinExtraArgumentsE1EEEPNS0_7IsolateE } { bug_309468 @@ -6297,9 +6274,7 @@ fun:_ZN3WTF10fastMallocEm fun:_ZN3WTF10RefCountedIN7WebCore11ScriptStateEEnwEm fun:_ZN7WebCore11ScriptState6createEN2v86HandleINS1_7ContextEEEN3WTF10PassRefPtrINS_15DOMWrapperWorldEEE - fun:_ZN7WebCore22WorkerScriptController25initializeContextIfNeededEv - fun:_ZN7WebCore22WorkerScriptController8evaluateERKN3WTF6StringES4_RKNS1_12TextPositionEPNS_31WorkerGlobalScopeExecutionStateE - fun:_ZN7WebCore22WorkerScriptController8evaluateERKNS_16ScriptSourceCodeEPN3WTF6RefPtrINS_10ErrorEventEEE + ... fun:_ZN7WebCore12WorkerThread12workerThreadEv fun:_ZN7WebCore12WorkerThread17workerThreadStartEPv fun:_ZN3WTFL16threadEntryPointEPv @@ -6490,3 +6465,98 @@ fun:_Znw* fun:_ZN7content27ServiceWorkerContextWrapper12InitInternalERKN4base8FilePathEPNS1_19SequencedTaskRunnerEPNS1_16MessageLoopProxyEPN5quota17QuotaManagerProxyE } +{ + bug_379359 + Memcheck:Leak + fun:_Znw* + fun:_ZN7content27ServiceWorkerContextWrapperC1EPNS_14BrowserContextE + fun:_ZN7content20StoragePartitionImpl6CreateEPNS_14BrowserContextEbRKN4base8FilePathE + fun:_ZN7content23StoragePartitionImplMap3GetERKSsS2_b + fun:_ZN7content12_GLOBAL__N_129GetStoragePartitionFromConfigEPNS_14BrowserContextERKSsS4_b + fun:_ZN7content14BrowserContext19GetStoragePartitionEPS0_PNS_12SiteInstanceE + fun:_ZN7content14BrowserContext26GetDefaultStoragePartitionEPS0_ + fun:_ZN7content21ShellBrowserMainParts21PreMainMessageLoopRunEv + fun:_ZN7content15BrowserMainLoop21PreMainMessageLoopRunEv +} +{ + bug_379943 + Memcheck:Leak + fun:_Znw* + ... + fun:_ZN7content23CreateFileSystemContextEPNS_14BrowserContextERKN4base8FilePathEbPN5quota17QuotaManagerProxyE + fun:_ZN7content20StoragePartitionImpl6CreateEPNS_14BrowserContextEbRKN4base8FilePathE + fun:_ZN7content23StoragePartitionImplMap3GetERKSsS2_b + fun:_ZN7content12_GLOBAL__N_129GetStoragePartitionFromConfigEPNS_14BrowserContextERKSsS4_b + fun:_ZN7content14BrowserContext19GetStoragePartitionEPS0_PNS_12SiteInstanceE + fun:_ZN7content14BrowserContext26GetDefaultStoragePartitionEPS0_ + fun:_ZN7content21ShellBrowserMainParts21PreMainMessageLoopRunEv + fun:_ZN7content15BrowserMainLoop21PreMainMessageLoopRunEv +} +{ + bug_380575 + Memcheck:Leak + fun:_Znw* + fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKSsPN3net20URLRequestJobFactory15ProtocolHandlerEEEE8allocateEmPKv + ... + fun:_ZNSt8_Rb_treeISsSt4pairIKSsPN3net20URLRequestJobFactory15ProtocolHandlerEESt10_Select1stIS6_ESt4lessISsESaIS6_EE17_M_insert_unique_ESt23_Rb_tree_const_iteratorIS6_ERKS6_ + fun:_ZNSt3mapISsPN3net20URLRequestJobFactory15ProtocolHandlerESt4lessISsESaISt4pairIKSsS3_EEE6insertESt17_Rb_tree_iteratorIS8_ERKS8_ + fun:_ZNSt3mapISsPN3net20URLRequestJobFactory15ProtocolHandlerESt4lessISsESaISt4pairIKSsS3_EEEixERS7_ + fun:_ZN3net24URLRequestJobFactoryImpl18SetProtocolHandlerERKSsPNS_20URLRequestJobFactory15ProtocolHandlerE + ... + fun:_ZN7content28ShellURLRequestContextGetter20GetURLRequestContextEv + fun:_ZN7content21ChromeAppCacheService20InitializeOnIOThreadERKN4base8FilePathEPNS_15ResourceContextEPN3net23URLRequestContextGetterE13scoped_refptrIN5quota20SpecialStoragePolicyEE +} +{ + bug_381065 + Memcheck:Leak + fun:_Znw* + ... + fun:_ZN7WebCore18ModulesInitializer20registerEventFactoryEv + fun:_ZN7WebCore15CoreInitializer4initEv + fun:_ZN5blink19initializeWithoutV8EPNS_8PlatformE + fun:_ZN5blink10initializeEPNS_8PlatformE + fun:_ZN7content25TestWebKitPlatformSupportC2Ev + fun:_ZN7content25TestWebKitPlatformSupportC1Ev + fun:_ZN7content17UnitTestTestSuiteC2EPN4base9TestSuiteE + fun:_ZN7content17UnitTestTestSuiteC1EPN4base9TestSuiteE +} +{ + bug_381156 + Memcheck:Uninitialized + ... + fun:_ZN*14SkTDynamicHashI10SkFlatData* + fun:_ZN16SkFlatDictionaryI7SkPaintNS0_16FlatteningTraitsEE24findAndReturnMutableFlatERKS0_ + fun:_ZN16SkFlatDictionaryI7SkPaintNS0_16FlatteningTraitsEE17findAndReturnFlatERKS0_ + fun:_ZN15SkPictureRecord16getFlatPaintDataERK7SkPaint + fun:_ZN15SkPictureRecord11addPaintPtrEPK7SkPaint + fun:_ZN15SkPictureRecord8addPaintERK7SkPaint + fun:_ZN15SkPictureRecord8drawPathERK6SkPathRK7SkPaint + fun:_ZN12SkBBoxRecord8drawPathERK6SkPathRK7SkPaint + fun:_ZN7WebCore15GraphicsContext8drawPathERK6SkPathRK7SkPaint + fun:_ZN7WebCore15GraphicsContext10strokePathERKNS_4PathE + fun:_ZNK7WebCore14RenderSVGShape11strokeShapeEPNS_15GraphicsContextE + fun:_ZNK7WebCore13RenderSVGPath11strokeShapeEPNS_15GraphicsContextE + fun:_ZN7WebCore27RenderSVGResourceSolidColor17postApplyResourceEPNS_12RenderObjectERPNS_15GraphicsContextEtPKNS_4PathEPKNS_14RenderSVGShapeE + fun:_ZN7WebCore14RenderSVGShape11strokeShapeEPNS_11RenderStyleEPNS_15GraphicsContextE + fun:_ZN7WebCore14RenderSVGShape5paintERNS_9PaintInfoERKNS_11LayoutPointE + fun:_ZN7WebCore9RenderBox5paintERNS_9PaintInfoERKNS_11LayoutPointE + fun:_ZN7WebCore13RenderSVGRoot13paintReplacedERNS_9PaintInfoERKNS_11LayoutPointE + fun:_ZN7WebCore14RenderReplaced5paintERNS_9PaintInfoERKNS_11LayoutPointE + fun:_ZN7WebCore11RenderBlock18paintAsInlineBlockEPNS_12RenderObjectERNS_9PaintInfoERKNS_11LayoutPointE +} +{ + bug_381584 + Memcheck:Leak + fun:_Znw* + fun:_ZN4base8internal20PostTaskAndReplyImpl16PostTaskAndReplyERKN15tracked_objects8LocationERKNS_8CallbackIFvvEEESA_ + fun:_ZN4base10TaskRunner16PostTaskAndReplyERKN15tracked_objects8LocationERKNS_8CallbackIFvvEEES9_ + fun:_ZN4base26PostTaskAndReplyWithResultI13scoped_refptrIN8chromeos8OwnerKeyEES4_EEbPNS_10TaskRunnerERKN15tracked_objects8LocationERKNS_8CallbackIFT_vEEERKNSB_IFvT0_EEE + fun:_ZN8chromeos23SessionManagerOperation14EnsureOwnerKeyERKN4base8CallbackIFvvEEE + fun:_ZN8chromeos23SessionManagerOperation12StartLoadingEv + fun:_ZN8chromeos21LoadSettingsOperation3RunEv + fun:_ZN8chromeos23SessionManagerOperation5StartEPNS_20SessionManagerClientE13scoped_refptrINS_12OwnerKeyUtilEES3_INS_8OwnerKeyEE + fun:_ZN8chromeos21DeviceSettingsService18StartNextOperationEv + fun:_ZN8chromeos21DeviceSettingsService7EnqueueEPNS_23SessionManagerOperationE + fun:_ZN8chromeos21DeviceSettingsService11EnqueueLoadEb + fun:_ZN8chromeos21DeviceSettingsService4LoadEv +} diff --git a/tools/valgrind/memcheck/suppressions_mac.txt b/tools/valgrind/memcheck/suppressions_mac.txt index 705ddb9a93..9b6a97824b 100644 --- a/tools/valgrind/memcheck/suppressions_mac.txt +++ b/tools/valgrind/memcheck/suppressions_mac.txt @@ -112,14 +112,7 @@ bug_257276_b Memcheck:Leak fun:malloc_zone_malloc - fun:_CFRuntimeCreateInstance - fun:CFNumberCreate - fun:get_colorspace - fun:initImagePng - fun:_CGImagePluginInitPNG - fun:makeImagePlus - fun:CGImageSourceCreateImageAtIndex - fun:CGImageCreateWithPNGDataProvider + ... fun:setCursorFromBundle fun:CoreCursorSet fun:-[NSCursor set] @@ -2459,3 +2452,16 @@ fun:_ZN7content17UnitTestTestSuiteC2EPN4base9TestSuiteE fun:_ZN7content17UnitTestTestSuiteC1EPN4base9TestSuiteE } +{ + bug_380568 + Memcheck:Leak + fun:calloc + fun:_internal_class_createInstanceFromZone + fun:_internal_class_createInstance + fun:NSAllocateObject + fun:+[NSObject(NSObject) alloc] + fun:-[VideoCaptureDeviceQTKit initWithFrameReceiver:] + fun:_ZN5media21VideoCaptureDeviceMac4InitENS_18VideoCaptureDevice4Name14CaptureApiTypeE + fun:_ZN5media28VideoCaptureDeviceFactoryMac6CreateERKNS_18VideoCaptureDevice4NameE + fun:_ZN5media45VideoCaptureDeviceTest_OpenInvalidDevice_Test8TestBodyEv +} diff --git a/tools/valgrind/tsan/suppressions.txt b/tools/valgrind/tsan/suppressions.txt index ac3386bb0d..0568d4cc52 100644 --- a/tools/valgrind/tsan/suppressions.txt +++ b/tools/valgrind/tsan/suppressions.txt @@ -828,26 +828,6 @@ fun:_vsnprintf_helper } { - bug_137973_a - ThreadSanitizer:Race - fun:media::Pipeline::OnVideoTimeUpdate - fun:base::internal::RunnableAdapter::Run -} -{ - bug_137973_b - ThreadSanitizer:Race - fun:media::Pipeline::SetState - fun:media::Pipeline::StopTask - fun:base::internal::RunnableAdapter::Run -} -{ - bug_137973_c - ThreadSanitizer:Race - fun:media::Pipeline::SetState - fun:media::Pipeline::SeekTask - fun:base::internal::RunnableAdapter::Run -} -{ bug_144894 ThreadSanitizer:Race fun:av_parser_close @@ -1051,7 +1031,7 @@ fun:base::internal::RunnableAdapter::Run } { - bug_344704 + bug_344704_a ThreadSanitizer:Race fun:base::Thread::message_loop fun:printing::PrintJob::UpdatePrintedDocument @@ -1060,6 +1040,17 @@ fun:PrintJobTest_SimplePrint_Test::TestBody } { + bug_344704_b + ThreadSanitizer:Race + fun:scoped_refptr::operator= + fun:base::MessageLoop::~MessageLoop + fun:base::MessageLoop::~MessageLoop + fun:base::DefaultDeleter::operator* + fun:base::internal::scoped_ptr_impl::~scoped_ptr_impl + fun:scoped_ptr::~scoped_ptr + fun:base::Thread::ThreadMain +} +{ bug_350982 ThreadSanitizer:Race fun:change_state |