package net.minecraft.util.profiling.jfr.stats; import java.time.Duration; import java.time.Instant; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import jdk.jfr.consumer.RecordedEvent; public record GcHeapStat(Instant timestamp, long heapUsed, GcHeapStat.Timing timing) { public static GcHeapStat from(RecordedEvent event) { return new GcHeapStat( event.getStartTime(), event.getLong("heapUsed"), event.getString("when").equalsIgnoreCase("before gc") ? GcHeapStat.Timing.BEFORE_GC : GcHeapStat.Timing.AFTER_GC ); } public static GcHeapStat.Summary summary(Duration duration, List stats, Duration gcTotalDuration, int totalGCs) { return new GcHeapStat.Summary(duration, gcTotalDuration, totalGCs, calculateAllocationRatePerSecond(stats)); } private static double calculateAllocationRatePerSecond(List stats) { long l = 0L; Map> map = (Map>)stats.stream() .collect(Collectors.groupingBy(gcHeapStatx -> gcHeapStatx.timing)); List list = (List)map.get(GcHeapStat.Timing.BEFORE_GC); List list2 = (List)map.get(GcHeapStat.Timing.AFTER_GC); for (int i = 1; i < list.size(); i++) { GcHeapStat gcHeapStat = (GcHeapStat)list.get(i); GcHeapStat gcHeapStat2 = (GcHeapStat)list2.get(i - 1); l += gcHeapStat.heapUsed - gcHeapStat2.heapUsed; } Duration duration = Duration.between(((GcHeapStat)stats.get(1)).timestamp, ((GcHeapStat)stats.get(stats.size() - 1)).timestamp); return (double)l / duration.getSeconds(); } public record Summary(Duration duration, Duration gcTotalDuration, int totalGCs, double allocationRateBytesPerSecond) { public float gcOverHead() { return (float)this.gcTotalDuration.toMillis() / (float)this.duration.toMillis(); } } static enum Timing { BEFORE_GC, AFTER_GC; } }