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 android.mediapc.cts.common; 18 19 import com.android.compatibility.common.util.ReportLog; 20 import com.android.compatibility.common.util.ResultType; 21 import com.android.compatibility.common.util.ResultUnit; 22 23 import com.google.auto.value.AutoValue; 24 import com.google.common.collect.ImmutableMap; 25 26 import java.util.HashMap; 27 import java.util.Map; 28 import java.util.function.BiPredicate; 29 30 /** 31 * A specific measurement for a Performance Class requirement. 32 */ 33 @AutoValue 34 public abstract class RequiredMeasurement<T> { 35 private static final String TAG = RequiredMeasurement.class.getSimpleName(); 36 37 private T measuredValue; // Note this is not part of the equals calculations 38 private boolean measuredValueSet = false; 39 builder()40 public static <T> Builder<T> builder() { 41 return new AutoValue_RequiredMeasurement.Builder<T>(); 42 } 43 id()44 public abstract String id(); 45 46 /** 47 * Tests if the measured value satisfies the expected value(eg >=) 48 * measuredValue, expectedValue 49 */ predicate()50 public abstract BiPredicate<T, T> predicate(); 51 52 /** 53 * Maps MPC level to the expected value. 54 */ expectedValues()55 public abstract ImmutableMap<Integer, T> expectedValues(); 56 setMeasuredValue(T measuredValue)57 public void setMeasuredValue(T measuredValue) { 58 this.measuredValueSet = true; 59 this.measuredValue = measuredValue; 60 } 61 getMeasuredValue()62 T getMeasuredValue() { 63 if (!measuredValueSet) { 64 throw new IllegalStateException( 65 "tried to get measured value before it was set for measurement " + id()); 66 } 67 return measuredValue; 68 } 69 isMeasuredValueSet()70 boolean isMeasuredValueSet() { 71 return measuredValueSet; 72 } 73 74 @AutoValue.Builder 75 public static abstract class Builder<T> { 76 setId(String id)77 public abstract Builder<T> setId(String id); 78 setPredicate(BiPredicate<T, T> predicate)79 public abstract Builder<T> setPredicate(BiPredicate<T, T> predicate); 80 expectedValuesBuilder()81 public abstract ImmutableMap.Builder<Integer, T> expectedValuesBuilder(); 82 addRequiredValue(Integer performanceClass, T expectedValue)83 public Builder<T> addRequiredValue(Integer performanceClass, T expectedValue) { 84 this.expectedValuesBuilder().put(performanceClass, expectedValue); 85 return this; 86 } 87 build()88 public abstract RequiredMeasurement<T> build(); 89 } 90 91 /** Is this requirement measurement valid for the given performance class */ appliesToPerformanceClass(int mediaPerformanceClass)92 public final boolean appliesToPerformanceClass(int mediaPerformanceClass) { 93 return expectedValues().containsKey(mediaPerformanceClass); 94 } 95 meetsPerformanceClass(int mediaPerformanceClass)96 public final RequirementConstants.Result meetsPerformanceClass(int mediaPerformanceClass) 97 throws IllegalStateException { 98 99 if (expectedValues().isEmpty()) { 100 return RequirementConstants.Result.NA; 101 } else if (!this.measuredValueSet) { 102 throw new IllegalStateException("measured value not set for required measurement " 103 + this.id()); 104 } 105 106 if (!this.expectedValues().containsKey(mediaPerformanceClass)) { 107 return RequirementConstants.Result.NA; 108 } else if (this.measuredValue == null || !this.predicate().test(this.measuredValue, 109 this.expectedValues().get(mediaPerformanceClass))) { 110 return RequirementConstants.Result.UNMET; 111 } else { 112 return RequirementConstants.Result.MET; 113 } 114 } 115 116 /** 117 * @return map PerfomenaceClass to result if that performance class has been met 118 */ getPerformanceClass()119 public Map<Integer, RequirementConstants.Result> getPerformanceClass() { 120 Map<Integer, RequirementConstants.Result> perfClassResults = new HashMap<>(); 121 for (Integer pc: this.expectedValues().keySet()) { 122 perfClassResults.put(pc, this.meetsPerformanceClass(pc)); 123 } 124 return perfClassResults; 125 } 126 127 @Override toString()128 public final String toString() { 129 return "Required Measurement with:" 130 + "\n\tId: " + this.id() 131 + "\n\tPredicate: " + this.predicate() 132 + "\n\tMeasured Value: " + this.measuredValue 133 + "\n\tExpected Values: " + this.expectedValues(); 134 } 135 writeValue(ReportLog log)136 public void writeValue(ReportLog log) throws IllegalStateException { 137 138 if (expectedValues().isEmpty()) { 139 // Some requirements include extra measurements when testing at a higher performance 140 // class. For these measurements, when testing at lower performance classes, the 141 // generated code may produce a correspoding RequiredMeasurement with an empty expected 142 // value map. If so, the measurement should just be ignored. 143 return; 144 } else if (!this.measuredValueSet) { 145 throw new IllegalStateException("measured value not set for required measurement:\n" 146 + this); 147 } 148 149 if (this.measuredValue == null) { 150 log.addValue(this.id(), "<nullptr>", ResultType.NEUTRAL, ResultUnit.NONE); 151 } else if (this.measuredValue instanceof Integer) { 152 log.addValue(this.id(), (int)this.measuredValue, ResultType.NEUTRAL, ResultUnit.NONE); 153 } else if (this.measuredValue instanceof Long) { 154 log.addValue(this.id(), (long)this.measuredValue, ResultType.NEUTRAL, ResultUnit.NONE); 155 } else if (this.measuredValue instanceof Float) { 156 log.addValue(this.id(), (float)this.measuredValue, ResultType.NEUTRAL, ResultUnit.NONE); 157 } else if (this.measuredValue instanceof Double) { 158 log.addValue(this.id(), (double)this.measuredValue, ResultType.NEUTRAL, 159 ResultUnit.NONE); 160 } else if (this.measuredValue instanceof Boolean) { 161 log.addValue(this.id(), (boolean)this.measuredValue, ResultType.NEUTRAL, 162 ResultUnit.NONE); 163 } else if (this.measuredValue instanceof String) { 164 log.addValue(this.id(), (String)this.measuredValue, ResultType.NEUTRAL, 165 ResultUnit.NONE); 166 } else { 167 // reporting all other types as Strings using toString() 168 log.addValue(this.id(), this.measuredValue.toString(), ResultType.NEUTRAL, 169 ResultUnit.NONE); 170 } 171 } 172 173 } 174