1 /* 2 * Copyright (C) 2012 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.cts.util; 18 19 import java.util.LinkedList; 20 import java.util.List; 21 22 import junit.framework.Assert; 23 24 25 /** 26 * Utility class to print performance measurement result back to host. 27 * For now, throws know exception with message. 28 * 29 * Format: 30 * Message = summary log SUMMARY_SEPARATOR [LOG_SEPARATOR log]* 31 * summary = message|target|unit|type|value, target can be " " if there is no target set. 32 * log for array = classMethodName:line_number|message|unit|type|space seSummaryparated values 33 */ 34 public class ReportLog { 35 private static final String LOG_SEPARATOR = "+++"; 36 private static final String SUMMARY_SEPARATOR = "++++"; 37 private static final String LOG_ELEM_SEPARATOR = "|"; 38 39 private List<String> mMessages = new LinkedList<String> (); 40 private String mSummary = null; 41 protected static int mDepth = 3; 42 43 /** 44 * print array of values to output log 45 * <p>Note: test identifier is inferred from call stack trace based on class and method name 46 */ printArray(String message, double[] values, ResultType type, ResultUnit unit)47 public void printArray(String message, double[] values, ResultType type, ResultUnit unit) { 48 doPrintArray(message, values, type, unit); 49 } 50 51 /** 52 * print array of values to output log 53 */ printArray(String testId, String message, double[] values, ResultType type, ResultUnit unit)54 public void printArray(String testId, String message, 55 double[] values, ResultType type, ResultUnit unit) { 56 doPrintArray(testId, message, values, type, unit); 57 } 58 59 /** 60 * Print a value to output log 61 * <p>Note: test identifier is inferred from call stack trace based on class and method name 62 */ printValue(String message, double value, ResultType type, ResultUnit unit)63 public void printValue(String message, double value, ResultType type, ResultUnit unit) { 64 double[] vals = { value }; 65 doPrintArray(message, vals, type, unit); 66 } 67 68 /** 69 * Print a value to output log 70 */ printValue(String testId, String message, double value, ResultType type, ResultUnit unit)71 public void printValue(String testId, String message, 72 double value, ResultType type, ResultUnit unit) { 73 double[] vals = { value }; 74 doPrintArray(testId, message, vals, type, unit); 75 } 76 doPrintArray(String message, double[] values, ResultType type, ResultUnit unit)77 private void doPrintArray(String message, double[] values, ResultType type, ResultUnit unit) { 78 doPrintArray(getClassMethodNames(mDepth + 1, true), message, values, type, unit); 79 } 80 doPrintArray(String testId, String message, double[] values, ResultType type, ResultUnit unit)81 private void doPrintArray(String testId, String message, 82 double[] values, ResultType type, ResultUnit unit) { 83 StringBuilder builder = new StringBuilder(); 84 // note mDepth + 1 as this function will be called by printVaue or printArray 85 // and we need caller of printValue / printArray 86 builder.append(testId); 87 builder.append(LOG_ELEM_SEPARATOR); 88 builder.append(message); 89 builder.append(LOG_ELEM_SEPARATOR); 90 builder.append(type.getXmlString()); 91 builder.append(LOG_ELEM_SEPARATOR); 92 builder.append(unit.getXmlString()); 93 builder.append(LOG_ELEM_SEPARATOR); 94 for (double v : values) { 95 builder.append(v); 96 builder.append(" "); 97 } 98 mMessages.add(builder.toString()); 99 printLog(builder.toString()); 100 } 101 102 /** 103 * record the result of benchmarking with performance target. 104 * Depending on the ResultType, the function can fail if the result 105 * does not meet the target. For example, for the type of HIGHER_BETTER, 106 * value of 1.0 with target of 2.0 will fail. 107 * 108 * @param message message to be printed in the final report 109 * @param target target performance for the benchmarking 110 * @param value measured value 111 * @param type 112 * @param unit 113 */ printSummaryWithTarget(String message, double target, double value, ResultType type, ResultUnit unit)114 public void printSummaryWithTarget(String message, double target, double value, 115 ResultType type, ResultUnit unit) { 116 mSummary = message + LOG_ELEM_SEPARATOR + target + LOG_ELEM_SEPARATOR + type.getXmlString() 117 + LOG_ELEM_SEPARATOR + unit.getXmlString() + LOG_ELEM_SEPARATOR + value; 118 boolean resultOk = true; 119 if (type == ResultType.HIGHER_BETTER) { 120 resultOk = value >= target; 121 } else if (type == ResultType.LOWER_BETTER) { 122 resultOk = value <= target; 123 } 124 if (!resultOk) { 125 Assert.fail("Measured result " + value + " does not meet perf target " + target + 126 " with type " + type.getXmlString()); 127 } 128 } 129 130 /** 131 * For standard report summary without target value. 132 * Note that this function will not fail as there is no target. 133 * @param message 134 * @param value 135 * @param type type of the value 136 * @param unit unit of the data 137 */ printSummary(String message, double value, ResultType type, ResultUnit unit)138 public void printSummary(String message, double value, ResultType type, ResultUnit unit) { 139 mSummary = message + LOG_ELEM_SEPARATOR + " " + LOG_ELEM_SEPARATOR + type.getXmlString() + 140 LOG_ELEM_SEPARATOR + unit.getXmlString() + LOG_ELEM_SEPARATOR + value; 141 } 142 143 /** 144 * @return a string representation of this report. 145 */ generateReport()146 protected String generateReport() { 147 if ((mSummary == null) && mMessages.isEmpty()) { 148 // just return empty string 149 return ""; 150 } 151 StringBuilder builder = new StringBuilder(); 152 builder.append(mSummary); 153 builder.append(SUMMARY_SEPARATOR); 154 for (String entry : mMessages) { 155 builder.append(entry); 156 builder.append(LOG_SEPARATOR); 157 } 158 // delete the last separator 159 if (builder.length() >= LOG_SEPARATOR.length()) { 160 builder.delete(builder.length() - LOG_SEPARATOR.length(), builder.length()); 161 } 162 mSummary = null; 163 mMessages.clear(); 164 return builder.toString(); 165 } 166 167 /** 168 * calculate rate per sec for given change happened during given timeInMSec. 169 * timeInSec with 0 value will be changed to small value to prevent divide by zero. 170 * @param change total change of quality for the given duration timeInMSec. 171 * @param timeInMSec 172 * @return 173 */ calcRatePerSec(double change, double timeInMSec)174 public static double calcRatePerSec(double change, double timeInMSec) { 175 if (timeInMSec == 0) { 176 return change * 1000.0 / 0.001; // do not allow zero 177 } else { 178 return change * 1000.0 / timeInMSec; 179 } 180 } 181 182 /** 183 * array version of calcRatePerSecArray 184 */ calcRatePerSecArray(double change, double[] timeInMSec)185 public static double[] calcRatePerSecArray(double change, double[] timeInMSec) { 186 double[] result = new double[timeInMSec.length]; 187 change *= 1000.0; 188 for (int i = 0; i < timeInMSec.length; i++) { 189 if (timeInMSec[i] == 0) { 190 result[i] = change / 0.001; 191 } else { 192 result[i] = change / timeInMSec[i]; 193 } 194 } 195 return result; 196 } 197 198 /** 199 * copy array from src to dst with given offset in dst. 200 * dst should be big enough to hold src 201 */ copyArray(double[] src, double[] dst, int dstOffset)202 public static void copyArray(double[] src, double[] dst, int dstOffset) { 203 for (int i = 0; i < src.length; i++) { 204 dst[dstOffset + i] = src[i]; 205 } 206 } 207 208 /** 209 * get classname#methodname from call stack of the current thread 210 */ getClassMethodNames()211 public static String getClassMethodNames() { 212 return getClassMethodNames(mDepth, false); 213 } 214 getClassMethodNames(int depth, boolean addLineNumber)215 private static String getClassMethodNames(int depth, boolean addLineNumber) { 216 StackTraceElement[] elements = Thread.currentThread().getStackTrace(); 217 String names = elements[depth].getClassName() + "#" + elements[depth].getMethodName() + 218 (addLineNumber ? ":" + elements[depth].getLineNumber() : ""); 219 return names; 220 } 221 222 /** 223 * to be overridden by child to print message to be passed 224 */ printLog(String msg)225 protected void printLog(String msg) { 226 227 } 228 } 229