/* * Copyright 2003-2012 Yusuke Yamamoto * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package samurai.gc; import samurai.util.GUIResourceBundle; import samurai.util.LineGraphDataSourceParser; import java.awt.Color; import java.util.regex.Matcher; import java.util.regex.Pattern; public class SunGCParser implements LineGraphDataSourceParser { private static GUIResourceBundle resources = GUIResourceBundle.getInstance(); private HeapGraph newGraph = null; private HeapGraph oldGraph = null; private HeapGraph permGraph = null; private boolean unloadingClasses = false; /* [GC 115008K->103309K("129664K"), 0.0254331 secs] */ private Pattern heapSizePtn = Pattern.compile("(?<=K\\()[0-9]+"); /* [GC "115008K"->103309K(129664K), 0.0254331 secs] */ private Pattern heapBeforeGCPtn = Pattern.compile("(?<= )[0-9]+(?=K->)"); /* [GC 115008K->"103309K"(129664K), 0.0254331 secs] */ private Pattern heapAfterGCPtn = Pattern.compile("(?<=K->)[0-9]*(?=K\\()"); /* [GC 115008K->103309K(129664K), [0.0254331] secs] */ private Pattern timeSpentPtn = Pattern.compile("(?<=, )[0-9\\.]*(?= secs\\]$)"); /* a pattern catches -verbosegc log [GC 115008K->103309K(129664K), 0.0254331 secs] [Full GC 61365K->51414K(129664K), 1.0320474 secs] */ private Pattern verboseGCPtn = Pattern.compile("\\[(ParNew|GC|Full GC) [0-9]+K->[0-9]+K\\([0-9]+K\\), [0-9\\.]+ secs\\]"); private Pattern printGCDetailsPtn = Pattern.compile("\\[(GC|Full GC) ([0-9\\.]+: )?\\["); /* a pattern catches new area gc log [ParNew 226778K->33381K(1022400K), 0.3251635 secs] [DefNew: 209792K->12630K(235968K), 0.1971975 secs] [PSYoungGen: 2715K->0K(33344K)] */ private Pattern newGCPtn = Pattern.compile("\\[(ParNew|DefNew|PSYoungGen):? [0-9]+K->[0-9]+K\\([0-9]+K\\)(, [0-9\\.]+ secs)?\\]"); /* a pattern catches old area gc log [Tenured: 0K->4271K(786432K), 0.1163157 secs] [CMS: 0K->4275K(786432K), 0.1640437 secs] [ParOldGen: 65738K->36992K(99072K)] [PSOldGen: 43812K->28039K(67968K)] */ private Pattern oldGCPtn = Pattern.compile("\\[(Tenured|CMS( \\(concurrent mode failure\\))?|ParOldGen|PSOldGen): [0-9]+K->[0-9]+K\\([0-9]+K\\)(, [0-9\\.]+ secs)?\\]"); /* a pattern catches permanent area gc log [Perm : 9991K->9991K(131072K)] [CMS Perm : 9993K->9982K(131072K)] [PSPermGen: 11772K->11755K(23552K)] */ private Pattern permGCPtn = Pattern.compile("\\[(Perm |CMS Perm |PSPermGen): [0-9]+K->[0-9]+K\\([0-9]+K\\)\\]"); private boolean gcTypeDetected = false; private boolean printGCDetails = false; public SunGCParser() { } private String unloadingHeader = null; public boolean parse(String line, LineGraphRenderer renderer) { int unloadingIndex = line.indexOf("[Unloading class "); if (unloadingClasses) { if (-1 == unloadingIndex) { line = unloadingHeader + line; unloadingClasses = false; } } else { if (-1 != unloadingIndex) { unloadingClasses = true; unloadingHeader = line.substring(0, unloadingIndex); } } if (!unloadingClasses && -1 != line.indexOf("[") && (-1 != line.indexOf("[GC") || -1 != line.indexOf("[Full GC") || -1 != line.indexOf("[ParNew "))) { if (!gcTypeDetected) { printGCDetails = printGCDetailsPtn.matcher(line).find(); initializeGraphs(renderer); gcTypeDetected = true; } try { if (!printGCDetails) { //-verbose:gc / -verbosegc newGraph.parse(line); return true; } else { //-XX:+PrintGCDetails if (-1 != line.indexOf("[GC ")) { // minor GC newGraph.parse(line); // rarely and strangely old gc happens with "[GC" oldGraph.parse(line); return true; } else { // Full GC newGraph.parse(line); oldGraph.parse(line); permGraph.parse(line); return true; } } } catch (NumberFormatException ignore) { System.err.println("unexpected format:" + line); } catch (StringIndexOutOfBoundsException sioobe) { System.err.println("unexpected format:" + line); } catch (IllegalArgumentException iae) { System.err.println("unexpected format:" + line); } catch (IllegalStateException ise) { System.err.println("unexpected format:" + line); } } return false; } private class HeapGraph{ double maxSize = 0; Pattern pattern; LineGraph lineGraph; boolean parseGCtime; HeapGraph(Pattern pattern,LineGraph lineGraph,boolean parseGCtime){ this.pattern = pattern; this.lineGraph = lineGraph; this.parseGCtime = parseGCtime; if(parseGCtime){ lineGraph.setColorAt(0, Color.GRAY); lineGraph.setColorAt(1, Color.RED); lineGraph.setColorAt(2, Color.YELLOW); }else{ lineGraph.setColorAt(0, Color.RED); lineGraph.setColorAt(1, Color.YELLOW); } } void parse(String line){ Matcher matcher = pattern.matcher(line); if(matcher.find()){ String found = matcher.group(); double currentSize = extract(found, heapSizePtn); if (maxSize < currentSize) { maxSize = currentSize; if(pattern == permGCPtn){ lineGraph.setYMax(0, maxSize); lineGraph.setYMax(1, maxSize); }else{ lineGraph.setYMax(1, maxSize); lineGraph.setYMax(2, maxSize); } } double heapBeforeGC = extract(found, heapBeforeGCPtn); double heapAfterGC = extract(found, heapAfterGCPtn); if (parseGCtime) { double timeSpent; Matcher timeSpentMatcher = timeSpentPtn.matcher(found); if(pattern == oldGCPtn || !timeSpentMatcher.find()){ timeSpentMatcher = timeSpentPtn.matcher(line); timeSpentMatcher.find(); timeSpent = Double.parseDouble(timeSpentMatcher.group()); } else { timeSpent = Double.parseDouble(timeSpentMatcher.group()); } lineGraph.addValues(new double[]{timeSpent, heapBeforeGC, heapAfterGC}); } else { lineGraph.addValues(new double[]{heapBeforeGC, heapAfterGC}); } } } } private double extract(String line, Pattern pattern) { Matcher m = pattern.matcher(line); if (m.find()) { return Double.parseDouble(m.group()); } else { throw new IllegalArgumentException(); } } private void initializeGraphs(LineGraphRenderer renderer) { if (printGCDetails) { newGraph = new HeapGraph(newGCPtn,renderer.addLineGraph(resources.getMessage("GraphPanel.new"), new String[]{resources.getMessage("GraphPanel.time") + "(secs)", resources.getMessage("GraphPanel.newBeforeGC"), resources.getMessage("GraphPanel.newAfterGC")}),true); oldGraph = new HeapGraph(oldGCPtn,renderer.addLineGraph(resources.getMessage("GraphPanel.old"), new String[]{resources.getMessage("GraphPanel.time") + "(secs)", resources.getMessage("GraphPanel.oldBeforeGC"), resources.getMessage("GraphPanel.oldAfterGC")}),true); permGraph = new HeapGraph(permGCPtn,renderer.addLineGraph(resources.getMessage("GraphPanel.permanent"), new String[]{ resources.getMessage("GraphPanel.permBeforeGC"), resources.getMessage("GraphPanel.permAfterGC")}),false); } else { newGraph = new HeapGraph(verboseGCPtn,renderer.addLineGraph(resources.getMessage("GraphPanel.memory"), new String[]{resources.getMessage("GraphPanel.time") + "(secs)", resources.getMessage("GraphPanel.heapBeforeGC"), resources.getMessage("GraphPanel.heapAfterGC")}),true); } } }