diff options
author | ernstm@chromium.org <ernstm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-16 11:49:43 +0000 |
---|---|---|
committer | ernstm@chromium.org <ernstm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-16 11:49:43 +0000 |
commit | bb82d679961b5c4ca2d938af15bd0b38d3e72d22 (patch) | |
tree | 495928688f666122496604501837bc8133668aac | |
parent | 86e4fa6746b34bbdd84901debb64d6de511699fc (diff) | |
download | chromium_src-bb82d679961b5c4ca2d938af15bd0b38d3e72d22.zip chromium_src-bb82d679961b5c4ca2d938af15bd0b38d3e72d22.tar.gz chromium_src-bb82d679961b5c4ca2d938af15bd0b38d3e72d22.tar.bz2 |
Made trace profiler work with trace-based benchmarks.
R=tonyg
BUG=282712
Review URL: https://chromiumcodereview.appspot.com/23902027
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@223330 0039d316-1c4b-4281-b951-d872f2087c98
10 files changed, 167 insertions, 40 deletions
diff --git a/tools/perf/measurements/rasterize_and_record.py b/tools/perf/measurements/rasterize_and_record.py index 4ed5a09..b5bc613 100644 --- a/tools/perf/measurements/rasterize_and_record.py +++ b/tools/perf/measurements/rasterize_and_record.py @@ -148,7 +148,7 @@ class RasterizeAndRecord(page_measurement.PageMeasurement): }); """) - tab.browser.StartTracing('webkit,webkit.console,benchmark', 60) + tab.browser.StartTracing('webkit.console,benchmark', 60) self._metrics.Start() tab.ExecuteJavaScript(""" @@ -166,10 +166,9 @@ class RasterizeAndRecord(page_measurement.PageMeasurement): time.sleep(float(self.options.stop_wait_time)) tab.ExecuteJavaScript('console.timeEnd("measureNextFrame")') - tab.browser.StopTracing() self._metrics.Stop() + timeline = tab.browser.StopTracing().AsTimelineModel() - timeline = tab.browser.GetTraceResultAndReset().AsTimelineModel() collector = StatsCollector(timeline) collector.GatherRenderingStats() diff --git a/tools/perf/measurements/smoothness.py b/tools/perf/measurements/smoothness.py index a26ba68..f44feef 100644 --- a/tools/perf/measurements/smoothness.py +++ b/tools/perf/measurements/smoothness.py @@ -28,6 +28,7 @@ class Smoothness(page_measurement.PageMeasurement): super(Smoothness, self).__init__('smoothness') self.force_enable_threaded_compositing = False self._metrics = None + self._trace_result = None def AddCommandLineOptions(self, parser): parser.add_option('--report-all-results', dest='report_all_results', @@ -43,9 +44,7 @@ class Smoothness(page_measurement.PageMeasurement): return hasattr(page, 'smoothness') def WillRunAction(self, page, tab, action): - # TODO(ernstm): remove 'webkit' category when - # https://codereview.chromium.org/23848006/ has landed. - tab.browser.StartTracing('webkit,webkit.console,benchmark', 60) + tab.browser.StartTracing('webkit.console,benchmark', 60) if tab.browser.platform.IsRawDisplayFrameRateSupported(): tab.browser.platform.StartRawDisplayFrameRateMeasurement() self._metrics = smoothness.SmoothnessMetrics(tab) @@ -59,7 +58,7 @@ class Smoothness(page_measurement.PageMeasurement): tab.browser.platform.StopRawDisplayFrameRateMeasurement() if not action.CanBeBound(): self._metrics.Stop() - tab.browser.StopTracing() + self._trace_result = tab.browser.StopTracing() def FindTimelineMarker(self, timeline): events = [s for @@ -80,8 +79,8 @@ class Smoothness(page_measurement.PageMeasurement): smoothness.CalcFirstPaintTimeResults(results, tab) - timeline = tab.browser.GetTraceResultAndReset().AsTimelineModel() - timeline_marker = self.FindTimelineMarker(timeline) + timeline_marker = self.FindTimelineMarker( + self._trace_result.AsTimelineModel()) benchmark_stats = GpuRenderingStats(timeline_marker, rendering_stats_deltas, self._metrics.is_using_gpu_benchmarking) diff --git a/tools/perf/metrics/timeline.py b/tools/perf/metrics/timeline.py index 6462646..6d9ef26 100644 --- a/tools/perf/metrics/timeline.py +++ b/tools/perf/metrics/timeline.py @@ -38,8 +38,7 @@ class TimelineMetric(Metric): console.timeEnd("__loading_measurement_was_here__"); """) - tab.browser.StopTracing() - trace_result = tab.browser.GetTraceResultAndReset() + trace_result = tab.browser.StopTracing() self._model = trace_result.AsTimelineModel() events = [s for s in self._model.GetAllEventsOfName( @@ -68,4 +67,3 @@ class TimelineMetric(Metric): results.Add(event_name, 'ms', total) results.Add(event_name + '_max', 'ms', biggest_jank) results.Add(event_name + '_avg', 'ms', total / len(times)) - diff --git a/tools/telemetry/telemetry/core/backends/browser_backend.py b/tools/telemetry/telemetry/core/backends/browser_backend.py index 2c6f058..22df0b1 100644 --- a/tools/telemetry/telemetry/core/backends/browser_backend.py +++ b/tools/telemetry/telemetry/core/backends/browser_backend.py @@ -66,9 +66,6 @@ class BrowserBackend(object): def StopTracing(self): raise NotImplementedError() - def GetTraceResultAndReset(self): - raise NotImplementedError() - def GetRemotePort(self, _): return util.GetAvailableLocalPort() 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 579cef4..aeadf92 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py +++ b/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py @@ -222,13 +222,11 @@ class ChromeBrowserBackend(browser_backend.BrowserBackend): """ if self._tracing_backend is None: self._tracing_backend = tracing_backend.TracingBackend(self._port) - self._tracing_backend.BeginTracing(custom_categories, timeout) + return self._tracing_backend.StartTracing(custom_categories, timeout) def StopTracing(self): - self._tracing_backend.EndTracing() - - def GetTraceResultAndReset(self): - return self._tracing_backend.GetTraceResultAndReset() + """ Stops tracing and returns the result as TraceResult object. """ + return self._tracing_backend.StopTracing() def GetProcessName(self, cmd_line): """Returns a user-friendly name for the process of the given |cmd_line|.""" diff --git a/tools/telemetry/telemetry/core/backends/chrome/tracing_backend.py b/tools/telemetry/telemetry/core/backends/chrome/tracing_backend.py index 4d0c68a..f080280 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/tracing_backend.py +++ b/tools/telemetry/telemetry/core/backends/chrome/tracing_backend.py @@ -8,7 +8,6 @@ import logging import socket import threading - from telemetry.core.backends.chrome import trace_result from telemetry.core.backends.chrome import websocket from telemetry.core.backends.chrome import websocket_browser_connection @@ -65,16 +64,97 @@ class RawTraceResultImpl(object): def AsTimelineModel(self): return model.TimelineModel(self._tracing_data) +class CategoryFilter(object): + def __init__(self, filter_string): + self.excluded = set() + self.included = set() + self.disabled = set() + self.contains_wildcards = False + + if not filter_string: + return + + if '*' in filter_string or '?' in filter_string: + self.contains_wildcards = True + + filter_set = set(filter_string.split(',')) + for category in filter_set: + if category == '': + continue + if category[0] == '-': + category = category[1:] + self.excluded.add(category) + elif category.startswith('disabled-by-default-'): + self.disabled.add(category) + else: + self.included.add(category) + + def IsSubset(self, other): + """ Determine if filter A (self) is a subset of filter B (other). + Returns True if A is a subset of B, False if A is not a subset of B, + and None if we can't tell for sure. + """ + # We don't handle filters with wildcards in this test. + if self.contains_wildcards or other.contains_wildcards: + return None + + # Disabled categories get into a trace if and only if they are contained in + # the 'disabled' set. Return False if A's disabled set is a superset of B's + # disabled set. + if len(self.disabled): + if self.disabled > other.disabled: + return False + + if len(self.included) and len(other.included): + # A and B have explicit include lists. If A includes something that B + # doesn't, return False. + if not self.included <= other.included: + return False + elif len(self.included): + # Only A has an explicit include list. If A includes something that B + # excludes, return False. + if len(self.included.intersection(other.excluded)): + return False + elif len(other.included): + # Only B has an explicit include list. We don't know which categories are + # contained in the default list, so return None. + return None + else: + # None of the filter have explicit include list. If B excludes categories + # that A doesn't exclude, return False. + if not other.excluded <= self.excluded: + return False + + return True + class TracingBackend(object): def __init__(self, devtools_port): self._conn = websocket_browser_connection.WebSocketBrowserConnection( devtools_port) self._thread = None + self._category_filter = None + self._nesting = 0 self._tracing_data = [] - def BeginTracing(self, custom_categories=None, timeout=10): + def _IsTracing(self): + return self._thread != None + + def StartTracing(self, custom_categories=None, timeout=10): + """ Starts tracing on the first nested call and returns True. Returns False + and does nothing on subsequent nested calls. + """ + self._nesting += 1 + if self._IsTracing(): + new_category_filter = CategoryFilter(custom_categories) + is_subset = new_category_filter.IsSubset(self._category_filter) + assert(is_subset != False) + if is_subset == None: + logging.warning('Cannot determine if category filter of nested ' + + 'StartTracing call is subset of current filter.') + return False self._CheckNotificationSupported() req = {'method': 'Tracing.start'} + self._category_filter = CategoryFilter(custom_categories) if custom_categories: req['params'] = {'categories': custom_categories} self._conn.SendRequest(req, timeout) @@ -82,22 +162,39 @@ class TracingBackend(object): # data, until Tracing.end is called. self._thread = threading.Thread(target=self._TracingReader) self._thread.start() + return True + + def StopTracing(self): + """ Stops tracing on the innermost (!) nested call, because we cannot get + results otherwise. Resets _tracing_data on the outermost nested call. + Returns the result of the trace, as TraceResult object. + """ + self._nesting -= 1 + assert self._nesting >= 0 + if self._IsTracing(): + req = {'method': 'Tracing.end'} + self._conn.SendRequest(req) + self._thread.join() + self._thread = None + if self._nesting == 0: + self._category_filter = None + return self._GetTraceResultAndReset() + else: + return self._GetTraceResult() - def EndTracing(self): - req = {'method': 'Tracing.end'} - self._conn.SendRequest(req) - self._thread.join() - self._thread = None - - def GetTraceResultAndReset(self): - assert not self._thread + def _GetTraceResult(self): + assert not self._IsTracing() if self._tracing_data and type(self._tracing_data[0]) in [str, unicode]: result_impl = TraceResultImpl(self._tracing_data) else: result_impl = RawTraceResultImpl(self._tracing_data) - self._tracing_data = [] return trace_result.TraceResult(result_impl) + def _GetTraceResultAndReset(self): + result = self._GetTraceResult() + self._tracing_data = [] + return result + def _TracingReader(self): while self._conn.socket: try: diff --git a/tools/telemetry/telemetry/core/backends/chrome/tracing_backend_unittest.py b/tools/telemetry/telemetry/core/backends/chrome/tracing_backend_unittest.py index afbb3b8..b2b0fa3 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/tracing_backend_unittest.py +++ b/tools/telemetry/telemetry/core/backends/chrome/tracing_backend_unittest.py @@ -11,6 +11,52 @@ from telemetry.core import util from telemetry.core.backends.chrome import tracing_backend from telemetry.unittest import tab_test_case +class CategoryFilterTest(unittest.TestCase): + def testIsSubset(self): + b = tracing_backend.CategoryFilter(None) + a = tracing_backend.CategoryFilter(None) + self.assertEquals(a.IsSubset(b), True) + + b = tracing_backend.CategoryFilter(None) + a = tracing_backend.CategoryFilter("test1,test2") + self.assertEquals(a.IsSubset(b), True) + + b = tracing_backend.CategoryFilter(None) + a = tracing_backend.CategoryFilter("-test1,-test2") + self.assertEquals(a.IsSubset(b), True) + + b = tracing_backend.CategoryFilter("test1,test2") + a = tracing_backend.CategoryFilter(None) + self.assertEquals(a.IsSubset(b), None) + + b = tracing_backend.CategoryFilter(None) + a = tracing_backend.CategoryFilter("test*") + self.assertEquals(a.IsSubset(b), None) + + b = tracing_backend.CategoryFilter("test?") + a = tracing_backend.CategoryFilter(None) + self.assertEquals(a.IsSubset(b), None) + + b = tracing_backend.CategoryFilter("test1") + a = tracing_backend.CategoryFilter("test1,test2") + self.assertEquals(a.IsSubset(b), False) + + b = tracing_backend.CategoryFilter("-test1") + a = tracing_backend.CategoryFilter("test1") + self.assertEquals(a.IsSubset(b), False) + + b = tracing_backend.CategoryFilter("test1,test2") + a = tracing_backend.CategoryFilter("test2,test1") + self.assertEquals(a.IsSubset(b), True) + + b = tracing_backend.CategoryFilter("-test1,-test2") + a = tracing_backend.CategoryFilter("-test2") + self.assertEquals(a.IsSubset(b), False) + + b = tracing_backend.CategoryFilter("disabled-by-default-test1") + a = tracing_backend.CategoryFilter( + "disabled-by-default-test1,disabled-by-default-test2") + self.assertEquals(a.IsSubset(b), False) class TracingBackendTest(tab_test_case.TabTestCase): def _StartServer(self): diff --git a/tools/telemetry/telemetry/core/browser.py b/tools/telemetry/telemetry/core/browser.py index bdf26d4..c436794 100644 --- a/tools/telemetry/telemetry/core/browser.py +++ b/tools/telemetry/telemetry/core/browser.py @@ -256,10 +256,6 @@ class Browser(object): def StopTracing(self): return self._browser_backend.StopTracing() - def GetTraceResultAndReset(self): - """Returns the result of the trace, as TraceResult object.""" - return self._browser_backend.GetTraceResultAndReset() - def Start(self): browser_options = self._browser_backend.browser_options if browser_options.clear_sytem_cache_for_browser_and_profile_on_start: diff --git a/tools/telemetry/telemetry/core/platform/profiler/strace_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/strace_profiler.py index f270106..c22140b 100644 --- a/tools/telemetry/telemetry/core/platform/profiler/strace_profiler.py +++ b/tools/telemetry/telemetry/core/platform/profiler/strace_profiler.py @@ -241,8 +241,7 @@ class StraceProfiler(profiler.Profiler): for single_process in self._process_profilers: out_json.extend(single_process.CollectProfile()) - self._browser_backend.StopTracing() - model = self._browser_backend.GetTraceResultAndReset().AsTimelineModel() + model = self._browser_backend.StopTracing().AsTimelineModel() out_json.extend(_GenerateTraceMetadata(model)) with open(self._output_file, 'w') as f: diff --git a/tools/telemetry/telemetry/core/platform/profiler/trace_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/trace_profiler.py index 122db9c..6262847 100644 --- a/tools/telemetry/telemetry/core/platform/profiler/trace_profiler.py +++ b/tools/telemetry/telemetry/core/platform/profiler/trace_profiler.py @@ -24,11 +24,9 @@ class TraceProfiler(profiler.Profiler): return True def CollectProfile(self): - self._browser_backend.StopTracing() - print 'Processing trace...' - trace_result = self._browser_backend.GetTraceResultAndReset() + trace_result = self._browser_backend.StopTracing() trace_file = '%s.json' % self._output_path |