1a8c51b3fSopenharmony_ci"""report.py - Utilities for reporting statistics about benchmark results
2a8c51b3fSopenharmony_ci"""
3a8c51b3fSopenharmony_ci
4a8c51b3fSopenharmony_ciimport unittest
5a8c51b3fSopenharmony_ciimport os
6a8c51b3fSopenharmony_ciimport re
7a8c51b3fSopenharmony_ciimport copy
8a8c51b3fSopenharmony_ciimport random
9a8c51b3fSopenharmony_ci
10a8c51b3fSopenharmony_cifrom scipy.stats import mannwhitneyu, gmean
11a8c51b3fSopenharmony_cifrom numpy import array
12a8c51b3fSopenharmony_ci
13a8c51b3fSopenharmony_ci
14a8c51b3fSopenharmony_ciclass BenchmarkColor(object):
15a8c51b3fSopenharmony_ci    def __init__(self, name, code):
16a8c51b3fSopenharmony_ci        self.name = name
17a8c51b3fSopenharmony_ci        self.code = code
18a8c51b3fSopenharmony_ci
19a8c51b3fSopenharmony_ci    def __repr__(self):
20a8c51b3fSopenharmony_ci        return '%s%r' % (self.__class__.__name__,
21a8c51b3fSopenharmony_ci                         (self.name, self.code))
22a8c51b3fSopenharmony_ci
23a8c51b3fSopenharmony_ci    def __format__(self, format):
24a8c51b3fSopenharmony_ci        return self.code
25a8c51b3fSopenharmony_ci
26a8c51b3fSopenharmony_ci
27a8c51b3fSopenharmony_ci# Benchmark Colors Enumeration
28a8c51b3fSopenharmony_ciBC_NONE = BenchmarkColor('NONE', '')
29a8c51b3fSopenharmony_ciBC_MAGENTA = BenchmarkColor('MAGENTA', '\033[95m')
30a8c51b3fSopenharmony_ciBC_CYAN = BenchmarkColor('CYAN', '\033[96m')
31a8c51b3fSopenharmony_ciBC_OKBLUE = BenchmarkColor('OKBLUE', '\033[94m')
32a8c51b3fSopenharmony_ciBC_OKGREEN = BenchmarkColor('OKGREEN', '\033[32m')
33a8c51b3fSopenharmony_ciBC_HEADER = BenchmarkColor('HEADER', '\033[92m')
34a8c51b3fSopenharmony_ciBC_WARNING = BenchmarkColor('WARNING', '\033[93m')
35a8c51b3fSopenharmony_ciBC_WHITE = BenchmarkColor('WHITE', '\033[97m')
36a8c51b3fSopenharmony_ciBC_FAIL = BenchmarkColor('FAIL', '\033[91m')
37a8c51b3fSopenharmony_ciBC_ENDC = BenchmarkColor('ENDC', '\033[0m')
38a8c51b3fSopenharmony_ciBC_BOLD = BenchmarkColor('BOLD', '\033[1m')
39a8c51b3fSopenharmony_ciBC_UNDERLINE = BenchmarkColor('UNDERLINE', '\033[4m')
40a8c51b3fSopenharmony_ci
41a8c51b3fSopenharmony_ciUTEST_MIN_REPETITIONS = 2
42a8c51b3fSopenharmony_ciUTEST_OPTIMAL_REPETITIONS = 9  # Lowest reasonable number, More is better.
43a8c51b3fSopenharmony_ciUTEST_COL_NAME = "_pvalue"
44a8c51b3fSopenharmony_ci
45a8c51b3fSopenharmony_ci_TIME_UNIT_TO_SECONDS_MULTIPLIER = {
46a8c51b3fSopenharmony_ci    "s": 1.0,
47a8c51b3fSopenharmony_ci    "ms": 1e-3,
48a8c51b3fSopenharmony_ci    "us": 1e-6,
49a8c51b3fSopenharmony_ci    "ns": 1e-9,
50a8c51b3fSopenharmony_ci}
51a8c51b3fSopenharmony_ci
52a8c51b3fSopenharmony_ci
53a8c51b3fSopenharmony_cidef color_format(use_color, fmt_str, *args, **kwargs):
54a8c51b3fSopenharmony_ci    """
55a8c51b3fSopenharmony_ci    Return the result of 'fmt_str.format(*args, **kwargs)' after transforming
56a8c51b3fSopenharmony_ci    'args' and 'kwargs' according to the value of 'use_color'. If 'use_color'
57a8c51b3fSopenharmony_ci    is False then all color codes in 'args' and 'kwargs' are replaced with
58a8c51b3fSopenharmony_ci    the empty string.
59a8c51b3fSopenharmony_ci    """
60a8c51b3fSopenharmony_ci    assert use_color is True or use_color is False
61a8c51b3fSopenharmony_ci    if not use_color:
62a8c51b3fSopenharmony_ci        args = [arg if not isinstance(arg, BenchmarkColor) else BC_NONE
63a8c51b3fSopenharmony_ci                for arg in args]
64a8c51b3fSopenharmony_ci        kwargs = {key: arg if not isinstance(arg, BenchmarkColor) else BC_NONE
65a8c51b3fSopenharmony_ci                  for key, arg in kwargs.items()}
66a8c51b3fSopenharmony_ci    return fmt_str.format(*args, **kwargs)
67a8c51b3fSopenharmony_ci
68a8c51b3fSopenharmony_ci
69a8c51b3fSopenharmony_cidef find_longest_name(benchmark_list):
70a8c51b3fSopenharmony_ci    """
71a8c51b3fSopenharmony_ci    Return the length of the longest benchmark name in a given list of
72a8c51b3fSopenharmony_ci    benchmark JSON objects
73a8c51b3fSopenharmony_ci    """
74a8c51b3fSopenharmony_ci    longest_name = 1
75a8c51b3fSopenharmony_ci    for bc in benchmark_list:
76a8c51b3fSopenharmony_ci        if len(bc['name']) > longest_name:
77a8c51b3fSopenharmony_ci            longest_name = len(bc['name'])
78a8c51b3fSopenharmony_ci    return longest_name
79a8c51b3fSopenharmony_ci
80a8c51b3fSopenharmony_ci
81a8c51b3fSopenharmony_cidef calculate_change(old_val, new_val):
82a8c51b3fSopenharmony_ci    """
83a8c51b3fSopenharmony_ci    Return a float representing the decimal change between old_val and new_val.
84a8c51b3fSopenharmony_ci    """
85a8c51b3fSopenharmony_ci    if old_val == 0 and new_val == 0:
86a8c51b3fSopenharmony_ci        return 0.0
87a8c51b3fSopenharmony_ci    if old_val == 0:
88a8c51b3fSopenharmony_ci        return float(new_val - old_val) / (float(old_val + new_val) / 2)
89a8c51b3fSopenharmony_ci    return float(new_val - old_val) / abs(old_val)
90a8c51b3fSopenharmony_ci
91a8c51b3fSopenharmony_ci
92a8c51b3fSopenharmony_cidef filter_benchmark(json_orig, family, replacement=""):
93a8c51b3fSopenharmony_ci    """
94a8c51b3fSopenharmony_ci    Apply a filter to the json, and only leave the 'family' of benchmarks.
95a8c51b3fSopenharmony_ci    """
96a8c51b3fSopenharmony_ci    regex = re.compile(family)
97a8c51b3fSopenharmony_ci    filtered = {}
98a8c51b3fSopenharmony_ci    filtered['benchmarks'] = []
99a8c51b3fSopenharmony_ci    for be in json_orig['benchmarks']:
100a8c51b3fSopenharmony_ci        if not regex.search(be['name']):
101a8c51b3fSopenharmony_ci            continue
102a8c51b3fSopenharmony_ci        filteredbench = copy.deepcopy(be)  # Do NOT modify the old name!
103a8c51b3fSopenharmony_ci        filteredbench['name'] = regex.sub(replacement, filteredbench['name'])
104a8c51b3fSopenharmony_ci        filtered['benchmarks'].append(filteredbench)
105a8c51b3fSopenharmony_ci    return filtered
106a8c51b3fSopenharmony_ci
107a8c51b3fSopenharmony_ci
108a8c51b3fSopenharmony_cidef get_unique_benchmark_names(json):
109a8c51b3fSopenharmony_ci    """
110a8c51b3fSopenharmony_ci    While *keeping* the order, give all the unique 'names' used for benchmarks.
111a8c51b3fSopenharmony_ci    """
112a8c51b3fSopenharmony_ci    seen = set()
113a8c51b3fSopenharmony_ci    uniqued = [x['name'] for x in json['benchmarks']
114a8c51b3fSopenharmony_ci               if x['name'] not in seen and
115a8c51b3fSopenharmony_ci               (seen.add(x['name']) or True)]
116a8c51b3fSopenharmony_ci    return uniqued
117a8c51b3fSopenharmony_ci
118a8c51b3fSopenharmony_ci
119a8c51b3fSopenharmony_cidef intersect(list1, list2):
120a8c51b3fSopenharmony_ci    """
121a8c51b3fSopenharmony_ci    Given two lists, get a new list consisting of the elements only contained
122a8c51b3fSopenharmony_ci    in *both of the input lists*, while preserving the ordering.
123a8c51b3fSopenharmony_ci    """
124a8c51b3fSopenharmony_ci    return [x for x in list1 if x in list2]
125a8c51b3fSopenharmony_ci
126a8c51b3fSopenharmony_ci
127a8c51b3fSopenharmony_cidef is_potentially_comparable_benchmark(x):
128a8c51b3fSopenharmony_ci    return ('time_unit' in x and 'real_time' in x and 'cpu_time' in x)
129a8c51b3fSopenharmony_ci
130a8c51b3fSopenharmony_ci
131a8c51b3fSopenharmony_cidef partition_benchmarks(json1, json2):
132a8c51b3fSopenharmony_ci    """
133a8c51b3fSopenharmony_ci    While preserving the ordering, find benchmarks with the same names in
134a8c51b3fSopenharmony_ci    both of the inputs, and group them.
135a8c51b3fSopenharmony_ci    (i.e. partition/filter into groups with common name)
136a8c51b3fSopenharmony_ci    """
137a8c51b3fSopenharmony_ci    json1_unique_names = get_unique_benchmark_names(json1)
138a8c51b3fSopenharmony_ci    json2_unique_names = get_unique_benchmark_names(json2)
139a8c51b3fSopenharmony_ci    names = intersect(json1_unique_names, json2_unique_names)
140a8c51b3fSopenharmony_ci    partitions = []
141a8c51b3fSopenharmony_ci    for name in names:
142a8c51b3fSopenharmony_ci        time_unit = None
143a8c51b3fSopenharmony_ci        # Pick the time unit from the first entry of the lhs benchmark.
144a8c51b3fSopenharmony_ci        # We should be careful not to crash with unexpected input.
145a8c51b3fSopenharmony_ci        for x in json1['benchmarks']:
146a8c51b3fSopenharmony_ci            if (x['name'] == name and is_potentially_comparable_benchmark(x)):
147a8c51b3fSopenharmony_ci                time_unit = x['time_unit']
148a8c51b3fSopenharmony_ci                break
149a8c51b3fSopenharmony_ci        if time_unit is None:
150a8c51b3fSopenharmony_ci            continue
151a8c51b3fSopenharmony_ci        # Filter by name and time unit.
152a8c51b3fSopenharmony_ci        # All the repetitions are assumed to be comparable.
153a8c51b3fSopenharmony_ci        lhs = [x for x in json1['benchmarks'] if x['name'] == name and
154a8c51b3fSopenharmony_ci               x['time_unit'] == time_unit]
155a8c51b3fSopenharmony_ci        rhs = [x for x in json2['benchmarks'] if x['name'] == name and
156a8c51b3fSopenharmony_ci               x['time_unit'] == time_unit]
157a8c51b3fSopenharmony_ci        partitions.append([lhs, rhs])
158a8c51b3fSopenharmony_ci    return partitions
159a8c51b3fSopenharmony_ci
160a8c51b3fSopenharmony_ci
161a8c51b3fSopenharmony_cidef get_timedelta_field_as_seconds(benchmark, field_name):
162a8c51b3fSopenharmony_ci    """
163a8c51b3fSopenharmony_ci    Get value of field_name field of benchmark, which is time with time unit
164a8c51b3fSopenharmony_ci    time_unit, as time in seconds.
165a8c51b3fSopenharmony_ci    """
166a8c51b3fSopenharmony_ci    timedelta = benchmark[field_name]
167a8c51b3fSopenharmony_ci    time_unit = benchmark.get('time_unit', 's')
168a8c51b3fSopenharmony_ci    return timedelta * _TIME_UNIT_TO_SECONDS_MULTIPLIER.get(time_unit)
169a8c51b3fSopenharmony_ci
170a8c51b3fSopenharmony_ci
171a8c51b3fSopenharmony_cidef calculate_geomean(json):
172a8c51b3fSopenharmony_ci    """
173a8c51b3fSopenharmony_ci    Extract all real/cpu times from all the benchmarks as seconds,
174a8c51b3fSopenharmony_ci    and calculate their geomean.
175a8c51b3fSopenharmony_ci    """
176a8c51b3fSopenharmony_ci    times = []
177a8c51b3fSopenharmony_ci    for benchmark in json['benchmarks']:
178a8c51b3fSopenharmony_ci        if 'run_type' in benchmark and benchmark['run_type'] == 'aggregate':
179a8c51b3fSopenharmony_ci            continue
180a8c51b3fSopenharmony_ci        times.append([get_timedelta_field_as_seconds(benchmark, 'real_time'),
181a8c51b3fSopenharmony_ci                      get_timedelta_field_as_seconds(benchmark, 'cpu_time')])
182a8c51b3fSopenharmony_ci    return gmean(times) if times else array([])
183a8c51b3fSopenharmony_ci
184a8c51b3fSopenharmony_ci
185a8c51b3fSopenharmony_cidef extract_field(partition, field_name):
186a8c51b3fSopenharmony_ci    # The count of elements may be different. We want *all* of them.
187a8c51b3fSopenharmony_ci    lhs = [x[field_name] for x in partition[0]]
188a8c51b3fSopenharmony_ci    rhs = [x[field_name] for x in partition[1]]
189a8c51b3fSopenharmony_ci    return [lhs, rhs]
190a8c51b3fSopenharmony_ci
191a8c51b3fSopenharmony_ci
192a8c51b3fSopenharmony_cidef calc_utest(timings_cpu, timings_time):
193a8c51b3fSopenharmony_ci    min_rep_cnt = min(len(timings_time[0]),
194a8c51b3fSopenharmony_ci                      len(timings_time[1]),
195a8c51b3fSopenharmony_ci                      len(timings_cpu[0]),
196a8c51b3fSopenharmony_ci                      len(timings_cpu[1]))
197a8c51b3fSopenharmony_ci
198a8c51b3fSopenharmony_ci    # Does *everything* has at least UTEST_MIN_REPETITIONS repetitions?
199a8c51b3fSopenharmony_ci    if min_rep_cnt < UTEST_MIN_REPETITIONS:
200a8c51b3fSopenharmony_ci        return False, None, None
201a8c51b3fSopenharmony_ci
202a8c51b3fSopenharmony_ci    time_pvalue = mannwhitneyu(
203a8c51b3fSopenharmony_ci        timings_time[0], timings_time[1], alternative='two-sided').pvalue
204a8c51b3fSopenharmony_ci    cpu_pvalue = mannwhitneyu(
205a8c51b3fSopenharmony_ci        timings_cpu[0], timings_cpu[1], alternative='two-sided').pvalue
206a8c51b3fSopenharmony_ci
207a8c51b3fSopenharmony_ci    return (min_rep_cnt >= UTEST_OPTIMAL_REPETITIONS), cpu_pvalue, time_pvalue
208a8c51b3fSopenharmony_ci
209a8c51b3fSopenharmony_ci
210a8c51b3fSopenharmony_cidef print_utest(bc_name, utest, utest_alpha, first_col_width, use_color=True):
211a8c51b3fSopenharmony_ci    def get_utest_color(pval):
212a8c51b3fSopenharmony_ci        return BC_FAIL if pval >= utest_alpha else BC_OKGREEN
213a8c51b3fSopenharmony_ci
214a8c51b3fSopenharmony_ci    # Check if we failed miserably with minimum required repetitions for utest
215a8c51b3fSopenharmony_ci    if not utest['have_optimal_repetitions'] and utest['cpu_pvalue'] is None and utest['time_pvalue'] is None:
216a8c51b3fSopenharmony_ci        return []
217a8c51b3fSopenharmony_ci
218a8c51b3fSopenharmony_ci    dsc = "U Test, Repetitions: {} vs {}".format(
219a8c51b3fSopenharmony_ci        utest['nr_of_repetitions'], utest['nr_of_repetitions_other'])
220a8c51b3fSopenharmony_ci    dsc_color = BC_OKGREEN
221a8c51b3fSopenharmony_ci
222a8c51b3fSopenharmony_ci    # We still got some results to show but issue a warning about it.
223a8c51b3fSopenharmony_ci    if not utest['have_optimal_repetitions']:
224a8c51b3fSopenharmony_ci        dsc_color = BC_WARNING
225a8c51b3fSopenharmony_ci        dsc += ". WARNING: Results unreliable! {}+ repetitions recommended.".format(
226a8c51b3fSopenharmony_ci            UTEST_OPTIMAL_REPETITIONS)
227a8c51b3fSopenharmony_ci
228a8c51b3fSopenharmony_ci    special_str = "{}{:<{}s}{endc}{}{:16.4f}{endc}{}{:16.4f}{endc}{}      {}"
229a8c51b3fSopenharmony_ci
230a8c51b3fSopenharmony_ci    return [color_format(use_color,
231a8c51b3fSopenharmony_ci                         special_str,
232a8c51b3fSopenharmony_ci                         BC_HEADER,
233a8c51b3fSopenharmony_ci                         "{}{}".format(bc_name, UTEST_COL_NAME),
234a8c51b3fSopenharmony_ci                         first_col_width,
235a8c51b3fSopenharmony_ci                         get_utest_color(
236a8c51b3fSopenharmony_ci                             utest['time_pvalue']), utest['time_pvalue'],
237a8c51b3fSopenharmony_ci                         get_utest_color(
238a8c51b3fSopenharmony_ci                             utest['cpu_pvalue']), utest['cpu_pvalue'],
239a8c51b3fSopenharmony_ci                         dsc_color, dsc,
240a8c51b3fSopenharmony_ci                         endc=BC_ENDC)]
241a8c51b3fSopenharmony_ci
242a8c51b3fSopenharmony_ci
243a8c51b3fSopenharmony_cidef get_difference_report(
244a8c51b3fSopenharmony_ci        json1,
245a8c51b3fSopenharmony_ci        json2,
246a8c51b3fSopenharmony_ci        utest=False):
247a8c51b3fSopenharmony_ci    """
248a8c51b3fSopenharmony_ci    Calculate and report the difference between each test of two benchmarks
249a8c51b3fSopenharmony_ci    runs specified as 'json1' and 'json2'. Output is another json containing
250a8c51b3fSopenharmony_ci    relevant details for each test run.
251a8c51b3fSopenharmony_ci    """
252a8c51b3fSopenharmony_ci    assert utest is True or utest is False
253a8c51b3fSopenharmony_ci
254a8c51b3fSopenharmony_ci    diff_report = []
255a8c51b3fSopenharmony_ci    partitions = partition_benchmarks(json1, json2)
256a8c51b3fSopenharmony_ci    for partition in partitions:
257a8c51b3fSopenharmony_ci        benchmark_name = partition[0][0]['name']
258a8c51b3fSopenharmony_ci        label = partition[0][0]['label'] if 'label' in partition[0][0] else ''
259a8c51b3fSopenharmony_ci        time_unit = partition[0][0]['time_unit']
260a8c51b3fSopenharmony_ci        measurements = []
261a8c51b3fSopenharmony_ci        utest_results = {}
262a8c51b3fSopenharmony_ci        # Careful, we may have different repetition count.
263a8c51b3fSopenharmony_ci        for i in range(min(len(partition[0]), len(partition[1]))):
264a8c51b3fSopenharmony_ci            bn = partition[0][i]
265a8c51b3fSopenharmony_ci            other_bench = partition[1][i]
266a8c51b3fSopenharmony_ci            measurements.append({
267a8c51b3fSopenharmony_ci                'real_time': bn['real_time'],
268a8c51b3fSopenharmony_ci                'cpu_time': bn['cpu_time'],
269a8c51b3fSopenharmony_ci                'real_time_other': other_bench['real_time'],
270a8c51b3fSopenharmony_ci                'cpu_time_other': other_bench['cpu_time'],
271a8c51b3fSopenharmony_ci                'time': calculate_change(bn['real_time'], other_bench['real_time']),
272a8c51b3fSopenharmony_ci                'cpu': calculate_change(bn['cpu_time'], other_bench['cpu_time'])
273a8c51b3fSopenharmony_ci            })
274a8c51b3fSopenharmony_ci
275a8c51b3fSopenharmony_ci        # After processing the whole partition, if requested, do the U test.
276a8c51b3fSopenharmony_ci        if utest:
277a8c51b3fSopenharmony_ci            timings_cpu = extract_field(partition, 'cpu_time')
278a8c51b3fSopenharmony_ci            timings_time = extract_field(partition, 'real_time')
279a8c51b3fSopenharmony_ci            have_optimal_repetitions, cpu_pvalue, time_pvalue = calc_utest(
280a8c51b3fSopenharmony_ci                timings_cpu, timings_time)
281a8c51b3fSopenharmony_ci            if cpu_pvalue and time_pvalue:
282a8c51b3fSopenharmony_ci                utest_results = {
283a8c51b3fSopenharmony_ci                    'have_optimal_repetitions': have_optimal_repetitions,
284a8c51b3fSopenharmony_ci                    'cpu_pvalue': cpu_pvalue,
285a8c51b3fSopenharmony_ci                    'time_pvalue': time_pvalue,
286a8c51b3fSopenharmony_ci                    'nr_of_repetitions': len(timings_cpu[0]),
287a8c51b3fSopenharmony_ci                    'nr_of_repetitions_other': len(timings_cpu[1])
288a8c51b3fSopenharmony_ci                }
289a8c51b3fSopenharmony_ci
290a8c51b3fSopenharmony_ci        # Store only if we had any measurements for given benchmark.
291a8c51b3fSopenharmony_ci        # E.g. partition_benchmarks will filter out the benchmarks having
292a8c51b3fSopenharmony_ci        # time units which are not compatible with other time units in the
293a8c51b3fSopenharmony_ci        # benchmark suite.
294a8c51b3fSopenharmony_ci        if measurements:
295a8c51b3fSopenharmony_ci            run_type = partition[0][0]['run_type'] if 'run_type' in partition[0][0] else ''
296a8c51b3fSopenharmony_ci            aggregate_name = partition[0][0]['aggregate_name'] if run_type == 'aggregate' and 'aggregate_name' in partition[0][0] else ''
297a8c51b3fSopenharmony_ci            diff_report.append({
298a8c51b3fSopenharmony_ci                'name': benchmark_name,
299a8c51b3fSopenharmony_ci                'label': label,
300a8c51b3fSopenharmony_ci                'measurements': measurements,
301a8c51b3fSopenharmony_ci                'time_unit': time_unit,
302a8c51b3fSopenharmony_ci                'run_type': run_type,
303a8c51b3fSopenharmony_ci                'aggregate_name': aggregate_name,
304a8c51b3fSopenharmony_ci                'utest': utest_results
305a8c51b3fSopenharmony_ci            })
306a8c51b3fSopenharmony_ci
307a8c51b3fSopenharmony_ci    lhs_gmean = calculate_geomean(json1)
308a8c51b3fSopenharmony_ci    rhs_gmean = calculate_geomean(json2)
309a8c51b3fSopenharmony_ci    if lhs_gmean.any() and rhs_gmean.any():
310a8c51b3fSopenharmony_ci        diff_report.append({
311a8c51b3fSopenharmony_ci            'name': 'OVERALL_GEOMEAN',
312a8c51b3fSopenharmony_ci            'label': '',
313a8c51b3fSopenharmony_ci            'measurements': [{
314a8c51b3fSopenharmony_ci                'real_time': lhs_gmean[0],
315a8c51b3fSopenharmony_ci                'cpu_time': lhs_gmean[1],
316a8c51b3fSopenharmony_ci                'real_time_other': rhs_gmean[0],
317a8c51b3fSopenharmony_ci                'cpu_time_other': rhs_gmean[1],
318a8c51b3fSopenharmony_ci                'time': calculate_change(lhs_gmean[0], rhs_gmean[0]),
319a8c51b3fSopenharmony_ci                'cpu': calculate_change(lhs_gmean[1], rhs_gmean[1])
320a8c51b3fSopenharmony_ci            }],
321a8c51b3fSopenharmony_ci            'time_unit': 's',
322a8c51b3fSopenharmony_ci            'run_type': 'aggregate',
323a8c51b3fSopenharmony_ci            'aggregate_name': 'geomean',
324a8c51b3fSopenharmony_ci            'utest': {}
325a8c51b3fSopenharmony_ci        })
326a8c51b3fSopenharmony_ci
327a8c51b3fSopenharmony_ci    return diff_report
328a8c51b3fSopenharmony_ci
329a8c51b3fSopenharmony_ci
330a8c51b3fSopenharmony_cidef print_difference_report(
331a8c51b3fSopenharmony_ci        json_diff_report,
332a8c51b3fSopenharmony_ci        include_aggregates_only=False,
333a8c51b3fSopenharmony_ci        utest=False,
334a8c51b3fSopenharmony_ci        utest_alpha=0.05,
335a8c51b3fSopenharmony_ci        use_color=True):
336a8c51b3fSopenharmony_ci    """
337a8c51b3fSopenharmony_ci    Calculate and report the difference between each test of two benchmarks
338a8c51b3fSopenharmony_ci    runs specified as 'json1' and 'json2'.
339a8c51b3fSopenharmony_ci    """
340a8c51b3fSopenharmony_ci    assert utest is True or utest is False
341a8c51b3fSopenharmony_ci
342a8c51b3fSopenharmony_ci    def get_color(res):
343a8c51b3fSopenharmony_ci        if res > 0.05:
344a8c51b3fSopenharmony_ci            return BC_FAIL
345a8c51b3fSopenharmony_ci        elif res > -0.07:
346a8c51b3fSopenharmony_ci            return BC_WHITE
347a8c51b3fSopenharmony_ci        else:
348a8c51b3fSopenharmony_ci            return BC_CYAN
349a8c51b3fSopenharmony_ci
350a8c51b3fSopenharmony_ci    first_col_width = find_longest_name(json_diff_report)
351a8c51b3fSopenharmony_ci    first_col_width = max(
352a8c51b3fSopenharmony_ci        first_col_width,
353a8c51b3fSopenharmony_ci        len('Benchmark'))
354a8c51b3fSopenharmony_ci    first_col_width += len(UTEST_COL_NAME)
355a8c51b3fSopenharmony_ci    first_line = "{:<{}s}Time             CPU      Time Old      Time New       CPU Old       CPU New".format(
356a8c51b3fSopenharmony_ci        'Benchmark', 12 + first_col_width)
357a8c51b3fSopenharmony_ci    output_strs = [first_line, '-' * len(first_line)]
358a8c51b3fSopenharmony_ci
359a8c51b3fSopenharmony_ci    fmt_str = "{}{:<{}s}{endc}{}{:+16.4f}{endc}{}{:+16.4f}{endc}{:14.0f}{:14.0f}{endc}{:14.0f}{:14.0f}"
360a8c51b3fSopenharmony_ci    for benchmark in json_diff_report:
361a8c51b3fSopenharmony_ci        # *If* we were asked to only include aggregates,
362a8c51b3fSopenharmony_ci        # and if it is non-aggregate, then don't print it.
363a8c51b3fSopenharmony_ci        if not include_aggregates_only or not 'run_type' in benchmark or benchmark['run_type'] == 'aggregate':
364a8c51b3fSopenharmony_ci            for measurement in benchmark['measurements']:
365a8c51b3fSopenharmony_ci                output_strs += [color_format(use_color,
366a8c51b3fSopenharmony_ci                                             fmt_str,
367a8c51b3fSopenharmony_ci                                             BC_HEADER,
368a8c51b3fSopenharmony_ci                                             benchmark['name'],
369a8c51b3fSopenharmony_ci                                             first_col_width,
370a8c51b3fSopenharmony_ci                                             get_color(measurement['time']),
371a8c51b3fSopenharmony_ci                                             measurement['time'],
372a8c51b3fSopenharmony_ci                                             get_color(measurement['cpu']),
373a8c51b3fSopenharmony_ci                                             measurement['cpu'],
374a8c51b3fSopenharmony_ci                                             measurement['real_time'],
375a8c51b3fSopenharmony_ci                                             measurement['real_time_other'],
376a8c51b3fSopenharmony_ci                                             measurement['cpu_time'],
377a8c51b3fSopenharmony_ci                                             measurement['cpu_time_other'],
378a8c51b3fSopenharmony_ci                                             endc=BC_ENDC)]
379a8c51b3fSopenharmony_ci
380a8c51b3fSopenharmony_ci        # After processing the measurements, if requested and
381a8c51b3fSopenharmony_ci        # if applicable (e.g. u-test exists for given benchmark),
382a8c51b3fSopenharmony_ci        # print the U test.
383a8c51b3fSopenharmony_ci        if utest and benchmark['utest']:
384a8c51b3fSopenharmony_ci            output_strs += print_utest(benchmark['name'],
385a8c51b3fSopenharmony_ci                                       benchmark['utest'],
386a8c51b3fSopenharmony_ci                                       utest_alpha=utest_alpha,
387a8c51b3fSopenharmony_ci                                       first_col_width=first_col_width,
388a8c51b3fSopenharmony_ci                                       use_color=use_color)
389a8c51b3fSopenharmony_ci
390a8c51b3fSopenharmony_ci    return output_strs
391a8c51b3fSopenharmony_ci
392a8c51b3fSopenharmony_ci
393a8c51b3fSopenharmony_ci###############################################################################
394a8c51b3fSopenharmony_ci# Unit tests
395a8c51b3fSopenharmony_ci
396a8c51b3fSopenharmony_ci
397a8c51b3fSopenharmony_ciclass TestGetUniqueBenchmarkNames(unittest.TestCase):
398a8c51b3fSopenharmony_ci    def load_results(self):
399a8c51b3fSopenharmony_ci        import json
400a8c51b3fSopenharmony_ci        testInputs = os.path.join(
401a8c51b3fSopenharmony_ci            os.path.dirname(
402a8c51b3fSopenharmony_ci                os.path.realpath(__file__)),
403a8c51b3fSopenharmony_ci            'Inputs')
404a8c51b3fSopenharmony_ci        testOutput = os.path.join(testInputs, 'test3_run0.json')
405a8c51b3fSopenharmony_ci        with open(testOutput, 'r') as f:
406a8c51b3fSopenharmony_ci            json = json.load(f)
407a8c51b3fSopenharmony_ci        return json
408a8c51b3fSopenharmony_ci
409a8c51b3fSopenharmony_ci    def test_basic(self):
410a8c51b3fSopenharmony_ci        expect_lines = [
411a8c51b3fSopenharmony_ci            'BM_One',
412a8c51b3fSopenharmony_ci            'BM_Two',
413a8c51b3fSopenharmony_ci            'short',  # These two are not sorted
414a8c51b3fSopenharmony_ci            'medium',  # These two are not sorted
415a8c51b3fSopenharmony_ci        ]
416a8c51b3fSopenharmony_ci        json = self.load_results()
417a8c51b3fSopenharmony_ci        output_lines = get_unique_benchmark_names(json)
418a8c51b3fSopenharmony_ci        print("\n")
419a8c51b3fSopenharmony_ci        print("\n".join(output_lines))
420a8c51b3fSopenharmony_ci        self.assertEqual(len(output_lines), len(expect_lines))
421a8c51b3fSopenharmony_ci        for i in range(0, len(output_lines)):
422a8c51b3fSopenharmony_ci            self.assertEqual(expect_lines[i], output_lines[i])
423a8c51b3fSopenharmony_ci
424a8c51b3fSopenharmony_ci
425a8c51b3fSopenharmony_ciclass TestReportDifference(unittest.TestCase):
426a8c51b3fSopenharmony_ci    @classmethod
427a8c51b3fSopenharmony_ci    def setUpClass(cls):
428a8c51b3fSopenharmony_ci        def load_results():
429a8c51b3fSopenharmony_ci            import json
430a8c51b3fSopenharmony_ci            testInputs = os.path.join(
431a8c51b3fSopenharmony_ci                os.path.dirname(
432a8c51b3fSopenharmony_ci                    os.path.realpath(__file__)),
433a8c51b3fSopenharmony_ci                'Inputs')
434a8c51b3fSopenharmony_ci            testOutput1 = os.path.join(testInputs, 'test1_run1.json')
435a8c51b3fSopenharmony_ci            testOutput2 = os.path.join(testInputs, 'test1_run2.json')
436a8c51b3fSopenharmony_ci            with open(testOutput1, 'r') as f:
437a8c51b3fSopenharmony_ci                json1 = json.load(f)
438a8c51b3fSopenharmony_ci            with open(testOutput2, 'r') as f:
439a8c51b3fSopenharmony_ci                json2 = json.load(f)
440a8c51b3fSopenharmony_ci            return json1, json2
441a8c51b3fSopenharmony_ci
442a8c51b3fSopenharmony_ci        json1, json2 = load_results()
443a8c51b3fSopenharmony_ci        cls.json_diff_report = get_difference_report(json1, json2)
444a8c51b3fSopenharmony_ci
445a8c51b3fSopenharmony_ci    def test_json_diff_report_pretty_printing(self):
446a8c51b3fSopenharmony_ci        expect_lines = [
447a8c51b3fSopenharmony_ci            ['BM_SameTimes', '+0.0000', '+0.0000', '10', '10', '10', '10'],
448a8c51b3fSopenharmony_ci            ['BM_2xFaster', '-0.5000', '-0.5000', '50', '25', '50', '25'],
449a8c51b3fSopenharmony_ci            ['BM_2xSlower', '+1.0000', '+1.0000', '50', '100', '50', '100'],
450a8c51b3fSopenharmony_ci            ['BM_1PercentFaster', '-0.0100', '-0.0100', '100', '99', '100', '99'],
451a8c51b3fSopenharmony_ci            ['BM_1PercentSlower', '+0.0100', '+0.0100', '100', '101', '100', '101'],
452a8c51b3fSopenharmony_ci            ['BM_10PercentFaster', '-0.1000', '-0.1000', '100', '90', '100', '90'],
453a8c51b3fSopenharmony_ci            ['BM_10PercentSlower', '+0.1000', '+0.1000', '100', '110', '100', '110'],
454a8c51b3fSopenharmony_ci            ['BM_100xSlower', '+99.0000', '+99.0000',
455a8c51b3fSopenharmony_ci                '100', '10000', '100', '10000'],
456a8c51b3fSopenharmony_ci            ['BM_100xFaster', '-0.9900', '-0.9900',
457a8c51b3fSopenharmony_ci                '10000', '100', '10000', '100'],
458a8c51b3fSopenharmony_ci            ['BM_10PercentCPUToTime', '+0.1000',
459a8c51b3fSopenharmony_ci                '-0.1000', '100', '110', '100', '90'],
460a8c51b3fSopenharmony_ci            ['BM_ThirdFaster', '-0.3333', '-0.3334', '100', '67', '100', '67'],
461a8c51b3fSopenharmony_ci            ['BM_NotBadTimeUnit', '-0.9000', '+0.2000', '0', '0', '0', '1'],
462a8c51b3fSopenharmony_ci            ['BM_hasLabel', '+0.0000', '+0.0000', '1', '1', '1', '1'],
463a8c51b3fSopenharmony_ci            ['OVERALL_GEOMEAN', '-0.8113', '-0.7779', '0', '0', '0', '0']
464a8c51b3fSopenharmony_ci        ]
465a8c51b3fSopenharmony_ci        output_lines_with_header = print_difference_report(
466a8c51b3fSopenharmony_ci            self.json_diff_report, use_color=False)
467a8c51b3fSopenharmony_ci        output_lines = output_lines_with_header[2:]
468a8c51b3fSopenharmony_ci        print("\n")
469a8c51b3fSopenharmony_ci        print("\n".join(output_lines_with_header))
470a8c51b3fSopenharmony_ci        self.assertEqual(len(output_lines), len(expect_lines))
471a8c51b3fSopenharmony_ci        for i in range(0, len(output_lines)):
472a8c51b3fSopenharmony_ci            parts = [x for x in output_lines[i].split(' ') if x]
473a8c51b3fSopenharmony_ci            self.assertEqual(len(parts), 7)
474a8c51b3fSopenharmony_ci            self.assertEqual(expect_lines[i], parts)
475a8c51b3fSopenharmony_ci
476a8c51b3fSopenharmony_ci    def test_json_diff_report_output(self):
477a8c51b3fSopenharmony_ci        expected_output = [
478a8c51b3fSopenharmony_ci            {
479a8c51b3fSopenharmony_ci                'name': 'BM_SameTimes',
480a8c51b3fSopenharmony_ci                'label': '',
481a8c51b3fSopenharmony_ci                'measurements': [{'time': 0.0000, 'cpu': 0.0000,
482a8c51b3fSopenharmony_ci                                  'real_time': 10, 'real_time_other': 10,
483a8c51b3fSopenharmony_ci                                  'cpu_time': 10, 'cpu_time_other': 10}],
484a8c51b3fSopenharmony_ci                'time_unit': 'ns',
485a8c51b3fSopenharmony_ci                'utest': {}
486a8c51b3fSopenharmony_ci            },
487a8c51b3fSopenharmony_ci            {
488a8c51b3fSopenharmony_ci                'name': 'BM_2xFaster',
489a8c51b3fSopenharmony_ci                'label': '',
490a8c51b3fSopenharmony_ci                'measurements': [{'time': -0.5000, 'cpu': -0.5000,
491a8c51b3fSopenharmony_ci                                  'real_time': 50, 'real_time_other': 25,
492a8c51b3fSopenharmony_ci                                  'cpu_time': 50, 'cpu_time_other': 25}],
493a8c51b3fSopenharmony_ci                'time_unit': 'ns',
494a8c51b3fSopenharmony_ci                'utest': {}
495a8c51b3fSopenharmony_ci            },
496a8c51b3fSopenharmony_ci            {
497a8c51b3fSopenharmony_ci                'name': 'BM_2xSlower',
498a8c51b3fSopenharmony_ci                'label': '',
499a8c51b3fSopenharmony_ci                'measurements': [{'time': 1.0000, 'cpu': 1.0000,
500a8c51b3fSopenharmony_ci                                  'real_time': 50, 'real_time_other': 100,
501a8c51b3fSopenharmony_ci                                  'cpu_time': 50, 'cpu_time_other': 100}],
502a8c51b3fSopenharmony_ci                'time_unit': 'ns',
503a8c51b3fSopenharmony_ci                'utest': {}
504a8c51b3fSopenharmony_ci            },
505a8c51b3fSopenharmony_ci            {
506a8c51b3fSopenharmony_ci                'name': 'BM_1PercentFaster',
507a8c51b3fSopenharmony_ci                'label': '',
508a8c51b3fSopenharmony_ci                'measurements': [{'time': -0.0100, 'cpu': -0.0100,
509a8c51b3fSopenharmony_ci                                  'real_time': 100, 'real_time_other': 98.9999999,
510a8c51b3fSopenharmony_ci                                  'cpu_time': 100, 'cpu_time_other': 98.9999999}],
511a8c51b3fSopenharmony_ci                'time_unit': 'ns',
512a8c51b3fSopenharmony_ci                'utest': {}
513a8c51b3fSopenharmony_ci            },
514a8c51b3fSopenharmony_ci            {
515a8c51b3fSopenharmony_ci                'name': 'BM_1PercentSlower',
516a8c51b3fSopenharmony_ci                'label': '',
517a8c51b3fSopenharmony_ci                'measurements': [{'time': 0.0100, 'cpu': 0.0100,
518a8c51b3fSopenharmony_ci                                  'real_time': 100, 'real_time_other': 101,
519a8c51b3fSopenharmony_ci                                  'cpu_time': 100, 'cpu_time_other': 101}],
520a8c51b3fSopenharmony_ci                'time_unit': 'ns',
521a8c51b3fSopenharmony_ci                'utest': {}
522a8c51b3fSopenharmony_ci            },
523a8c51b3fSopenharmony_ci            {
524a8c51b3fSopenharmony_ci                'name': 'BM_10PercentFaster',
525a8c51b3fSopenharmony_ci                'label': '',
526a8c51b3fSopenharmony_ci                'measurements': [{'time': -0.1000, 'cpu': -0.1000,
527a8c51b3fSopenharmony_ci                                  'real_time': 100, 'real_time_other': 90,
528a8c51b3fSopenharmony_ci                                  'cpu_time': 100, 'cpu_time_other': 90}],
529a8c51b3fSopenharmony_ci                'time_unit': 'ns',
530a8c51b3fSopenharmony_ci                'utest': {}
531a8c51b3fSopenharmony_ci            },
532a8c51b3fSopenharmony_ci            {
533a8c51b3fSopenharmony_ci                'name': 'BM_10PercentSlower',
534a8c51b3fSopenharmony_ci                'label': '',
535a8c51b3fSopenharmony_ci                'measurements': [{'time': 0.1000, 'cpu': 0.1000,
536a8c51b3fSopenharmony_ci                                  'real_time': 100, 'real_time_other': 110,
537a8c51b3fSopenharmony_ci                                  'cpu_time': 100, 'cpu_time_other': 110}],
538a8c51b3fSopenharmony_ci                'time_unit': 'ns',
539a8c51b3fSopenharmony_ci                'utest': {}
540a8c51b3fSopenharmony_ci            },
541a8c51b3fSopenharmony_ci            {
542a8c51b3fSopenharmony_ci                'name': 'BM_100xSlower',
543a8c51b3fSopenharmony_ci                'label': '',
544a8c51b3fSopenharmony_ci                'measurements': [{'time': 99.0000, 'cpu': 99.0000,
545a8c51b3fSopenharmony_ci                                  'real_time': 100, 'real_time_other': 10000,
546a8c51b3fSopenharmony_ci                                  'cpu_time': 100, 'cpu_time_other': 10000}],
547a8c51b3fSopenharmony_ci                'time_unit': 'ns',
548a8c51b3fSopenharmony_ci                'utest': {}
549a8c51b3fSopenharmony_ci            },
550a8c51b3fSopenharmony_ci            {
551a8c51b3fSopenharmony_ci                'name': 'BM_100xFaster',
552a8c51b3fSopenharmony_ci                'label': '',
553a8c51b3fSopenharmony_ci                'measurements': [{'time': -0.9900, 'cpu': -0.9900,
554a8c51b3fSopenharmony_ci                                  'real_time': 10000, 'real_time_other': 100,
555a8c51b3fSopenharmony_ci                                  'cpu_time': 10000, 'cpu_time_other': 100}],
556a8c51b3fSopenharmony_ci                'time_unit': 'ns',
557a8c51b3fSopenharmony_ci                'utest': {}
558a8c51b3fSopenharmony_ci            },
559a8c51b3fSopenharmony_ci            {
560a8c51b3fSopenharmony_ci                'name': 'BM_10PercentCPUToTime',
561a8c51b3fSopenharmony_ci                'label': '',
562a8c51b3fSopenharmony_ci                'measurements': [{'time': 0.1000, 'cpu': -0.1000,
563a8c51b3fSopenharmony_ci                                  'real_time': 100, 'real_time_other': 110,
564a8c51b3fSopenharmony_ci                                  'cpu_time': 100, 'cpu_time_other': 90}],
565a8c51b3fSopenharmony_ci                'time_unit': 'ns',
566a8c51b3fSopenharmony_ci                'utest': {}
567a8c51b3fSopenharmony_ci            },
568a8c51b3fSopenharmony_ci            {
569a8c51b3fSopenharmony_ci                'name': 'BM_ThirdFaster',
570a8c51b3fSopenharmony_ci                'label': '',
571a8c51b3fSopenharmony_ci                'measurements': [{'time': -0.3333, 'cpu': -0.3334,
572a8c51b3fSopenharmony_ci                                  'real_time': 100, 'real_time_other': 67,
573a8c51b3fSopenharmony_ci                                  'cpu_time': 100, 'cpu_time_other': 67}],
574a8c51b3fSopenharmony_ci                'time_unit': 'ns',
575a8c51b3fSopenharmony_ci                'utest': {}
576a8c51b3fSopenharmony_ci            },
577a8c51b3fSopenharmony_ci            {
578a8c51b3fSopenharmony_ci                'name': 'BM_NotBadTimeUnit',
579a8c51b3fSopenharmony_ci                'label': '',
580a8c51b3fSopenharmony_ci                'measurements': [{'time': -0.9000, 'cpu': 0.2000,
581a8c51b3fSopenharmony_ci                                  'real_time': 0.4, 'real_time_other': 0.04,
582a8c51b3fSopenharmony_ci                                  'cpu_time': 0.5, 'cpu_time_other': 0.6}],
583a8c51b3fSopenharmony_ci                'time_unit': 's',
584a8c51b3fSopenharmony_ci                'utest': {}
585a8c51b3fSopenharmony_ci            },
586a8c51b3fSopenharmony_ci            {
587a8c51b3fSopenharmony_ci                'name': 'BM_hasLabel',
588a8c51b3fSopenharmony_ci                'label': 'a label',
589a8c51b3fSopenharmony_ci                'measurements': [{'time': 0.0000, 'cpu': 0.0000,
590a8c51b3fSopenharmony_ci                                  'real_time': 1, 'real_time_other': 1,
591a8c51b3fSopenharmony_ci                                  'cpu_time': 1, 'cpu_time_other': 1}],
592a8c51b3fSopenharmony_ci                'time_unit': 's',
593a8c51b3fSopenharmony_ci                'utest': {}
594a8c51b3fSopenharmony_ci            },
595a8c51b3fSopenharmony_ci            {
596a8c51b3fSopenharmony_ci                'name': 'OVERALL_GEOMEAN',
597a8c51b3fSopenharmony_ci                'label': '',
598a8c51b3fSopenharmony_ci                'measurements': [{'real_time': 3.1622776601683826e-06, 'cpu_time': 3.2130844755623912e-06,
599a8c51b3fSopenharmony_ci                                  'real_time_other': 1.9768988699420897e-07, 'cpu_time_other': 2.397447755209533e-07,
600a8c51b3fSopenharmony_ci                                  'time': -0.8112976497120911, 'cpu': -0.7778551721181174}],
601a8c51b3fSopenharmony_ci                'time_unit': 's',
602a8c51b3fSopenharmony_ci                'run_type': 'aggregate',
603a8c51b3fSopenharmony_ci                'aggregate_name': 'geomean', 'utest': {}
604a8c51b3fSopenharmony_ci            },
605a8c51b3fSopenharmony_ci        ]
606a8c51b3fSopenharmony_ci        self.assertEqual(len(self.json_diff_report), len(expected_output))
607a8c51b3fSopenharmony_ci        for out, expected in zip(
608a8c51b3fSopenharmony_ci                self.json_diff_report, expected_output):
609a8c51b3fSopenharmony_ci            self.assertEqual(out['name'], expected['name'])
610a8c51b3fSopenharmony_ci            self.assertEqual(out['label'], expected['label'])
611a8c51b3fSopenharmony_ci            self.assertEqual(out['time_unit'], expected['time_unit'])
612a8c51b3fSopenharmony_ci            assert_utest(self, out, expected)
613a8c51b3fSopenharmony_ci            assert_measurements(self, out, expected)
614a8c51b3fSopenharmony_ci
615a8c51b3fSopenharmony_ci
616a8c51b3fSopenharmony_ciclass TestReportDifferenceBetweenFamilies(unittest.TestCase):
617a8c51b3fSopenharmony_ci    @classmethod
618a8c51b3fSopenharmony_ci    def setUpClass(cls):
619a8c51b3fSopenharmony_ci        def load_result():
620a8c51b3fSopenharmony_ci            import json
621a8c51b3fSopenharmony_ci            testInputs = os.path.join(
622a8c51b3fSopenharmony_ci                os.path.dirname(
623a8c51b3fSopenharmony_ci                    os.path.realpath(__file__)),
624a8c51b3fSopenharmony_ci                'Inputs')
625a8c51b3fSopenharmony_ci            testOutput = os.path.join(testInputs, 'test2_run.json')
626a8c51b3fSopenharmony_ci            with open(testOutput, 'r') as f:
627a8c51b3fSopenharmony_ci                json = json.load(f)
628a8c51b3fSopenharmony_ci            return json
629a8c51b3fSopenharmony_ci
630a8c51b3fSopenharmony_ci        json = load_result()
631a8c51b3fSopenharmony_ci        json1 = filter_benchmark(json, "BM_Z.ro", ".")
632a8c51b3fSopenharmony_ci        json2 = filter_benchmark(json, "BM_O.e", ".")
633a8c51b3fSopenharmony_ci        cls.json_diff_report = get_difference_report(json1, json2)
634a8c51b3fSopenharmony_ci
635a8c51b3fSopenharmony_ci    def test_json_diff_report_pretty_printing(self):
636a8c51b3fSopenharmony_ci        expect_lines = [
637a8c51b3fSopenharmony_ci            ['.', '-0.5000', '-0.5000', '10', '5', '10', '5'],
638a8c51b3fSopenharmony_ci            ['./4', '-0.5000', '-0.5000', '40', '20', '40', '20'],
639a8c51b3fSopenharmony_ci            ['Prefix/.', '-0.5000', '-0.5000', '20', '10', '20', '10'],
640a8c51b3fSopenharmony_ci            ['Prefix/./3', '-0.5000', '-0.5000', '30', '15', '30', '15'],
641a8c51b3fSopenharmony_ci            ['OVERALL_GEOMEAN', '-0.5000', '-0.5000', '0', '0', '0', '0']
642a8c51b3fSopenharmony_ci        ]
643a8c51b3fSopenharmony_ci        output_lines_with_header = print_difference_report(
644a8c51b3fSopenharmony_ci            self.json_diff_report, use_color=False)
645a8c51b3fSopenharmony_ci        output_lines = output_lines_with_header[2:]
646a8c51b3fSopenharmony_ci        print("\n")
647a8c51b3fSopenharmony_ci        print("\n".join(output_lines_with_header))
648a8c51b3fSopenharmony_ci        self.assertEqual(len(output_lines), len(expect_lines))
649a8c51b3fSopenharmony_ci        for i in range(0, len(output_lines)):
650a8c51b3fSopenharmony_ci            parts = [x for x in output_lines[i].split(' ') if x]
651a8c51b3fSopenharmony_ci            self.assertEqual(len(parts), 7)
652a8c51b3fSopenharmony_ci            self.assertEqual(expect_lines[i], parts)
653a8c51b3fSopenharmony_ci
654a8c51b3fSopenharmony_ci    def test_json_diff_report(self):
655a8c51b3fSopenharmony_ci        expected_output = [
656a8c51b3fSopenharmony_ci            {
657a8c51b3fSopenharmony_ci                'name': u'.',
658a8c51b3fSopenharmony_ci                'measurements': [{'time': -0.5, 'cpu': -0.5, 'real_time': 10, 'real_time_other': 5, 'cpu_time': 10, 'cpu_time_other': 5}],
659a8c51b3fSopenharmony_ci                'time_unit': 'ns',
660a8c51b3fSopenharmony_ci                'utest': {}
661a8c51b3fSopenharmony_ci            },
662a8c51b3fSopenharmony_ci            {
663a8c51b3fSopenharmony_ci                'name': u'./4',
664a8c51b3fSopenharmony_ci                'measurements': [{'time': -0.5, 'cpu': -0.5, 'real_time': 40, 'real_time_other': 20, 'cpu_time': 40, 'cpu_time_other': 20}],
665a8c51b3fSopenharmony_ci                'time_unit': 'ns',
666a8c51b3fSopenharmony_ci                'utest': {},
667a8c51b3fSopenharmony_ci            },
668a8c51b3fSopenharmony_ci            {
669a8c51b3fSopenharmony_ci                'name': u'Prefix/.',
670a8c51b3fSopenharmony_ci                'measurements': [{'time': -0.5, 'cpu': -0.5, 'real_time': 20, 'real_time_other': 10, 'cpu_time': 20, 'cpu_time_other': 10}],
671a8c51b3fSopenharmony_ci                'time_unit': 'ns',
672a8c51b3fSopenharmony_ci                'utest': {}
673a8c51b3fSopenharmony_ci            },
674a8c51b3fSopenharmony_ci            {
675a8c51b3fSopenharmony_ci                'name': u'Prefix/./3',
676a8c51b3fSopenharmony_ci                'measurements': [{'time': -0.5, 'cpu': -0.5, 'real_time': 30, 'real_time_other': 15, 'cpu_time': 30, 'cpu_time_other': 15}],
677a8c51b3fSopenharmony_ci                'time_unit': 'ns',
678a8c51b3fSopenharmony_ci                'utest': {}
679a8c51b3fSopenharmony_ci            },
680a8c51b3fSopenharmony_ci            {
681a8c51b3fSopenharmony_ci                'name': 'OVERALL_GEOMEAN',
682a8c51b3fSopenharmony_ci                'measurements': [{'real_time': 2.213363839400641e-08, 'cpu_time': 2.213363839400641e-08,
683a8c51b3fSopenharmony_ci                                  'real_time_other': 1.1066819197003185e-08, 'cpu_time_other': 1.1066819197003185e-08,
684a8c51b3fSopenharmony_ci                                  'time': -0.5000000000000009, 'cpu': -0.5000000000000009}],
685a8c51b3fSopenharmony_ci                'time_unit': 's',
686a8c51b3fSopenharmony_ci                'run_type': 'aggregate',
687a8c51b3fSopenharmony_ci                'aggregate_name': 'geomean',
688a8c51b3fSopenharmony_ci                'utest': {}
689a8c51b3fSopenharmony_ci            }
690a8c51b3fSopenharmony_ci        ]
691a8c51b3fSopenharmony_ci        self.assertEqual(len(self.json_diff_report), len(expected_output))
692a8c51b3fSopenharmony_ci        for out, expected in zip(
693a8c51b3fSopenharmony_ci                self.json_diff_report, expected_output):
694a8c51b3fSopenharmony_ci            self.assertEqual(out['name'], expected['name'])
695a8c51b3fSopenharmony_ci            self.assertEqual(out['time_unit'], expected['time_unit'])
696a8c51b3fSopenharmony_ci            assert_utest(self, out, expected)
697a8c51b3fSopenharmony_ci            assert_measurements(self, out, expected)
698a8c51b3fSopenharmony_ci
699a8c51b3fSopenharmony_ci
700a8c51b3fSopenharmony_ciclass TestReportDifferenceWithUTest(unittest.TestCase):
701a8c51b3fSopenharmony_ci    @classmethod
702a8c51b3fSopenharmony_ci    def setUpClass(cls):
703a8c51b3fSopenharmony_ci        def load_results():
704a8c51b3fSopenharmony_ci            import json
705a8c51b3fSopenharmony_ci            testInputs = os.path.join(
706a8c51b3fSopenharmony_ci                os.path.dirname(
707a8c51b3fSopenharmony_ci                    os.path.realpath(__file__)),
708a8c51b3fSopenharmony_ci                'Inputs')
709a8c51b3fSopenharmony_ci            testOutput1 = os.path.join(testInputs, 'test3_run0.json')
710a8c51b3fSopenharmony_ci            testOutput2 = os.path.join(testInputs, 'test3_run1.json')
711a8c51b3fSopenharmony_ci            with open(testOutput1, 'r') as f:
712a8c51b3fSopenharmony_ci                json1 = json.load(f)
713a8c51b3fSopenharmony_ci            with open(testOutput2, 'r') as f:
714a8c51b3fSopenharmony_ci                json2 = json.load(f)
715a8c51b3fSopenharmony_ci            return json1, json2
716a8c51b3fSopenharmony_ci
717a8c51b3fSopenharmony_ci        json1, json2 = load_results()
718a8c51b3fSopenharmony_ci        cls.json_diff_report = get_difference_report(
719a8c51b3fSopenharmony_ci            json1, json2, utest=True)
720a8c51b3fSopenharmony_ci
721a8c51b3fSopenharmony_ci    def test_json_diff_report_pretty_printing(self):
722a8c51b3fSopenharmony_ci        expect_lines = [
723a8c51b3fSopenharmony_ci            ['BM_One', '-0.1000', '+0.1000', '10', '9', '100', '110'],
724a8c51b3fSopenharmony_ci            ['BM_Two', '+0.1111', '-0.0111', '9', '10', '90', '89'],
725a8c51b3fSopenharmony_ci            ['BM_Two', '-0.1250', '-0.1628', '8', '7', '86', '72'],
726a8c51b3fSopenharmony_ci            ['BM_Two_pvalue',
727a8c51b3fSopenharmony_ci             '1.0000',
728a8c51b3fSopenharmony_ci             '0.6667',
729a8c51b3fSopenharmony_ci             'U',
730a8c51b3fSopenharmony_ci             'Test,',
731a8c51b3fSopenharmony_ci             'Repetitions:',
732a8c51b3fSopenharmony_ci             '2',
733a8c51b3fSopenharmony_ci             'vs',
734a8c51b3fSopenharmony_ci             '2.',
735a8c51b3fSopenharmony_ci             'WARNING:',
736a8c51b3fSopenharmony_ci             'Results',
737a8c51b3fSopenharmony_ci             'unreliable!',
738a8c51b3fSopenharmony_ci             '9+',
739a8c51b3fSopenharmony_ci             'repetitions',
740a8c51b3fSopenharmony_ci             'recommended.'],
741a8c51b3fSopenharmony_ci            ['short', '-0.1250', '-0.0625', '8', '7', '80', '75'],
742a8c51b3fSopenharmony_ci            ['short', '-0.4325', '-0.1351', '8', '5', '77', '67'],
743a8c51b3fSopenharmony_ci            ['short_pvalue',
744a8c51b3fSopenharmony_ci             '0.7671',
745a8c51b3fSopenharmony_ci             '0.2000',
746a8c51b3fSopenharmony_ci             'U',
747a8c51b3fSopenharmony_ci             'Test,',
748a8c51b3fSopenharmony_ci             'Repetitions:',
749a8c51b3fSopenharmony_ci             '2',
750a8c51b3fSopenharmony_ci             'vs',
751a8c51b3fSopenharmony_ci             '3.',
752a8c51b3fSopenharmony_ci             'WARNING:',
753a8c51b3fSopenharmony_ci             'Results',
754a8c51b3fSopenharmony_ci             'unreliable!',
755a8c51b3fSopenharmony_ci             '9+',
756a8c51b3fSopenharmony_ci             'repetitions',
757a8c51b3fSopenharmony_ci             'recommended.'],
758a8c51b3fSopenharmony_ci            ['medium', '-0.3750', '-0.3375', '8', '5', '80', '53'],
759a8c51b3fSopenharmony_ci            ['OVERALL_GEOMEAN', '+1.6405', '-0.6985', '0', '0', '0', '0']
760a8c51b3fSopenharmony_ci        ]
761a8c51b3fSopenharmony_ci        output_lines_with_header = print_difference_report(
762a8c51b3fSopenharmony_ci            self.json_diff_report, utest=True, utest_alpha=0.05, use_color=False)
763a8c51b3fSopenharmony_ci        output_lines = output_lines_with_header[2:]
764a8c51b3fSopenharmony_ci        print("\n")
765a8c51b3fSopenharmony_ci        print("\n".join(output_lines_with_header))
766a8c51b3fSopenharmony_ci        self.assertEqual(len(output_lines), len(expect_lines))
767a8c51b3fSopenharmony_ci        for i in range(0, len(output_lines)):
768a8c51b3fSopenharmony_ci            parts = [x for x in output_lines[i].split(' ') if x]
769a8c51b3fSopenharmony_ci            self.assertEqual(expect_lines[i], parts)
770a8c51b3fSopenharmony_ci
771a8c51b3fSopenharmony_ci    def test_json_diff_report_pretty_printing_aggregates_only(self):
772a8c51b3fSopenharmony_ci        expect_lines = [
773a8c51b3fSopenharmony_ci            ['BM_One', '-0.1000', '+0.1000', '10', '9', '100', '110'],
774a8c51b3fSopenharmony_ci            ['BM_Two_pvalue',
775a8c51b3fSopenharmony_ci             '1.0000',
776a8c51b3fSopenharmony_ci             '0.6667',
777a8c51b3fSopenharmony_ci             'U',
778a8c51b3fSopenharmony_ci             'Test,',
779a8c51b3fSopenharmony_ci             'Repetitions:',
780a8c51b3fSopenharmony_ci             '2',
781a8c51b3fSopenharmony_ci             'vs',
782a8c51b3fSopenharmony_ci             '2.',
783a8c51b3fSopenharmony_ci             'WARNING:',
784a8c51b3fSopenharmony_ci             'Results',
785a8c51b3fSopenharmony_ci             'unreliable!',
786a8c51b3fSopenharmony_ci             '9+',
787a8c51b3fSopenharmony_ci             'repetitions',
788a8c51b3fSopenharmony_ci             'recommended.'],
789a8c51b3fSopenharmony_ci            ['short', '-0.1250', '-0.0625', '8', '7', '80', '75'],
790a8c51b3fSopenharmony_ci            ['short', '-0.4325', '-0.1351', '8', '5', '77', '67'],
791a8c51b3fSopenharmony_ci            ['short_pvalue',
792a8c51b3fSopenharmony_ci             '0.7671',
793a8c51b3fSopenharmony_ci             '0.2000',
794a8c51b3fSopenharmony_ci             'U',
795a8c51b3fSopenharmony_ci             'Test,',
796a8c51b3fSopenharmony_ci             'Repetitions:',
797a8c51b3fSopenharmony_ci             '2',
798a8c51b3fSopenharmony_ci             'vs',
799a8c51b3fSopenharmony_ci             '3.',
800a8c51b3fSopenharmony_ci             'WARNING:',
801a8c51b3fSopenharmony_ci             'Results',
802a8c51b3fSopenharmony_ci             'unreliable!',
803a8c51b3fSopenharmony_ci             '9+',
804a8c51b3fSopenharmony_ci             'repetitions',
805a8c51b3fSopenharmony_ci             'recommended.'],
806a8c51b3fSopenharmony_ci            ['OVERALL_GEOMEAN', '+1.6405', '-0.6985', '0', '0', '0', '0']
807a8c51b3fSopenharmony_ci        ]
808a8c51b3fSopenharmony_ci        output_lines_with_header = print_difference_report(
809a8c51b3fSopenharmony_ci            self.json_diff_report, include_aggregates_only=True, utest=True, utest_alpha=0.05, use_color=False)
810a8c51b3fSopenharmony_ci        output_lines = output_lines_with_header[2:]
811a8c51b3fSopenharmony_ci        print("\n")
812a8c51b3fSopenharmony_ci        print("\n".join(output_lines_with_header))
813a8c51b3fSopenharmony_ci        self.assertEqual(len(output_lines), len(expect_lines))
814a8c51b3fSopenharmony_ci        for i in range(0, len(output_lines)):
815a8c51b3fSopenharmony_ci            parts = [x for x in output_lines[i].split(' ') if x]
816a8c51b3fSopenharmony_ci            self.assertEqual(expect_lines[i], parts)
817a8c51b3fSopenharmony_ci
818a8c51b3fSopenharmony_ci    def test_json_diff_report(self):
819a8c51b3fSopenharmony_ci        expected_output = [
820a8c51b3fSopenharmony_ci            {
821a8c51b3fSopenharmony_ci                'name': u'BM_One',
822a8c51b3fSopenharmony_ci                'measurements': [
823a8c51b3fSopenharmony_ci                    {'time': -0.1,
824a8c51b3fSopenharmony_ci                     'cpu': 0.1,
825a8c51b3fSopenharmony_ci                     'real_time': 10,
826a8c51b3fSopenharmony_ci                     'real_time_other': 9,
827a8c51b3fSopenharmony_ci                     'cpu_time': 100,
828a8c51b3fSopenharmony_ci                     'cpu_time_other': 110}
829a8c51b3fSopenharmony_ci                ],
830a8c51b3fSopenharmony_ci                'time_unit': 'ns',
831a8c51b3fSopenharmony_ci                'utest': {}
832a8c51b3fSopenharmony_ci            },
833a8c51b3fSopenharmony_ci            {
834a8c51b3fSopenharmony_ci                'name': u'BM_Two',
835a8c51b3fSopenharmony_ci                'measurements': [
836a8c51b3fSopenharmony_ci                    {'time': 0.1111111111111111,
837a8c51b3fSopenharmony_ci                     'cpu': -0.011111111111111112,
838a8c51b3fSopenharmony_ci                     'real_time': 9,
839a8c51b3fSopenharmony_ci                     'real_time_other': 10,
840a8c51b3fSopenharmony_ci                     'cpu_time': 90,
841a8c51b3fSopenharmony_ci                     'cpu_time_other': 89},
842a8c51b3fSopenharmony_ci                    {'time': -0.125, 'cpu': -0.16279069767441862, 'real_time': 8,
843a8c51b3fSopenharmony_ci                        'real_time_other': 7, 'cpu_time': 86, 'cpu_time_other': 72}
844a8c51b3fSopenharmony_ci                ],
845a8c51b3fSopenharmony_ci                'time_unit': 'ns',
846a8c51b3fSopenharmony_ci                'utest': {
847a8c51b3fSopenharmony_ci                    'have_optimal_repetitions': False, 'cpu_pvalue': 0.6666666666666666, 'time_pvalue': 1.0
848a8c51b3fSopenharmony_ci                }
849a8c51b3fSopenharmony_ci            },
850a8c51b3fSopenharmony_ci            {
851a8c51b3fSopenharmony_ci                'name': u'short',
852a8c51b3fSopenharmony_ci                'measurements': [
853a8c51b3fSopenharmony_ci                    {'time': -0.125,
854a8c51b3fSopenharmony_ci                     'cpu': -0.0625,
855a8c51b3fSopenharmony_ci                     'real_time': 8,
856a8c51b3fSopenharmony_ci                     'real_time_other': 7,
857a8c51b3fSopenharmony_ci                     'cpu_time': 80,
858a8c51b3fSopenharmony_ci                     'cpu_time_other': 75},
859a8c51b3fSopenharmony_ci                    {'time': -0.4325,
860a8c51b3fSopenharmony_ci                     'cpu': -0.13506493506493514,
861a8c51b3fSopenharmony_ci                     'real_time': 8,
862a8c51b3fSopenharmony_ci                     'real_time_other': 4.54,
863a8c51b3fSopenharmony_ci                     'cpu_time': 77,
864a8c51b3fSopenharmony_ci                     'cpu_time_other': 66.6}
865a8c51b3fSopenharmony_ci                ],
866a8c51b3fSopenharmony_ci                'time_unit': 'ns',
867a8c51b3fSopenharmony_ci                'utest': {
868a8c51b3fSopenharmony_ci                    'have_optimal_repetitions': False, 'cpu_pvalue': 0.2, 'time_pvalue': 0.7670968684102772
869a8c51b3fSopenharmony_ci                }
870a8c51b3fSopenharmony_ci            },
871a8c51b3fSopenharmony_ci            {
872a8c51b3fSopenharmony_ci                'name': u'medium',
873a8c51b3fSopenharmony_ci                'measurements': [
874a8c51b3fSopenharmony_ci                    {'time': -0.375,
875a8c51b3fSopenharmony_ci                     'cpu': -0.3375,
876a8c51b3fSopenharmony_ci                     'real_time': 8,
877a8c51b3fSopenharmony_ci                     'real_time_other': 5,
878a8c51b3fSopenharmony_ci                     'cpu_time': 80,
879a8c51b3fSopenharmony_ci                     'cpu_time_other': 53}
880a8c51b3fSopenharmony_ci                ],
881a8c51b3fSopenharmony_ci                'time_unit': 'ns',
882a8c51b3fSopenharmony_ci                'utest': {}
883a8c51b3fSopenharmony_ci            },
884a8c51b3fSopenharmony_ci            {
885a8c51b3fSopenharmony_ci                'name': 'OVERALL_GEOMEAN',
886a8c51b3fSopenharmony_ci                'measurements': [{'real_time': 8.48528137423858e-09, 'cpu_time': 8.441336246629233e-08,
887a8c51b3fSopenharmony_ci                                  'real_time_other': 2.2405267593145244e-08, 'cpu_time_other': 2.5453661413660466e-08,
888a8c51b3fSopenharmony_ci                                  'time': 1.6404861082353634, 'cpu': -0.6984640740519662}],
889a8c51b3fSopenharmony_ci                'time_unit': 's',
890a8c51b3fSopenharmony_ci                'run_type': 'aggregate',
891a8c51b3fSopenharmony_ci                'aggregate_name': 'geomean',
892a8c51b3fSopenharmony_ci                'utest': {}
893a8c51b3fSopenharmony_ci            }
894a8c51b3fSopenharmony_ci        ]
895a8c51b3fSopenharmony_ci        self.assertEqual(len(self.json_diff_report), len(expected_output))
896a8c51b3fSopenharmony_ci        for out, expected in zip(
897a8c51b3fSopenharmony_ci                self.json_diff_report, expected_output):
898a8c51b3fSopenharmony_ci            self.assertEqual(out['name'], expected['name'])
899a8c51b3fSopenharmony_ci            self.assertEqual(out['time_unit'], expected['time_unit'])
900a8c51b3fSopenharmony_ci            assert_utest(self, out, expected)
901a8c51b3fSopenharmony_ci            assert_measurements(self, out, expected)
902a8c51b3fSopenharmony_ci
903a8c51b3fSopenharmony_ci
904a8c51b3fSopenharmony_ciclass TestReportDifferenceWithUTestWhileDisplayingAggregatesOnly(
905a8c51b3fSopenharmony_ci        unittest.TestCase):
906a8c51b3fSopenharmony_ci    @classmethod
907a8c51b3fSopenharmony_ci    def setUpClass(cls):
908a8c51b3fSopenharmony_ci        def load_results():
909a8c51b3fSopenharmony_ci            import json
910a8c51b3fSopenharmony_ci            testInputs = os.path.join(
911a8c51b3fSopenharmony_ci                os.path.dirname(
912a8c51b3fSopenharmony_ci                    os.path.realpath(__file__)),
913a8c51b3fSopenharmony_ci                'Inputs')
914a8c51b3fSopenharmony_ci            testOutput1 = os.path.join(testInputs, 'test3_run0.json')
915a8c51b3fSopenharmony_ci            testOutput2 = os.path.join(testInputs, 'test3_run1.json')
916a8c51b3fSopenharmony_ci            with open(testOutput1, 'r') as f:
917a8c51b3fSopenharmony_ci                json1 = json.load(f)
918a8c51b3fSopenharmony_ci            with open(testOutput2, 'r') as f:
919a8c51b3fSopenharmony_ci                json2 = json.load(f)
920a8c51b3fSopenharmony_ci            return json1, json2
921a8c51b3fSopenharmony_ci
922a8c51b3fSopenharmony_ci        json1, json2 = load_results()
923a8c51b3fSopenharmony_ci        cls.json_diff_report = get_difference_report(
924a8c51b3fSopenharmony_ci            json1, json2, utest=True)
925a8c51b3fSopenharmony_ci
926a8c51b3fSopenharmony_ci    def test_json_diff_report_pretty_printing(self):
927a8c51b3fSopenharmony_ci        expect_lines = [
928a8c51b3fSopenharmony_ci            ['BM_One', '-0.1000', '+0.1000', '10', '9', '100', '110'],
929a8c51b3fSopenharmony_ci            ['BM_Two', '+0.1111', '-0.0111', '9', '10', '90', '89'],
930a8c51b3fSopenharmony_ci            ['BM_Two', '-0.1250', '-0.1628', '8', '7', '86', '72'],
931a8c51b3fSopenharmony_ci            ['BM_Two_pvalue',
932a8c51b3fSopenharmony_ci             '1.0000',
933a8c51b3fSopenharmony_ci             '0.6667',
934a8c51b3fSopenharmony_ci             'U',
935a8c51b3fSopenharmony_ci             'Test,',
936a8c51b3fSopenharmony_ci             'Repetitions:',
937a8c51b3fSopenharmony_ci             '2',
938a8c51b3fSopenharmony_ci             'vs',
939a8c51b3fSopenharmony_ci             '2.',
940a8c51b3fSopenharmony_ci             'WARNING:',
941a8c51b3fSopenharmony_ci             'Results',
942a8c51b3fSopenharmony_ci             'unreliable!',
943a8c51b3fSopenharmony_ci             '9+',
944a8c51b3fSopenharmony_ci             'repetitions',
945a8c51b3fSopenharmony_ci             'recommended.'],
946a8c51b3fSopenharmony_ci            ['short', '-0.1250', '-0.0625', '8', '7', '80', '75'],
947a8c51b3fSopenharmony_ci            ['short', '-0.4325', '-0.1351', '8', '5', '77', '67'],
948a8c51b3fSopenharmony_ci            ['short_pvalue',
949a8c51b3fSopenharmony_ci             '0.7671',
950a8c51b3fSopenharmony_ci             '0.2000',
951a8c51b3fSopenharmony_ci             'U',
952a8c51b3fSopenharmony_ci             'Test,',
953a8c51b3fSopenharmony_ci             'Repetitions:',
954a8c51b3fSopenharmony_ci             '2',
955a8c51b3fSopenharmony_ci             'vs',
956a8c51b3fSopenharmony_ci             '3.',
957a8c51b3fSopenharmony_ci             'WARNING:',
958a8c51b3fSopenharmony_ci             'Results',
959a8c51b3fSopenharmony_ci             'unreliable!',
960a8c51b3fSopenharmony_ci             '9+',
961a8c51b3fSopenharmony_ci             'repetitions',
962a8c51b3fSopenharmony_ci             'recommended.'],
963a8c51b3fSopenharmony_ci            ['medium', '-0.3750', '-0.3375', '8', '5', '80', '53'],
964a8c51b3fSopenharmony_ci            ['OVERALL_GEOMEAN', '+1.6405', '-0.6985', '0', '0', '0', '0']
965a8c51b3fSopenharmony_ci        ]
966a8c51b3fSopenharmony_ci        output_lines_with_header = print_difference_report(
967a8c51b3fSopenharmony_ci            self.json_diff_report,
968a8c51b3fSopenharmony_ci            utest=True, utest_alpha=0.05, use_color=False)
969a8c51b3fSopenharmony_ci        output_lines = output_lines_with_header[2:]
970a8c51b3fSopenharmony_ci        print("\n")
971a8c51b3fSopenharmony_ci        print("\n".join(output_lines_with_header))
972a8c51b3fSopenharmony_ci        self.assertEqual(len(output_lines), len(expect_lines))
973a8c51b3fSopenharmony_ci        for i in range(0, len(output_lines)):
974a8c51b3fSopenharmony_ci            parts = [x for x in output_lines[i].split(' ') if x]
975a8c51b3fSopenharmony_ci            self.assertEqual(expect_lines[i], parts)
976a8c51b3fSopenharmony_ci
977a8c51b3fSopenharmony_ci    def test_json_diff_report(self):
978a8c51b3fSopenharmony_ci        expected_output = [
979a8c51b3fSopenharmony_ci            {
980a8c51b3fSopenharmony_ci                'name': u'BM_One',
981a8c51b3fSopenharmony_ci                'measurements': [
982a8c51b3fSopenharmony_ci                    {'time': -0.1,
983a8c51b3fSopenharmony_ci                     'cpu': 0.1,
984a8c51b3fSopenharmony_ci                     'real_time': 10,
985a8c51b3fSopenharmony_ci                     'real_time_other': 9,
986a8c51b3fSopenharmony_ci                     'cpu_time': 100,
987a8c51b3fSopenharmony_ci                     'cpu_time_other': 110}
988a8c51b3fSopenharmony_ci                ],
989a8c51b3fSopenharmony_ci                'time_unit': 'ns',
990a8c51b3fSopenharmony_ci                'utest': {}
991a8c51b3fSopenharmony_ci            },
992a8c51b3fSopenharmony_ci            {
993a8c51b3fSopenharmony_ci                'name': u'BM_Two',
994a8c51b3fSopenharmony_ci                'measurements': [
995a8c51b3fSopenharmony_ci                    {'time': 0.1111111111111111,
996a8c51b3fSopenharmony_ci                     'cpu': -0.011111111111111112,
997a8c51b3fSopenharmony_ci                     'real_time': 9,
998a8c51b3fSopenharmony_ci                     'real_time_other': 10,
999a8c51b3fSopenharmony_ci                     'cpu_time': 90,
1000a8c51b3fSopenharmony_ci                     'cpu_time_other': 89},
1001a8c51b3fSopenharmony_ci                    {'time': -0.125, 'cpu': -0.16279069767441862, 'real_time': 8,
1002a8c51b3fSopenharmony_ci                        'real_time_other': 7, 'cpu_time': 86, 'cpu_time_other': 72}
1003a8c51b3fSopenharmony_ci                ],
1004a8c51b3fSopenharmony_ci                'time_unit': 'ns',
1005a8c51b3fSopenharmony_ci                'utest': {
1006a8c51b3fSopenharmony_ci                    'have_optimal_repetitions': False, 'cpu_pvalue': 0.6666666666666666, 'time_pvalue': 1.0
1007a8c51b3fSopenharmony_ci                }
1008a8c51b3fSopenharmony_ci            },
1009a8c51b3fSopenharmony_ci            {
1010a8c51b3fSopenharmony_ci                'name': u'short',
1011a8c51b3fSopenharmony_ci                'measurements': [
1012a8c51b3fSopenharmony_ci                    {'time': -0.125,
1013a8c51b3fSopenharmony_ci                     'cpu': -0.0625,
1014a8c51b3fSopenharmony_ci                     'real_time': 8,
1015a8c51b3fSopenharmony_ci                     'real_time_other': 7,
1016a8c51b3fSopenharmony_ci                     'cpu_time': 80,
1017a8c51b3fSopenharmony_ci                     'cpu_time_other': 75},
1018a8c51b3fSopenharmony_ci                    {'time': -0.4325,
1019a8c51b3fSopenharmony_ci                     'cpu': -0.13506493506493514,
1020a8c51b3fSopenharmony_ci                     'real_time': 8,
1021a8c51b3fSopenharmony_ci                     'real_time_other': 4.54,
1022a8c51b3fSopenharmony_ci                     'cpu_time': 77,
1023a8c51b3fSopenharmony_ci                     'cpu_time_other': 66.6}
1024a8c51b3fSopenharmony_ci                ],
1025a8c51b3fSopenharmony_ci                'time_unit': 'ns',
1026a8c51b3fSopenharmony_ci                'utest': {
1027a8c51b3fSopenharmony_ci                    'have_optimal_repetitions': False, 'cpu_pvalue': 0.2, 'time_pvalue': 0.7670968684102772
1028a8c51b3fSopenharmony_ci                }
1029a8c51b3fSopenharmony_ci            },
1030a8c51b3fSopenharmony_ci            {
1031a8c51b3fSopenharmony_ci                'name': u'medium',
1032a8c51b3fSopenharmony_ci                'measurements': [
1033a8c51b3fSopenharmony_ci                    {'real_time_other': 5,
1034a8c51b3fSopenharmony_ci                     'cpu_time': 80,
1035a8c51b3fSopenharmony_ci                     'time': -0.375,
1036a8c51b3fSopenharmony_ci                     'real_time': 8,
1037a8c51b3fSopenharmony_ci                     'cpu_time_other': 53,
1038a8c51b3fSopenharmony_ci                     'cpu': -0.3375
1039a8c51b3fSopenharmony_ci                     }
1040a8c51b3fSopenharmony_ci                ],
1041a8c51b3fSopenharmony_ci                'utest': {},
1042a8c51b3fSopenharmony_ci                'time_unit': u'ns',
1043a8c51b3fSopenharmony_ci                'aggregate_name': ''
1044a8c51b3fSopenharmony_ci            },
1045a8c51b3fSopenharmony_ci            {
1046a8c51b3fSopenharmony_ci                'name': 'OVERALL_GEOMEAN',
1047a8c51b3fSopenharmony_ci                'measurements': [{'real_time': 8.48528137423858e-09, 'cpu_time': 8.441336246629233e-08,
1048a8c51b3fSopenharmony_ci                                  'real_time_other': 2.2405267593145244e-08, 'cpu_time_other': 2.5453661413660466e-08,
1049a8c51b3fSopenharmony_ci                                  'time': 1.6404861082353634, 'cpu': -0.6984640740519662}],
1050a8c51b3fSopenharmony_ci                'time_unit': 's',
1051a8c51b3fSopenharmony_ci                'run_type': 'aggregate',
1052a8c51b3fSopenharmony_ci                'aggregate_name': 'geomean',
1053a8c51b3fSopenharmony_ci                'utest': {}
1054a8c51b3fSopenharmony_ci            }
1055a8c51b3fSopenharmony_ci        ]
1056a8c51b3fSopenharmony_ci        self.assertEqual(len(self.json_diff_report), len(expected_output))
1057a8c51b3fSopenharmony_ci        for out, expected in zip(
1058a8c51b3fSopenharmony_ci                self.json_diff_report, expected_output):
1059a8c51b3fSopenharmony_ci            self.assertEqual(out['name'], expected['name'])
1060a8c51b3fSopenharmony_ci            self.assertEqual(out['time_unit'], expected['time_unit'])
1061a8c51b3fSopenharmony_ci            assert_utest(self, out, expected)
1062a8c51b3fSopenharmony_ci            assert_measurements(self, out, expected)
1063a8c51b3fSopenharmony_ci
1064a8c51b3fSopenharmony_ci
1065a8c51b3fSopenharmony_ciclass TestReportDifferenceForPercentageAggregates(
1066a8c51b3fSopenharmony_ci        unittest.TestCase):
1067a8c51b3fSopenharmony_ci    @classmethod
1068a8c51b3fSopenharmony_ci    def setUpClass(cls):
1069a8c51b3fSopenharmony_ci        def load_results():
1070a8c51b3fSopenharmony_ci            import json
1071a8c51b3fSopenharmony_ci            testInputs = os.path.join(
1072a8c51b3fSopenharmony_ci                os.path.dirname(
1073a8c51b3fSopenharmony_ci                    os.path.realpath(__file__)),
1074a8c51b3fSopenharmony_ci                'Inputs')
1075a8c51b3fSopenharmony_ci            testOutput1 = os.path.join(testInputs, 'test4_run0.json')
1076a8c51b3fSopenharmony_ci            testOutput2 = os.path.join(testInputs, 'test4_run1.json')
1077a8c51b3fSopenharmony_ci            with open(testOutput1, 'r') as f:
1078a8c51b3fSopenharmony_ci                json1 = json.load(f)
1079a8c51b3fSopenharmony_ci            with open(testOutput2, 'r') as f:
1080a8c51b3fSopenharmony_ci                json2 = json.load(f)
1081a8c51b3fSopenharmony_ci            return json1, json2
1082a8c51b3fSopenharmony_ci
1083a8c51b3fSopenharmony_ci        json1, json2 = load_results()
1084a8c51b3fSopenharmony_ci        cls.json_diff_report = get_difference_report(
1085a8c51b3fSopenharmony_ci            json1, json2, utest=True)
1086a8c51b3fSopenharmony_ci
1087a8c51b3fSopenharmony_ci    def test_json_diff_report_pretty_printing(self):
1088a8c51b3fSopenharmony_ci        expect_lines = [
1089a8c51b3fSopenharmony_ci            ['whocares', '-0.5000', '+0.5000', '0', '0', '0', '0']
1090a8c51b3fSopenharmony_ci        ]
1091a8c51b3fSopenharmony_ci        output_lines_with_header = print_difference_report(
1092a8c51b3fSopenharmony_ci            self.json_diff_report,
1093a8c51b3fSopenharmony_ci            utest=True, utest_alpha=0.05, use_color=False)
1094a8c51b3fSopenharmony_ci        output_lines = output_lines_with_header[2:]
1095a8c51b3fSopenharmony_ci        print("\n")
1096a8c51b3fSopenharmony_ci        print("\n".join(output_lines_with_header))
1097a8c51b3fSopenharmony_ci        self.assertEqual(len(output_lines), len(expect_lines))
1098a8c51b3fSopenharmony_ci        for i in range(0, len(output_lines)):
1099a8c51b3fSopenharmony_ci            parts = [x for x in output_lines[i].split(' ') if x]
1100a8c51b3fSopenharmony_ci            self.assertEqual(expect_lines[i], parts)
1101a8c51b3fSopenharmony_ci
1102a8c51b3fSopenharmony_ci    def test_json_diff_report(self):
1103a8c51b3fSopenharmony_ci        expected_output = [
1104a8c51b3fSopenharmony_ci            {
1105a8c51b3fSopenharmony_ci                'name': u'whocares',
1106a8c51b3fSopenharmony_ci                'measurements': [
1107a8c51b3fSopenharmony_ci                    {'time': -0.5,
1108a8c51b3fSopenharmony_ci                     'cpu': 0.5,
1109a8c51b3fSopenharmony_ci                     'real_time': 0.01,
1110a8c51b3fSopenharmony_ci                     'real_time_other': 0.005,
1111a8c51b3fSopenharmony_ci                     'cpu_time': 0.10,
1112a8c51b3fSopenharmony_ci                     'cpu_time_other': 0.15}
1113a8c51b3fSopenharmony_ci                ],
1114a8c51b3fSopenharmony_ci                'time_unit': 'ns',
1115a8c51b3fSopenharmony_ci                'utest': {}
1116a8c51b3fSopenharmony_ci            }
1117a8c51b3fSopenharmony_ci        ]
1118a8c51b3fSopenharmony_ci        self.assertEqual(len(self.json_diff_report), len(expected_output))
1119a8c51b3fSopenharmony_ci        for out, expected in zip(
1120a8c51b3fSopenharmony_ci                self.json_diff_report, expected_output):
1121a8c51b3fSopenharmony_ci            self.assertEqual(out['name'], expected['name'])
1122a8c51b3fSopenharmony_ci            self.assertEqual(out['time_unit'], expected['time_unit'])
1123a8c51b3fSopenharmony_ci            assert_utest(self, out, expected)
1124a8c51b3fSopenharmony_ci            assert_measurements(self, out, expected)
1125a8c51b3fSopenharmony_ci
1126a8c51b3fSopenharmony_ci
1127a8c51b3fSopenharmony_ciclass TestReportSorting(unittest.TestCase):
1128a8c51b3fSopenharmony_ci    @classmethod
1129a8c51b3fSopenharmony_ci    def setUpClass(cls):
1130a8c51b3fSopenharmony_ci        def load_result():
1131a8c51b3fSopenharmony_ci            import json
1132a8c51b3fSopenharmony_ci            testInputs = os.path.join(
1133a8c51b3fSopenharmony_ci                os.path.dirname(
1134a8c51b3fSopenharmony_ci                    os.path.realpath(__file__)),
1135a8c51b3fSopenharmony_ci                'Inputs')
1136a8c51b3fSopenharmony_ci            testOutput = os.path.join(testInputs, 'test4_run.json')
1137a8c51b3fSopenharmony_ci            with open(testOutput, 'r') as f:
1138a8c51b3fSopenharmony_ci                json = json.load(f)
1139a8c51b3fSopenharmony_ci            return json
1140a8c51b3fSopenharmony_ci
1141a8c51b3fSopenharmony_ci        cls.json = load_result()
1142a8c51b3fSopenharmony_ci
1143a8c51b3fSopenharmony_ci    def test_json_diff_report_pretty_printing(self):
1144a8c51b3fSopenharmony_ci        import util
1145a8c51b3fSopenharmony_ci
1146a8c51b3fSopenharmony_ci        expected_names = [
1147a8c51b3fSopenharmony_ci            "99 family 0 instance 0 repetition 0",
1148a8c51b3fSopenharmony_ci            "98 family 0 instance 0 repetition 1",
1149a8c51b3fSopenharmony_ci            "97 family 0 instance 0 aggregate",
1150a8c51b3fSopenharmony_ci            "96 family 0 instance 1 repetition 0",
1151a8c51b3fSopenharmony_ci            "95 family 0 instance 1 repetition 1",
1152a8c51b3fSopenharmony_ci            "94 family 0 instance 1 aggregate",
1153a8c51b3fSopenharmony_ci            "93 family 1 instance 0 repetition 0",
1154a8c51b3fSopenharmony_ci            "92 family 1 instance 0 repetition 1",
1155a8c51b3fSopenharmony_ci            "91 family 1 instance 0 aggregate",
1156a8c51b3fSopenharmony_ci            "90 family 1 instance 1 repetition 0",
1157a8c51b3fSopenharmony_ci            "89 family 1 instance 1 repetition 1",
1158a8c51b3fSopenharmony_ci            "88 family 1 instance 1 aggregate"
1159a8c51b3fSopenharmony_ci        ]
1160a8c51b3fSopenharmony_ci
1161a8c51b3fSopenharmony_ci        for n in range(len(self.json['benchmarks']) ** 2):
1162a8c51b3fSopenharmony_ci            random.shuffle(self.json['benchmarks'])
1163a8c51b3fSopenharmony_ci            sorted_benchmarks = util.sort_benchmark_results(self.json)[
1164a8c51b3fSopenharmony_ci                'benchmarks']
1165a8c51b3fSopenharmony_ci            self.assertEqual(len(expected_names), len(sorted_benchmarks))
1166a8c51b3fSopenharmony_ci            for out, expected in zip(sorted_benchmarks, expected_names):
1167a8c51b3fSopenharmony_ci                self.assertEqual(out['name'], expected)
1168a8c51b3fSopenharmony_ci
1169a8c51b3fSopenharmony_ci
1170a8c51b3fSopenharmony_cidef assert_utest(unittest_instance, lhs, rhs):
1171a8c51b3fSopenharmony_ci    if lhs['utest']:
1172a8c51b3fSopenharmony_ci        unittest_instance.assertAlmostEqual(
1173a8c51b3fSopenharmony_ci            lhs['utest']['cpu_pvalue'],
1174a8c51b3fSopenharmony_ci            rhs['utest']['cpu_pvalue'])
1175a8c51b3fSopenharmony_ci        unittest_instance.assertAlmostEqual(
1176a8c51b3fSopenharmony_ci            lhs['utest']['time_pvalue'],
1177a8c51b3fSopenharmony_ci            rhs['utest']['time_pvalue'])
1178a8c51b3fSopenharmony_ci        unittest_instance.assertEqual(
1179a8c51b3fSopenharmony_ci            lhs['utest']['have_optimal_repetitions'],
1180a8c51b3fSopenharmony_ci            rhs['utest']['have_optimal_repetitions'])
1181a8c51b3fSopenharmony_ci    else:
1182a8c51b3fSopenharmony_ci        # lhs is empty. assert if rhs is not.
1183a8c51b3fSopenharmony_ci        unittest_instance.assertEqual(lhs['utest'], rhs['utest'])
1184a8c51b3fSopenharmony_ci
1185a8c51b3fSopenharmony_ci
1186a8c51b3fSopenharmony_cidef assert_measurements(unittest_instance, lhs, rhs):
1187a8c51b3fSopenharmony_ci    for m1, m2 in zip(lhs['measurements'], rhs['measurements']):
1188a8c51b3fSopenharmony_ci        unittest_instance.assertEqual(m1['real_time'], m2['real_time'])
1189a8c51b3fSopenharmony_ci        unittest_instance.assertEqual(m1['cpu_time'], m2['cpu_time'])
1190a8c51b3fSopenharmony_ci        # m1['time'] and m1['cpu'] hold values which are being calculated,
1191a8c51b3fSopenharmony_ci        # and therefore we must use almost-equal pattern.
1192a8c51b3fSopenharmony_ci        unittest_instance.assertAlmostEqual(m1['time'], m2['time'], places=4)
1193a8c51b3fSopenharmony_ci        unittest_instance.assertAlmostEqual(m1['cpu'], m2['cpu'], places=4)
1194a8c51b3fSopenharmony_ci
1195a8c51b3fSopenharmony_ci
1196a8c51b3fSopenharmony_ciif __name__ == '__main__':
1197a8c51b3fSopenharmony_ci    unittest.main()
1198a8c51b3fSopenharmony_ci
1199a8c51b3fSopenharmony_ci# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
1200a8c51b3fSopenharmony_ci# kate: tab-width: 4; replace-tabs on; indent-width 4; tab-indents: off;
1201a8c51b3fSopenharmony_ci# kate: indent-mode python; remove-trailing-spaces modified;
1202