1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.microdroid.test.common;
18 
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24 
25 /** This class processes the metrics for both device tests and host tests. */
26 public final class MetricsProcessor {
27     private final String mPrefix;
28 
getMetricPrefix(String debugTag)29     public static String getMetricPrefix(String debugTag) {
30         return "avf_perf"
31             + ((debugTag != null && !debugTag.isEmpty()) ? "[" + debugTag + "]" : "")
32             + "/";
33     }
34 
MetricsProcessor(String prefix)35     public MetricsProcessor(String prefix) {
36         mPrefix = prefix;
37     }
38 
39     /**
40      * Computes the min, max, average and standard deviation of the given metrics and saves them in
41      * a {@link Map} with the corresponding keys equal to [mPrefix + name +
42      * _[min|max|average|stdev]_ + unit].
43      */
computeStats(List<? extends Number> metrics, String name, String unit)44     public Map<String, Double> computeStats(List<? extends Number> metrics, String name,
45             String unit) {
46         List<Double> values = new ArrayList<>(metrics.size());
47         for (Number metric : metrics) {
48             values.add(metric.doubleValue());
49         }
50         Collections.sort(values);
51 
52         double sum = 0;
53         double min = Double.POSITIVE_INFINITY;
54         double max = Double.NEGATIVE_INFINITY;
55         for (Double d : values) {
56             sum += d;
57             if (min > d) min = d;
58             if (max < d) max = d;
59         }
60         double avg = sum / values.size();
61         double sqSum = 0;
62         for (Double d : values) {
63             sqSum += (d - avg) * (d - avg);
64         }
65         double stdDev = Math.sqrt(sqSum / (values.size() - 1));
66         double median = Double.NaN;
67         if (values.size() > 0) {
68             int rank = values.size() / 2;
69             if (values.size() % 2 == 0) {
70                 median = (values.get(rank - 1) + values.get(rank)) / 2;
71             } else {
72                 median = values.get(rank);
73             }
74         }
75         Map<String, Double> stats = new HashMap<String, Double>();
76         String prefix = mPrefix + name;
77         stats.put(prefix + "_min_" + unit, min);
78         stats.put(prefix + "_max_" + unit, max);
79         stats.put(prefix + "_average_" + unit, avg);
80         stats.put(prefix + "_stdev_" + unit, stdDev);
81         stats.put(prefix + "_median_" + unit, median);
82         return stats;
83     }
84 }
85