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 com.android.tradefed.util;
17 
18 import com.android.tradefed.log.LogUtil.CLog;
19 
20 import java.io.BufferedReader;
21 import java.io.File;
22 import java.io.FileReader;
23 import java.io.IOException;
24 import java.util.HashMap;
25 import java.util.Map;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28 
29 /** Helper class to parse info from an Allocation Sites section of hprof reports. */
30 public class HprofAllocSiteParser {
31 
32     private static final String ALLOC_SITES_START_PATTERN = "SITES BEGIN";
33     private static final String ALLOC_SITES_END_PATTERN = "SITES END";
34     private boolean mHasAllocSiteStarted = false;
35     // format:
36     //            percent          live          alloc'ed  stack class
37     //   rank   self  accum     bytes objs     bytes  objs trace name
38     //      1 12.24% 12.24%  12441616    1  12441616     1 586322 byte[]
39     private static final Pattern RANK_PATTERN =
40             Pattern.compile(
41                     "(\\s+)([0-9]*)(\\s+)([0-9]*\\.?[0-9]+%)(\\s+)([0-9]*\\.?[0-9]+%)(\\s+)"
42                             + "([0-9]+)(\\s+)([0-9]+)(\\s+)([0-9]+)(\\s+)([0-9]+)(\\s+)([0-9]+)"
43                             + "(\\s+)(.*)");
44 
45     /**
46      * Parse a text hprof report.
47      *
48      * @param hprofReport file containing the hprof report.
49      * @return a Map containing the results
50      */
parse(File hprofReport)51     public Map<String, String> parse(File hprofReport) throws IOException {
52         Map<String, String> results = new HashMap<>();
53         if (hprofReport == null || !hprofReport.exists()) {
54             return results;
55         }
56         internalParse(hprofReport, results);
57         return results;
58     }
59 
60     /**
61      * Actual parsing line by line of the report to extract information.
62      *
63      * @param report the {@link File} containing the hprof report.
64      * @param currentRes the {@link Map} where the allocation sites will be stored.
65      */
internalParse(File report, Map<String, String> currentRes)66     private void internalParse(File report, Map<String, String> currentRes) throws IOException {
67         try (BufferedReader br = new BufferedReader(new FileReader(report))) {
68             for (String line; (line = br.readLine()) != null; ) {
69                 handleAllocSites(line, currentRes);
70             }
71         }
72     }
73 
74     /** Handles the allocation sites in the hprof report. */
handleAllocSites(String line, Map<String, String> currentRes)75     private void handleAllocSites(String line, Map<String, String> currentRes) {
76         if (line.startsWith(ALLOC_SITES_START_PATTERN)) {
77             mHasAllocSiteStarted = true;
78         } else if (line.startsWith(ALLOC_SITES_END_PATTERN)) {
79             mHasAllocSiteStarted = false;
80         } else if (mHasAllocSiteStarted) {
81             Matcher m = RANK_PATTERN.matcher(line);
82             if (m.find()) {
83                 CLog.d(
84                         "Rank %s-%s-%s-%s-%s-%s-%s-%s-%s",
85                         m.group(2),
86                         m.group(4),
87                         m.group(6),
88                         m.group(8),
89                         m.group(10),
90                         m.group(12),
91                         m.group(14),
92                         m.group(16),
93                         m.group(18));
94                 currentRes.put(String.format("Rank%s", m.group(2)), m.group(12));
95             }
96         }
97     }
98 }
99