1 /* 2 * Copyright (C) 2016 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 com.android.tradefed.util; 17 18 import com.android.tradefed.log.LogUtil.CLog; 19 20 import java.util.ArrayList; 21 import java.util.List; 22 import java.util.regex.Matcher; 23 import java.util.regex.Pattern; 24 25 /** 26 * A utility class to parse simpleperf result. 27 * <p/> 28 * Should be useful when implementing test result receiver 29 * 30 * @see <a href="https://android.googlesource.com/platform/system/extras/+/master/simpleperf/"> 31 * Introduction of simpleperf</a> 32 */ 33 public final class SimplePerfStatResultParser { 34 35 // static immutable field 36 private static final String SIMPLEPERF_METRIC_HEAD = "Performance counter statistics:"; 37 private static final Pattern TOTAL_TIME_SENTENCE_PATTERN = Pattern 38 .compile("Total test time: (\\d+\\.\\d+) seconds."); 39 private static final Pattern TOTAL_METRIC_SENTENCE_PATTERN = Pattern 40 .compile("\\s*([0-9,\\.]*?)(\\(ms\\))?\\s+([0-9a-z_:-]*?)\\s+#\\s+([^#]*)"); 41 42 // Private constructor to prevent other program to have an instance SimplePerfStatResultParser()43 private SimplePerfStatResultParser() { 44 // Do nothing 45 } 46 47 /** 48 * Utility method to parse single line of simpleperf results 49 * 50 * @param line single line of simpleperf results 51 * @return List of String contains information. If length is 0, no output parsed. If length is 52 * 1, it is total time. If length is 3, it contains metric(pos 0), benchmark(pos 1) and 53 * comment(pos 2) 54 */ parseSingleLine(String line)55 public static List<String> parseSingleLine(String line) { 56 List<String> result = new ArrayList<>(); 57 58 if (line == null) { 59 return result; 60 } 61 62 // Skip header line and empty line 63 if (line.contains(SIMPLEPERF_METRIC_HEAD) || line.equals("")) { 64 return result; 65 } 66 67 // Last line contains total test time 68 Matcher matcher; 69 matcher = TOTAL_TIME_SENTENCE_PATTERN.matcher(line); 70 if (matcher.matches()) { 71 result.add(matcher.group(1)); 72 return result; 73 } 74 75 // Metric -- benchmark -- comment line 76 matcher = TOTAL_METRIC_SENTENCE_PATTERN.matcher(line); 77 if (matcher.matches()) { 78 result.add(matcher.group(1)); 79 result.add(matcher.group(3)); 80 result.add(matcher.group(4)); 81 } 82 return result; 83 } 84 85 /** 86 * Utility method to parse multiple lines of simpleperf output 87 * 88 * @param output multiple lines of string 89 * @return {@link SimplePerfResult} object to hold simpleperf result information 90 */ parseRawOutput(String output)91 public static SimplePerfResult parseRawOutput(String output) { 92 SimplePerfResult result = new SimplePerfResult(); 93 if (output == null) { 94 return null; 95 } 96 int idx = output.indexOf(SIMPLEPERF_METRIC_HEAD); 97 if (idx == -1) { 98 CLog.e("Cannot find simpleperf metric head message"); 99 return null; 100 } else { 101 result.setCommandRawOutput(output.substring(0, idx)); 102 String simpleperfOutput = output.substring(idx + SIMPLEPERF_METRIC_HEAD.length() + 1); 103 result.setSimplePerfRawOutput(simpleperfOutput); 104 String[] lines = simpleperfOutput.split("\n"); 105 for (String line : lines) { 106 List<String> singleLineResults = parseSingleLine(line); 107 if (singleLineResults.size() == 1) { 108 result.setTotalTestTime(singleLineResults.get(0)); 109 } else if (singleLineResults.size() == 3) { 110 result.addBenchmarkComment(singleLineResults.get(1), singleLineResults.get(2)); 111 result.addBenchmarkMetrics(singleLineResults.get(1), singleLineResults.get(0)); 112 } else { 113 CLog.i("Line skipped. " + line); 114 } 115 } 116 } 117 return result; 118 } 119 } 120