/* * Copyright (c) 2013-2015 mgm technology partners GmbH * * 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 com.mgmtp.perfload.perfalyzer.reportpreparation; import com.google.common.base.Charsets; import com.mgmtp.perfload.perfalyzer.reportpreparation.NumberDataSet.SeriesPoint; import com.mgmtp.perfload.perfalyzer.reportpreparation.PlotCreator.AxisType; import com.mgmtp.perfload.perfalyzer.reportpreparation.PlotCreator.ChartDimensions; import com.mgmtp.perfload.perfalyzer.reportpreparation.PlotCreator.RendererType; import com.mgmtp.perfload.perfalyzer.util.Marker; import com.mgmtp.perfload.perfalyzer.util.MemoryFormat; import com.mgmtp.perfload.perfalyzer.util.PerfAlyzerFile; import com.mgmtp.perfload.perfalyzer.util.TestMetadata; import com.mgmtp.perfload.perfalyzer.util.TimestampNormalizer; import com.tagtraum.perf.gcviewer.imp.DataReader; import com.tagtraum.perf.gcviewer.imp.DataReaderFactory; import com.tagtraum.perf.gcviewer.math.IntData; import com.tagtraum.perf.gcviewer.model.GCEvent; import com.tagtraum.perf.gcviewer.model.GCModel; import org.apache.commons.lang3.text.StrBuilder; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.text.NumberFormat; import java.time.ZonedDateTime; import java.util.Iterator; import java.util.List; import java.util.ResourceBundle; import static com.google.common.collect.Lists.newArrayListWithCapacity; import static com.mgmtp.perfload.perfalyzer.constants.PerfAlyzerConstants.DELIMITER; import static com.mgmtp.perfload.perfalyzer.util.StrBuilderUtils.appendEscapedAndQuoted; import static org.apache.commons.io.FileUtils.writeLines; /** * @author ctchinda */ public class GcLogReportPreparationStrategy extends AbstractReportPreparationStrategy { private final TimestampNormalizer timestampNormalizer; private final MemoryFormat memoryFormat; private final Marker marker; public GcLogReportPreparationStrategy(final NumberFormat intNumberFormat, final NumberFormat floatNumberFormat, final List<DisplayData> displayDataList, final ResourceBundle resourceBundle, final PlotCreator plotCreator, final TestMetadata testMetadata, final TimestampNormalizer timestampNormalizer, final MemoryFormat memoryFormat, final Marker marker, final DataRange dataRange) { super(intNumberFormat, floatNumberFormat, displayDataList, resourceBundle, plotCreator, testMetadata, dataRange); this.timestampNormalizer = timestampNormalizer; this.memoryFormat = memoryFormat; this.marker = marker; } @Override public void processFiles(final File sourceDir, final File destDir, final List<PerfAlyzerFile> files) throws IOException { for (PerfAlyzerFile f : files) { log.info("Processing file '{}'...", f); GCModel origModel; try (InputStream is = new FileInputStream(new File(sourceDir, f.getFile().getPath()))) { DataReader dataReader = new DataReaderFactory().getDataReader(is); origModel = dataReader.read(); } catch (IOException ex) { log.error("Error reading GC log file: " + f.getFile(), ex); continue; } GCModel model = new GCModel(); model.setFormat(origModel.getFormat()); for (Iterator<GCEvent> it = origModel.getGCEvents(); it.hasNext(); ) { GCEvent event = it.next(); ZonedDateTime datestamp = event.getDatestamp(); if (datestamp == null) { // we assume there are generally no datestamps if the first event does not have one log.error( "Unsupported GC log format. Please activate date stamp logging (-XX:+PrintGCDateStamps for Oracle JDK)."); break; } if (timestampNormalizer.isInRange(datestamp)) { if (marker == null || marker.isInRange(datestamp)) { model.add(event); } } } if (model.size() > 0) { NumberDataSet dataSetHeap = new NumberDataSet(); NumberDataSet dataSetGcTimes = new NumberDataSet(); for (Iterator<GCEvent> it = model.getGCEvents(); it.hasNext(); ) { GCEvent event = it.next(); ZonedDateTime timestamp = event.getDatestamp(); long seconds = timestampNormalizer.normalizeTimestamp(timestamp, 0L) / 1000; dataSetHeap.addSeriesPoint("total", new SeriesPoint(seconds, event.getTotal() / 1024)); dataSetHeap.addSeriesPoint("used", new SeriesPoint(seconds, event.getPreUsed() / 1024)); dataSetHeap.addSeriesPoint("used", new SeriesPoint(seconds, event.getPostUsed() / 1024)); dataSetGcTimes.addSeriesPoint("time", new SeriesPoint(seconds, event.getPause() * 1000)); } if (dataSetHeap.isEmpty() || dataSetGcTimes.isEmpty()) { continue; } PerfAlyzerFile perfAlyzerFile = f.copy().setExtension("png"); if (marker != null) { perfAlyzerFile.setMarker(marker.getName()); } File destFile = new File(destDir, perfAlyzerFile.getFile().getPath()); plotCreator.writePlotFile(destFile, AxisType.LINEAR, AxisType.LINEAR, RendererType.LINES, ChartDimensions.WIDE, dataRange, false, dataSetHeap, dataSetGcTimes); List<CharSequence> gcLines = newArrayListWithCapacity(2); writeHeader(gcLines); writeData(model, gcLines); perfAlyzerFile = f.copy().setExtension("csv"); if (marker != null) { perfAlyzerFile.setMarker(marker.getName()); } writeLines(new File(destDir, perfAlyzerFile.getFile().getPath()), Charsets.UTF_8.name(), gcLines); } } } private void writeHeader(final List<CharSequence> gcLines) { StrBuilder sb = new StrBuilder(500); appendEscapedAndQuoted(sb, DELIMITER, "total"); appendEscapedAndQuoted(sb, DELIMITER, "tenured"); appendEscapedAndQuoted(sb, DELIMITER, "young"); appendEscapedAndQuoted(sb, DELIMITER, "permgen"); appendEscapedAndQuoted(sb, DELIMITER, "freed memory"); appendEscapedAndQuoted(sb, DELIMITER, "freed memory/min"); appendEscapedAndQuoted(sb, DELIMITER, "total gc time"); appendEscapedAndQuoted(sb, DELIMITER, "full gc time (min/max)"); appendEscapedAndQuoted(sb, DELIMITER, "throughput"); appendEscapedAndQuoted(sb, DELIMITER, "num full gc"); appendEscapedAndQuoted(sb, DELIMITER, "full gc performance"); appendEscapedAndQuoted(sb, DELIMITER, "gc performance"); gcLines.add(sb); } private void writeData(final GCModel model, final List<CharSequence> gcLines) { StrBuilder sb = new StrBuilder(500); appendEscapedAndQuoted(sb, DELIMITER, memoryFormat.format(model.getFootprint())); appendEscapedAndQuoted(sb, DELIMITER, formatGcValue(model.getTenuredAllocatedSizes())); appendEscapedAndQuoted(sb, DELIMITER, formatGcValue(model.getYoungAllocatedSizes())); appendEscapedAndQuoted(sb, DELIMITER, formatGcValue(model.getPermAllocatedSizes())); appendEscapedAndQuoted(sb, DELIMITER, memoryFormat.format(model.getFreedMemory())); appendEscapedAndQuoted(sb, DELIMITER, memoryFormat.format(model.getFreedMemory() / model.getRunningTime() * 60.0)); appendEscapedAndQuoted(sb, DELIMITER, model.hasCorrectTimestamp() ? floatNumberFormat.format(model.getPause().getSum()) + " s" : "n/a"); appendEscapedAndQuoted(sb, DELIMITER, model.getFullGCPause().getN() > 0 ? intNumberFormat.format(model.getFullGCPause().getMin()) + " s / " + intNumberFormat.format(model.getFullGCPause().getMax()) + " s" : "n/a"); appendEscapedAndQuoted(sb, DELIMITER, model.hasCorrectTimestamp() ? floatNumberFormat.format(model.getThroughput()) + " %" : "n/a"); appendEscapedAndQuoted(sb, DELIMITER, model.getFullGCPause().getN() > 0 ? intNumberFormat.format(model.getFullGCPause().getN()) : "n/a"); appendEscapedAndQuoted(sb, DELIMITER, model.getFullGCPause().getN() > 0 ? memoryFormat.format( model.getFreedMemoryByFullGC().getSum() / model.getFullGCPause().getSum()) + "/s" : "n/a"); appendEscapedAndQuoted(sb, DELIMITER, model.getGCPause().getN() > 0 ? memoryFormat.format( model.getFreedMemoryByGC().getSum() / model.getGCPause().getSum()) + "/s" : "n/a"); gcLines.add(sb); } private String formatGcValue(final IntData data) { return data.getN() > 0 ? memoryFormat.format(data.getMax()) : "n/a"; } }