Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: tools/metrics/histograms/find_unmapped_histograms.py

Issue 1143323006: Histograms.xml python script housekeeping (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@bad_message
Patch Set: Small whitespace adjustment Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/metrics/histograms/__init__.py ('k') | tools/metrics/histograms/histogram_ownership.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
11 """ 11 """
12 12
13 import commands
14 import extract_histograms
15 import hashlib 13 import hashlib
16 import logging 14 import logging
17 import optparse 15 import optparse
18 import os 16 import os
19 import re 17 import re
18 import subprocess
20 import sys 19 import sys
21 20
21 sys.path.append(os.path.join(os.path.dirname(__file__), '..')) # tools/metrics
22 from common import path_util
23 from histograms import extract_histograms
24
22 25
23 ADJACENT_C_STRING_REGEX = re.compile(r""" 26 ADJACENT_C_STRING_REGEX = re.compile(r"""
24 (" # Opening quotation mark 27 (" # Opening quotation mark
25 [^"]*) # Literal string contents 28 [^"]*) # Literal string contents
26 " # Closing quotation mark 29 " # Closing quotation mark
27 \s* # Any number of spaces 30 \s* # Any number of spaces
28 " # Another opening quotation mark 31 " # Another opening quotation mark
29 """, re.VERBOSE) 32 """, re.VERBOSE)
30 CONSTANT_REGEX = re.compile(r""" 33 CONSTANT_REGEX = re.compile(r"""
31 (\w*::)? # Optional namespace 34 (\w*::)? # Optional namespace
32 k[A-Z] # Match a constant identifier: 'k' followed by an uppercase letter 35 k[A-Z] # Match a constant identifier: 'k' followed by an uppercase letter
33 \w* # Match the rest of the constant identifier 36 \w* # Match the rest of the constant identifier
34 $ # Make sure there's only the identifier, nothing else 37 $ # Make sure there's only the identifier, nothing else
35 """, re.VERBOSE) 38 """, re.VERBOSE)
36 HISTOGRAM_REGEX = re.compile(r""" 39 HISTOGRAM_REGEX = re.compile(r"""
37 UMA_HISTOGRAM # Match the shared prefix for standard UMA histogram macros 40 UMA_HISTOGRAM # Match the shared prefix for standard UMA histogram macros
38 \w* # Match the rest of the macro name, e.g. '_ENUMERATION' 41 \w* # Match the rest of the macro name, e.g. '_ENUMERATION'
39 \( # Match the opening parenthesis for the macro 42 \( # Match the opening parenthesis for the macro
40 \s* # Match any whitespace -- especially, any newlines 43 \s* # Match any whitespace -- especially, any newlines
41 ([^,)]*) # Capture the first parameter to the macro 44 ([^,)]*) # Capture the first parameter to the macro
42 [,)] # Match the comma/paren that delineates the first parameter 45 [,)] # Match the comma/paren that delineates the first parameter
43 """, re.VERBOSE) 46 """, re.VERBOSE)
44 47
45 48
49 def RunGit(command):
50 """Run a git subcommand, returning its output."""
51 # On Windows, use shell=True to get PATH interpretation.
52 command = ['git'] + command
53 logging.info(' '.join(command))
54 shell = (os.name == 'nt')
55 proc = subprocess.Popen(command, shell=shell, stdout=subprocess.PIPE)
56 out = proc.communicate()[0].strip()
57 return out
58
59
46 class DirectoryNotFoundException(Exception): 60 class DirectoryNotFoundException(Exception):
47 """Base class to distinguish locally defined exceptions from standard ones.""" 61 """Base class to distinguish locally defined exceptions from standard ones."""
48 def __init__(self, msg): 62 def __init__(self, msg):
49 self.msg = msg 63 self.msg = msg
50 64
51 def __str__(self): 65 def __str__(self):
52 return self.msg 66 return self.msg
53 67
54 68
55 def findDefaultRoot():
56 """Find the root of the chromium repo, in case the script is run from the
57 histograms dir.
58
59 Returns:
60 string: path to the src dir of the repo.
61
62 Raises:
63 DirectoryNotFoundException if the target directory cannot be found.
64 """
65 path = os.getcwd()
66 while path:
67 head, tail = os.path.split(path)
68 if tail == 'src':
69 return path
70 if path == head:
71 break
72 path = head
73 raise DirectoryNotFoundException('Could not find src/ dir')
74
75
76 def collapseAdjacentCStrings(string): 69 def collapseAdjacentCStrings(string):
77 """Collapses any adjacent C strings into a single string. 70 """Collapses any adjacent C strings into a single string.
78 71
79 Useful to re-combine strings that were split across multiple lines to satisfy 72 Useful to re-combine strings that were split across multiple lines to satisfy
80 the 80-col restriction. 73 the 80-col restriction.
81 74
82 Args: 75 Args:
83 string: The string to recombine, e.g. '"Foo"\n "bar"' 76 string: The string to recombine, e.g. '"Foo"\n "bar"'
84 77
85 Returns: 78 Returns:
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 histogram) 116 histogram)
124 117
125 118
126 def readChromiumHistograms(): 119 def readChromiumHistograms():
127 """Searches the Chromium source for all histogram names. 120 """Searches the Chromium source for all histogram names.
128 121
129 Also prints warnings for any invocations of the UMA_HISTOGRAM_* macros with 122 Also prints warnings for any invocations of the UMA_HISTOGRAM_* macros with
130 names that might vary during a single run of the app. 123 names that might vary during a single run of the app.
131 124
132 Returns: 125 Returns:
133 A set cotaining any found literal histogram names. 126 A set containing any found literal histogram names.
134 """ 127 """
135 logging.info('Scanning Chromium source for histograms...') 128 logging.info('Scanning Chromium source for histograms...')
136 129
137 # Use git grep to find all invocations of the UMA_HISTOGRAM_* macros. 130 # Use git grep to find all invocations of the UMA_HISTOGRAM_* macros.
138 # Examples: 131 # Examples:
139 # 'path/to/foo.cc:420: UMA_HISTOGRAM_COUNTS_100("FooGroup.FooName",' 132 # 'path/to/foo.cc:420: UMA_HISTOGRAM_COUNTS_100("FooGroup.FooName",'
140 # 'path/to/bar.cc:632: UMA_HISTOGRAM_ENUMERATION(' 133 # 'path/to/bar.cc:632: UMA_HISTOGRAM_ENUMERATION('
141 locations = commands.getoutput('git gs UMA_HISTOGRAM').split('\n') 134 locations = RunGit(['gs', 'UMA_HISTOGRAM']).split('\n')
142 filenames = set([location.split(':')[0] for location in locations]) 135 filenames = set([location.split(':')[0] for location in locations])
143 136
144 histograms = set() 137 histograms = set()
145 for filename in filenames: 138 for filename in filenames:
146 contents = '' 139 contents = ''
147 with open(filename, 'r') as f: 140 with open(filename, 'r') as f:
148 contents = f.read() 141 contents = f.read()
149 142
150 matches = set(HISTOGRAM_REGEX.findall(contents)) 143 matches = set(HISTOGRAM_REGEX.findall(contents))
151 for histogram in matches: 144 for histogram in matches:
152 histogram = collapseAdjacentCStrings(histogram) 145 histogram = collapseAdjacentCStrings(histogram)
153 146
154 # Must begin and end with a quotation mark. 147 # Must begin and end with a quotation mark.
155 if histogram[0] != '"' or histogram[-1] != '"': 148 if not histogram or histogram[0] != '"' or histogram[-1] != '"':
Ilya Sherman 2015/05/31 00:41:02 Why did you need to add "not histogram" to this co
ncarter (slow) 2015/06/01 17:04:12 This comment caused this script to die because we
Ilya Sherman 2015/06/01 20:25:45 Okay, thanks for the explanation. I was mostly ju
156 logNonLiteralHistogram(filename, histogram) 149 logNonLiteralHistogram(filename, histogram)
157 continue 150 continue
158 151
159 # Must not include any quotation marks other than at the beginning or end. 152 # Must not include any quotation marks other than at the beginning or end.
160 histogram_stripped = histogram.strip('"') 153 histogram_stripped = histogram.strip('"')
161 if '"' in histogram_stripped: 154 if '"' in histogram_stripped:
162 logNonLiteralHistogram(filename, histogram) 155 logNonLiteralHistogram(filename, histogram)
163 continue 156 continue
164 157
165 histograms.add(histogram_stripped) 158 histograms.add(histogram_stripped)
(...skipping 19 matching lines...) Expand all
185 name: The string to hash (a histogram name). 178 name: The string to hash (a histogram name).
186 179
187 Returns: 180 Returns:
188 Histogram hash as a string representing a hex number (with leading 0x). 181 Histogram hash as a string representing a hex number (with leading 0x).
189 """ 182 """
190 return '0x' + hashlib.md5(name).hexdigest()[:16] 183 return '0x' + hashlib.md5(name).hexdigest()[:16]
191 184
192 185
193 def main(): 186 def main():
194 # Find default paths. 187 # Find default paths.
195 default_root = findDefaultRoot() 188 default_root = path_util.GetInputFile('/')
196 default_histograms_path = os.path.join( 189 default_histograms_path = path_util.GetInputFile(
197 default_root, 'tools/metrics/histograms/histograms.xml') 190 'tools/metrics/histograms/histograms.xml')
198 default_extra_histograms_path = os.path.join( 191 default_extra_histograms_path = path_util.GetInputFile(
199 default_root, 'tools/histograms/histograms.xml') 192 'tools/histograms/histograms.xml')
200 193
201 # Parse command line options 194 # Parse command line options
202 parser = optparse.OptionParser() 195 parser = optparse.OptionParser()
203 parser.add_option( 196 parser.add_option(
204 '--root-directory', dest='root_directory', default=default_root, 197 '--root-directory', dest='root_directory', default=default_root,
205 help='scan within DIRECTORY for histograms [optional, defaults to "%s"]' % 198 help='scan within DIRECTORY for histograms [optional, defaults to "%s"]' %
206 default_root, 199 default_root,
207 metavar='DIRECTORY') 200 metavar='DIRECTORY')
208 parser.add_option( 201 parser.add_option(
209 '--histograms-file', dest='histograms_file_location', 202 '--histograms-file', dest='histograms_file_location',
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 logging.info('Histograms in Chromium but not in XML files:') 240 logging.info('Histograms in Chromium but not in XML files:')
248 logging.info('-------------------------------------------------') 241 logging.info('-------------------------------------------------')
249 for histogram in sorted(unmapped_histograms): 242 for histogram in sorted(unmapped_histograms):
250 logging.info(' %s - %s', histogram, hashHistogramName(histogram)) 243 logging.info(' %s - %s', histogram, hashHistogramName(histogram))
251 else: 244 else:
252 logging.info('Success! No unmapped histograms found.') 245 logging.info('Success! No unmapped histograms found.')
253 246
254 247
255 if __name__ == '__main__': 248 if __name__ == '__main__':
256 main() 249 main()
OLDNEW
« no previous file with comments | « tools/metrics/histograms/__init__.py ('k') | tools/metrics/histograms/histogram_ownership.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698