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 CreateLowOverheadFilter(): 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 "base", 21 "benchmark", 22 "webkit.console", 23 "blink.console", 24 "trace_event_overhead" 25 ] 26 return ChromeTraceCategoryFilter(filter_string=','.join(categories)) 27 28 29def CreateDefaultOverheadFilter(): 30 """Returns a filter with the best-effort amount of overhead. 31 32 This matches Chrome tracing's default category filter setting, i.e., enable 33 all categories except the disabled-by-default-* ones. 34 35 We should use '*' instead of '' (empty string) here. On the Chrome side, both 36 '*' and '' mean default category filter setting. However, if someone adds 37 additional category filters, the behavior becomes different. 38 39 For example: 40 '*': enable all categories except the disabled-by-default-* ones. 41 '': enable all categories except the disabled-by-default-* ones. 42 43 Now add an additional category filter 'abc' to '*' and '': 44 '*,abc': enable all categories (including 'abc') except the 45 disabled-by-default-* ones. 46 'abc': enable only 'abc', and disable all other ones. 47 """ 48 return ChromeTraceCategoryFilter(filter_string='*') 49 50 51def CreateDebugOverheadFilter(): 52 """Returns a filter with as many traces enabled as is useful.""" 53 return ChromeTraceCategoryFilter( 54 filter_string='*,disabled-by-default-cc.debug') 55 56 57_delay_re = re.compile(r'DELAY[(][A-Za-z0-9._;]+[)]') 58 59 60class ChromeTraceCategoryFilter(object): 61 """A set of included and excluded categories that should be traced. 62 63 The ChromeTraceCategoryFilter allows fine tuning of what data is traced for 64 Chrome. Basic choice of which tracers to use is done by TracingConfig. 65 66 Providing filter_string=None gives the default category filter, which leaves 67 what to trace up to the individual trace systems. 68 """ 69 def __init__(self, filter_string=None): 70 self._included_categories = set() 71 self._excluded_categories = set() 72 self._disabled_by_default_categories = set() 73 self._synthetic_delays = set() 74 self.contains_wildcards = False 75 self.AddFilterString(filter_string) 76 77 def AddFilterString(self, filter_string): 78 if filter_string is None: 79 return 80 81 filter_set = set([cf.strip() for cf in filter_string.split(',')]) 82 for category in filter_set: 83 self.AddFilter(category) 84 85 def AddFilter(self, category): 86 if category == '': 87 return 88 89 if ',' in category: 90 raise ValueError("Invalid category filter name: '%s'" % category) 91 92 if '*' in category or '?' in category: 93 self.contains_wildcards = True 94 95 if _delay_re.match(category): 96 self._synthetic_delays.add(category) 97 return 98 99 if category[0] == '-': 100 assert not category[1:] in self._included_categories 101 self._excluded_categories.add(category[1:]) 102 return 103 104 if category.startswith('disabled-by-default-'): 105 self._disabled_by_default_categories.add(category) 106 return 107 108 assert not category in self._excluded_categories 109 self._included_categories.add(category) 110 111 @property 112 def included_categories(self): 113 return self._included_categories 114 115 @property 116 def excluded_categories(self): 117 return self._excluded_categories 118 119 @property 120 def disabled_by_default_categories(self): 121 return self._disabled_by_default_categories 122 123 @property 124 def synthetic_delays(self): 125 return self._synthetic_delays 126 127 @property 128 def filter_string(self): 129 return self._GetFilterString(stable_output=False) 130 131 @property 132 def stable_filter_string(self): 133 return self._GetFilterString(stable_output=True) 134 135 def _GetFilterString(self, stable_output): 136 # Note: This outputs fields in an order that intentionally matches 137 # trace_event_impl's CategoryFilter string order. 138 lists = [] 139 lists.append(self._included_categories) 140 lists.append(self._disabled_by_default_categories) 141 lists.append(['-%s' % x for x in self._excluded_categories]) 142 lists.append(self._synthetic_delays) 143 categories = [] 144 for l in lists: 145 if stable_output: 146 l = list(l) 147 l.sort() 148 categories.extend(l) 149 return ','.join(categories) 150 151 def GetDictForChromeTracing(self): 152 INCLUDED_CATEGORIES_PARAM = 'included_categories' 153 EXCLUDED_CATEGORIES_PARAM = 'excluded_categories' 154 SYNTHETIC_DELAYS_PARAM = 'synthetic_delays' 155 156 result = {} 157 if self._included_categories or self._disabled_by_default_categories: 158 result[INCLUDED_CATEGORIES_PARAM] = list( 159 self._included_categories | self._disabled_by_default_categories) 160 if self._excluded_categories: 161 result[EXCLUDED_CATEGORIES_PARAM] = list(self._excluded_categories) 162 if self._synthetic_delays: 163 result[SYNTHETIC_DELAYS_PARAM] = list(self._synthetic_delays) 164 return result 165 166 def AddDisabledByDefault(self, category): 167 assert category.startswith('disabled-by-default-') 168 self._disabled_by_default_categories.add(category) 169 170 def AddIncludedCategory(self, category_glob): 171 """Explicitly enables anything matching category_glob.""" 172 assert not category_glob.startswith('disabled-by-default-') 173 assert not category_glob in self._excluded_categories 174 self._included_categories.add(category_glob) 175 176 def AddExcludedCategory(self, category_glob): 177 """Explicitly disables anything matching category_glob.""" 178 assert not category_glob.startswith('disabled-by-default-') 179 assert not category_glob in self._included_categories 180 self._excluded_categories.add(category_glob) 181 182 def AddSyntheticDelay(self, delay): 183 assert _delay_re.match(delay) 184 self._synthetic_delays.add(delay) 185 186 def IsSubset(self, other): 187 """ Determine if filter A (self) is a subset of filter B (other). 188 Returns True if A is a subset of B, False if A is not a subset of B, 189 and None if we can't tell for sure. 190 """ 191 # We don't handle filters with wildcards in this test. 192 if self.contains_wildcards or other.contains_wildcards: 193 return None 194 195 # Disabled categories get into a trace if and only if they are contained in 196 # the 'disabled' set. Return False if A's disabled set is not a subset of 197 # B's disabled set. 198 if not self.disabled_by_default_categories <= \ 199 other.disabled_by_default_categories: 200 return False 201 202 # If A defines more or different synthetic delays than B, then A is not a 203 # subset. 204 if not self.synthetic_delays <= other.synthetic_delays: 205 return False 206 207 if self.included_categories and other.included_categories: 208 # A and B have explicit include lists. If A includes something that B 209 # doesn't, return False. 210 if not self.included_categories <= other.included_categories: 211 return False 212 elif self.included_categories: 213 # Only A has an explicit include list. If A includes something that B 214 # excludes, return False. 215 if self.included_categories.intersection(other.excluded_categories): 216 return False 217 elif other.included_categories: 218 # Only B has an explicit include list. We don't know which categories are 219 # contained in the default list, so return None. 220 return None 221 else: 222 # None of the filter have explicit include list. If B excludes categories 223 # that A doesn't exclude, return False. 224 if not other.excluded_categories <= self.excluded_categories: 225 return False 226 227 return True 228