diff --git a/README b/README index 570f4095..e3c0d1c5 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -GCViewer 1.31 +GCViewer 1.31 fork with cmdline interface ============= GCViewer is a little tool that visualizes verbose GC output @@ -8,6 +8,10 @@ is free software released under GNU LGPL. You can start GCViewer by simply double-clicking on gcviewer-1.3x.jar or running java -jar gcviewer-1.3x.jar (it needs a java 1.6 vm to run). +For a cmdline based report summary just type: +java -jar gcviewer-1.3x.jar gc.log summary.csv +to gegenrate a report. + Supported verbose:gc formats are: diff --git a/pom.xml b/pom.xml index 2bdd4cf2..183c11d9 100644 --- a/pom.xml +++ b/pom.xml @@ -92,7 +92,7 @@ - com.tagtraum.perf.gcviewer.GCViewer + com.tagtraum.perf.gcviewer.Main true diff --git a/src/main/java/com/tagtraum/perf/gcviewer/Main.java b/src/main/java/com/tagtraum/perf/gcviewer/Main.java new file mode 100755 index 00000000..355f5f1f --- /dev/null +++ b/src/main/java/com/tagtraum/perf/gcviewer/Main.java @@ -0,0 +1,62 @@ +package com.tagtraum.perf.gcviewer; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import javax.swing.SwingUtilities; + +import com.tagtraum.perf.gcviewer.exp.summary.SummaryExporter; +import com.tagtraum.perf.gcviewer.imp.DataReader; +import com.tagtraum.perf.gcviewer.imp.DataReaderFactory; +import com.tagtraum.perf.gcviewer.model.GCModel; + +public class Main { + + public static void main(final String[] args) { + if (args.length == 2) { + final String gcfile = args[0]; + final String summaryFilePath = args[1]; + + //export summary: + try { + exportSummary(summaryFilePath, gcfile); + } + catch(IOException e1) { + e1.printStackTrace(); + } + //exit: quick & dirty, but does not really matter + System.exit(0); + + } else if (args.length > 1) { + usage(); + } else { + GCViewer.main(args); + } + } + + private static void exportSummary(String summaryFilePath, String gcFilename) throws IOException + { + SummaryExporter exporter = new SummaryExporter(); + GCModel model = loadModel(new File(gcFilename).toURI().toURL()); + exporter.exportSummaryFromModel(model, gcFilename, summaryFilePath); + } + + private static GCModel loadModel(final URL url) throws IOException { + DataReaderFactory factory = new DataReaderFactory(); + final InputStream in = url.openStream(); + final DataReader reader = factory.getDataReader(in); + final GCModel model = reader.read(); + model.setURL(url); + return model; + + } + + private static void usage() { + System.out.println("Welcome to GCViewer with cmdline"); + System.out.println("java -jar gcviewer.jar [] []"); + } + + +} diff --git a/src/main/java/com/tagtraum/perf/gcviewer/exp/summary/CsvSummaryExportFormatter.java b/src/main/java/com/tagtraum/perf/gcviewer/exp/summary/CsvSummaryExportFormatter.java new file mode 100755 index 00000000..7d3fa6ed --- /dev/null +++ b/src/main/java/com/tagtraum/perf/gcviewer/exp/summary/CsvSummaryExportFormatter.java @@ -0,0 +1,21 @@ +/** + * + */ +package com.tagtraum.perf.gcviewer.exp.summary; + +/** + * @author sean + * + */ +public class CsvSummaryExportFormatter implements ISummaryExportFormatter { + + private String separator = ", "; + + /* (non-Javadoc) + * @see com.tagtraum.perf.gcviewer.exp.ISummaryExportFormatter#exportValue(java.lang.String, java.lang.String) + */ + //@Override + public String formatLine(String tag, String value, String units) { + return tag + separator + value + separator + units; + } +} diff --git a/src/main/java/com/tagtraum/perf/gcviewer/exp/summary/ISummaryExportFormatter.java b/src/main/java/com/tagtraum/perf/gcviewer/exp/summary/ISummaryExportFormatter.java new file mode 100755 index 00000000..48bd8f3c --- /dev/null +++ b/src/main/java/com/tagtraum/perf/gcviewer/exp/summary/ISummaryExportFormatter.java @@ -0,0 +1,12 @@ +/** + * + */ +package com.tagtraum.perf.gcviewer.exp.summary; + +/** + * @author sean + * + */ +public interface ISummaryExportFormatter { + String formatLine(String tag, String value, String units); +} diff --git a/src/main/java/com/tagtraum/perf/gcviewer/exp/summary/SummaryExporter.java b/src/main/java/com/tagtraum/perf/gcviewer/exp/summary/SummaryExporter.java new file mode 100755 index 00000000..c2f0b98b --- /dev/null +++ b/src/main/java/com/tagtraum/perf/gcviewer/exp/summary/SummaryExporter.java @@ -0,0 +1,301 @@ +/** + * + */ +package com.tagtraum.perf.gcviewer.exp.summary; + +import java.io.*; +import java.util.Date; + +import com.tagtraum.perf.gcviewer.model.GCModel; +import com.tagtraum.perf.gcviewer.util.*; + +/** + * @author sean + * SR: adding feature to auto export summary data, when run from command line + * + * + * HISTORY: + * + * 04/04/2011 SR + * - added unit test for the CSV output, for the Sun JDK + * - removed embedded commas from the value field in the CSV output + * - added another column for the units for each field + * - lines that had extra value for std. deviation, or for %, have now been split into two lines + * + * TODO: datetime fields like 'totalTime' need to separate out their units. + * + */ +public class SummaryExporter { + private ISummaryExportFormatter formatter; + + /* + * field formatters + * */ + private NumberFormatNoCommas pauseFormatter; + private MemoryFormatNoCommas footprintSlopeFormatter; + private NumberFormatNoCommas percentFormatter; + private NumberFormatNoCommas gcTimeFormatter; + private MemoryFormatNoCommas footprintFormatter; + private NumberFormatNoCommas throughputFormatter; + private TimeFormat totalTimeFormatter; + private MemoryFormatNoCommas freedMemoryPerMinFormatter; + private MemoryFormatNoCommas sigmaMemoryFormatter; + + public SummaryExporter() + { + //use the default csv formatter + this.formatter = new CsvSummaryExportFormatter(); + initialiseFormatters(); + } + + public SummaryExporter(ISummaryExportFormatter formatter) + { + this.formatter = formatter; + initialiseFormatters(); + } + + private void initialiseFormatters() { + pauseFormatter = new NumberFormatNoCommas(); + pauseFormatter.setMaximumFractionDigits(5); + + totalTimeFormatter = new TimeFormat(); + + gcTimeFormatter = new NumberFormatNoCommas(); + gcTimeFormatter.setMaximumFractionDigits(2); + + throughputFormatter = new NumberFormatNoCommas(); + throughputFormatter.setMaximumFractionDigits(2); + + footprintFormatter = new MemoryFormatNoCommas(); + + sigmaMemoryFormatter = new MemoryFormatNoCommas(); + + footprintSlopeFormatter = new MemoryFormatNoCommas(); + + freedMemoryPerMinFormatter = new MemoryFormatNoCommas(); + + percentFormatter = new NumberFormatNoCommas(); + percentFormatter.setMaximumFractionDigits(1); + percentFormatter.setMinimumFractionDigits(1); + } + + private void exportValue(PrintWriter writer, String tag, boolean bValue) + { + exportValue(writer, tag, bValue ? "true" : "false", "bool"); + } + + private void exportValue(PrintWriter writer, String tag, String value, String units) + { + String strFormatted = formatter.formatLine(tag, value, units); + writer.println(strFormatted); + } + + public void exportSummaryFromModel(GCModel model, String gcLogFileDesc, String filePath) throws IOException + { + FileWriter outFile = new FileWriter(filePath); + PrintWriter out = new PrintWriter(outFile); + + exportValue(out, "gcLogFile", gcLogFileDesc, "-"); + + exportMemorySummary(out, model); + exportPauseSummary(out, model); + exportOverallSummary(out, model); + + out.flush(); + out.close(); + } + + private void exportOverallSummary(PrintWriter out, GCModel model) { + exportValue(out, "accumPause", gcTimeFormatter.formatDouble(model.getPause().getSum()), "s"); + + Formatted formed = footprintFormatter.formatToFormatted(model.getFootprint()); + exportValue(out, "footprint", formed.getValue(), formed.getUnits()); + + formed = footprintFormatter.formatToFormatted(model.getFreedMemory()); + exportValue(out, "freedMemory", formed.getValue(), formed.getUnits()); + + if (model.hasCorrectTimestamp()) { + exportValue(out, "throughput", throughputFormatter.formatDouble(model.getThroughput()), "%"); + formed = totalTimeFormatter.formatToFormatted(new Date((long)model.getRunningTime()*1000l)); + exportValue(out, "totalTime", formed.getValue(), formed.getUnits()); + + formed = freedMemoryPerMinFormatter.formatToFormatted(model.getFreedMemory()/model.getRunningTime()*60.0); + exportValue(out, "freedMemoryPerMin", formed.getValue(), formed.getUnits() + "/min"); + } else { + exportValue(out, "throughput", "n.a.", "%"); + exportValue(out, "totalTime", "n.a.", "s"); + exportValue(out, "freedMemoryPerMin", "n.a.", "M/min"); + } + + final boolean gcDataAvailable = model.getGCPause().getN() > 0; + if (gcDataAvailable) { + formed = footprintFormatter.formatToFormatted(model.getFreedMemoryByGC().getSum()/model.getGCPause().getSum()); + exportValue(out, "gcPerformance", formed.getValue(), formed.getUnits() + "/s"); + } + else { + exportValue(out, "gcPerformance", "n.a.", "M/s"); + } + + final boolean fullGCDataAvailable = model.getFullGCPause().getN() > 0; + + if (fullGCDataAvailable) { + formed = footprintFormatter.formatToFormatted(model.getFreedMemoryByFullGC().getSum()/model.getFullGCPause().getSum()); + exportValue(out, "fullGCPerformance", formed.getValue(), formed.getUnits() + "/s"); + } + else { + exportValue(out, "fullGCPerformance", "n.a.", "M/s"); + } + } + + private void exportPauseSummary(PrintWriter out, GCModel model) { + final boolean pauseDataAvailable = model.getPause().getN() != 0; + final boolean gcDataAvailable = model.getGCPause().getN() > 0; + final boolean fullGCDataAvailable = model.getFullGCPause().getN() > 0; + + if (pauseDataAvailable) { + exportValue(out, "avgPauseIsSig", isSignificant(model.getPause().average(), model.getPause().standardDeviation()) ); + exportValue(out, "avgPause", pauseFormatter.formatDouble(model.getPause().average()), "s"); + exportValue(out, "avgPause\u03c3", pauseFormatter.formatDouble(model.getPause().standardDeviation()), "s"); + + exportValue(out, "minPause", pauseFormatter.formatDouble(model.getPause().getMin()), "s"); + exportValue(out, "maxPause", pauseFormatter.formatDouble(model.getPause().getMax()), "s"); + + if (gcDataAvailable) { + exportValue(out, "avgGCPauseIsSig", isSignificant(model.getGCPause().average(), model.getGCPause().standardDeviation()) ); + exportValue(out, "avgGCPause", pauseFormatter.formatDouble(model.getGCPause().average()), "s"); + exportValue(out, "avgGCPause\u03c3", pauseFormatter.formatDouble(model.getGCPause().standardDeviation()), "s"); + } + else { + exportValue(out, "avgGCPause", "n.a.", "s"); + } + + if (fullGCDataAvailable) { + exportValue(out, "avgFullGCPauseIsSig", isSignificant(model.getFullGCPause().average(), model.getPause().standardDeviation())); + exportValue(out, "avgFullGCPause", pauseFormatter.formatDouble(model.getFullGCPause().average()), "s"); + exportValue(out, "avgFullGCPause\u03c3", pauseFormatter.formatDouble(model.getFullGCPause().standardDeviation()), "s"); + } + else { + exportValue(out, "avgFullGCPause", "n.a.", "s"); + } + } + else { + exportValue(out, "avgPause", "n.a.", "s"); + exportValue(out, "minPause", "n.a.", "s"); + exportValue(out, "maxPause", "n.a.", "s"); + exportValue(out, "avgGCPause", "n.a.", "s"); + exportValue(out, "avgFullGCPause", "n.a.", "s"); + } + exportValue(out, "accumPause", gcTimeFormatter.formatDouble(model.getPause().getSum()), "s"); + exportValue(out, "fullGCPause", gcTimeFormatter.formatDouble(model.getFullGCPause().getSum()), "s"); + exportValue(out, "fullGCPausePc", percentFormatter.formatDouble(model.getFullGCPause().getSum()*100.0/model.getPause().getSum()), "%"); + exportValue(out, "gcPause", gcTimeFormatter.formatDouble(model.getGCPause().getSum()), "s"); + exportValue(out, "gcPausePc", percentFormatter.formatDouble(model.getGCPause().getSum()*100.0/model.getPause().getSum()), "%"); + } + + private boolean isSignificant(final double average, final double standardDeviation) { + // at least 68.3% of all points are within 0.75 to 1.25 times the average value + // Note: this may or may not be a good measure, but it at least helps to mark some bad data as such + return average-standardDeviation > 0.75 * average; + } + + private void exportMemorySummary(PrintWriter out, GCModel model) { + Formatted formed = footprintFormatter.formatToFormatted(model.getFootprint()); + exportValue(out, "footprint", formed.getValue(), formed.getUnits()); + + // check whether we have full gc data at all + final boolean fullGCDataVailable = model.getFootprintAfterFullGC().getN() != 0; + final boolean fullGCSlopeDataVailable = model.getFootprintAfterFullGC().getN() > 1; + + if (!fullGCDataVailable) { + exportValue(out, "footprintAfterFullGC", "n.a.", "M"); + exportValue(out, "slopeAfterFullGC", "n.a.", "M/s"); + exportValue(out, "freedMemoryByFullGC", "n.a.", "M"); + exportValue(out, "avgFreedMemoryByFullGC", "n.a.", "M"); + exportValue(out, "avgFreedMemoryByFullGC\u03c3", "n.a.", "M"); + exportValue(out, "avgFreedMemoryByFullGCisSig", "n.a.", "bool"); + } + else { + formed = footprintFormatter.formatToFormatted(model.getFootprintAfterFullGC().average()); + exportValue(out, "footprintAfterFullGC", formed.getValue(), formed.getUnits()); + formed = sigmaMemoryFormat(model.getFootprintAfterFullGC().standardDeviation()); + exportValue(out, "footprintAfterFullGC\u03c3", formed.getValue(), formed.getUnits()); + exportValue(out, "footprintAfterFullGCisSig", isSignificant(model.getFootprintAfterFullGC().average(), + model.getFootprintAfterFullGC().standardDeviation())); + formed = footprintFormatter.formatToFormatted(model.getFreedMemoryByFullGC().getSum()); + exportValue(out, "freedMemoryByFullGC", formed.getValue(), formed.getUnits()); + exportValue(out, "freedMemoryByFullGCpc", percentFormatter.formatDouble(model.getFreedMemoryByFullGC().getSum()*100.0/model.getFreedMemory()), "%"); + + formed = footprintFormatter.formatToFormatted(model.getFreedMemoryByFullGC().average()); + exportValue(out, "avgFreedMemoryByFullGC", formed.getValue(), formed.getUnits() + "/coll"); + formed = sigmaMemoryFormat(model.getFreedMemoryByFullGC().standardDeviation()); + exportValue(out, "avgFreedMemoryByFullGC\u03c3", formed.getValue(), formed.getUnits() + "/coll"); + exportValue(out, "avgFreedMemoryByFullGCisSig", isSignificant(model.getFreedMemoryByFullGC().average(), + model.getFreedMemoryByFullGC().standardDeviation())); + if (fullGCSlopeDataVailable) { + formed = footprintSlopeFormatter.formatToFormatted(model.getPostFullGCSlope().slope()); + exportValue(out, "slopeAfterFullGC", formed.getValue(), formed.getUnits() + "/s"); + + formed = footprintSlopeFormatter.formatToFormatted(model.getRelativePostFullGCIncrease().slope()); + exportValue(out, "avgRelativePostFullGCInc", formed.getValue(), formed.getUnits() + "/coll"); + } + else { + exportValue(out, "slopeAfterFullGC", "n.a.", "M/s"); + exportValue(out, "avgRelativePostFullGCInc", "n.a.", "M/coll"); + } + } + // check whether we have gc data at all (or only full gc) + final boolean gcDataAvailable = model.getFootprintAfterGC().getN() != 0; + + if (!gcDataAvailable) { + exportValue(out, "footprintAfterGC", "n.a.", "M"); + exportValue(out, "slopeAfterGC", "n.a.", "M/s"); + exportValue(out, "freedMemoryByGC", "n.a.", "M"); + exportValue(out, "avgFreedMemoryByGC", "n.a.", "M/coll"); + exportValue(out, "avgRelativePostGCInc", "n.a.", "M/coll"); + } + else { + formed = footprintFormatter.formatToFormatted(model.getFootprintAfterGC().average()); + exportValue(out, "footprintAfterGC", formed.getValue(), formed.getUnits()); + + formed = sigmaMemoryFormat(model.getFootprintAfterGC().standardDeviation()); + exportValue(out, "footprintAfterGC\u03c3", formed.getValue(), formed.getUnits()); + exportValue(out, "footprintAfterGCisSig", isSignificant(model.getFootprintAfterGC().average(), + model.getFootprintAfterGC().standardDeviation())); + if (fullGCDataVailable && model.getRelativePostGCIncrease().getN() != 0) { + formed = footprintSlopeFormatter.formatToFormatted(model.getPostGCSlope()); + exportValue(out, "slopeAfterGC", formed.getValue(), formed.getUnits() + "/s"); + + formed = footprintSlopeFormatter.formatToFormatted(model.getRelativePostGCIncrease().average()); + exportValue(out, "avgRelativePostGCInc", formed.getValue(), formed.getUnits() + "/coll"); + } + else { + exportValue(out, "slopeAfterGC", "n.a.", "M/s"); + exportValue(out, "avgRelativePostGCInc", "n.a.", "M/coll"); + } + + formed = footprintFormatter.formatToFormatted(model.getFreedMemoryByGC().getSum()); + exportValue(out, "freedMemoryByGC", formed.getValue(), formed.getUnits()); + + exportValue(out, "freedMemoryByGCpc", percentFormatter.formatDouble(model.getFreedMemoryByGC().getSum()*100.0/model.getFreedMemory()), "%"); + + formed = footprintFormatter.formatToFormatted(model.getFreedMemoryByGC().average()); + exportValue(out, "avgFreedMemoryByGC", formed.getValue(), formed.getUnits() + "/coll"); + formed = sigmaMemoryFormat(model.getFreedMemoryByGC().standardDeviation()); + exportValue(out, "avgFreedMemoryByGC\u03c3", formed.getValue(), formed.getUnits() + "/coll"); + exportValue(out, "avgFreedMemoryByGCisSig", isSignificant(model.getFreedMemoryByGC().average(), + model.getFreedMemoryByGC().standardDeviation())); + } + formed = footprintFormatter.formatToFormatted(model.getFreedMemory()); + exportValue(out, "freedMemory", formed.getValue(), formed.getUnits()); + } + + private Formatted sigmaMemoryFormat(double value) { + if (Double.isNaN(value)) + { + StringBuffer buffer = new StringBuffer("NaN"); + return new Formatted(buffer, ' '); + } + return sigmaMemoryFormatter.formatToFormatted(value); + } +} + diff --git a/src/main/java/com/tagtraum/perf/gcviewer/util/Formatted.java b/src/main/java/com/tagtraum/perf/gcviewer/util/Formatted.java new file mode 100755 index 00000000..51029ae4 --- /dev/null +++ b/src/main/java/com/tagtraum/perf/gcviewer/util/Formatted.java @@ -0,0 +1,37 @@ +package com.tagtraum.perf.gcviewer.util; + +//@author sean +// +//class to keep the formatted amount, separate from the units. +//this makes for better export format of data. +public class Formatted { + StringBuffer bufferValue; + String units; + + public Formatted(StringBuffer toAppendTo, char units) + { + this.bufferValue = toAppendTo; + this.units = "" + units; + } + + public Formatted(StringBuffer toAppendTo, String units) + { + this.bufferValue = toAppendTo; + this.units = units; + } + + public StringBuffer getBuffer() + { + return bufferValue; + } + + public String getUnits() + { + return units; + } + + public String getValue() + { + return bufferValue.toString(); + } +} diff --git a/src/main/java/com/tagtraum/perf/gcviewer/util/MemoryFormat.java b/src/main/java/com/tagtraum/perf/gcviewer/util/MemoryFormat.java index fb253c08..2eb5f0df 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/util/MemoryFormat.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/util/MemoryFormat.java @@ -14,11 +14,12 @@ */ public class MemoryFormat extends NumberFormat { - private static final long ONE_KB = 1024; - private static final long TEN_KB = ONE_KB * 10l; - private static final long ONE_MB = 1024l * ONE_KB; - private static final long TEN_MB = ONE_MB * 10; - private NumberFormat format = NumberFormat.getInstance(); + private static final long serialVersionUID = 7269835290617687327L; + protected static final long ONE_KB = 1024; + protected static final long TEN_KB = ONE_KB * 10l; + protected static final long ONE_MB = 1024l * ONE_KB; + protected static final long TEN_MB = ONE_MB * 10; + protected NumberFormat format = NumberFormat.getInstance(); public MemoryFormat() { format.setMaximumFractionDigits(3); @@ -71,4 +72,8 @@ else if (bytes >= TEN_KB) { public Number parse(String source, ParsePosition parsePosition) { throw new RuntimeException("Not implemented."); } + + + + } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/util/MemoryFormatNoCommas.java b/src/main/java/com/tagtraum/perf/gcviewer/util/MemoryFormatNoCommas.java new file mode 100755 index 00000000..743c0fbb --- /dev/null +++ b/src/main/java/com/tagtraum/perf/gcviewer/util/MemoryFormatNoCommas.java @@ -0,0 +1,68 @@ +package com.tagtraum.perf.gcviewer.util; + +import java.text.FieldPosition; + +/** + * MemoryFormat. + *

+ * Date: Sep 17, 2005 + * Time: 5:13:32 PM + * + * @author Hendrik Schreiber + */ +public class MemoryFormatNoCommas extends MemoryFormat { + + public MemoryFormatNoCommas() { + format = new NumberFormatNoCommas(); + format.setMaximumFractionDigits(3); + } + + public Formatted formatToFormatted(double memInK) { + StringBuffer toAppendTo = new StringBuffer(); + FieldPosition pos = new FieldPosition(0); + + Formatted formed = formatToFormatted(memInK, toAppendTo, pos, false); + + return formed; + } + + protected Formatted formatToFormatted(double memInK, StringBuffer toAppendTo, FieldPosition pos, boolean bAppendUnits) { + + char units = ' '; + + int iOrigMaxFracDigits = format.getMaximumFractionDigits(); + int iOrigMinFracDigits = format.getMinimumFractionDigits(); + format.setMaximumFractionDigits(3); + format.setMinimumFractionDigits(format.getMinimumFractionDigits()); + + final double bytes = memInK * ONE_KB; + if (bytes >= TEN_MB) { + format.format(bytes / ONE_MB, toAppendTo, pos); + units = 'M'; + if(bAppendUnits) + toAppendTo.append(units); + } + else if (bytes >= TEN_KB) { + format.format(bytes / ONE_KB, toAppendTo, pos); + units = 'K'; + if(bAppendUnits) + toAppendTo.append(units); + } + else { + int maxFrac = format.getMaximumFractionDigits(); + format.setMaximumFractionDigits(0); + format.format(bytes, toAppendTo, pos); + format.setMaximumFractionDigits(maxFrac); + units = 'B'; + if(bAppendUnits) + toAppendTo.append(units); + } + + format.setMaximumFractionDigits(iOrigMaxFracDigits); + format.setMinimumFractionDigits(iOrigMinFracDigits); + + return new Formatted(toAppendTo, units); + } + + +} diff --git a/src/main/java/com/tagtraum/perf/gcviewer/util/NumberFormatNoCommas.java b/src/main/java/com/tagtraum/perf/gcviewer/util/NumberFormatNoCommas.java new file mode 100755 index 00000000..f1a72235 --- /dev/null +++ b/src/main/java/com/tagtraum/perf/gcviewer/util/NumberFormatNoCommas.java @@ -0,0 +1,73 @@ +package com.tagtraum.perf.gcviewer.util; + +import java.text.NumberFormat; +import java.text.FieldPosition; +import java.text.ParsePosition; + +/** + * @author sean + * + * Allows formatting + */ +public class NumberFormatNoCommas extends NumberFormat { + + private NumberFormat format = NumberFormat.getInstance(); + + private int iMaxFracDigits; + private int iMinFracDigits; + + public NumberFormatNoCommas() { + iMaxFracDigits = 3; + iMinFracDigits = format.getMinimumFractionDigits(); + } + + public void setMaximumFractionDigits(int newValue) { + iMaxFracDigits = newValue; + } + + public void setMinimumFractionDigits(int newValue) { + iMinFracDigits = newValue; + } + + public String formatDouble(double dVal) { + return format(dVal, new StringBuffer(), new FieldPosition(0)).toString(); + } + + public StringBuffer format(double dVal, StringBuffer toAppendTo, FieldPosition pos) { + int iOrigMaxFracDigits = format.getMaximumFractionDigits(); + int iOrigMinFracDigits = format.getMinimumFractionDigits(); + format.setMaximumFractionDigits(iMaxFracDigits); + format.setMinimumFractionDigits(iMinFracDigits); + String withCommas = format.format(dVal); //call this, to perform rounding + format.setMaximumFractionDigits(iOrigMaxFracDigits); + format.setMinimumFractionDigits(iOrigMinFracDigits); + + return removeCommas(toAppendTo, withCommas); + } + + public StringBuffer format(long lVal, StringBuffer toAppendTo, FieldPosition pos) { + String withCommas = format.format(lVal); //call this, to perform rounding + return removeCommas(toAppendTo, withCommas); + } + + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + String withCommas = format.format(obj); //call this, to perform rounding + return removeCommas(toAppendTo, withCommas); + } + + /** + * @param toAppendTo + * @param withCommas + * @return + */ + private StringBuffer removeCommas(StringBuffer toAppendTo, String withCommas) { + String noCommas = withCommas.replaceAll(",", ""); + + toAppendTo.append(noCommas); + return toAppendTo; + } + + public Number parse(String source, ParsePosition parsePosition) { + throw new RuntimeException("Not implemented."); + } +} diff --git a/src/main/java/com/tagtraum/perf/gcviewer/util/TimeFormat.java b/src/main/java/com/tagtraum/perf/gcviewer/util/TimeFormat.java old mode 100644 new mode 100755 index 0d2382f3..dace308e --- a/src/main/java/com/tagtraum/perf/gcviewer/util/TimeFormat.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/util/TimeFormat.java @@ -22,6 +22,7 @@ public class TimeFormat extends DateFormat { private static final long ONE_HOUR = ONE_MINUTE * 60l; private static final long ONE_DAY = ONE_HOUR * 24l; + private SimpleDateFormat millisFormat = new SimpleDateFormat("S"); private SimpleDateFormat secondsFormat = new SimpleDateFormat("s's'"); private SimpleDateFormat minuteFormat = new SimpleDateFormat("m'm'"); private SimpleDateFormat hourFormat = new SimpleDateFormat("H'h'"); @@ -29,10 +30,19 @@ public class TimeFormat extends DateFormat { public TimeFormat() { final TimeZone utcTimeZone = TimeZone.getTimeZone("UTC"); + millisFormat.setTimeZone(utcTimeZone); minuteFormat.setTimeZone(utcTimeZone); hourFormat.setTimeZone(utcTimeZone); } + //@author sean + public Formatted formatToFormatted(Date date) { + StringBuffer appendTo = new StringBuffer(); + appendTo.append(date.getTime() / ONE_SECOND); + Formatted formed = new Formatted(appendTo, "s"); + return formed; + } + public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { long time = date.getTime(); if (time >= ONE_DAY * 365) {