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 */ printArray(String message, double[] values, ResultType type, ResultUnit unit)46 public void printArray(String message, double[] values, ResultType type, ResultUnit unit) { 47 doPrintArray(message, values, type, unit); 48 } 49 50 /** 51 * Print a value to output log 52 */ printValue(String message, double value, ResultType type, ResultUnit unit)53 public void printValue(String message, double value, ResultType type, ResultUnit unit) { 54 double[] vals = { value }; 55 doPrintArray(message, vals, type, unit); 56 } 57 doPrintArray(String message, double[] values, ResultType type, ResultUnit unit)58 private void doPrintArray(String message, double[] values, ResultType type, ResultUnit unit) { 59 StringBuilder builder = new StringBuilder(); 60 // note mDepth + 1 as this function will be called by printVaue or printArray 61 // and we need caller of printValue / printArray 62 builder.append(getClassMethodNames(mDepth + 1, true) + LOG_ELEM_SEPARATOR + message + 63 LOG_ELEM_SEPARATOR + type.getXmlString() + LOG_ELEM_SEPARATOR + 64 unit.getXmlString() + LOG_ELEM_SEPARATOR); 65 for (double v : values) { 66 builder.append(v); 67 builder.append(" "); 68 } 69 mMessages.add(builder.toString()); 70 printLog(builder.toString()); 71 } 72 73 /** 74 * record the result of benchmarking with performance target. 75 * Depending on the ResultType, the function can fail if the result 76 * does not meet the target. For example, for the type of HIGHER_BETTER, 77 * value of 1.0 with target of 2.0 will fail. 78 * 79 * @param message message to be printed in the final report 80 * @param target target performance for the benchmarking 81 * @param value measured value 82 * @param type 83 * @param unit 84 */ printSummaryWithTarget(String message, double target, double value, ResultType type, ResultUnit unit)85 public void printSummaryWithTarget(String message, double target, double value, 86 ResultType type, ResultUnit unit) { 87 mSummary = message + LOG_ELEM_SEPARATOR + target + LOG_ELEM_SEPARATOR + type.getXmlString() 88 + LOG_ELEM_SEPARATOR + unit.getXmlString() + LOG_ELEM_SEPARATOR + value; 89 boolean resultOk = true; 90 if (type == ResultType.HIGHER_BETTER) { 91 resultOk = value >= target; 92 } else if (type == ResultType.LOWER_BETTER) { 93 resultOk = value <= target; 94 } 95 if (!resultOk) { 96 Assert.fail("Measured result " + value + " does not meet perf target " + target + 97 " with type " + type.getXmlString()); 98 } 99 } 100 101 /** 102 * For standard report summary without target value. 103 * Note that this function will not fail as there is no target. 104 * @param message 105 * @param value 106 * @param type type of the value 107 * @param unit unit of the data 108 */ printSummary(String message, double value, ResultType type, ResultUnit unit)109 public void printSummary(String message, double value, ResultType type, ResultUnit unit) { 110 mSummary = message + LOG_ELEM_SEPARATOR + " " + LOG_ELEM_SEPARATOR + type.getXmlString() + 111 LOG_ELEM_SEPARATOR + unit.getXmlString() + LOG_ELEM_SEPARATOR + value; 112 } 113 114 /** 115 * @return a string representation of this report. 116 */ generateReport()117 protected String generateReport() { 118 if ((mSummary == null) && mMessages.isEmpty()) { 119 // just return empty string 120 return ""; 121 } 122 StringBuilder builder = new StringBuilder(); 123 builder.append(mSummary); 124 builder.append(SUMMARY_SEPARATOR); 125 for (String entry : mMessages) { 126 builder.append(entry); 127 builder.append(LOG_SEPARATOR); 128 } 129 // delete the last separator 130 if (builder.length() >= LOG_SEPARATOR.length()) { 131 builder.delete(builder.length() - LOG_SEPARATOR.length(), builder.length()); 132 } 133 mSummary = null; 134 mMessages.clear(); 135 return builder.toString(); 136 } 137 138 /** 139 * calculate rate per sec for given change happened during given timeInMSec. 140 * timeInSec with 0 value will be changed to small value to prevent divide by zero. 141 * @param change total change of quality for the given duration timeInMSec. 142 * @param timeInMSec 143 * @return 144 */ calcRatePerSec(double change, double timeInMSec)145 public static double calcRatePerSec(double change, double timeInMSec) { 146 if (timeInMSec == 0) { 147 return change * 1000.0 / 0.001; // do not allow zero 148 } else { 149 return change * 1000.0 / timeInMSec; 150 } 151 } 152 153 /** 154 * array version of calcRatePerSecArray 155 */ calcRatePerSecArray(double change, double[] timeInMSec)156 public static double[] calcRatePerSecArray(double change, double[] timeInMSec) { 157 double[] result = new double[timeInMSec.length]; 158 change *= 1000.0; 159 for (int i = 0; i < timeInMSec.length; i++) { 160 if (timeInMSec[i] == 0) { 161 result[i] = change / 0.001; 162 } else { 163 result[i] = change / timeInMSec[i]; 164 } 165 } 166 return result; 167 } 168 169 /** 170 * copy array from src to dst with given offset in dst. 171 * dst should be big enough to hold src 172 */ copyArray(double[] src, double[] dst, int dstOffset)173 public static void copyArray(double[] src, double[] dst, int dstOffset) { 174 for (int i = 0; i < src.length; i++) { 175 dst[dstOffset + i] = src[i]; 176 } 177 } 178 179 /** 180 * get classname#methodname from call stack of the current thread 181 */ getClassMethodNames()182 public static String getClassMethodNames() { 183 return getClassMethodNames(mDepth, false); 184 } 185 getClassMethodNames(int depth, boolean addLineNumber)186 private static String getClassMethodNames(int depth, boolean addLineNumber) { 187 StackTraceElement[] elements = Thread.currentThread().getStackTrace(); 188 String names = elements[depth].getClassName() + "#" + elements[depth].getMethodName() + 189 (addLineNumber ? ":" + elements[depth].getLineNumber() : ""); 190 return names; 191 } 192 193 /** 194 * to be overridden by child to print message to be passed 195 */ printLog(String msg)196 protected void printLog(String msg) { 197 198 } 199 } 200