1# Copyright 2014 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import re 6 7 8def CreateNoOverheadFilter(): 9 """Returns a filter with the least overhead possible. 10 11 This contains no sub-traces of thread tasks, so it's only useful for 12 capturing the cpu-time spent on threads (as well as needed benchmark 13 traces). 14 15 FIXME: Remove webkit.console when blink.console lands in chromium and 16 the ref builds are updated. crbug.com/386847 17 """ 18 categories = [ 19 "toplevel", 20 "benchmark", 21 "webkit.console", 22 "blink.console", 23 "trace_event_overhead" 24 ] 25 return TracingCategoryFilter(filter_string=','.join(categories)) 26 27 28def CreateMinimalOverheadFilter(): 29 """Returns a filter with the best-effort amount of overhead.""" 30 return TracingCategoryFilter(filter_string='') 31 32 33def CreateDebugOverheadFilter(): 34 """Returns a filter with as many traces enabled as is useful.""" 35 return TracingCategoryFilter(filter_string='*,disabled-by-default-cc.debug') 36 37 38_delay_re = re.compile(r'DELAY[(][A-Za-z0-9._;]+[)]') 39 40 41class TracingCategoryFilter(object): 42 """A set of included and excluded categories that should be traced. 43 44 The TraceCategoryFilter allows fine tuning of what data is traced. Basic 45 choice of which tracers to use is done by TracingOptions. 46 47 Providing filter_string=None gives the default category filter, which leaves 48 what to trace up to the individual trace systems. 49 """ 50 def __init__(self, filter_string=None): 51 self._included_categories = set() 52 self._excluded_categories = set() 53 self._disabled_by_default_categories = set() 54 self._synthetic_delays = set() 55 self.contains_wildcards = False 56 self.AddFilterString(filter_string) 57 58 def AddFilterString(self, filter_string): 59 if filter_string == None: 60 return 61 62 if '*' in filter_string or '?' in filter_string: 63 self.contains_wildcards = True 64 65 filter_set = set([cf.strip() for cf in filter_string.split(',')]) 66 for category in filter_set: 67 if category == '': 68 continue 69 70 if _delay_re.match(category): 71 self._synthetic_delays.add(category) 72 continue 73 74 if category[0] == '-': 75 assert not category[1:] in self._included_categories 76 self._excluded_categories.add(category[1:]) 77 continue 78 79 if category.startswith('disabled-by-default-'): 80 self._disabled_by_default_categories.add(category) 81 continue 82 83 assert not category in self._excluded_categories 84 self._included_categories.add(category) 85 86 @property 87 def included_categories(self): 88 return self._included_categories 89 90 @property 91 def excluded_categories(self): 92 return self._excluded_categories 93 94 @property 95 def disabled_by_default_categories(self): 96 return self._disabled_by_default_categories 97 98 @property 99 def synthetic_delays(self): 100 return self._synthetic_delays 101 102 @property 103 def filter_string(self): 104 return self._GetFilterString(stable_output=False) 105 106 @property 107 def stable_filter_string(self): 108 return self._GetFilterString(stable_output=True) 109 110 def _GetFilterString(self, stable_output): 111 # Note: This outputs fields in an order that intentionally matches 112 # trace_event_impl's CategoryFilter string order. 113 lists = [] 114 lists.append(self._included_categories) 115 lists.append(self._disabled_by_default_categories) 116 lists.append(['-%s' % x for x in self._excluded_categories]) 117 lists.append(self._synthetic_delays) 118 categories = [] 119 for l in lists: 120 if stable_output: 121 l = list(l) 122 l.sort() 123 categories.extend(l) 124 return ','.join(categories) 125 126 def GetDictForChromeTracing(self): 127 INCLUDED_CATEGORIES_PARAM = 'included_categories' 128 EXCLUDED_CATEGORIES_PARAM = 'excluded_categories' 129 SYNTHETIC_DELAYS_PARAM = 'synthetic_delays' 130 131 result = {} 132 if self._included_categories or self._disabled_by_default_categories: 133 result[INCLUDED_CATEGORIES_PARAM] = list( 134 self._included_categories | self._disabled_by_default_categories) 135 if self._excluded_categories: 136 result[EXCLUDED_CATEGORIES_PARAM] = list(self._excluded_categories) 137 if self._synthetic_delays: 138 result[SYNTHETIC_DELAYS_PARAM] = list(self._synthetic_delays) 139 return result 140 141 def AddDisabledByDefault(self, category): 142 assert category.startswith('disabled-by-default-') 143 self._disabled_by_default_categories.add(category) 144 145 def AddIncludedCategory(self, category_glob): 146 """Explicitly enables anything matching category_glob.""" 147 assert not category_glob.startswith('disabled-by-default-') 148 assert not category_glob in self._excluded_categories 149 self._included_categories.add(category_glob) 150 151 def AddExcludedCategory(self, category_glob): 152 """Explicitly disables anything matching category_glob.""" 153 assert not category_glob.startswith('disabled-by-default-') 154 assert not category_glob in self._included_categories 155 self._excluded_categories.add(category_glob) 156 157 def AddSyntheticDelay(self, delay): 158 assert _delay_re.match(delay) 159 self._synthetic_delays.add(delay) 160 161 def IsSubset(self, other): 162 """ Determine if filter A (self) is a subset of filter B (other). 163 Returns True if A is a subset of B, False if A is not a subset of B, 164 and None if we can't tell for sure. 165 """ 166 # We don't handle filters with wildcards in this test. 167 if self.contains_wildcards or other.contains_wildcards: 168 return None 169 170 # Disabled categories get into a trace if and only if they are contained in 171 # the 'disabled' set. Return False if A's disabled set is not a subset of 172 # B's disabled set. 173 if not self.disabled_by_default_categories <= \ 174 other.disabled_by_default_categories: 175 return False 176 177 # If A defines more or different synthetic delays than B, then A is not a 178 # subset. 179 if not self.synthetic_delays <= other.synthetic_delays: 180 return False 181 182 if self.included_categories and other.included_categories: 183 # A and B have explicit include lists. If A includes something that B 184 # doesn't, return False. 185 if not self.included_categories <= other.included_categories: 186 return False 187 elif self.included_categories: 188 # Only A has an explicit include list. If A includes something that B 189 # excludes, return False. 190 if self.included_categories.intersection(other.excluded_categories): 191 return False 192 elif other.included_categories: 193 # Only B has an explicit include list. We don't know which categories are 194 # contained in the default list, so return None. 195 return None 196 else: 197 # None of the filter have explicit include list. If B excludes categories 198 # that A doesn't exclude, return False. 199 if not other.excluded_categories <= self.excluded_categories: 200 return False 201 202 return True 203