1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package gc.g1.plab.lib; 24 25 import java.util.Arrays; 26 import java.util.HashMap; 27 import java.util.List; 28 import java.util.Map; 29 import java.util.Optional; 30 import java.util.Scanner; 31 import java.util.regex.Matcher; 32 import java.util.regex.Pattern; 33 import java.util.stream.Collectors; 34 35 /** 36 * LogParser class parses VM output to get PLAB and ConsumptionStats values. 37 * 38 * Typical GC log with PLAB statistics (options - -Xlog:gc=debug,gc+plab=debug) looks like: 39 * 40 * [0.330s][debug][gc,plab ] GC(0) Young PLAB allocation: allocated: 1825632B, wasted: 29424B, unused: 2320B, used: 1793888B, undo waste: 0B, 41 * [0.330s][debug][gc,plab ] GC(0) Young other allocation: region end waste: 0B, regions filled: 2, direct allocated: 271520B, failure used: 0B, failure wasted: 0B 42 * [0.330s][debug][gc,plab ] GC(0) Young sizing: calculated: 358776B, actual: 358776B 43 * [0.330s][debug][gc,plab ] GC(0) Old PLAB allocation: allocated: 427248B, wasted: 592B, unused: 368584B, used: 58072B, undo waste: 0B, 44 * [0.330s][debug][gc,plab ] GC(0) Old other allocation: region end waste: 0B, regions filled: 1, direct allocated: 41704B, failure used: 0B, failure wasted: 0B 45 * [0.330s][debug][gc,plab ] GC(0) Old sizing: calculated: 11608B, actual: 11608B 46 */ 47 final public class LogParser { 48 49 /** 50 * Type of parsed log element. 51 */ 52 public static enum ReportType { 53 SURVIVOR_STATS, 54 OLD_STATS 55 } 56 57 private final String log; 58 59 // Contains Map of PLAB statistics for given log. 60 private final PlabReport report; 61 62 // GC ID 63 private static final Pattern GC_ID_PATTERN = Pattern.compile("\\[gc,plab\\s*\\] GC\\((\\d+)\\)"); 64 // Pattern for extraction pair <name>: <numeric value> 65 private static final Pattern PAIRS_PATTERN = Pattern.compile("\\w* \\w+:\\s+\\d+"); 66 67 /** 68 * Construct LogParser object, parse log file with PLAB statistics and store it into report. 69 * 70 * @param log - VM Output 71 */ 72 public LogParser(String log) { 73 if (log == null) { 74 throw new IllegalArgumentException("Parameter log should not be null."); 75 } 76 this.log = log; 77 report = parseLines(); 78 } 79 80 /** 81 * @return log which was processed 82 */ 83 public String getLog() { 84 return log; 85 } 86 87 /** 88 * Returns the GC log entries for Survivor and Old stats. 89 * The entries are represented as a map of gcID to the StatMap. 90 * 91 * @return The log entries for the Survivor and Old stats. 92 */ 93 public PlabReport getEntries() { 94 return report; 95 } 96 97 private PlabReport parseLines() throws NumberFormatException { 98 try (Scanner lineScanner = new Scanner(log)) { 99 PlabReport plabReport = new PlabReport(); 100 Optional<Long> gc_id; 101 while (lineScanner.hasNextLine()) { 102 String line = lineScanner.nextLine(); 103 gc_id = getGcId(line, GC_ID_PATTERN); 104 if (gc_id.isPresent()) { 105 Matcher matcher = PAIRS_PATTERN.matcher(line); 106 if (matcher.find()) { 107 if (!plabReport.containsKey(gc_id.get())) { 108 plabReport.put(gc_id.get(), new PlabGCStatistics()); 109 } 110 ReportType reportType = line.contains("Young") ? ReportType.SURVIVOR_STATS : ReportType.OLD_STATS; 111 112 PlabGCStatistics gcStat = plabReport.get(gc_id.get()); 113 if (!gcStat.containsKey(reportType)) { 114 gcStat.put(reportType, new PlabInfo()); 115 } 116 117 // Extract all pairs from log. 118 PlabInfo plabInfo = gcStat.get(reportType); 119 do { 120 String pair = matcher.group(); 121 String[] nameValue = pair.replaceAll(": ", ":").split(":"); 122 plabInfo.put(nameValue[0].trim(), Long.parseLong(nameValue[1])); 123 } while (matcher.find()); 124 } 125 } 126 } 127 return plabReport; 128 } 129 } 130 131 private static Optional<Long> getGcId(String line, Pattern pattern) { 132 Matcher number = pattern.matcher(line); 133 if (number.find()) { 134 return Optional.of(Long.parseLong(number.group(1))); 135 } 136 return Optional.empty(); 137 } 138 139 /** 140 * Extracts GC ID from log. 141 * 142 * @param line - one line of log. 143 * @return GC ID 144 */ 145 public static Long getGcIdFromLine(String line, Pattern pattern) { 146 Optional<Long> gcId = getGcId(line, pattern); 147 if (!gcId.isPresent()) { 148 System.out.println(line); 149 throw new RuntimeException("Cannot find GC ID in log."); 150 } 151 return gcId.get(); 152 } 153 154 /** 155 * Returns Map<Long,PlabStatistics> which contains specified statistics for specified gc ids. 156 * @param specifiedGcId gc id to get 157 * @param type PLAB type 158 * @param fieldsName name of fields in PlabStatistics 159 * @return 160 **/ 161 public Map<Long, PlabInfo> getSpecifiedStats(List<Long> specifiedGcId, LogParser.ReportType type, List<String> fieldsName) { 162 return getSpecifiedStats(specifiedGcId, type, fieldsName, true); 163 } 164 165 /** 166 * Returns PlabStatistics for specified GC ID. 167 * @param specifiedGcId 168 * @param type type of statistics 169 * @param fieldsName name of fields in PlabStatistics 170 * @return 171 **/ 172 public PlabInfo getSpecifiedStats(long specifiedGcId, LogParser.ReportType type, List<String> fieldsName) { 173 PlabInfo info = getSpecifiedStats(Arrays.asList(specifiedGcId), type, fieldsName, true).get(specifiedGcId); 174 if (info == null) { 175 System.out.println(log); 176 throw new RuntimeException("Cannot find PLAB statistics in log ( GC_ID=" + specifiedGcId + " type=" + type + " )"); 177 } 178 return info; 179 } 180 181 /** 182 * Returns Map<Long,PlabStatistics> which contains specified statistics. Filters out specified gc ids. 183 * @param specifiedGcIdForExclude 184 * @param type 185 * @param fieldsName 186 * @return 187 **/ 188 public Map<Long, PlabInfo> getExcludedSpecifiedStats(List<Long> specifiedGcIdForExclude, LogParser.ReportType type, List<String> fieldsName) { 189 return getSpecifiedStats(specifiedGcIdForExclude, type, fieldsName, false); 190 } 191 192 private Map<Long, PlabInfo> getSpecifiedStats(List<Long> gcIds, LogParser.ReportType type, List<String> fieldNames, boolean extractId) { 193 return new HashMap<>( 194 getEntries().entryStream() 195 .filter(gcLogItem -> extractId == gcIds.contains(gcLogItem.getKey())) 196 .collect(Collectors.toMap(gcLogItem -> gcLogItem.getKey(), 197 gcLogItem -> gcLogItem.getValue().get(type).filter(fieldNames) 198 ) 199 ) 200 ); 201 } 202 }