1 /* 2 * Copyright (C) 2017 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 android.multiuser; 17 18 import static android.multiuser.BenchmarkResults.DECLARED_VALUE_IF_ERROR_MS; 19 20 import android.app.Activity; 21 import android.app.Instrumentation; 22 import android.os.Bundle; 23 import android.util.Log; 24 25 import androidx.test.InstrumentationRegistry; 26 27 import org.junit.rules.TestRule; 28 import org.junit.runner.Description; 29 import org.junit.runners.model.Statement; 30 31 import java.util.ArrayList; 32 33 public class BenchmarkResultsReporter implements TestRule { 34 private final BenchmarkRunner mRunner; 35 BenchmarkResultsReporter(BenchmarkRunner benchmarkRunner)36 public BenchmarkResultsReporter(BenchmarkRunner benchmarkRunner) { 37 mRunner = benchmarkRunner; 38 } 39 40 @Override apply(final Statement base, final Description description)41 public Statement apply(final Statement base, final Description description) { 42 return new Statement() { 43 @Override 44 public void evaluate() throws Throwable { 45 final String tag = description.getTestClass().getSimpleName(); 46 final String methodName = description.getMethodName(); 47 Throwable error = null; 48 49 try { 50 base.evaluate(); 51 error = mRunner.getErrorOrNull(); 52 } catch (Exception e) { 53 error = e; 54 } 55 56 if (error != null) { 57 Log.e(tag, "Test " + methodName + " failed.", error); 58 Log.d(tag, "Logcat displays the results ignoring the fact that it failed;\n" 59 + "however, fake results of " + DECLARED_VALUE_IF_ERROR_MS + "ms " 60 + "will be reported to the instrumentation caller to signify failure."); 61 } 62 63 final String summary = getSummaryString(methodName, mRunner.getStatsToLog()); 64 logSummary(tag, summary, mRunner.getAllDurations()); 65 66 Bundle stats; 67 if (error == null) { 68 stats = mRunner.getStatsToReport(); 69 stats.putString(Instrumentation.REPORT_KEY_STREAMRESULT, summary); 70 } else { 71 stats = BenchmarkResults.getFailedStatsToReport(); 72 final String failSummary = getSummaryString(methodName, 73 BenchmarkResults.getFailedStatsToLog()); 74 stats.putString(Instrumentation.REPORT_KEY_STREAMRESULT, failSummary); 75 } 76 InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, stats); 77 78 if (error != null) { 79 throw error; 80 } 81 } 82 }; 83 } 84 85 /** 86 * Prints, for example: 87 * UserLifecycleTests: (summary string) 88 * UserLifecycleTests: 1->101 89 * UserLifecycleTests: 2->102 90 * UserLifecycleTests: 3->103 91 * UserLifecycleTests: 4->102 92 */ 93 private void logSummary(String tag, String summary, ArrayList<Long> durations) { 94 final StringBuilder sb = new StringBuilder(summary); 95 final int size = durations.size(); 96 for (int i = 0; i < size; ++i) { 97 sb.append("\n").append(i+1).append("->").append(durations.get(i)); 98 } 99 Log.d(tag, sb.toString()); 100 } 101 102 /** 103 * For example: 104 * testName 105 * Sigma (ms): 1 106 * Mean (ms): 2 107 * Median (ms): 3 108 */ 109 private String getSummaryString(String testName, Bundle stats) { 110 final StringBuilder sb = new StringBuilder(); 111 sb.append("\n\n").append(getKey(testName)); 112 for (String key : stats.keySet()) { 113 sb.append("\n").append(key).append(": ").append(stats.get(key)); 114 } 115 return sb.toString(); 116 } 117 118 private String getKey(String testName) { 119 return testName.replaceAll("Perf$", ""); 120 } 121 } 122