diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReaderSun.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReaderSun.java index 00e6b06b..25f84c27 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReaderSun.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReaderSun.java @@ -66,18 +66,18 @@ public AbstractDataReaderSun(InputStream in, GcLogType gcLogType) throws Unsuppo * @param line line that is parsed * @return amount of memory in kilobyte */ - private int getMemoryInKiloByte(int memoryValue, char memUnit, String line) { + private int getMemoryInKiloByte(double memoryValue, char memUnit, String line) { if ('B' == memUnit) { - return memoryValue / 1024; + return (int) (memoryValue / 1024); } else if ('K' == memUnit) { - return memoryValue; + return (int) memoryValue; } else if ('M' == memUnit) { - return memoryValue * 1024; + return (int) (memoryValue * 1024); } else if ('G' == memUnit) { - return memoryValue * 1024*1024; + return (int) (memoryValue * 1024*1024); } else { if (LOG.isLoggable(Level.WARNING)) { @@ -142,7 +142,7 @@ protected void setMemoryExtended(GCEvent event, String line, ParsePosition pos) // if format is "before"->"after"("total"), the next parentesis is the one of the "total" endOfNextNumber = separatorPos; } - event.setPreUsed(getMemoryInKiloByte(NumberParser.parseInt(line, currentPos, endOfNextNumber-currentPos-1), + event.setPreUsed(getMemoryInKiloByte(NumberParser.parseDouble(line, currentPos, endOfNextNumber-currentPos-1), line.charAt(endOfNextNumber-1), line)); @@ -158,13 +158,13 @@ protected void setMemoryExtended(GCEvent event, String line, ParsePosition pos) endOfNextNumber = currentPos; // goto end of next number - while (Character.isDigit(line.charAt(endOfNextNumber))) { + for (char c = line.charAt(endOfNextNumber); Character.isDigit(c) || c == '.'; c = line.charAt(endOfNextNumber)) { ++endOfNextNumber; } ++endOfNextNumber; } - event.setPostUsed(getMemoryInKiloByte(NumberParser.parseInt(line, currentPos, endOfNextNumber-currentPos-1), + event.setPostUsed(getMemoryInKiloByte(NumberParser.parseDouble(line, currentPos, endOfNextNumber-currentPos-1), line.charAt(endOfNextNumber-1), line)); currentPos = endOfNextNumber; @@ -173,7 +173,7 @@ protected void setMemoryExtended(GCEvent event, String line, ParsePosition pos) // skip "(" and read heap size ++currentPos; endOfNextNumber = line.indexOf(")", currentPos); - event.setTotal(getMemoryInKiloByte(NumberParser.parseInt(line, currentPos, endOfNextNumber-currentPos-1), + event.setTotal(getMemoryInKiloByte(NumberParser.parseDouble(line, currentPos, endOfNextNumber-currentPos-1), line.charAt(endOfNextNumber-1), line)); currentPos = endOfNextNumber; diff --git a/src/main/java/com/tagtraum/perf/gcviewer/util/NumberParser.java b/src/main/java/com/tagtraum/perf/gcviewer/util/NumberParser.java index 7473b7e3..2bdb0e1f 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/util/NumberParser.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/util/NumberParser.java @@ -208,4 +208,12 @@ public static long parseLong(char[] cb, int offset, int length) throws NumberFor return -result; } } + + public static double parseDouble(String s, int offset, int length) { + // Currently, this method is unlikely to be as efficient as those above. + // This logic is factored out so as to allow future optimisations. For + // example, we might want to make some simplifying assumptions about the + // kind of doubles present in GC logs. + return Double.parseDouble(s.substring(offset, offset + length)); + } } diff --git a/src/test/java/com/tagtraum/perf/gcviewer/imp/TestAbstractDataReaderSun.java b/src/test/java/com/tagtraum/perf/gcviewer/imp/TestAbstractDataReaderSun.java index 15c81f2b..30bf44e2 100644 --- a/src/test/java/com/tagtraum/perf/gcviewer/imp/TestAbstractDataReaderSun.java +++ b/src/test/java/com/tagtraum/perf/gcviewer/imp/TestAbstractDataReaderSun.java @@ -77,6 +77,23 @@ public void setMemorySimplePreHeap_postHeap() throws ParseException { assertEquals("heap after", 4000, event.getPostUsed()); } + /** + * Tests parsing of memory information like "118.5M(118.0M)->128.4K(112.0M)" (notice the dots). + */ + @Test + public void setExtendedMemoryFloatingPointPreEden_postEden() throws ParseException { + String line = " [Eden: 118.5M(118.0M)->128.4K(112.0M) Survivors: 10.0M->16.0M Heap: 548.6M(640.0M)->440.6M(640.0M)]"; + + ParsePosition pos = new ParsePosition(0); + pos.setIndex(line.indexOf("Eden:") + "Eden:".length() + 1); + + GCEvent event = new GCEvent(); + dataReader.setMemoryExtended(event, line, pos); + + assertEquals("heap before", 121344, event.getPreUsed()); + assertEquals("heap after", 128, event.getPostUsed()); + } + /** * Subclass of {@link AbstractDataReaderSun} which makes those methods public, I want to test here. *