| OLD | NEW |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Scans the Chromium source for histograms that are absent from histograms.xml. | 5 """Scans the Chromium source for histograms that are absent from histograms.xml. |
| 6 | 6 |
| 7 This is a heuristic scan, so a clean run of this script does not guarantee that | 7 This is a heuristic scan, so a clean run of this script does not guarantee that |
| 8 all histograms in the Chromium source are properly mapped. Notably, field | 8 all histograms in the Chromium source are properly mapped. Notably, field |
| 9 trials are entirely ignored by this script. | 9 trials are entirely ignored by this script. |
| 10 | 10 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 ( # Nested group | 68 ( # Nested group |
| 69 "[^"]*" # Literal string | 69 "[^"]*" # Literal string |
| 70 | # or | 70 | # or |
| 71 [a-zA-Z][a-zA-Z0-9_]+ # Macro constant name | 71 [a-zA-Z][a-zA-Z0-9_]+ # Macro constant name |
| 72 ) # End of alternation | 72 ) # End of alternation |
| 73 \s* # Optional whitespace | 73 \s* # Optional whitespace |
| 74 ){2,} # Group repeated 2 or more times | 74 ){2,} # Group repeated 2 or more times |
| 75 $ # End of string | 75 $ # End of string |
| 76 """, re.VERBOSE) | 76 """, re.VERBOSE) |
| 77 HISTOGRAM_REGEX = re.compile(r""" | 77 HISTOGRAM_REGEX = re.compile(r""" |
| 78 UMA_HISTOGRAM # Match the shared prefix for standard UMA histogram macros | 78 (\w* # Capture the whole macro name |
| 79 \w* # Match the rest of the macro name, e.g. '_ENUMERATION' | 79 UMA_HISTOGRAM_ # Match the shared prefix for standard UMA histogram macros |
| 80 (\w*)) # Match the rest of the macro name, e.g. '_ENUMERATION' |
| 80 \( # Match the opening parenthesis for the macro | 81 \( # Match the opening parenthesis for the macro |
| 81 \s* # Match any whitespace -- especially, any newlines | 82 \s* # Match any whitespace -- especially, any newlines |
| 82 ([^,)]*) # Capture the first parameter to the macro | 83 ([^,)]*) # Capture the first parameter to the macro |
| 83 [,)] # Match the comma/paren that delineates the first parameter | 84 [,)] # Match the comma/paren that delineates the first parameter |
| 84 """, re.VERBOSE) | 85 """, re.VERBOSE) |
| 86 STANDARD_HISTOGRAM_SUFFIXES = frozenset(['TIMES', 'MEDIUM_TIMES', 'LONG_TIMES', |
| 87 'LONG_TIMES_100', 'CUSTOM_TIMES', |
| 88 'COUNTS', 'COUNTS_100', 'COUNTS_1000', |
| 89 'COUNTS_10000', 'CUSTOM_COUNTS', |
| 90 'MEMORY_KB', 'MEMORY_MB', |
| 91 'MEMORY_LARGE_MB', 'PERCENTAGE', |
| 92 'BOOLEAN', 'ENUMERATION', |
| 93 'CUSTOM_ENUMERATION', 'SPARSE_SLOWLY']) |
| 94 OTHER_STANDARD_HISTOGRAMS = frozenset(['SCOPED_UMA_HISTOGRAM_TIMER', |
| 95 'SCOPED_UMA_HISTOGRAM_LONG_TIMER']) |
| 96 # The following suffixes are not defined in //base/metrics but the first |
| 97 # argument to the macro is the full name of the histogram as a literal string. |
| 98 STANDARD_LIKE_SUFFIXES = frozenset(['SCROLL_LATENCY_SHORT', |
| 99 'SCROLL_LATENCY_LONG', |
| 100 'TOUCH_TO_SCROLL_LATENCY', |
| 101 'LARGE_MEMORY_MB', 'MEGABYTES_LINEAR', |
| 102 'LINEAR', 'ALLOCATED_MEGABYTES', |
| 103 'CUSTOM_TIMES_MICROS', |
| 104 'TIME_IN_MINUTES_MONTH_RANGE', |
| 105 'TIMES_16H', 'MINUTES', 'MBYTES', |
| 106 'ASPECT_RATIO', 'LOCATION_RESPONSE_TIMES', |
| 107 'LOCK_TIMES', 'OOM_KILL_TIME_INTERVAL']) |
| 108 OTHER_STANDARD_LIKE_HISTOGRAMS = frozenset(['SCOPED_BLINK_UMA_HISTOGRAM_TIMER']) |
| 85 | 109 |
| 86 | 110 |
| 87 def RunGit(command): | 111 def RunGit(command): |
| 88 """Run a git subcommand, returning its output.""" | 112 """Run a git subcommand, returning its output.""" |
| 89 # On Windows, use shell=True to get PATH interpretation. | 113 # On Windows, use shell=True to get PATH interpretation. |
| 90 command = ['git'] + command | 114 command = ['git'] + command |
| 91 logging.info(' '.join(command)) | 115 logging.info(' '.join(command)) |
| 92 shell = (os.name == 'nt') | 116 shell = (os.name == 'nt') |
| 93 proc = subprocess.Popen(command, shell=shell, stdout=subprocess.PIPE) | 117 proc = subprocess.Popen(command, shell=shell, stdout=subprocess.PIPE) |
| 94 out = proc.communicate()[0].strip() | 118 out = proc.communicate()[0].strip() |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 # Examples: | 218 # Examples: |
| 195 # 'path/to/foo.cc:420: UMA_HISTOGRAM_COUNTS_100("FooGroup.FooName",' | 219 # 'path/to/foo.cc:420: UMA_HISTOGRAM_COUNTS_100("FooGroup.FooName",' |
| 196 # 'path/to/bar.cc:632: UMA_HISTOGRAM_ENUMERATION(' | 220 # 'path/to/bar.cc:632: UMA_HISTOGRAM_ENUMERATION(' |
| 197 locations = RunGit(['gs', 'UMA_HISTOGRAM']).split('\n') | 221 locations = RunGit(['gs', 'UMA_HISTOGRAM']).split('\n') |
| 198 all_filenames = set(location.split(':')[0] for location in locations); | 222 all_filenames = set(location.split(':')[0] for location in locations); |
| 199 filenames = [f for f in all_filenames | 223 filenames = [f for f in all_filenames |
| 200 if C_FILENAME.match(f) and not TEST_FILENAME.match(f)] | 224 if C_FILENAME.match(f) and not TEST_FILENAME.match(f)] |
| 201 | 225 |
| 202 histograms = set() | 226 histograms = set() |
| 203 location_map = dict() | 227 location_map = dict() |
| 228 unknown_macros = set() |
| 229 all_suffixes = STANDARD_HISTOGRAM_SUFFIXES | STANDARD_LIKE_SUFFIXES |
| 230 all_others = OTHER_STANDARD_HISTOGRAMS | OTHER_STANDARD_LIKE_HISTOGRAMS |
| 204 for filename in filenames: | 231 for filename in filenames: |
| 205 contents = '' | 232 contents = '' |
| 206 with open(filename, 'r') as f: | 233 with open(filename, 'r') as f: |
| 207 contents = f.read() | 234 contents = f.read() |
| 208 | 235 |
| 209 for match in HISTOGRAM_REGEX.finditer(contents): | 236 for match in HISTOGRAM_REGEX.finditer(contents): |
| 210 histogram = collapseAdjacentCStrings(match.group(1)) | 237 line_number = contents[:match.start()].count('\n') + 1 |
| 211 histogram = removeComments(histogram) | 238 if (match.group(2) not in all_suffixes and |
| 239 match.group(1) not in all_others): |
| 240 full_macro_name = match.group(1) |
| 241 if (full_macro_name not in unknown_macros): |
| 242 logging.warning('%s:%d: Unknown macro name: <%s>' % |
| 243 (filename, line_number, match.group(1))) |
| 244 unknown_macros.add(full_macro_name) |
| 245 |
| 246 continue |
| 247 |
| 248 histogram = removeComments(match.group(3)) |
| 249 histogram = collapseAdjacentCStrings(histogram) |
| 212 | 250 |
| 213 # Must begin and end with a quotation mark. | 251 # Must begin and end with a quotation mark. |
| 214 if not histogram or histogram[0] != '"' or histogram[-1] != '"': | 252 if not histogram or histogram[0] != '"' or histogram[-1] != '"': |
| 215 logNonLiteralHistogram(filename, histogram) | 253 logNonLiteralHistogram(filename, histogram) |
| 216 continue | 254 continue |
| 217 | 255 |
| 218 # Must not include any quotation marks other than at the beginning or end. | 256 # Must not include any quotation marks other than at the beginning or end. |
| 219 histogram_stripped = histogram.strip('"') | 257 histogram_stripped = histogram.strip('"') |
| 220 if '"' in histogram_stripped: | 258 if '"' in histogram_stripped: |
| 221 logNonLiteralHistogram(filename, histogram) | 259 logNonLiteralHistogram(filename, histogram) |
| 222 continue | 260 continue |
| 223 | 261 |
| 224 if histogram_stripped not in histograms: | 262 if histogram_stripped not in histograms: |
| 225 histograms.add(histogram_stripped) | 263 histograms.add(histogram_stripped) |
| 226 line_number = contents[:match.start()].count('\n') + 1 | |
| 227 location_map[histogram_stripped] = '%s:%d' % (filename, line_number) | 264 location_map[histogram_stripped] = '%s:%d' % (filename, line_number) |
| 228 | 265 |
| 229 return histograms, location_map | 266 return histograms, location_map |
| 230 | 267 |
| 231 | 268 |
| 232 def readXmlHistograms(histograms_file_location): | 269 def readXmlHistograms(histograms_file_location): |
| 233 """Parses all histogram names from histograms.xml. | 270 """Parses all histogram names from histograms.xml. |
| 234 | 271 |
| 235 Returns: | 272 Returns: |
| 236 A set cotaining the parsed histogram names. | 273 A set cotaining the parsed histogram names. |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 logging.info('%s: %s - %s', location_map[histogram], histogram, | 355 logging.info('%s: %s - %s', location_map[histogram], histogram, |
| 319 hashHistogramName(histogram)) | 356 hashHistogramName(histogram)) |
| 320 else: | 357 else: |
| 321 logging.info(' %s - %s', histogram, hashHistogramName(histogram)) | 358 logging.info(' %s - %s', histogram, hashHistogramName(histogram)) |
| 322 else: | 359 else: |
| 323 logging.info('Success! No unmapped histograms found.') | 360 logging.info('Success! No unmapped histograms found.') |
| 324 | 361 |
| 325 | 362 |
| 326 if __name__ == '__main__': | 363 if __name__ == '__main__': |
| 327 main() | 364 main() |
| OLD | NEW |