Index: tools/telemetry/telemetry/core/platform/tracing_category_filter.py |
diff --git a/tools/telemetry/telemetry/core/platform/tracing_category_filter.py b/tools/telemetry/telemetry/core/platform/tracing_category_filter.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..06f2502a75f58ca782d23a8255ecf4431d11a52d |
--- /dev/null |
+++ b/tools/telemetry/telemetry/core/platform/tracing_category_filter.py |
@@ -0,0 +1,179 @@ |
+# 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 re |
+ |
+ |
+def CreateNoOverheadFilter(): |
+ """Returns a filter with the least overhead possible. |
+ |
+ This contains no sub-traces of thread tasks, so it's only useful for |
+ capturing the cpu-time spent on threads (as well as needed benchmark |
+ traces). |
+ |
+ FIXME: Remove webkit.console when blink.console lands in chromium and |
+ the ref builds are updated. crbug.com/386847 |
+ """ |
+ categories = [ |
+ "toplevel", |
+ "benchmark", |
+ "webkit.console", |
+ "blink.console", |
+ "trace_event_overhead" |
+ ] |
+ return TracingCategoryFilter(filter_string=','.join(categories)) |
+ |
+ |
+def CreateMinimalOverheadFilter(): |
+ """Returns a filter with the best-effort amount of overhead.""" |
+ return TracingCategoryFilter(filter_string='') |
+ |
+ |
+def CreateDebugOverheadFilter(): |
+ """Returns a filter with as many traces enabled as is useful.""" |
+ return TracingCategoryFilter(filter_string='*,disabled-by-default-cc.debug') |
+ |
+ |
+_delay_re = re.compile(r'DELAY[(][A-Za-z0-9._;]+[)]') |
+ |
+ |
+class TracingCategoryFilter(object): |
+ """A set of included and excluded categories that should be traced. |
+ |
+ The TraceCategoryFilter allows fine tuning of what data is traced. Basic |
+ choice of which tracers to use is done by TracingOptions. |
+ |
+ Providing filter_string=None gives the default category filter, which leaves |
+ what to trace up to the individual trace systems. |
+ """ |
+ def __init__(self, filter_string=None): |
+ self._included_categories = set() |
+ self._excluded_categories = set() |
+ self._disabled_by_default_categories = set() |
+ self._synthetic_delays = set() |
+ self.contains_wildcards = False |
+ |
+ if filter_string == None: |
+ 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 _delay_re.match(category): |
+ self._synthetic_delays.add(category) |
+ continue |
+ |
+ if category[0] == '-': |
+ self._excluded_categories.add(category[1:]) |
+ continue |
+ |
+ if category.startswith('disabled-by-default-'): |
+ self._disabled_by_default_categories.add(category) |
+ continue |
+ |
+ self.included_categories.add(category) |
+ |
+ @property |
+ def included_categories(self): |
+ return self._included_categories |
+ |
+ @property |
+ def excluded_categories(self): |
+ return self._excluded_categories |
+ |
+ @property |
+ def disabled_by_default_categories(self): |
+ return self._disabled_by_default_categories |
+ |
+ @property |
+ def synthetic_delays(self): |
+ return self._synthetic_delays |
+ |
+ @property |
+ def filter_string(self): |
+ return self._GetFilterString(stable_output=False) |
+ |
+ @property |
+ def stable_filter_string(self): |
+ return self._GetFilterString(stable_output=True) |
+ |
+ def _GetFilterString(self, stable_output): |
+ # Note: This outputs fields in an order that intentionally matches |
+ # trace_event_impl's CategoryFilter string order. |
+ lists = [] |
+ lists.append(self._included_categories) |
+ lists.append(self._disabled_by_default_categories) |
+ lists.append(['-%s' % x for x in self._excluded_categories]) |
+ lists.append(self._synthetic_delays) |
+ categories = [] |
+ for l in lists: |
+ if stable_output: |
+ l = list(l) |
+ l.sort() |
+ categories.extend(l) |
+ return ','.join(categories) |
+ |
+ def AddIncludedCategory(self, category_glob): |
+ """Explicitly enables anything matching category_glob.""" |
+ assert not category_glob.startswith('disabled-by-default-') |
+ if category_glob not in self._included_categories: |
+ self._included_categories.append(category_glob) |
+ |
+ def AddExcludedCategory(self, category_glob): |
+ """Explicitly disables anything matching category_glob.""" |
+ assert not category_glob.startswith('disabled-by-default-') |
+ if category_glob not in self._excluded_categories: |
+ self._excluded_categories.append(category_glob) |
+ |
+ def AddSyntheticDelay(self, delay): |
+ assert _delay_re.match(delay) |
+ self._synthetic_delays.add(delay) |
+ |
+ 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 not a subset of |
+ # B's disabled set. |
+ if not self.disabled_by_default_categories <= \ |
+ other.disabled_by_default_categories: |
+ return False |
+ |
+ # If A defines more or different synthetic delays than B, then A is not a |
+ # subset. |
+ if not self.synthetic_delays <= other.synthetic_delays: |
+ return False |
+ |
+ if self.included_categories and other.included_categories: |
+ # A and B have explicit include lists. If A includes something that B |
+ # doesn't, return False. |
+ if not self.included_categories <= other.included_categories: |
+ return False |
+ elif self.included_categories: |
+ # Only A has an explicit include list. If A includes something that B |
+ # excludes, return False. |
+ if self.included_categories.intersection(other.excluded_categories): |
+ return False |
+ elif other.included_categories: |
+ # 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_categories <= self.excluded_categories: |
+ return False |
+ |
+ return True |