Chinglin Yu | e559b12 | 2021-01-07 18:56:06 +0800 | [diff] [blame] | 1 | # Copyright 2021 The Chromium OS Authors. All rights reserved. |
| 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
| 4 | |
| 5 | """Routines for reading performance results from a directory. |
| 6 | |
| 7 | The directory should match the format created by the 'bootperf' |
| 8 | script; see comments in that script for a summary of the layout. |
| 9 | """ |
| 10 | |
| 11 | import fnmatch |
| 12 | import json |
| 13 | import os |
| 14 | import re |
| 15 | |
| 16 | import resultset |
| 17 | |
| 18 | |
| 19 | _PERF_KEYVAL_PATTERN = re.compile('(.*){perf}=(.*)\n') |
| 20 | |
| 21 | def _ReadResultsJSONFile(results, file_): |
| 22 | """Read a tast results-chart.json file and process the results. |
| 23 | |
| 24 | The `file_` parameter is a file object with contents in tast |
| 25 | perf results-chart.json format: |
| 26 | { <keyname>: { "summary": { "values": [<values (a list)>] } } } |
| 27 | |
| 28 | Each iteration's results are appended to the `results` parameter, |
| 29 | which should be an instance of TestResultSet. |
| 30 | |
| 31 | Args: |
| 32 | results: A TestResultSet where the result data will be |
| 33 | collected. |
| 34 | file_: File object for the results file to be read. |
| 35 | """ |
| 36 | # kvd: a dict of key => value dictionary. |
| 37 | # Example: {'seconds_chrome_exec_to_login':'1.75', ...}. |
| 38 | # Key and value are both string. |
| 39 | # kvd_list is a list of kvd. |
| 40 | kvd_list = [] |
| 41 | # Sample results-chart.json data: |
| 42 | # { |
| 43 | # "seconds_kernel_to_startup": { |
| 44 | # "summary": { |
| 45 | # "units": "seconds", |
| 46 | # "improvement_direction": "down", |
| 47 | # "type": "list_of_scalar_values", |
| 48 | # "values": [ |
| 49 | # 1.4, |
| 50 | # 1.41 |
| 51 | # ] |
| 52 | # } |
| 53 | # }, |
| 54 | # } |
| 55 | result_chart_json = json.load(file_) |
| 56 | for key, res in result_chart_json.items(): |
| 57 | values = res['summary']['values'] |
| 58 | for i, val in enumerate(values): |
| 59 | if i >= len(kvd_list): |
| 60 | kvd_list.append({}) |
| 61 | kvd_list[i][key] = val |
| 62 | for kvd in kvd_list: |
| 63 | results.AddIterationResults(kvd) |
| 64 | |
| 65 | _RESULTS_CHART = 'summary/tests/platform.BootPerf/results-chart.json' |
| 66 | |
Chinglin Yu | d52e8e7 | 2021-03-24 15:40:54 +0800 | [diff] [blame^] | 67 | def _ReadKeyvalFile(results, file_): |
| 68 | """Read an autotest keyval file, and process the results. |
| 69 | |
| 70 | The `file_` parameter is a file object with contents in autotest |
| 71 | perf keyval format: |
| 72 | <keyname>{perf}=<value> |
| 73 | |
| 74 | Each iteration of the test is terminated with a single blank line, |
| 75 | including the last iteration. Each iteration's results are added |
| 76 | to the `results` parameter, which should be an instance of |
| 77 | TestResultSet. |
| 78 | |
| 79 | Args: |
| 80 | results: A TestResultSet where the result data will be collected. |
| 81 | file_: File object for the results file to be read. |
| 82 | """ |
| 83 | kvd = {} |
| 84 | for line in file_: |
| 85 | if line == '\n': |
| 86 | results.AddIterationResults(kvd) |
| 87 | kvd = {} |
| 88 | continue |
| 89 | m = _PERF_KEYVAL_PATTERN.match(line) |
| 90 | if m is None: |
| 91 | continue |
| 92 | kvd[m.group(1)] = m.group(2) |
| 93 | |
| 94 | |
| 95 | _RESULTS_KEYVAL = 'summary/platform_BootPerfServer/results/keyval' |
| 96 | |
Chinglin Yu | e559b12 | 2021-01-07 18:56:06 +0800 | [diff] [blame] | 97 | def ReadResultsDirectory(dir_): |
| 98 | """Process results from a 'bootperf' output directory. |
| 99 | |
| 100 | The accumulated results are returned in a newly created |
| 101 | TestResultSet object. |
| 102 | |
| 103 | Args: |
| 104 | dir_: The directory containing the test results keyval file. |
| 105 | |
| 106 | Returns: |
| 107 | The TestResultSet object. |
| 108 | """ |
| 109 | res_set = resultset.TestResultSet(dir_) |
| 110 | dirlist = fnmatch.filter(os.listdir(dir_), 'run.???') |
| 111 | dirlist.sort() |
| 112 | for rundir in dirlist: |
| 113 | keyval_path = os.path.join(dir_, rundir, _RESULTS_CHART) |
Chinglin Yu | d52e8e7 | 2021-03-24 15:40:54 +0800 | [diff] [blame^] | 114 | # Test if the run.??? dir contains a tast result-chart.json file. |
| 115 | if os.path.exists(keyval_path): |
| 116 | reader = _ReadResultsJSONFile |
| 117 | else: |
| 118 | # The directory is generated using autotest. |
| 119 | keyval_path = os.path.join(dir_, rundir, _RESULTS_KEYVAL) |
| 120 | reader = _ReadKeyvalFile |
| 121 | |
Chinglin Yu | e559b12 | 2021-01-07 18:56:06 +0800 | [diff] [blame] | 122 | try: |
| 123 | kvf = open(keyval_path) |
| 124 | except IOError as e: |
| 125 | print('Warning: error in reading the test result: ', e) |
| 126 | continue |
Chinglin Yu | d52e8e7 | 2021-03-24 15:40:54 +0800 | [diff] [blame^] | 127 | reader(res_set, kvf) |
Chinglin Yu | e559b12 | 2021-01-07 18:56:06 +0800 | [diff] [blame] | 128 | res_set.FinalizeResults() |
| 129 | return res_set |