| # Copyright 2014 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from collections import defaultdict |
| |
| from telemetry.value import failure |
| from telemetry.value import merge_values |
| from telemetry.value import skip |
| |
| |
| class Summary(object): |
| """Computes summary values from the per-page-run values produced by a test. |
| |
| Some telemetry benchmark repeat a number of times in order to get a reliable |
| measurement. The test does not have to handle merging of these runs: |
| summarizer does it for you. |
| |
| For instance, if two pages run, 3 and 1 time respectively: |
| ScalarValue(page1, 'foo', units='ms', 1) |
| ScalarValue(page1, 'foo', units='ms', 1) |
| ScalarValue(page1, 'foo', units='ms', 1) |
| ScalarValue(page2, 'foo', units='ms', 2) |
| |
| Then summarizer will produce two sets of values. First, |
| computed_per_page_values: |
| [ |
| ListOfScalarValues(page1, 'foo', units='ms', [1,1,1])], |
| ListOfScalarValues(page2, 'foo', units='ms', [2])] |
| ] |
| |
| In addition, it will produce a summary value: |
| [ |
| ListOfScalarValues(page=None, 'foo', units='ms', [1,1,1,2])] |
| ] |
| |
| """ |
| def __init__(self, all_page_specific_values): |
| had_failures = any(isinstance(v, failure.FailureValue) for v in |
| all_page_specific_values) |
| self.had_failures = had_failures |
| self._computed_per_page_values = [] |
| self._computed_summary_values = [] |
| self._interleaved_computed_per_page_values_and_summaries = [] |
| self._ComputePerPageValues(all_page_specific_values) |
| |
| @property |
| def computed_per_page_values(self): |
| return self._computed_per_page_values |
| |
| @property |
| def computed_summary_values(self): |
| return self._computed_summary_values |
| |
| @property |
| def interleaved_computed_per_page_values_and_summaries(self): |
| """Returns the computed per page values and summary values interleaved. |
| |
| All the results for a given name are printed together. First per page |
| values, then summary values. |
| |
| """ |
| return self._interleaved_computed_per_page_values_and_summaries |
| |
| def _ComputePerPageValues(self, all_page_specific_values): |
| all_successful_page_values = [ |
| v for v in all_page_specific_values if not (isinstance( |
| v, failure.FailureValue) or isinstance(v, skip.SkipValue))] |
| |
| # We will later need to determine how many values were originally created |
| # for each value name, to apply a workaround meant to clean up the printf |
| # output. |
| num_successful_pages_for_value_name = defaultdict(int) |
| for v in all_successful_page_values: |
| num_successful_pages_for_value_name[v.name] += 1 |
| |
| # By here, due to page repeat options, all_values_from_successful_pages |
| # contains values of the same name not only from mulitple pages, but also |
| # from the same name. So even if, for instance, only one page ran, it may |
| # have run twice, producing two 'x' values. |
| # |
| # So, get rid of the repeated pages by merging. |
| merged_page_values = merge_values.MergeLikeValuesFromSamePage( |
| all_successful_page_values) |
| |
| # Now we have a bunch of values, but there is only one value_name per page. |
| # Suppose page1 and page2 ran, producing values x and y. We want to print |
| # x for page1 |
| # x for page2 |
| # x for page1, page2 combined |
| # |
| # y for page1 |
| # y for page2 |
| # y for page1, page2 combined |
| # |
| # We already have the x values in the values array. But, we will need |
| # them indexable by the value name. |
| # |
| # The following dict maps value_name -> list of pages that have values of |
| # that name. |
| per_page_values_by_value_name = defaultdict(list) |
| for value in merged_page_values: |
| per_page_values_by_value_name[value.name].append(value) |
| |
| # We already have the x values in the values array. But, we also need |
| # the values merged across the pages. And, we will need them indexed by |
| # value name so that we can find them when printing out value names in |
| # alphabetical order. |
| merged_pages_value_by_value_name = {} |
| if not self.had_failures: |
| for value in merge_values.MergeLikeValuesFromDifferentPages( |
| all_successful_page_values): |
| assert value.name not in merged_pages_value_by_value_name |
| merged_pages_value_by_value_name[value.name] = value |
| |
| # sorted_value names will govern the order we start printing values. |
| value_names = set([v.name for v in merged_page_values]) |
| sorted_value_names = sorted(value_names) |
| |
| # Time to walk through the values by name, printing first the page-specific |
| # values and then the merged_site value. |
| for value_name in sorted_value_names: |
| per_page_values = per_page_values_by_value_name.get(value_name, []) |
| |
| # Sort the values by their url |
| sorted_per_page_values = list(per_page_values) |
| sorted_per_page_values.sort( |
| key=lambda per_page_values: per_page_values.page.display_name) |
| |
| # Output the page-specific results. |
| num_successful_pages_for_this_value_name = ( |
| num_successful_pages_for_value_name[value_name]) |
| for per_page_value in sorted_per_page_values: |
| self._ComputePerPageValue(per_page_value, |
| num_successful_pages_for_this_value_name) |
| |
| # Output the combined values. |
| merged_pages_value = merged_pages_value_by_value_name.get(value_name, |
| None) |
| if merged_pages_value: |
| self._computed_summary_values.append(merged_pages_value) |
| self._interleaved_computed_per_page_values_and_summaries.append( |
| merged_pages_value) |
| |
| def _ComputePerPageValue( |
| self, value, num_successful_pages_for_this_value_name): |
| # If there were any page errors, we typically will print nothing. |
| # |
| # Note: this branch is structured less-densely to improve legibility. |
| if num_successful_pages_for_this_value_name > 1: |
| should_print = True |
| elif (self.had_failures and |
| num_successful_pages_for_this_value_name == 1): |
| should_print = True |
| else: |
| should_print = False |
| |
| if not should_print: |
| return |
| |
| # Actually save the result. |
| self._computed_per_page_values.append(value) |
| self._interleaved_computed_per_page_values_and_summaries.append(value) |