/* * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package gc.g1.plab.lib; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; import jdk.test.lib.Pair; /** * LogParser class parses VM output to get PLAB and ConsumptionStats values. * * Typical GC log with PLAB statistics looks like: * * #1: [GC pause (WhiteBox Initiated Young GC) (young) (allocated = 0 wasted = 0 unused = 0 used = 0 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) * (allocated = 70692 wasted = 1450 unused = 1287 used = 67955 undo_waste = 0 region_end_waste = 0 regions filled = 1 direct_allocated = 19003 failure_used = 0 failure_waste = 0) (plab_sz = 13591 desired_plab_sz = 10193) * where first line is statistic for young PLAB and second line is for old PLAB. */ final public class LogParser { // Name for GC ID field in report. public final static String GC_ID = "gc_id"; /** * Type of parsed log element. */ public static enum ReportType { SURVIVOR_STATS, OLD_STATS } private final String log; private final List>> reportHolder; // GC ID private static final Pattern GC_ID_PATTERN = Pattern.compile("#(\\d+):"); // Pattern for extraction pair = private static final Pattern PAIRS_PATTERN = Pattern.compile("\\w+\\s*=\\s*\\d+"); /** * Construct LogParser Object * * @param log - VM Output */ public LogParser(String log) { if (log == null) { throw new IllegalArgumentException("Parameter log should not be null."); } this.log = log; reportHolder = parseLines(); } /** * @return log which is being processed */ public String getLog() { return log; } /** * Returns list of log entries. * * @return list of Pair with ReportType and Map of parameters/values. */ public List>> getEntries() { return reportHolder; } private List>> parseLines() throws NumberFormatException { Scanner lineScanner = new Scanner(log); List>> allocationStatistics = new ArrayList<>(); long gc_id = 0; while (lineScanner.hasNextLine()) { String line = lineScanner.nextLine(); // If no any prefix - this is the Old PLAB statistics ReportType currentStats = ReportType.OLD_STATS; // #NUMBER - this is first line of PLAB statistics if (line.startsWith("#")) { currentStats = ReportType.SURVIVOR_STATS; gc_id = getGcId(line); } Matcher matcher = PAIRS_PATTERN.matcher(line); if (matcher.find()) { HashMap map = new HashMap<>(); map.put(GC_ID, gc_id); allocationStatistics.add(new Pair<>(currentStats, map)); // Extract all pairs from log. do { String pair = matcher.group(); String[] nameValue = pair.replaceAll(" ", "").split("="); map.put(nameValue[0], Long.parseLong(nameValue[1])); } while (matcher.find()); } } return allocationStatistics; } private long getGcId(String line) { Matcher number = GC_ID_PATTERN.matcher(line); if (number.find()) { return Long.parseLong(number.group(1)); } throw new RuntimeException("Should not reach"); } }