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 * [2,244s][info ][gc ] GC(30) Concurrent Mark abort 39 * [2,245s][debug ][gc,plab] GC(33) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) 40 * [2,245s][debug ][gc,plab] GC(33) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) 41 * [2,245s][info ][gc ] GC(33) Pause Young (G1 Evacuation Pause) 127M->127M(128M) (2,244s, 2,245s) 0,899ms 42 * [2,246s][debug ][gc,plab] GC(34) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) 43 * [2,246s][debug ][gc,plab] GC(34) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) 44 * [2,246s][info ][gc ] GC(34) Pause Initial Mark (G1 Evacuation Pause) 127M->127M(128M) (2,245s, 2,246s) 0,907ms 45 46 */ 47 final public class LogParser { 48 49 // Name for GC ID field in report. 50 public final static String GC_ID = "gc_id"; 51 52 /** 53 * Type of parsed log element. 54 */ 55 public static enum ReportType { 56 57 SURVIVOR_STATS, 58 OLD_STATS 59 } 60 61 private final String log; 62 63 private final Map<Long, Map<ReportType, Map<String,Long>>> reportHolder; 64 65 // GC ID 66 private static final Pattern GC_ID_PATTERN = Pattern.compile("\\[gc,plab\\s*\\] GC\\((\\d+)\\)"); 67 // Pattern for extraction pair <name>=<numeric value> 68 private static final Pattern PAIRS_PATTERN = Pattern.compile("\\w+\\s+=\\s+\\d+"); 69 70 /** 71 * Construct LogParser Object 72 * 73 * @param log - VM Output 74 */ 75 public LogParser(String log) { 76 if (log == null) { 77 throw new IllegalArgumentException("Parameter log should not be null."); 78 } 79 this.log = log; 80 reportHolder = parseLines(); 81 } 82 83 /** 84 * @return log which is being processed 85 */ 86 public String getLog() { 87 return log; 88 } 89 90 /** 91 * Returns list of log entries. 92 * 93 * @return list of Pair with ReportType and Map of parameters/values. 94 */ 95 public Map<Long,Map<ReportType, Map<String,Long>>> getEntries() { 96 return reportHolder; 97 } 98 99 private Map<Long,Map<ReportType, Map<String,Long>>> parseLines() throws NumberFormatException { 100 Scanner lineScanner = new Scanner(log); 101 Map<Long,Map<ReportType, Map<String,Long>>> allocationStatistics = new HashMap<>(); 102 Optional<Long> gc_id; 103 while (lineScanner.hasNextLine()) { 104 String line = lineScanner.nextLine(); 105 gc_id = getGcId(line); 106 if ( gc_id.isPresent() ) { 107 Matcher matcher = PAIRS_PATTERN.matcher(line); 108 if (matcher.find()) { 109 Map<ReportType,Map<String, Long>> oneReportItem; 110 ReportType reportType; 111 // Second line in log is statistics for Old PLAB allocation 112 if ( !allocationStatistics.containsKey(gc_id.get()) ) { 113 oneReportItem = new EnumMap<>(ReportType.class); 114 reportType = ReportType.SURVIVOR_STATS; 115 allocationStatistics.put(gc_id.get(), oneReportItem); 116 } else { 117 oneReportItem = allocationStatistics.get(gc_id.get()); 118 reportType = ReportType.OLD_STATS; 119 } 120 121 // Extract all pairs from log. 122 HashMap<String, Long> plabStats = new HashMap<>(); 123 do { 124 String pair = matcher.group(); 125 String[] nameValue = pair.replaceAll(" ", "").split("="); 126 plabStats.put(nameValue[0], Long.parseLong(nameValue[1])); 127 } while (matcher.find()); 128 oneReportItem.put(reportType,plabStats); 129 } 130 } 131 } 132 return allocationStatistics; 133 } 134 135 private Optional<Long> getGcId(String line) { 136 Matcher number = GC_ID_PATTERN.matcher(line); 137 if (number.find()) { 138 return Optional.of(Long.parseLong(number.group(1))); 139 } 140 return Optional.empty(); 141 } 142 } | 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 * [2,244s][info ][gc ] GC(30) Concurrent Mark abort 39 * [2,245s][debug ][gc,plab] GC(33) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) 40 * [2,245s][debug ][gc,plab] GC(33) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) 41 * [2,245s][info ][gc ] GC(33) Pause Young (G1 Evacuation Pause) 127M->127M(128M) (2,244s, 2,245s) 0,899ms 42 * [2,246s][debug ][gc,plab] GC(34) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) 43 * [2,246s][debug ][gc,plab] GC(34) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) 44 * [2,246s][info ][gc ] GC(34) Pause Initial Mark (G1 Evacuation Pause) 127M->127M(128M) (2,245s, 2,246s) 0,907ms 45 * 46 * This log will produce next Map as result: 47 * 48 * { 33= { ReportType.SURVIVOR_STATS = { "allocated" = 1, 49 * "wasted" = 0, 50 * ... 51 * } 52 * ReportType.OLD_STATS = { "allocated" = "1", 53 * "wasted" = 0, 54 * ... 55 * } 56 * }, 57 * 34= { ReportType.SURVIVOR_STATS = { "allocated" = 1, 58 * "wasted" = 0, 59 * ... 60 * } 61 * ReportType.OLD_STATS = { "allocated" = "1", 62 * "wasted" = 0, 63 * ... 64 * } 65 * } 66 * ... 67 * } 68 */ 69 final public class LogParser { 70 71 // Name for GC ID field in report. 72 public final static String GC_ID = "gc_id"; 73 74 /** 75 * Type of parsed log element. 76 */ 77 public static enum ReportType { 78 79 SURVIVOR_STATS, 80 OLD_STATS 81 } 82 83 private final String log; 84 85 // Contains Map of PLAB statistics for given log. 86 private final Map<Long, Map<ReportType, Map<String, Long>>> report; 87 88 // GC ID 89 private static final Pattern GC_ID_PATTERN = Pattern.compile("\\[gc,plab\\s*\\] GC\\((\\d+)\\)"); 90 // Pattern for extraction pair <name>=<numeric value> 91 private static final Pattern PAIRS_PATTERN = Pattern.compile("\\w+\\s+=\\s+\\d+"); 92 93 /** 94 * Construct LogParser object, parse log file with PLAB statistics and store it into report. 95 * 96 * @param log - VM Output 97 */ 98 public LogParser(String log) { 99 if (log == null) { 100 throw new IllegalArgumentException("Parameter log should not be null."); 101 } 102 this.log = log; 103 report = parseLines(); 104 } 105 106 /** 107 * @return log which was processed 108 */ 109 public String getLog() { 110 return log; 111 } 112 113 /** 114 * Returns Map of log entries which contains Long as key and Map as value: 115 * Map<ReportType, Map<String,Long>>. ReportType is a key, value is Map of String as key and Long as value. 116 * 117 * @return Returns Map of log entries. 118 */ 119 public Map<Long, Map<ReportType, Map<String, Long>>> getEntries() { 120 return report; 121 } 122 123 private Map<Long, Map<ReportType, Map<String, Long>>> parseLines() throws NumberFormatException { 124 Scanner lineScanner = new Scanner(log); 125 Map<Long, Map<ReportType, Map<String, Long>>> allocationStatistics = new HashMap<>(); 126 Optional<Long> gc_id; 127 while (lineScanner.hasNextLine()) { 128 String line = lineScanner.nextLine(); 129 gc_id = getGcId(line); 130 if (gc_id.isPresent()) { 131 Matcher matcher = PAIRS_PATTERN.matcher(line); 132 if (matcher.find()) { 133 Map<ReportType, Map<String, Long>> oneReportItem; 134 ReportType reportType; 135 // Second line in log is statistics for Old PLAB allocation 136 if (!allocationStatistics.containsKey(gc_id.get())) { 137 oneReportItem = new EnumMap<>(ReportType.class); 138 reportType = ReportType.SURVIVOR_STATS; 139 allocationStatistics.put(gc_id.get(), oneReportItem); 140 } else { 141 oneReportItem = allocationStatistics.get(gc_id.get()); 142 reportType = ReportType.OLD_STATS; 143 } 144 145 // Extract all pairs from log. 146 HashMap<String, Long> plabStats = new HashMap<>(); 147 do { 148 String pair = matcher.group(); 149 String[] nameValue = pair.replaceAll(" ", "").split("="); 150 plabStats.put(nameValue[0], Long.parseLong(nameValue[1])); 151 } while (matcher.find()); 152 oneReportItem.put(reportType, plabStats); 153 } 154 } 155 } 156 return allocationStatistics; 157 } 158 159 private Optional<Long> getGcId(String line) { 160 Matcher number = GC_ID_PATTERN.matcher(line); 161 if (number.find()) { 162 return Optional.of(Long.parseLong(number.group(1))); 163 } 164 return Optional.empty(); 165 } 166 } |