Chromium Code Reviews| 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 """Extract histogram names from the description XML file. | 5 """Extract histogram names from the description XML file. |
| 6 | 6 |
| 7 For more information on the format of the XML file, which is self-documenting, | 7 For more information on the format of the XML file, which is self-documenting, |
| 8 see histograms.xml; however, here is a simple example to get you started. The | 8 see histograms.xml; however, here is a simple example to get you started. The |
| 9 XML below will generate the following five histograms: | 9 XML below will generate the following five histograms: |
| 10 | 10 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 56 | 56 |
| 57 import copy | 57 import copy |
| 58 import logging | 58 import logging |
| 59 import xml.dom.minidom | 59 import xml.dom.minidom |
| 60 | 60 |
| 61 OWNER_FIELD_PLACEHOLDER = ( | 61 OWNER_FIELD_PLACEHOLDER = ( |
| 62 'Please list the metric\'s owners. Add more owner tags as needed.') | 62 'Please list the metric\'s owners. Add more owner tags as needed.') |
| 63 | 63 |
| 64 MAX_HISTOGRAM_SUFFIX_DEPENDENCY_DEPTH = 5 | 64 MAX_HISTOGRAM_SUFFIX_DEPENDENCY_DEPTH = 5 |
| 65 | 65 |
| 66 DEFAULT_BASE_HISTOGRAM_OBSOLETE_REASON = ( | |
| 67 'Base histogram. Use suffixes of this histogram instead.') | |
| 68 | |
| 66 | 69 |
| 67 class Error(Exception): | 70 class Error(Exception): |
| 68 pass | 71 pass |
| 69 | 72 |
| 70 | 73 |
| 71 def _JoinChildNodes(tag): | 74 def _JoinChildNodes(tag): |
| 72 """Join child nodes into a single text. | 75 """Join child nodes into a single text. |
| 73 | 76 |
| 74 Applicable to leafs like 'summary' and 'detail'. | 77 Applicable to leafs like 'summary' and 'detail'. |
| 75 | 78 |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 223 def _ExtractOwners(xml_node): | 226 def _ExtractOwners(xml_node): |
| 224 """Extract all owners into a list from owner tag under |xml_node|.""" | 227 """Extract all owners into a list from owner tag under |xml_node|.""" |
| 225 owners = [] | 228 owners = [] |
| 226 for owner_node in xml_node.getElementsByTagName('owner'): | 229 for owner_node in xml_node.getElementsByTagName('owner'): |
| 227 owner_entry = _NormalizeString(_JoinChildNodes(owner_node)) | 230 owner_entry = _NormalizeString(_JoinChildNodes(owner_node)) |
| 228 if OWNER_FIELD_PLACEHOLDER not in owner_entry: | 231 if OWNER_FIELD_PLACEHOLDER not in owner_entry: |
| 229 owners.append(owner_entry) | 232 owners.append(owner_entry) |
| 230 return owners | 233 return owners |
| 231 | 234 |
| 232 | 235 |
| 236 def _ProcessBaseHistogramAttribute(node, histogram_entry): | |
| 237 if node.hasAttribute('base'): | |
| 238 is_base = node.getAttribute('base').lower() == 'true' | |
| 239 histogram_entry['base'] = is_base | |
| 240 if is_base and 'obsolete' not in histogram_entry: | |
| 241 histogram_entry['obsolete'] = DEFAULT_BASE_HISTOGRAM_OBSOLETE_REASON | |
| 242 | |
| 243 | |
| 233 def _ExtractHistogramsFromXmlTree(tree, enums): | 244 def _ExtractHistogramsFromXmlTree(tree, enums): |
| 234 """Extract all <histogram> nodes in the tree into a dictionary.""" | 245 """Extract all <histogram> nodes in the tree into a dictionary.""" |
| 235 | 246 |
| 236 # Process the histograms. The descriptions can include HTML tags. | 247 # Process the histograms. The descriptions can include HTML tags. |
| 237 histograms = {} | 248 histograms = {} |
| 238 have_errors = False | 249 have_errors = False |
| 239 last_name = None | 250 last_name = None |
| 240 for histogram in tree.getElementsByTagName('histogram'): | 251 for histogram in tree.getElementsByTagName('histogram'): |
| 241 name = histogram.getAttribute('name') | 252 name = histogram.getAttribute('name') |
| 242 if last_name is not None and name.lower() < last_name.lower(): | 253 if last_name is not None and name.lower() < last_name.lower(): |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 281 | 292 |
| 282 # Handle enum types. | 293 # Handle enum types. |
| 283 if histogram.hasAttribute('enum'): | 294 if histogram.hasAttribute('enum'): |
| 284 enum_name = histogram.getAttribute('enum') | 295 enum_name = histogram.getAttribute('enum') |
| 285 if enum_name not in enums: | 296 if enum_name not in enums: |
| 286 logging.error('Unknown enum %s in histogram %s', enum_name, name) | 297 logging.error('Unknown enum %s in histogram %s', enum_name, name) |
| 287 have_errors = True | 298 have_errors = True |
| 288 else: | 299 else: |
| 289 histogram_entry['enum'] = enums[enum_name] | 300 histogram_entry['enum'] = enums[enum_name] |
| 290 | 301 |
| 302 _ProcessBaseHistogramAttribute(histogram, histogram_entry) | |
| 303 | |
| 291 return histograms, have_errors | 304 return histograms, have_errors |
| 292 | 305 |
| 293 | 306 |
| 294 # Finds an <obsolete> node amongst |node|'s immediate children and returns its | 307 # Finds an <obsolete> node amongst |node|'s immediate children and returns its |
| 295 # content as a string. Returns None if no such node exists. | 308 # content as a string. Returns None if no such node exists. |
| 296 def _GetObsoleteReason(node): | 309 def _GetObsoleteReason(node): |
| 297 for child in node.childNodes: | 310 for child in node.childNodes: |
| 298 if child.localName == 'obsolete': | 311 if child.localName == 'obsolete': |
| 299 # There can be at most 1 obsolete element per node. | 312 # There can be at most 1 obsolete element per node. |
| 300 return _JoinChildNodes(child) | 313 return _JoinChildNodes(child) |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 391 if with_suffixes: | 404 if with_suffixes: |
| 392 suffixes_to_add = with_suffixes | 405 suffixes_to_add = with_suffixes |
| 393 else: | 406 else: |
| 394 suffixes_to_add = suffix_nodes | 407 suffixes_to_add = suffix_nodes |
| 395 for suffix in suffixes_to_add: | 408 for suffix in suffixes_to_add: |
| 396 suffix_name = suffix.getAttribute('name') | 409 suffix_name = suffix.getAttribute('name') |
| 397 try: | 410 try: |
| 398 new_histogram_name = _ExpandHistogramNameWithSuffixes( | 411 new_histogram_name = _ExpandHistogramNameWithSuffixes( |
| 399 suffix_name, histogram_name, histogram_suffixes) | 412 suffix_name, histogram_name, histogram_suffixes) |
| 400 if new_histogram_name != histogram_name: | 413 if new_histogram_name != histogram_name: |
| 401 histograms[new_histogram_name] = copy.deepcopy( | 414 new_histogram = copy.deepcopy(histograms[histogram_name]) |
| 402 histograms[histogram_name]) | 415 # Do not copy forward base histogram state to suffixed |
| 416 # histograms. Any suffixed histograms that wish to remain base | |
| 417 # histogram must explicitly declare themselves as base histograms. | |
|
Ilya Sherman
2016/10/18 21:05:58
nit: s/histogram/histograms
Bryan McQuade
2016/10/18 23:15:19
done, thanks!
| |
| 418 if new_histogram.get('base', False): | |
| 419 del new_histogram['base'] | |
| 420 if (new_histogram.get('obsolete', '') == | |
| 421 DEFAULT_BASE_HISTOGRAM_OBSOLETE_REASON): | |
| 422 del new_histogram['obsolete'] | |
| 423 histograms[new_histogram_name] = new_histogram | |
| 403 | 424 |
| 404 suffix_label = suffix_labels.get(suffix_name, '') | 425 suffix_label = suffix_labels.get(suffix_name, '') |
| 405 | 426 |
| 406 # TODO(yiyaoliu): Rename these to be consistent with the new naming. | 427 # TODO(yiyaoliu): Rename these to be consistent with the new naming. |
| 407 # It is kept unchanged for now to be it's used by dashboards. | 428 # It is kept unchanged for now to be it's used by dashboards. |
| 408 if 'fieldtrial_groups' not in histograms[new_histogram_name]: | 429 if 'fieldtrial_groups' not in histograms[new_histogram_name]: |
| 409 histograms[new_histogram_name]['fieldtrial_groups'] = [] | 430 histograms[new_histogram_name]['fieldtrial_groups'] = [] |
| 410 histograms[new_histogram_name]['fieldtrial_groups'].append( | 431 histograms[new_histogram_name]['fieldtrial_groups'].append( |
| 411 suffix_name) | 432 suffix_name) |
| 412 | 433 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 429 # group itself was obsolete as well. | 450 # group itself was obsolete as well. |
| 430 obsolete_reason = _GetObsoleteReason(suffix) | 451 obsolete_reason = _GetObsoleteReason(suffix) |
| 431 if not obsolete_reason: | 452 if not obsolete_reason: |
| 432 obsolete_reason = group_obsolete_reason | 453 obsolete_reason = group_obsolete_reason |
| 433 | 454 |
| 434 # If the suffix has an obsolete tag, all histograms it generates | 455 # If the suffix has an obsolete tag, all histograms it generates |
| 435 # inherit it. | 456 # inherit it. |
| 436 if obsolete_reason: | 457 if obsolete_reason: |
| 437 histograms[new_histogram_name]['obsolete'] = obsolete_reason | 458 histograms[new_histogram_name]['obsolete'] = obsolete_reason |
| 438 | 459 |
| 460 _ProcessBaseHistogramAttribute(suffix, histograms[new_histogram_name]) | |
| 461 | |
| 439 except Error: | 462 except Error: |
| 440 have_errors = True | 463 have_errors = True |
| 441 | 464 |
| 442 return have_errors | 465 return have_errors |
| 443 | 466 |
| 444 | 467 |
| 445 def ExtractHistogramsFromFile(file_handle): | 468 def ExtractHistogramsFromFile(file_handle): |
| 446 """Compute the histogram names and descriptions from the XML representation. | 469 """Compute the histogram names and descriptions from the XML representation. |
| 447 | 470 |
| 448 Args: | 471 Args: |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 478 with open(filename, 'r') as f: | 501 with open(filename, 'r') as f: |
| 479 histograms, had_errors = ExtractHistogramsFromFile(f) | 502 histograms, had_errors = ExtractHistogramsFromFile(f) |
| 480 if had_errors: | 503 if had_errors: |
| 481 logging.error('Error parsing %s', filename) | 504 logging.error('Error parsing %s', filename) |
| 482 raise Error() | 505 raise Error() |
| 483 return histograms | 506 return histograms |
| 484 | 507 |
| 485 | 508 |
| 486 def ExtractNames(histograms): | 509 def ExtractNames(histograms): |
| 487 return sorted(histograms.keys()) | 510 return sorted(histograms.keys()) |
| OLD | NEW |