Index: tools/telemetry/telemetry/value/merge_values.py |
diff --git a/tools/telemetry/telemetry/value/merge_values.py b/tools/telemetry/telemetry/value/merge_values.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..27546cc490050ba393ebdf81d9b5107474f24f43 |
--- /dev/null |
+++ b/tools/telemetry/telemetry/value/merge_values.py |
@@ -0,0 +1,116 @@ |
+# Copyright (c) 2013 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. |
+def MergeLikeValuesFromSamePage(all_values): |
+ """Merges values that measure the same thing on the same page. |
+ |
+ A page may end up being measured multiple times, meaning that we may end up |
+ with something like this: |
+ ScalarValue(page1, 'x', 1) |
+ ScalarValue(page2, 'x', 4) |
+ ScalarValue(page1, 'x', 2) |
+ ScalarValue(page2, 'x', 5) |
+ |
+ This function will produce: |
+ ListOfScalarValues(page1, 'x', [1, 2]) |
+ ListOfScalarValues(page2, 'x', [4, 5]) |
+ |
+ The workhorse of this code is Value.MergeLikeValuesFromSamePage. |
+ |
+ This requires (but assumes) that the values passed in with the same grouping |
+ key pass the Value.IsMergableWith test. If this is not obeyed, the |
+ results will be undefined. |
+ """ |
+ return _MergeLikeValuesCommon( |
+ all_values, |
+ lambda x: (x.page, x.name), |
+ lambda v0, merge_group: v0.MergeLikeValuesFromSamePage(merge_group)) |
+ |
+ |
+def MergeLikeValuesFromDifferentPages(all_values, group_by_name_suffix=False): |
+ """Merges values that measure the same thing on different pages. |
+ |
+ After using MergeLikeValuesFromSamePage, one still ends up with values from |
+ different pages: |
+ ScalarValue(page1, 'x', 1) |
+ ScalarValue(page1, 'y', 30) |
+ ScalarValue(page2, 'x', 2) |
+ ScalarValue(page2, 'y', 40) |
+ |
+ This function will group the values of the same value_name together: |
+ ListOfScalarValues(None, 'x', [1, 2]) |
+ ListOfScalarValues(None, 'y', [30, 40]) |
+ |
+ If group_by_name_suffix is True, then x.z and y.z are considered to be the |
+ same value and are grouped together. If false, then x.z and y.z are |
+ considered different. |
+ |
+ The workhorse of this code is Value.MergeLikeValuesFromDifferentPages. |
+ |
+ Not all values that go into this function will come out: not every value can |
+ be merged across pages. Values whose MergeLikeValuesFromDifferentPages returns |
+ None will be omitted from the results. |
+ |
+ This requires (but assumes) that the values passed in with the same name pass |
+ the Value.IsMergableWith test. If this is not obeyed, the results |
+ will be undefined. |
+ """ |
+ if group_by_name_suffix: |
+ def key(value): |
+ return value.name_suffix |
+ else: |
+ key = lambda x: x.name |
+ return _MergeLikeValuesCommon( |
+ all_values, |
+ key, |
+ lambda v0, merge_group: v0.MergeLikeValuesFromDifferentPages( |
+ merge_group, group_by_name_suffix=group_by_name_suffix)) |
+ |
+ |
+def _MergeLikeValuesCommon(all_values, key_func, merge_func): |
+ """Groups all_values by key_func then applies merge_func to the groups. |
+ |
+ This takes the all_values list and groups each item in that using the key |
+ provided by key_func. This produces groups of values with like keys. Thes are |
+ then handed to the merge_func to produce a new key. If merge_func produces a |
+ non-None return, it is added to the list of returned values. |
+ """ |
+ # When merging, we want to merge values in a consistent order, e.g. so that |
+ # Scalar(1), Scalar(2) predictably produces ListOfScalarValues([1,2]) rather |
+ # than 2,1. |
+ # |
+ # To do this, the values are sorted by key up front. Then, grouping is |
+ # performed using a dictionary, but as new groups are found, the order in |
+ # which they were found is also noted. |
+ # |
+ # Merging is then performed on groups in group-creation-order. This ensures |
+ # that the returned array is in a stable order, group by group. |
+ # |
+ # Within a group, the order is stable because of the original sort. |
+ all_values = list(all_values) |
+ merge_groups = GroupStably(all_values, key_func) |
+ |
+ res = [] |
+ for merge_group in merge_groups: |
+ v0 = merge_group[0] |
+ vM = merge_func(v0, merge_group) |
+ if vM: |
+ res.append(vM) |
+ return res |
+ |
+def GroupStably(all_values, key_func): |
+ """Groups an array by key_func, with the groups returned in a stable order. |
+ |
+ Returns a list of groups. |
+ """ |
+ all_values = list(all_values) |
+ |
+ merge_groups = {} |
+ merge_groups_in_creation_order = [] |
+ for value in all_values: |
+ key = key_func(value) |
+ if key not in merge_groups: |
+ merge_groups[key] = [] |
+ merge_groups_in_creation_order.append(merge_groups[key]) |
+ merge_groups[key].append(value) |
+ return merge_groups_in_creation_order |