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.EnumMap; 26 import java.util.HashMap; 27 import java.util.Map; 28 import java.util.Optional; 29 import java.util.Scanner; 30 import java.util.regex.Matcher; 31 import java.util.regex.Pattern; 32 33 /** 34 * LogParser class parses VM output to get PLAB and ConsumptionStats values. 35 * 36 * Typical GC log with PLAB statistics (options - -Xlog:gc=debug,gc+plab=debug) looks like: 37 * 38 * [0.330s][debug][gc,plab ] GC(0) Young PLAB allocation: allocated: 1825632B, wasted: 29424B, unused: 2320B, used: 1793888B, undo waste: 0B, 39 * [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 40 * [0.330s][debug][gc,plab ] GC(0) Young sizing: calculated: 358776B, actual: 358776B 41 * [0.330s][debug][gc,plab ] GC(0) Old PLAB allocation: allocated: 427248B, wasted: 592B, unused: 368584B, used: 58072B, undo waste: 0B, 42 * [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 43 * [0.330s][debug][gc,plab ] GC(0) Old sizing: calculated: 11608B, actual: 11608B 44 */ 45 final public class LogParser { 46 47 // Name for GC ID field in report. 48 public final static String GC_ID = "gc_id"; 49 50 /** 51 * Type of parsed log element. 52 */ 53 public static enum ReportType { 54 SURVIVOR_STATS, 55 OLD_STATS 56 } 57 58 private final String log; 59 60 private final Map<Long, Map<ReportType, Map<String,Long>>> reportHolder; 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 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 reportHolder = parseLines(); 78 } 79 80 /** 81 * @return log which is being processed 82 */ 83 public String getLog() { 84 return log; 85 } 86 87 /** 88 * Returns list of log entries. 89 * 90 * @return list of Pair with ReportType and Map of parameters/values. 91 */ 92 public Map<Long,Map<ReportType, Map<String,Long>>> getEntries() { 93 return reportHolder; 94 } 95 96 private Map<Long,Map<ReportType, Map<String,Long>>> parseLines() throws NumberFormatException { 97 Scanner lineScanner = new Scanner(log); 98 Map<Long,Map<ReportType, Map<String,Long>>> allocationStatistics = new HashMap<>(); 99 Optional<Long> gc_id; 100 while (lineScanner.hasNextLine()) { 101 String line = lineScanner.nextLine(); 102 gc_id = getGcId(line); 103 if ( gc_id.isPresent() ) { 104 Matcher matcher = PAIRS_PATTERN.matcher(line); 105 if (matcher.find()) { 106 Map<ReportType,Map<String, Long>> oneReportItem; 107 ReportType reportType; 108 109 if (!allocationStatistics.containsKey(gc_id.get())) { 110 allocationStatistics.put(gc_id.get(), new EnumMap<>(ReportType.class)); 111 } 112 113 if ( line.contains("Young") ) { 114 reportType = ReportType.SURVIVOR_STATS; 115 } else { 116 reportType = ReportType.OLD_STATS; 117 } 118 119 oneReportItem = allocationStatistics.get(gc_id.get()); 120 if (!oneReportItem.containsKey(reportType)) { 121 oneReportItem.put(reportType,new HashMap<String, Long>()); 122 } 123 124 // Extract all pairs from log. 125 Map<String, Long> plabStats = oneReportItem.get(reportType); 126 do { 127 String pair = matcher.group(); 128 String[] nameValue = pair.replaceAll(": ", ":").split(":"); 129 plabStats.put(nameValue[0].trim(), Long.parseLong(nameValue[1])); 130 } while (matcher.find()); 131 } 132 } 133 } 134 return allocationStatistics; 135 } 136 137 private Optional<Long> getGcId(String line) { 138 Matcher number = GC_ID_PATTERN.matcher(line); 139 if (number.find()) { 140 return Optional.of(Long.parseLong(number.group(1))); 141 } 142 return Optional.empty(); 143 } 144 }