1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you 5 * may not use this file except in compliance with the License. You may 6 * 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 13 * implied. See the License for the specific language governing 14 * permissions and limitations under the License. 15 */ 16 17 package com.android.vts.entity; 18 19 import com.android.vts.proto.VtsReportMessage.VtsProfilingRegressionMode; 20 import com.android.vts.util.StatSummary; 21 import com.google.appengine.api.datastore.Entity; 22 import com.google.appengine.api.datastore.Key; 23 import com.google.appengine.api.datastore.KeyFactory; 24 import com.googlecode.objectify.annotation.Cache; 25 import com.googlecode.objectify.annotation.Id; 26 import com.googlecode.objectify.annotation.Ignore; 27 import com.googlecode.objectify.annotation.Index; 28 import java.util.ArrayList; 29 import java.util.HashMap; 30 import java.util.List; 31 import java.util.Map; 32 import java.util.logging.Level; 33 import java.util.logging.Logger; 34 import lombok.Data; 35 import lombok.NoArgsConstructor; 36 37 import static com.googlecode.objectify.ObjectifyService.ofy; 38 39 @com.googlecode.objectify.annotation.Entity(name = "ProfilingPointSummary") 40 @Cache 41 @Data 42 @NoArgsConstructor 43 /** Entity describing a profiling point summary. */ 44 public class ProfilingPointSummaryEntity implements DashboardEntity { 45 protected static final Logger logger = 46 Logger.getLogger(ProfilingPointSummaryEntity.class.getName()); 47 protected static final String DELIMITER = "#"; 48 49 public static final String KIND = "ProfilingPointSummary"; 50 public static final String ALL = "ALL"; 51 52 // Property keys 53 public static final String START_TIME = "startTime"; 54 public static final String MEAN = "mean"; 55 public static final String SUMSQ = "sumSq"; 56 public static final String MIN = "min"; 57 public static final String MAX = "max"; 58 public static final String LABELS = "labels"; 59 public static final String LABEL_MEANS = "labelMeans"; 60 public static final String LABEL_SUMSQS = "labelSumSqs"; 61 public static final String LABEL_MINS = "labelMins"; 62 public static final String LABEL_MAXES = "labelMaxes"; 63 public static final String LABEL_COUNTS = "labelCounts"; 64 public static final String COUNT = "count"; 65 public static final String BRANCH = "branch"; 66 public static final String BUILD_FLAVOR = "buildFlavor"; 67 public static final String SERIES = "series"; 68 69 @Ignore 70 private Key key; 71 72 /** ID field */ 73 @Id private String name; 74 75 /** branch field */ 76 @Index private String branch; 77 78 /** build field */ 79 @Index private String buildFlavor; 80 81 /** total count */ 82 @Index private int count; 83 84 /** For each label count field */ 85 @Index private List<String> labelCounts; 86 87 /** Maximum value for each label */ 88 private List<Integer> labelMaxes; 89 90 /** Mean value for each label */ 91 private List<Integer> labelMeans; 92 93 /** Minimum value for each label */ 94 private List<Integer> labelMins; 95 96 /** Label name for each label point */ 97 private List<String> labels; 98 99 /** Summation for sequence for each label */ 100 private List<Integer> labelSumSqs; 101 102 /** Maximum value for total */ 103 private Long max; 104 105 /** Mean value for total */ 106 private Long mean; 107 108 /** Minimum value for total */ 109 private Long min; 110 111 /** The list of series */ 112 private String series; 113 114 /** The start time field of the test */ 115 private Long startTime; 116 117 /** The summation of sequences */ 118 private Long sumSq; 119 120 @Ignore private StatSummary globalStats; 121 122 @Ignore private Map<String, StatSummary> labelStats; 123 124 /* 125 public final StatSummary globalStats; 126 public final List<String> labels; 127 public final Map<String, StatSummary> labelStats; 128 public final String branch; 129 public final String buildFlavor; 130 public final String series; 131 public final long startTime; 132 */ 133 134 /** 135 * Create a ProfilingPointSummaryEntity object. 136 * 137 * @param parentKey The Key object for the parent TestRunEntity in the database. 138 * @param globalStats The StatSummary object recording global statistics about the profiling 139 * point. 140 * @param labels The list of data labels. 141 * @param labelStats The map from data label to StatSummary object for the label. 142 * @param branch The branch. 143 * @param buildFlavor The device build flavor. 144 * @param series The string describing the profiling point series (e.g. binder or passthrough). 145 * @param startTime The timestamp indicating the beginning of the summary. 146 */ ProfilingPointSummaryEntity( Key parentKey, StatSummary globalStats, List<String> labels, Map<String, StatSummary> labelStats, String branch, String buildFlavor, String series, long startTime)147 public ProfilingPointSummaryEntity( 148 Key parentKey, 149 StatSummary globalStats, 150 List<String> labels, 151 Map<String, StatSummary> labelStats, 152 String branch, 153 String buildFlavor, 154 String series, 155 long startTime) { 156 this.globalStats = globalStats; 157 this.labels = labels; 158 this.labelStats = labelStats; 159 this.buildFlavor = buildFlavor == null ? ALL : buildFlavor; 160 this.branch = branch == null ? ALL : branch; 161 this.series = series == null ? "" : series; 162 this.startTime = startTime; 163 this.key = createKey(parentKey, this.branch, this.buildFlavor, this.series, this.startTime); 164 } 165 166 /** 167 * Create a new ProfilingPointSummaryEntity object. 168 * 169 * @param parentKey The Key object for the parent TestRunEntity in the database. 170 * @param branch The branch. 171 * @param buildFlavor The buildFlavor name. 172 * @param series The string describing the profiling point series (e.g. binder or passthrough). 173 * @param startTime The timestamp indicating the beginning of the summary. 174 */ ProfilingPointSummaryEntity( Key parentKey, String branch, String buildFlavor, String series, long startTime)175 public ProfilingPointSummaryEntity( 176 Key parentKey, String branch, String buildFlavor, String series, long startTime) { 177 this( 178 parentKey, 179 new StatSummary(null, VtsProfilingRegressionMode.UNKNOWN_REGRESSION_MODE), 180 new ArrayList<>(), 181 new HashMap<>(), 182 branch, 183 buildFlavor, 184 series, 185 startTime); 186 } 187 188 /** 189 * Create a key for a ProfilingPointSummaryEntity. 190 * 191 * @param parentKey The Key object for the parent TestRunEntity in the database. 192 * @param branch The branch. 193 * @param buildFlavor The device build flavor. 194 * @param series The string describing the profiling point series (e.g. binder or passthrough). 195 * @param startTime The timestamp indicating the beginning of the summary. 196 * @return a Key object for the ProfilingPointSummaryEntity in the database. 197 */ createKey( Key parentKey, String branch, String buildFlavor, String series, long startTime)198 public static Key createKey( 199 Key parentKey, String branch, String buildFlavor, String series, long startTime) { 200 StringBuilder sb = new StringBuilder(); 201 sb.append(branch); 202 sb.append(DELIMITER); 203 sb.append(buildFlavor); 204 sb.append(DELIMITER); 205 sb.append(series); 206 sb.append(DELIMITER); 207 sb.append(startTime); 208 return KeyFactory.createKey(parentKey, KIND, sb.toString()); 209 } 210 211 /** 212 * Updates the profiling summary with the data from a new profiling report. 213 * 214 * @param profilingRun The profiling point run entity object containing profiling data. 215 */ update(ProfilingPointRunEntity profilingRun)216 public void update(ProfilingPointRunEntity profilingRun) { 217 if (profilingRun.getLabels() != null 218 && profilingRun.getLabels().size() == profilingRun.getValues().size()) { 219 for (int i = 0; i < profilingRun.getLabels().size(); i++) { 220 String label = profilingRun.getLabels().get(i); 221 if (!this.labelStats.containsKey(label)) { 222 VtsProfilingRegressionMode vtsProfilingRegressionMode = 223 profilingRun.getVtsProfilingRegressionMode( 224 profilingRun.getRegressionMode()); 225 StatSummary summary = new StatSummary(label, vtsProfilingRegressionMode); 226 this.labelStats.put(label, summary); 227 } 228 StatSummary summary = this.labelStats.get(label); 229 summary.updateStats(profilingRun.getValues().get(i)); 230 } 231 this.labels.clear(); 232 this.labels.addAll(profilingRun.getLabels()); 233 } 234 for (long value : profilingRun.getValues()) { 235 this.globalStats.updateStats(value); 236 } 237 } 238 239 /** Saving function for the instance of this class */ 240 @Override save()241 public com.googlecode.objectify.Key<ProfilingPointSummaryEntity> save() { 242 return ofy().save().entity(this).now(); 243 } 244 toEntity()245 public Entity toEntity() { 246 Entity profilingSummary; 247 profilingSummary = new Entity(this.key); 248 profilingSummary.setUnindexedProperty(MEAN, this.globalStats.getMean()); 249 profilingSummary.setUnindexedProperty(SUMSQ, this.globalStats.getSumSq()); 250 profilingSummary.setUnindexedProperty(MIN, this.globalStats.getMin()); 251 profilingSummary.setUnindexedProperty(MAX, this.globalStats.getMax()); 252 profilingSummary.setUnindexedProperty(COUNT, this.globalStats.getCount()); 253 profilingSummary.setIndexedProperty(START_TIME, this.startTime); 254 profilingSummary.setIndexedProperty(BRANCH, this.branch); 255 profilingSummary.setIndexedProperty(BUILD_FLAVOR, this.buildFlavor); 256 profilingSummary.setIndexedProperty(SERIES, this.series); 257 if (this.labels.size() != 0) { 258 List<Double> labelMeans = new ArrayList<>(); 259 List<Double> labelSumsqs = new ArrayList<>(); 260 List<Double> labelMins = new ArrayList<>(); 261 List<Double> labelMaxes = new ArrayList<>(); 262 List<Long> labelCounts = new ArrayList<>(); 263 for (String label : this.labels) { 264 if (!this.labelStats.containsKey(label)) continue; 265 StatSummary labelStat = this.labelStats.get(label); 266 labelMeans.add(labelStat.getMean()); 267 labelSumsqs.add(labelStat.getSumSq()); 268 labelMins.add(labelStat.getMin()); 269 labelMaxes.add(labelStat.getMax()); 270 labelCounts.add(new Long(labelStat.getCount())); 271 } 272 profilingSummary.setUnindexedProperty(LABELS, this.labels); 273 profilingSummary.setUnindexedProperty(LABEL_MEANS, labelMeans); 274 profilingSummary.setUnindexedProperty(LABEL_SUMSQS, labelSumsqs); 275 profilingSummary.setUnindexedProperty(LABEL_MINS, labelMins); 276 profilingSummary.setUnindexedProperty(LABEL_MAXES, labelMaxes); 277 profilingSummary.setUnindexedProperty(LABEL_COUNTS, labelCounts); 278 } 279 280 return profilingSummary; 281 } 282 283 /** 284 * Convert an Entity object to a ProfilingPointSummaryEntity. 285 * 286 * @param e The entity to process. 287 * @return ProfilingPointSummaryEntity object with the properties from e, or null if 288 * incompatible. 289 */ 290 @SuppressWarnings("unchecked") fromEntity(Entity e)291 public static ProfilingPointSummaryEntity fromEntity(Entity e) { 292 if (!e.getKind().equals(KIND) 293 || !e.hasProperty(MEAN) 294 || !e.hasProperty(SUMSQ) 295 || !e.hasProperty(MIN) 296 || !e.hasProperty(MAX) 297 || !e.hasProperty(COUNT) 298 || !e.hasProperty(START_TIME) 299 || !e.hasProperty(BRANCH) 300 || !e.hasProperty(BUILD_FLAVOR) 301 || !e.hasProperty(SERIES)) { 302 logger.log( 303 Level.WARNING, "Missing profiling point attributes in entity: " + e.toString()); 304 return null; 305 } 306 try { 307 Key parentKey = e.getParent(); 308 double mean = (double) e.getProperty(MEAN); 309 double sumsq = (double) e.getProperty(SUMSQ); 310 double min = (double) e.getProperty(MIN); 311 double max = (double) e.getProperty(MAX); 312 int count = (int) (long) e.getProperty(COUNT); 313 StatSummary globalStats = 314 new StatSummary( 315 null, 316 min, 317 max, 318 mean, 319 sumsq, 320 count, 321 VtsProfilingRegressionMode.UNKNOWN_REGRESSION_MODE); 322 Map<String, StatSummary> labelStats = new HashMap<>(); 323 List<String> labels = new ArrayList<>(); 324 if (e.hasProperty(LABELS)) { 325 labels = (List<String>) e.getProperty(LABELS); 326 List<Double> labelMeans = (List<Double>) e.getProperty(LABEL_MEANS); 327 List<Double> labelSumsqs = (List<Double>) e.getProperty(LABEL_SUMSQS); 328 List<Double> labelMins = (List<Double>) e.getProperty(LABEL_MINS); 329 List<Double> labelMaxes = (List<Double>) e.getProperty(LABEL_MAXES); 330 List<Long> labelCounts = (List<Long>) e.getProperty(LABEL_COUNTS); 331 if (labels.size() != labelMeans.size() 332 || labels.size() != labelSumsqs.size() 333 || labels.size() != labelMins.size() 334 || labels.size() != labelMaxes.size() 335 || labels.size() != labelCounts.size()) { 336 logger.log(Level.WARNING, "Jagged label information for entity: " + e.getKey()); 337 return null; 338 } 339 for (int i = 0; i < labels.size(); ++i) { 340 StatSummary labelStat = 341 new StatSummary( 342 labels.get(i), 343 labelMins.get(i), 344 labelMaxes.get(i), 345 labelMeans.get(i), 346 labelSumsqs.get(i), 347 labelCounts.get(i).intValue(), 348 VtsProfilingRegressionMode.UNKNOWN_REGRESSION_MODE); 349 labelStats.put(labels.get(i), labelStat); 350 } 351 } 352 String branch = (String) e.getProperty(BRANCH); 353 String buildFlavor = (String) e.getProperty(BUILD_FLAVOR); 354 String series = (String) e.getProperty(SERIES); 355 long startTime = (long) e.getProperty(START_TIME); 356 return new ProfilingPointSummaryEntity( 357 parentKey, 358 globalStats, 359 labels, 360 labelStats, 361 branch, 362 buildFlavor, 363 series, 364 startTime); 365 } catch (ClassCastException exception) { 366 // Invalid cast 367 logger.log(Level.WARNING, "Error parsing profiling point summary entity.", exception); 368 } 369 return null; 370 } 371 } 372