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 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 private static Optional<Long> getGcId(String line, Pattern pattern) { 131 Matcher number = pattern.matcher(line); 132 if (number.find()) { 133 return Optional.of(Long.parseLong(number.group(1))); 134 } 135 return Optional.empty(); 136 } 137 138 /** 139 * Extracts GC ID from log. 140 * 141 * @param line - one line of log. 142 * @return GC ID 143 */ 144 public static Long getGcIdFromLine(String line, Pattern pattern) { 145 Optional<Long> gcId = getGcId(line, pattern); 146 if (!gcId.isPresent()) { 147 System.out.println(line); 148 throw new RuntimeException("Cannot find GC ID in log."); 149 } 150 return gcId.get(); 151 } 152 153 /** 154 * Returns Map<Long,PlabStatistics> which contains specified statistics for specified gc ids. 155 * @param specifiedGcId gc id to get 156 * @param type PLAB type 157 * @param fieldsName name of fields in PlabStatistics 158 * @return 159 **/ 160 public Map<Long, PlabInfo> getSpecifiedStats(List<Long> specifiedGcId, LogParser.ReportType type, List<String> fieldsName) { 161 return getSpecifiedStats(specifiedGcId, type, fieldsName, true); 162 } 163 164 /** 165 * Returns PlabStatistics for specified GC ID. 166 * @param specifiedGcId 167 * @param type type of statistics 168 * @param fieldsName name of fields in PlabStatistics 169 * @return 170 **/ 171 public PlabInfo getSpecifiedStats(long specifiedGcId, LogParser.ReportType type, List<String> fieldsName) { 172 PlabInfo info = getSpecifiedStats(Arrays.asList(specifiedGcId), type, fieldsName, true).get(specifiedGcId); 173 if (info == null) { 174 System.out.println(log); 175 throw new RuntimeException("Cannot find PLAB statistics in log ( GC_ID=" + specifiedGcId + " type=" + type + " )"); 176 } 177 return info; 178 } 179 180 /** 181 * Returns Map<Long,PlabStatistics> which contains specified statistics. Filters out specified gc ids. 182 * @param specifiedGcIdForExclude 183 * @param type 184 * @param fieldsName 185 * @return 186 **/ 187 public Map<Long, PlabInfo> getExcludedSpecifiedStats(List<Long> specifiedGcIdForExclude, LogParser.ReportType type, List<String> fieldsName) { 188 return getSpecifiedStats(specifiedGcIdForExclude, type, fieldsName, false); 189 } 190 191 private Map<Long, PlabInfo> getSpecifiedStats(List<Long> gcIds, LogParser.ReportType type, List<String> fieldNames, boolean extractId) { 192 return new HashMap<>( 193 getEntries().entryStream() 194 .filter(gcLogItem -> extractId == gcIds.contains(gcLogItem.getKey())) 195 .collect(Collectors.toMap(gcLogItem -> gcLogItem.getKey(), 196 gcLogItem -> gcLogItem.getValue().get(type).filter(fieldNames) 197 ) 198 ) 199 ); 200 } 201 }