diff --git a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/JFRAnalyzerImpl.java b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/JFRAnalyzerImpl.java index a0670fba..51fbba90 100644 --- a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/JFRAnalyzerImpl.java +++ b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/JFRAnalyzerImpl.java @@ -396,9 +396,10 @@ private void parseEventItem(IItem item) { synchronized (this.context.getEvents()) { this.context.addEvent(event); - if (event.getSettingFor() != null) { - RecordedEvent.SettingFor sf = event.getSettingFor(); - this.context.putEventTypeId(sf.getEventType(), sf.getEventId()); + if (event.getActiveSetting() != null) { + RecordedEvent.ActiveSetting activeSetting = event.getActiveSetting(); + this.context.putEventTypeId(activeSetting.eventType(), activeSetting.eventId()); + this.context.putActiveSetting(activeSetting, event); } } } diff --git a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/common/EventConstant.java b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/common/EventConstant.java index 1be02f28..646c6689 100644 --- a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/common/EventConstant.java +++ b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/common/EventConstant.java @@ -31,7 +31,7 @@ public abstract class EventConstant { public static String NATIVE_EXECUTION_SAMPLE = "jdk.NativeMethodSample"; public static String EXECUTE_VM_OPERATION = "jdk.ExecuteVMOperation"; - public static String OBJECT_ALLOCATION_SAMPLE = "jdk.ObjectAllocationSample"; // TODO + public static String OBJECT_ALLOCATION_SAMPLE = "jdk.ObjectAllocationSample"; public static String OBJECT_ALLOCATION_IN_NEW_TLAB = "jdk.ObjectAllocationInNewTLAB"; public static String OBJECT_ALLOCATION_OUTSIDE_TLAB = "jdk.ObjectAllocationOutsideTLAB"; diff --git a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/AllocatedMemoryExtractor.java b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/AllocatedMemoryExtractor.java index 32e70bc6..5963b4f0 100644 --- a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/AllocatedMemoryExtractor.java +++ b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/AllocatedMemoryExtractor.java @@ -33,35 +33,37 @@ public AllocatedMemoryExtractor(JFRAnalysisContext context) { @Override void visitObjectAllocationInNewTLAB(RecordedEvent event) { - RecordedStackTrace stackTrace = event.getStackTrace(); - if (stackTrace == null) { + if (this.useObjectAllocationSample) { return; } + this.visitTLABEvent(event, "tlabSize"); + } - AllocationsExtractor.AllocTaskData allocThreadData = getThreadData(event.getThread()); - if (allocThreadData.getSamples() == null) { - allocThreadData.setSamples(new HashMap<>()); + @Override + void visitObjectAllocationOutsideTLAB(RecordedEvent event) { + if (this.useObjectAllocationSample) { + return; } - - long eventTotal = event.getLong("tlabSize"); - - allocThreadData.getSamples().compute(stackTrace, (k, temp) -> temp == null ? eventTotal : temp + eventTotal); - allocThreadData.allocatedMemory += eventTotal; + this.visitTLABEvent(event, "allocationSize"); } @Override - void visitObjectAllocationOutsideTLAB(RecordedEvent event) { + void visitObjectAllocationSample(RecordedEvent event) { + this.visitTLABEvent(event, "weight"); + } + + void visitTLABEvent(RecordedEvent event, String fieldName) { RecordedStackTrace stackTrace = event.getStackTrace(); if (stackTrace == null) { - return; + stackTrace = StackTraceUtil.DUMMY_STACK_TRACE; } - AllocTaskData allocThreadData = getThreadData(event.getThread()); + AllocationsExtractor.AllocTaskData allocThreadData = getThreadData(event.getThread()); if (allocThreadData.getSamples() == null) { allocThreadData.setSamples(new HashMap<>()); } - long eventTotal = event.getLong("allocationSize"); + long eventTotal = event.getLong(fieldName); allocThreadData.getSamples().compute(stackTrace, (k, temp) -> temp == null ? eventTotal : temp + eventTotal); allocThreadData.allocatedMemory += eventTotal; diff --git a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/AllocationsExtractor.java b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/AllocationsExtractor.java index b31c337f..c958d738 100644 --- a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/AllocationsExtractor.java +++ b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/AllocationsExtractor.java @@ -26,12 +26,16 @@ import java.util.*; import java.util.stream.Collectors; +import static org.eclipse.jifa.jfr.common.EventConstant.OBJECT_ALLOCATION_SAMPLE; + public class AllocationsExtractor extends Extractor { + protected boolean useObjectAllocationSample; - protected static final List INTERESTED = Collections.unmodifiableList(new ArrayList() { + protected static final List INTERESTED = Collections.unmodifiableList(new ArrayList<>() { { add(EventConstant.OBJECT_ALLOCATION_IN_NEW_TLAB); add(EventConstant.OBJECT_ALLOCATION_OUTSIDE_TLAB); + add(OBJECT_ALLOCATION_SAMPLE); } }); @@ -49,6 +53,11 @@ protected static class AllocTaskData extends TaskData { public AllocationsExtractor(JFRAnalysisContext context) { super(context, INTERESTED); + try { + this.useObjectAllocationSample = this.context.getActiveSettingBool(OBJECT_ALLOCATION_SAMPLE, "enabled"); + } catch (Exception e) { + this.useObjectAllocationSample = false; + } } AllocTaskData getThreadData(RecordedThread thread) { @@ -57,9 +66,29 @@ AllocTaskData getThreadData(RecordedThread thread) { @Override void visitObjectAllocationInNewTLAB(RecordedEvent event) { + if (useObjectAllocationSample) { + return; + } + visitEvent(event); + } + + @Override + void visitObjectAllocationOutsideTLAB(RecordedEvent event) { + if (useObjectAllocationSample) { + return; + } + this.visitEvent(event); + } + + @Override + void visitObjectAllocationSample(RecordedEvent event) { + this.visitEvent(event); + } + + void visitEvent(RecordedEvent event) { RecordedStackTrace stackTrace = event.getStackTrace(); if (stackTrace == null) { - return; + stackTrace = StackTraceUtil.DUMMY_STACK_TRACE; } AllocTaskData allocThreadData = getThreadData(event.getThread()); @@ -71,11 +100,6 @@ void visitObjectAllocationInNewTLAB(RecordedEvent event) { allocThreadData.allocations += 1; } - @Override - void visitObjectAllocationOutsideTLAB(RecordedEvent event) { - this.visitObjectAllocationInNewTLAB(event); - } - private List buildThreadAllocations() { List taskAllocations = new ArrayList<>(); for (AllocTaskData data : this.data.values()) { diff --git a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/CPUSampleExtractor.java b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/CPUSampleExtractor.java index 33f4ce45..0120dbd3 100644 --- a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/CPUSampleExtractor.java +++ b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/CPUSampleExtractor.java @@ -42,7 +42,7 @@ void visitExecutionSample(RecordedEvent event) { @Override void visitActiveSetting(RecordedEvent event) { - if (this.context.isExecutionSampleEventTypeId(event.getSettingFor().getEventId())) { + if (this.context.isExecutionSampleEventTypeId(event.getActiveSetting().eventId())) { if (EventConstant.WALL.equals(event.getString("name"))) { this.isWallClockEvents = true; } diff --git a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/CPUTimeExtractor.java b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/CPUTimeExtractor.java index d2587e92..da326da9 100644 --- a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/CPUTimeExtractor.java +++ b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/CPUTimeExtractor.java @@ -79,7 +79,7 @@ private static class CpuTaskData extends TaskData { private boolean isWallClockEvents = false; - private static final RecordedStackTrace DUMMY_STACK_TRACE = newDummyStackTrace("", "", "NO Frame"); + private static final RecordedThread DUMMY_THREAD = new RecordedThread("Dummy Thread", -1L, -1L); private static final RecordedThread GC_THREAD = new RecordedThread("GC Thread", -10L, -10L); @@ -126,7 +126,7 @@ void visitGarbageCollection(RecordedEvent event) { @Override void visitActiveSetting(RecordedEvent event) { - if (event.getSettingFor().getEventId() == threadCPULoadEventId + if (event.getActiveSetting().eventId() == threadCPULoadEventId && EventConstant.PERIOD.equals(event.getString("name"))) { updatePeriod(event.getValue("value")); } @@ -135,7 +135,7 @@ void visitActiveSetting(RecordedEvent event) { this.isWallClockEvents = true; } - if (this.context.isExecutionSampleEventTypeId(event.getSettingFor().getEventId())) { + if (this.context.isExecutionSampleEventTypeId(event.getActiveSetting().eventId())) { if (EventConstant.WALL.equals(event.getString("name"))) { this.isWallClockEvents = true; } else if (EventConstant.INTERVAL.equals(event.getString("name"))) { @@ -198,7 +198,7 @@ void visitThreadCPULoad(RecordedEvent event) { void visitExecutionSample(RecordedEvent event) { RecordedStackTrace stackTrace = event.getStackTrace(); if (stackTrace == null) { - stackTrace = DUMMY_STACK_TRACE; + stackTrace = StackTraceUtil.DUMMY_STACK_TRACE; } RecordedThread thread = event.getThread("eventThread"); @@ -269,7 +269,7 @@ private List buildThreadCPUTime() { gc.setTask(context.getThread(GC_THREAD)); gc.setUser(gcTime); Map gcSamples = new HashMap<>(); - gcSamples.put(StackTraceUtil.build(newDummyStackTrace("", "JVM", "GC"), context.getSymbols()), 1L); + gcSamples.put(StackTraceUtil.build(StackTraceUtil.newDummyStackTrace("", "JVM", "GC"), context.getSymbols()), 1L); gc.setSamples(gcSamples); threadCPUTimes.add(gc); } @@ -299,22 +299,6 @@ public void fillResult(AnalysisResult result) { result.setCpuTime(cpuResult); } - private static RecordedStackTrace newDummyStackTrace(String packageName, String className, String methodName) { - RecordedStackTrace st = new RecordedStackTrace(); - List list = new ArrayList<>(); - RecordedFrame f = new RecordedFrame(); - RecordedMethod m = new RecordedMethod(); - RecordedClass c = new RecordedClass(); - c.setPackageName(packageName); - c.setName(className); - m.setType(c); - f.setMethod(m); - m.setName(methodName); - list.add(f); - st.setFrames(list); - return st; - } - private static long detectAsyncProfilerInterval() { long interval = 0; String intervalStr = System.getProperty("asyncProfilerCpuIntervalMs"); diff --git a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/EventVisitor.java b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/EventVisitor.java index a5b8e187..809508e4 100644 --- a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/EventVisitor.java +++ b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/EventVisitor.java @@ -71,6 +71,10 @@ void visitObjectAllocationOutsideTLAB(RecordedEvent event) { throw new UnsupportedOperationException(); } + void visitObjectAllocationSample(RecordedEvent event) { + throw new UnsupportedOperationException(); + } + void visitFileRead(RecordedEvent event) { throw new UnsupportedOperationException(); } diff --git a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/Extractor.java b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/Extractor.java index a7f89bab..7021ec88 100644 --- a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/Extractor.java +++ b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/Extractor.java @@ -38,6 +38,7 @@ public abstract class Extractor extends EventVisitor { put(EventConstant.EXECUTE_VM_OPERATION, EventVisitor::visitExecuteVMOperation); put(EventConstant.OBJECT_ALLOCATION_IN_NEW_TLAB, EventVisitor::visitObjectAllocationInNewTLAB); put(EventConstant.OBJECT_ALLOCATION_OUTSIDE_TLAB, EventVisitor::visitObjectAllocationOutsideTLAB); + put(EventConstant.OBJECT_ALLOCATION_SAMPLE, EventVisitor::visitObjectAllocationSample); put(EventConstant.FILE_FORCE, EventVisitor::visitFileForce); put(EventConstant.FILE_READ, EventVisitor::visitFileRead); diff --git a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/JFRAnalysisContext.java b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/JFRAnalysisContext.java index 921739e2..baaa6b7a 100644 --- a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/JFRAnalysisContext.java +++ b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/JFRAnalysisContext.java @@ -23,8 +23,11 @@ import java.util.*; +import static org.eclipse.jifa.jfr.common.EventConstant.OBJECT_ALLOCATION_SAMPLE; + public class JFRAnalysisContext { private final Map eventTypeIds = new HashMap<>(); + private final Map activeSettings = new HashMap<>(); private final Map threads = new HashMap<>(); private final Map threadNameMap = new HashMap<>(); @Getter @@ -51,13 +54,26 @@ public synchronized void putEventTypeId(String key, Long id) { } } + public synchronized void putActiveSetting(RecordedEvent.ActiveSetting activeSetting, RecordedEvent event) { + this.activeSettings.put(activeSetting, event.getString("value")); + } + + public synchronized boolean getActiveSettingBool(String eventName, String settingName) { + Long eventId = this.getEventTypeId(OBJECT_ALLOCATION_SAMPLE); + RecordedEvent.ActiveSetting setting = new RecordedEvent.ActiveSetting(eventName, eventId, settingName); + String v = this.activeSettings.get(setting); + if (v != null) { + return Boolean.parseBoolean(v); + } + throw new RuntimeException("should not reach here"); + } + public synchronized boolean isExecutionSampleEventTypeId(long id) { return executionSampleEventTypeIds.contains(id); } public synchronized JavaThread getThread(RecordedThread thread) { return threads.computeIfAbsent(thread.getJavaThreadId(), id -> { - JavaThread javaThread = new JavaThread(); javaThread.setId(id); javaThread.setJavaId(thread.getJavaThreadId()); diff --git a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/WallClockExtractor.java b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/WallClockExtractor.java index 2eea4837..087933c1 100644 --- a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/WallClockExtractor.java +++ b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/extractor/WallClockExtractor.java @@ -85,7 +85,7 @@ void visitActiveSetting(RecordedEvent event) { this.isWallClockEvents = true; } - if (event.getSettingFor().getEventId() == methodSampleEventId) { + if (event.getActiveSetting().eventId() == methodSampleEventId) { if (EventConstant.WALL.equals(event.getString("name"))) { this.isWallClockEvents = true; this.interval = Long.parseLong(event.getString("value")) * 1000 * 1000; diff --git a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/model/jfr/RecordedEvent.java b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/model/jfr/RecordedEvent.java index 3ecb4088..e76a8aea 100644 --- a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/model/jfr/RecordedEvent.java +++ b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/model/jfr/RecordedEvent.java @@ -30,6 +30,9 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; + +import static org.eclipse.jifa.jfr.common.EventConstant.ACTIVE_SETTING; @Slf4j public class RecordedEvent { @@ -46,7 +49,7 @@ public class RecordedEvent { @Getter private EventType eventType; @Getter - private SettingFor settingFor = null; + private ActiveSetting activeSetting = null; public static RecordedEvent newInstance(IItem item, SymbolTable symbols) { RecordedEvent event = new RecordedEvent(item); @@ -80,9 +83,11 @@ private void init(SymbolTable symbols) { // fix for JDK Mission Control lib if ((itemTypeId.startsWith(EventConstant.EXECUTION_SAMPLE) && !itemTypeId.equals(EventConstant.EXECUTION_SAMPLE))) { itemTypeId = EventConstant.EXECUTION_SAMPLE; - } else if (itemTypeId.startsWith(EventConstant.OBJECT_ALLOCATION_OUTSIDE_TLAB) && !itemTypeId.equals(EventConstant.OBJECT_ALLOCATION_OUTSIDE_TLAB)) { + } else if (itemTypeId.startsWith(EventConstant.OBJECT_ALLOCATION_OUTSIDE_TLAB) + && !itemTypeId.equals(EventConstant.OBJECT_ALLOCATION_OUTSIDE_TLAB)) { itemTypeId = EventConstant.OBJECT_ALLOCATION_OUTSIDE_TLAB; - } else if (itemTypeId.startsWith(EventConstant.OBJECT_ALLOCATION_IN_NEW_TLAB) && !itemTypeId.equals(EventConstant.OBJECT_ALLOCATION_IN_NEW_TLAB)) { + } else if (itemTypeId.startsWith(EventConstant.OBJECT_ALLOCATION_IN_NEW_TLAB) + && !itemTypeId.equals(EventConstant.OBJECT_ALLOCATION_IN_NEW_TLAB)) { itemTypeId = EventConstant.OBJECT_ALLOCATION_IN_NEW_TLAB; } @@ -139,15 +144,29 @@ private void init(SymbolTable symbols) { stackTrace = st; } - if ("jdk.ActiveSetting".equals(itemType.getIdentifier())) { + if (ACTIVE_SETTING.equals(itemType.getIdentifier())) { + String eventName = null; + long eventId = -1; + String settingName = null; for (Map.Entry, ? extends IDescribable> entry : itemType.getAccessorKeys().entrySet()) { - IMemberAccessor accessor = itemType.getAccessor(entry.getKey()); if (entry.getKey().getIdentifier().equals("settingFor")) { + IMemberAccessor accessor = itemType.getAccessor(entry.getKey()); LabeledIdentifier id = (LabeledIdentifier) accessor.getMember(item); - this.settingFor = new SettingFor(id.getInterfaceId(), id.getImplementationId()); + eventName = id.getInterfaceId(); + eventId = id.getImplementationId(); + continue; + } + if (entry.getKey().getIdentifier().equals("name")) { + IMemberAccessor accessor = itemType.getAccessor(entry.getKey()); + settingName = (String) accessor.getMember(item); + } + if (eventName != null && settingName != null && eventId >= 0) { break; } } + if (eventName != null && settingName != null && eventId >= 0) { + this.activeSetting = new ActiveSetting(eventName, eventId, settingName); + } } } @@ -296,14 +315,16 @@ private static String formatPackage(IMCPackage mcPackage) { return FormatToolkit.getPackage(mcPackage); } - @Getter - public static class SettingFor { - private final String eventType; - private final long eventId; + public record ActiveSetting(String eventType, Long eventId, String settingName) { + @Override + public boolean equals(Object b) { + if (!(b instanceof ActiveSetting other)) { + return false; + } - SettingFor(String eventType, long eventId) { - this.eventId = eventId; - this.eventType = eventType; + return Objects.equals(eventType, other.eventType()) + && Objects.equals(eventId, other.eventId()) + && Objects.equals(settingName, other.settingName()); } } } diff --git a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/util/StackTraceUtil.java b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/util/StackTraceUtil.java index 55349d3d..4f4ad396 100644 --- a/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/util/StackTraceUtil.java +++ b/analysis/jfr/src/main/java/org/eclipse/jifa/jfr/util/StackTraceUtil.java @@ -12,6 +12,7 @@ ********************************************************************************/ package org.eclipse.jifa.jfr.util; +import org.eclipse.jifa.jfr.model.jfr.RecordedClass; import org.eclipse.jifa.jfr.model.jfr.RecordedFrame; import org.eclipse.jifa.jfr.model.jfr.RecordedMethod; import org.eclipse.jifa.jfr.model.jfr.RecordedStackTrace; @@ -22,9 +23,12 @@ import org.eclipse.jifa.jfr.model.Frame; import org.eclipse.jifa.jfr.model.StackTrace; +import java.util.ArrayList; import java.util.List; public class StackTraceUtil { + public static final RecordedStackTrace DUMMY_STACK_TRACE = StackTraceUtil.newDummyStackTrace("", "", "NO Frame"); + // FIXME: need cache public static StackTrace build(RecordedStackTrace stackTrace, SymbolTable symbols) { StackTrace result = new StackTrace(); @@ -80,4 +84,20 @@ public static StackTrace build(RecordedStackTrace stackTrace, SymbolTable list = new ArrayList<>(); + RecordedFrame f = new RecordedFrame(); + RecordedMethod m = new RecordedMethod(); + RecordedClass c = new RecordedClass(); + c.setPackageName(packageName); + c.setName(className); + m.setType(c); + f.setMethod(m); + m.setName(methodName); + list.add(f); + st.setFrames(list); + return st; + } } diff --git a/analysis/jfr/src/test/java/org/eclipse/jifa/jfr/TestJFRAnalyzer.java b/analysis/jfr/src/test/java/org/eclipse/jifa/jfr/TestJFRAnalyzer.java index 7b317b57..39a47e21 100644 --- a/analysis/jfr/src/test/java/org/eclipse/jifa/jfr/TestJFRAnalyzer.java +++ b/analysis/jfr/src/test/java/org/eclipse/jifa/jfr/TestJFRAnalyzer.java @@ -225,6 +225,31 @@ public void testAllocations() throws IOException { Assertions.assertEquals("99.92", t.get().getRight()); } + @Test + public void testAllocations2() throws IOException { + Path path = createTmpFileForResource("object-allocation-sample.jfr"); + JFRAnalyzerImpl analyzer = new JFRAnalyzerImpl(path, DimensionBuilder.ALLOC, null, ProgressListener.NoOpProgressListener); + AnalysisResult result = analyzer.getResult(); + Assertions.assertNotNull(result.getAllocations()); + + List taskAllocations = result.getAllocations().getList(); + Optional optional = + taskAllocations.stream().filter(item -> item.getTask().getName().equals("main")).findAny(); + Assertions.assertTrue(optional.isPresent()); + TaskAllocations ta = optional.get(); + SimpleFlameGraph g = SimpleFlameGraph.parse(ta); + Assertions.assertEquals(327, g.totalSampleValue.intValue()); + + List> list = g.queryLeafNodes(10); + Assertions.assertEquals(list.size(), 1); + + Optional> t = + list.stream().filter(item -> item.getLeft().contains("alloc(int)")).findAny(); + Assertions.assertTrue(t.isPresent()); + Assertions.assertEquals(321, Long.valueOf(t.get().getMiddle())); + Assertions.assertEquals("98.17", t.get().getRight()); + } + @Test public void testAllocatedMemory() throws IOException { Path path = createTmpFileForResource("jfr.jfr"); @@ -250,6 +275,31 @@ public void testAllocatedMemory() throws IOException { Assertions.assertEquals("99.98", t.get().getRight()); } + @Test + public void testAllocatedMemory2() throws IOException { + Path path = createTmpFileForResource("object-allocation-sample.jfr"); + JFRAnalyzerImpl analyzer = new JFRAnalyzerImpl(path, DimensionBuilder.MEM, null, ProgressListener.NoOpProgressListener); + AnalysisResult result = analyzer.getResult(); + Assertions.assertNotNull(result.getAllocatedMemory()); + + List taskAllocations = result.getAllocatedMemory().getList(); + Optional optional = + taskAllocations.stream().filter(item -> item.getTask().getName().equals("main")).findAny(); + Assertions.assertTrue(optional.isPresent()); + TaskAllocatedMemory ta = optional.get(); + SimpleFlameGraph g = SimpleFlameGraph.parse(ta); + Assertions.assertEquals(12638637000L, g.totalSampleValue.longValue()); + + List> list = g.queryLeafNodes(10); + Assertions.assertEquals(list.size(), 1); + + Optional> t = + list.stream().filter(item -> item.getLeft().contains("alloc(int)")).findAny(); + Assertions.assertTrue(t.isPresent()); + Assertions.assertEquals(12615151608L, Long.valueOf(t.get().getMiddle())); + Assertions.assertEquals("99.81", t.get().getRight()); + } + @Test public void testCpuAndAllocAndMem() throws IOException { Path path = createTmpFileForResource("jfr.jfr"); diff --git a/analysis/jfr/src/test/resources/object-allocation-sample.jfr b/analysis/jfr/src/test/resources/object-allocation-sample.jfr new file mode 100644 index 00000000..f866bdb4 Binary files /dev/null and b/analysis/jfr/src/test/resources/object-allocation-sample.jfr differ