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