• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 package com.android.game.qualification.metric;
17 
18 import com.android.annotations.Nullable;
19 import com.android.game.qualification.CertificationRequirements;
20 import com.android.tradefed.device.metric.DeviceMetricData;
21 import com.android.tradefed.invoker.IInvocationContext;
22 import com.android.tradefed.metrics.proto.MetricMeasurement.DataType;
23 import com.android.tradefed.metrics.proto.MetricMeasurement.Measurements;
24 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
25 
26 import com.google.common.base.Preconditions;
27 
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.LinkedHashMap;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Objects;
34 import java.util.stream.Collectors;
35 
36 /**
37  * Summary of frame time metrics data.
38  */
39 public class MetricSummary {
40     public enum TimeType {
41         PRESENT,
42         READY
43     }
44 
45     private int loopCount;
46     private long loadTimeMs;
47     private Map<TimeType, List<LoopSummary>> summaries;
48 
MetricSummary( int loopCount, long loadTimeMs, Map<TimeType, List<LoopSummary>> summaries)49     private MetricSummary(
50             int loopCount,
51             long loadTimeMs,
52             Map<TimeType, List<LoopSummary>> summaries) {
53         this.loopCount = loopCount;
54         this.loadTimeMs = loadTimeMs;
55         this.summaries = summaries;
56     }
57 
58     @Nullable
parseRunMetrics( IInvocationContext context, HashMap<String, Metric> metrics)59     public static MetricSummary parseRunMetrics(
60             IInvocationContext context, HashMap<String, Metric> metrics) {
61         int loopCount = 0;
62         if (metrics.containsKey("loop_count")) {
63             loopCount = (int) metrics.get("loop_count").getMeasurements().getSingleInt();
64         }
65 
66         if (loopCount == 0) {
67             return null;
68         }
69 
70         Map<TimeType, List<LoopSummary>> summaries = new LinkedHashMap<>();
71         for (TimeType type : TimeType.values()) {
72             summaries.put(type, new ArrayList<>());
73             for (int i = 0; i < loopCount; i++) {
74                 LoopSummary loopSummary = LoopSummary.parseRunMetrics(context, type, i, metrics);
75                 summaries.get(type).add(loopSummary);
76             }
77         }
78         return new MetricSummary(
79                 loopCount,
80                 metrics.get("load_time").getMeasurements().getSingleInt(),
81                 summaries);
82     }
83 
getLoadTimeMs()84     public long getLoadTimeMs() {
85         return loadTimeMs;
86     }
87 
getLoopSummaries()88     public List<LoopSummary> getLoopSummaries() {
89         return summaries.get(TimeType.PRESENT);
90     }
91 
addToMetricData(DeviceMetricData runData)92     public void addToMetricData(DeviceMetricData runData) {
93         runData.addMetric(
94                 "loop_count",
95                 Metric.newBuilder()
96                         .setType(DataType.PROCESSED)
97                         .setMeasurements(Measurements.newBuilder().setSingleInt(loopCount)));
98         runData.addMetric(
99                 "load_time",
100                 Metric.newBuilder()
101                         .setType(DataType.RAW)
102                         .setMeasurements(Measurements.newBuilder().setSingleInt(loadTimeMs)));
103 
104         for (int i = 0; i < loopCount; i++) {
105             for (TimeType type : TimeType.values()) {
106                 LoopSummary summary = summaries.get(type).get(i);
107                 summary.addToMetricData(runData, i, type);
108             }
109         }
110     }
111 
112     @Override
equals(Object o)113     public boolean equals(Object o) {
114         if (this == o) return true;
115         if (o == null || getClass() != o.getClass()) return false;
116         MetricSummary summary = (MetricSummary) o;
117         return loopCount == summary.loopCount &&
118                 loadTimeMs == summary.loadTimeMs &&
119                 Objects.equals(summaries, summary.summaries);
120     }
121 
122     @Override
hashCode()123     public int hashCode() {
124         return Objects.hash(loopCount, loadTimeMs, summaries);
125     }
126 
toString()127     public String toString() {
128         StringBuilder sb = new StringBuilder();
129         // Report primary metrics.
130         sb.append("Summary\n");
131         sb.append("-------\n");
132         sb.append("Load time: ");
133         if (getLoadTimeMs() == -1) {
134             sb.append("unknown");
135         } else {
136             sb.append(getLoadTimeMs());
137             sb.append(" ms\n");
138         }
139         sb.append("\n");
140 
141         // Report secondary metrics.
142         sb.append("Details\n");
143         sb.append("-------\n");
144 
145 
146         for (int i = 0; i < loopCount; i++) {
147             if (summaries.get(TimeType.PRESENT).get(i).getCount() == 0) {
148                 continue;
149             }
150             sb.append("Loop ");
151             sb.append(i);
152             sb.append('\n');
153             for (TimeType type : TimeType.values()) {
154                 sb.append(type);
155                 sb.append(" Time Statistics\n");
156                 sb.append(summaries.get(type).get(i));
157                 sb.append("\n");
158             }
159         }
160         return sb.toString();
161     }
162 
msToNs(float value)163     private static long msToNs(float value) {
164         return (long) (value * 1e6f);
165     }
166 
167     public static class Builder {
168         @Nullable
169         private CertificationRequirements mRequirements;
170         private long mVSyncPeriodNs;
171         private int loopCount = 0;
172         private long loadTimeMs = -1;
173         private Map<TimeType, List<LoopSummary.Builder>> summaries = new LinkedHashMap<>();
174 
Builder(@ullable CertificationRequirements requirements, long vSyncPeriodNs)175         public Builder(@Nullable CertificationRequirements requirements, long vSyncPeriodNs) {
176             mRequirements = requirements;
177             mVSyncPeriodNs = vSyncPeriodNs;
178             for (TimeType type : TimeType.values()) {
179                 summaries.put(type, new ArrayList<>());
180             }
181         }
182 
getLatestSummary(TimeType type)183         private LoopSummary.Builder getLatestSummary(TimeType type) {
184             Preconditions.checkState(loopCount > 0, "First loop has not been started.");
185             List<LoopSummary.Builder> list = summaries.get(type);
186             return list.get(list.size() - 1);
187         }
188 
setLoadTimeMs(long loadTimeMs)189         public void setLoadTimeMs(long loadTimeMs) {
190             this.loadTimeMs = loadTimeMs;
191         }
192 
addFrameTime(TimeType type, long frameTimeNs)193         public void addFrameTime(TimeType type, long frameTimeNs) {
194             LoopSummary.Builder summary = getLatestSummary(type);
195             summary.addFrameTime(frameTimeNs);
196         }
197 
beginLoop()198         public void beginLoop() {
199             loopCount++;
200             for (TimeType type : TimeType.values()) {
201                 summaries.get(type).add(new LoopSummary.Builder(mRequirements, mVSyncPeriodNs));
202             }
203         }
204 
endLoop()205         public void endLoop() {
206             // Do nothing.
207         }
208 
build()209         public MetricSummary build() {
210             Map<TimeType, List<LoopSummary>> summaryMap = new HashMap<>();
211             for (Map.Entry<TimeType, List<LoopSummary.Builder>> entry : summaries.entrySet()) {
212                 summaryMap.put(
213                         entry.getKey(),
214                         entry.getValue().stream()
215                                 .map(LoopSummary.Builder::build)
216                                 .collect(Collectors.toList()));
217             }
218             return new MetricSummary(loopCount, loadTimeMs, summaryMap);
219         }
220     }
221 }
222