From 2c8886631ac4a3dd5c1fae6ba53c875372a6f166 Mon Sep 17 00:00:00 2001 From: Lukas Bloder Date: Fri, 24 Oct 2025 09:38:32 +0200 Subject: [PATCH 1/3] remove vendored code and upgrade to async profiler 4.2 --- .../api/sentry-async-profiler.api | 299 +------- sentry-async-profiler/build.gradle.kts | 3 +- ...AsyncProfilerToSentryProfileConverter.java | 17 +- .../convert/NonAggregatingEventCollector.java | 4 +- .../profiling/JavaContinuousProfiler.java | 5 +- .../asyncprofiler/convert/Arguments.java | 132 ---- .../asyncprofiler/convert/Classifier.java | 156 ---- .../vendor/asyncprofiler/convert/Frame.java | 68 -- .../asyncprofiler/convert/JfrConverter.java | 300 -------- .../vendor/asyncprofiler/jfr/ClassRef.java | 17 - .../vendor/asyncprofiler/jfr/Dictionary.java | 116 --- .../asyncprofiler/jfr/DictionaryInt.java | 125 --- .../vendor/asyncprofiler/jfr/Element.java | 18 - .../vendor/asyncprofiler/jfr/JfrClass.java | 44 -- .../vendor/asyncprofiler/jfr/JfrField.java | 24 - .../vendor/asyncprofiler/jfr/JfrReader.java | 714 ------------------ .../vendor/asyncprofiler/jfr/MethodRef.java | 21 - .../vendor/asyncprofiler/jfr/StackTrace.java | 21 - .../jfr/event/AllocationSample.java | 47 -- .../asyncprofiler/jfr/event/CPULoad.java | 23 - .../jfr/event/ContendedLock.java | 44 -- .../vendor/asyncprofiler/jfr/event/Event.java | 68 -- .../jfr/event/EventAggregator.java | 157 ---- .../jfr/event/EventCollector.java | 27 - .../jfr/event/ExecutionSample.java | 30 - .../jfr/event/GCHeapSummary.java | 30 - .../asyncprofiler/jfr/event/LiveObject.java | 47 -- .../asyncprofiler/jfr/event/MallocEvent.java | 25 - .../jfr/event/MallocLeakAggregator.java | 69 -- .../asyncprofiler/jfr/event/ObjectCount.java | 25 - 30 files changed, 24 insertions(+), 2652 deletions(-) delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/Arguments.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/Classifier.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/Frame.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/JfrConverter.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/ClassRef.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/DictionaryInt.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Element.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrClass.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrField.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrReader.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/MethodRef.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/StackTrace.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/AllocationSample.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/CPULoad.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/ContendedLock.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventAggregator.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/ExecutionSample.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/GCHeapSummary.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/LiveObject.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/MallocEvent.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/MallocLeakAggregator.java delete mode 100644 sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/ObjectCount.java diff --git a/sentry-async-profiler/api/sentry-async-profiler.api b/sentry-async-profiler/api/sentry-async-profiler.api index 6366fccc24b..045465349c2 100644 --- a/sentry-async-profiler/api/sentry-async-profiler.api +++ b/sentry-async-profiler/api/sentry-async-profiler.api @@ -3,18 +3,18 @@ public final class io/sentry/asyncprofiler/BuildConfig { public static final field VERSION_NAME Ljava/lang/String; } -public final class io/sentry/asyncprofiler/convert/JfrAsyncProfilerToSentryProfileConverter : io/sentry/asyncprofiler/vendor/asyncprofiler/convert/JfrConverter { - public fun (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrReader;Lio/sentry/asyncprofiler/vendor/asyncprofiler/convert/Arguments;Lio/sentry/SentryStackTraceFactory;Lio/sentry/ILogger;)V +public final class io/sentry/asyncprofiler/convert/JfrAsyncProfilerToSentryProfileConverter : one/convert/JfrConverter { + public fun (Lone/jfr/JfrReader;Lone/convert/Arguments;Lio/sentry/SentryStackTraceFactory;Lio/sentry/ILogger;)V public static fun convertFromFileStatic (Ljava/lang/String;)Lio/sentry/protocol/profiling/SentryProfile; } -public final class io/sentry/asyncprofiler/convert/NonAggregatingEventCollector : io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector { +public final class io/sentry/asyncprofiler/convert/NonAggregatingEventCollector : one/jfr/event/EventCollector { public fun ()V public fun afterChunk ()V public fun beforeChunk ()V - public fun collect (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event;)V + public fun collect (Lone/jfr/event/Event;)V public fun finish ()Z - public fun forEach (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector$Visitor;)V + public fun forEach (Lone/jfr/event/EventCollector$Visitor;)V } public final class io/sentry/asyncprofiler/profiling/JavaContinuousProfiler : io/sentry/IContinuousProfiler, io/sentry/transport/RateLimiter$IRateLimitObserver { @@ -45,292 +45,3 @@ public final class io/sentry/asyncprofiler/provider/AsyncProfilerProfileConverte public fun convertFromFile (Ljava/lang/String;)Lio/sentry/protocol/profiling/SentryProfile; } -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/convert/Arguments { - public field alloc Z - public field bci Z - public field classify Z - public field cpu Z - public field dot Z - public field exclude Ljava/util/regex/Pattern; - public final field files Ljava/util/List; - public field from J - public field grain D - public field help Z - public field highlight Ljava/lang/String; - public field include Ljava/util/regex/Pattern; - public field inverted Z - public field leak Z - public field lines Z - public field live Z - public field lock Z - public field minwidth D - public field nativemem Z - public field norm Z - public field output Ljava/lang/String; - public field reverse Z - public field simple Z - public field skip I - public field state Ljava/lang/String; - public field threads Z - public field title Ljava/lang/String; - public field to J - public field total Z - public field wall Z - public fun ([Ljava/lang/String;)V -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/convert/Frame : java/util/HashMap { - public static final field TYPE_C1_COMPILED B - public static final field TYPE_CPP B - public static final field TYPE_INLINED B - public static final field TYPE_INTERPRETED B - public static final field TYPE_JIT_COMPILED B - public static final field TYPE_KERNEL B - public static final field TYPE_NATIVE B -} - -public abstract class io/sentry/asyncprofiler/vendor/asyncprofiler/convert/JfrConverter { - protected final field args Lio/sentry/asyncprofiler/vendor/asyncprofiler/convert/Arguments; - protected final field collector Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector; - protected final field jfr Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrReader; - protected field methodNames Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary; - public fun (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrReader;Lio/sentry/asyncprofiler/vendor/asyncprofiler/convert/Arguments;)V - protected fun collectEvents ()V - public fun convert ()V - protected fun convertChunk ()V - protected fun createCollector (Lio/sentry/asyncprofiler/vendor/asyncprofiler/convert/Arguments;)Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector; - public synthetic fun getCategory (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/StackTrace;)Lio/sentry/asyncprofiler/vendor/asyncprofiler/convert/Classifier$Category; - public fun getClassName (J)Ljava/lang/String; - public fun getMethodName (JB)Ljava/lang/String; - public fun getPlainThreadName (I)Ljava/lang/String; - public fun getStackTraceElement (JBI)Ljava/lang/StackTraceElement; - public fun getThreadName (I)Ljava/lang/String; - protected fun getThreadStates (Z)Ljava/util/BitSet; - protected fun isNativeFrame (B)Z - protected fun toThreadState (Ljava/lang/String;)I - protected fun toTicks (J)J -} - -protected abstract class io/sentry/asyncprofiler/vendor/asyncprofiler/convert/JfrConverter$AggregatedEventVisitor : io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector$Visitor { - protected fun (Lio/sentry/asyncprofiler/vendor/asyncprofiler/convert/JfrConverter;)V - protected abstract fun visit (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event;J)V - public final fun visit (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event;JJ)V -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/ClassRef { - public final field name J - public fun (J)V -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary { - public fun ()V - public fun (I)V - public fun clear ()V - public fun forEach (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary$Visitor;)V - public fun get (J)Ljava/lang/Object; - public fun preallocate (I)I - public fun put (JLjava/lang/Object;)V - public fun size ()I -} - -public abstract interface class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary$Visitor { - public abstract fun visit (JLjava/lang/Object;)V -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/DictionaryInt { - public fun ()V - public fun (I)V - public fun clear ()V - public fun forEach (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/DictionaryInt$Visitor;)V - public fun get (J)I - public fun get (JI)I - public fun preallocate (I)I - public fun put (JI)V -} - -public abstract interface class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/DictionaryInt$Visitor { - public abstract fun visit (JI)V -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrClass { - public fun field (Ljava/lang/String;)Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrField; -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrField { -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrReader : java/io/Closeable { - public field chunkEndNanos J - public field chunkStartNanos J - public field chunkStartTicks J - public final field classes Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary; - public field endNanos J - public final field enums Ljava/util/Map; - public final field javaThreads Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary; - public final field methods Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary; - public final field settings Ljava/util/Map; - public final field stackTraces Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary; - public field startNanos J - public field startTicks J - public field stopAtNewChunk Z - public final field strings Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary; - public final field symbols Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary; - public final field threads Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary; - public field ticksPerSec J - public final field types Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary; - public final field typesByName Ljava/util/Map; - public fun (Ljava/lang/String;)V - public fun (Ljava/nio/ByteBuffer;)V - public fun close ()V - public fun durationNanos ()J - public fun eof ()Z - public fun getBytes ()[B - public fun getDouble ()D - public fun getEnumKey (Ljava/lang/String;Ljava/lang/String;)I - public fun getEnumValue (Ljava/lang/String;I)Ljava/lang/String; - public fun getFloat ()F - public fun getString ()Ljava/lang/String; - public fun getVarint ()I - public fun getVarlong ()J - public fun hasMoreChunks ()Z - public fun incomplete ()Z - public fun readAllEvents ()Ljava/util/List; - public fun readAllEvents (Ljava/lang/Class;)Ljava/util/List; - public fun readEvent ()Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event; - public fun readEvent (Ljava/lang/Class;)Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event; - public fun registerEvent (Ljava/lang/String;Ljava/lang/Class;)V -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/MethodRef { - public final field cls J - public final field name J - public final field sig J - public fun (JJJ)V -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/StackTrace { - public final field locations [I - public final field methods [J - public final field types [B - public fun ([J[B[I)V -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/AllocationSample : io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event { - public final field allocationSize J - public final field classId I - public final field tlabSize J - public fun (JIIIJJ)V - public fun classId ()J - public fun hashCode ()I - public fun sameGroup (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event;)Z - public fun value ()J -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/CPULoad : io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event { - public final field jvmSystem F - public final field jvmUser F - public final field machineTotal F - public fun (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrReader;)V -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/ContendedLock : io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event { - public final field classId I - public final field duration J - public fun (JIIJI)V - public fun classId ()J - public fun hashCode ()I - public fun sameGroup (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event;)Z - public fun value ()J -} - -public abstract class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event : java/lang/Comparable { - public final field stackTraceId I - public final field tid I - public final field time J - protected fun (JII)V - public fun classId ()J - public fun compareTo (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event;)I - public synthetic fun compareTo (Ljava/lang/Object;)I - public fun hashCode ()I - public fun sameGroup (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event;)Z - public fun samples ()J - public fun toString ()Ljava/lang/String; - public fun value ()J -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventAggregator : io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector { - public fun (ZD)V - public fun afterChunk ()V - public fun beforeChunk ()V - public fun coarsen (D)V - public fun collect (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event;)V - public fun collect (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event;JJ)V - public fun finish ()Z - public fun forEach (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector$Visitor;)V - public fun size ()I -} - -public abstract interface class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector { - public abstract fun afterChunk ()V - public abstract fun beforeChunk ()V - public abstract fun collect (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event;)V - public abstract fun finish ()Z - public abstract fun forEach (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector$Visitor;)V -} - -public abstract interface class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector$Visitor { - public abstract fun visit (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event;JJ)V -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/ExecutionSample : io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event { - public final field samples I - public final field threadState I - public fun (JIIII)V - public fun samples ()J - public fun value ()J -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/GCHeapSummary : io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event { - public final field afterGC Z - public final field committed J - public final field gcId I - public final field reserved J - public final field used J - public fun (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrReader;)V -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/LiveObject : io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event { - public final field allocationSize J - public final field allocationTime J - public final field classId I - public fun (JIIIJJ)V - public fun classId ()J - public fun hashCode ()I - public fun sameGroup (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event;)Z - public fun value ()J -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/MallocEvent : io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event { - public final field address J - public final field size J - public fun (JIIJJ)V - public fun value ()J -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/MallocLeakAggregator : io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector { - public fun (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector;)V - public fun afterChunk ()V - public fun beforeChunk ()V - public fun collect (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event;)V - public fun finish ()Z - public fun forEach (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector$Visitor;)V -} - -public final class io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/ObjectCount : io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event { - public final field classId I - public final field count J - public final field gcId I - public final field totalSize J - public fun (Lio/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrReader;)V -} - diff --git a/sentry-async-profiler/build.gradle.kts b/sentry-async-profiler/build.gradle.kts index 5b78d5b99e4..d2cf0a44c87 100644 --- a/sentry-async-profiler/build.gradle.kts +++ b/sentry-async-profiler/build.gradle.kts @@ -20,7 +20,8 @@ kotlin { explicitApi() } dependencies { api(projects.sentry) - implementation("tools.profiler:async-profiler:3.0") + implementation("tools.profiler:async-profiler:4.2") + implementation("tools.profiler:jfr-converter:4.2") compileOnly(libs.jetbrains.annotations) compileOnly(libs.nopen.annotations) diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/convert/JfrAsyncProfilerToSentryProfileConverter.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/convert/JfrAsyncProfilerToSentryProfileConverter.java index f6db9a86ab3..b7b5662a8e5 100644 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/convert/JfrAsyncProfilerToSentryProfileConverter.java +++ b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/convert/JfrAsyncProfilerToSentryProfileConverter.java @@ -5,12 +5,6 @@ import io.sentry.Sentry; import io.sentry.SentryLevel; import io.sentry.SentryStackTraceFactory; -import io.sentry.asyncprofiler.vendor.asyncprofiler.convert.Arguments; -import io.sentry.asyncprofiler.vendor.asyncprofiler.convert.JfrConverter; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.JfrReader; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.StackTrace; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.Event; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.EventCollector; import io.sentry.protocol.SentryStackFrame; import io.sentry.protocol.profiling.SentryProfile; import io.sentry.protocol.profiling.SentrySample; @@ -20,6 +14,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import one.convert.Arguments; +import one.convert.JfrConverter; +import one.jfr.JfrReader; +import one.jfr.StackTrace; +import one.jfr.event.Event; +import one.jfr.event.EventCollector; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -247,6 +247,11 @@ private String extractSanitizedClassName(String classNameWithLambdas) { } } + private String getPlainThreadName(int tid) { + String threadName = jfr.threads.get(tid); + return threadName == null ? "[tid=" + tid + ']' : threadName; + } + private boolean hasPackageStructure(String className) { return className.lastIndexOf('.') > 0; } diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/convert/NonAggregatingEventCollector.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/convert/NonAggregatingEventCollector.java index c39259b7799..da42b34868b 100644 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/convert/NonAggregatingEventCollector.java +++ b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/convert/NonAggregatingEventCollector.java @@ -1,9 +1,9 @@ package io.sentry.asyncprofiler.convert; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.Event; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.EventCollector; import java.util.ArrayList; import java.util.List; +import one.jfr.event.Event; +import one.jfr.event.EventCollector; import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java index 7af3032f9ae..8abd9a2d895 100644 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java +++ b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java @@ -230,7 +230,10 @@ private void start() { // Example command: start,jfr,event=wall,interval=9900us,file=/path/to/trace.jfr final String command = String.format( - "start,jfr,event=wall,interval=%s,file=%s", profilingIntervalMicros, filename); + "start,jfr,event=wall,nobatch,interval=%s,file=%s", + profilingIntervalMicros, filename); + + logger.log(SentryLevel.INFO, command); profiler.execute(command); diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/Arguments.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/Arguments.java deleted file mode 100644 index f3b44fccc09..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/Arguments.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.convert; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.*; -import java.util.regex.Pattern; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -@ApiStatus.Internal -public final class Arguments { - public @NotNull String title = "Flame Graph"; - public @Nullable String highlight; - public @Nullable String output; - public @Nullable String state; - public @Nullable Pattern include; - public @Nullable Pattern exclude; - public double minwidth; - public double grain; - public int skip; - public boolean help; - public boolean reverse; - public boolean inverted; - public boolean cpu; - public boolean wall; - public boolean alloc; - public boolean nativemem; - public boolean leak; - public boolean live; - public boolean lock; - public boolean threads; - public boolean classify; - public boolean total; - public boolean lines; - public boolean bci; - public boolean simple; - public boolean norm; - public boolean dot; - public long from; - public long to; - public final List files = new ArrayList<>(); - - public Arguments(String... args) { - for (int i = 0; i < args.length; i++) { - String arg = args[i]; - String fieldName; - if (arg.startsWith("--")) { - fieldName = arg.substring(2); - } else if (arg.startsWith("-") && arg.length() == 2) { - fieldName = alias(arg.charAt(1)); - } else { - files.add(arg); - continue; - } - - try { - Field f = Arguments.class.getDeclaredField(fieldName); - if ((f.getModifiers() & (Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL)) != 0) { - throw new IllegalArgumentException(arg); - } - - Class type = f.getType(); - if (type == String.class) { - f.set(this, args[++i]); - } else if (type == boolean.class) { - f.setBoolean(this, true); - } else if (type == int.class) { - f.setInt(this, Integer.parseInt(args[++i])); - } else if (type == double.class) { - f.setDouble(this, Double.parseDouble(args[++i])); - } else if (type == long.class) { - f.setLong(this, parseTimestamp(args[++i])); - } else if (type == Pattern.class) { - f.set(this, Pattern.compile(args[++i])); - } - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new IllegalArgumentException(arg); - } - } - } - - private static String alias(char c) { - switch (c) { - case 'h': - return "help"; - case 'o': - return "output"; - case 'r': - return "reverse"; - case 'i': - return "inverted"; - case 'I': - return "include"; - case 'X': - return "exclude"; - case 't': - return "threads"; - case 's': - return "state"; - default: - return String.valueOf(c); - } - } - - // Milliseconds or HH:mm:ss.S or yyyy-MM-dd'T'HH:mm:ss.S - private static long parseTimestamp(String time) { - if (time.indexOf(':') < 0) { - return Long.parseLong(time); - } - - GregorianCalendar cal = new GregorianCalendar(); - StringTokenizer st = new StringTokenizer(time, "-:.T"); - - if (time.indexOf('T') > 0) { - cal.set(Calendar.YEAR, Integer.parseInt(st.nextToken())); - cal.set(Calendar.MONTH, Integer.parseInt(st.nextToken()) - 1); - cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(st.nextToken())); - } - cal.set(Calendar.HOUR_OF_DAY, st.hasMoreTokens() ? Integer.parseInt(st.nextToken()) : 0); - cal.set(Calendar.MINUTE, st.hasMoreTokens() ? Integer.parseInt(st.nextToken()) : 0); - cal.set(Calendar.SECOND, st.hasMoreTokens() ? Integer.parseInt(st.nextToken()) : 0); - cal.set(Calendar.MILLISECOND, st.hasMoreTokens() ? Integer.parseInt(st.nextToken()) : 0); - - return cal.getTimeInMillis(); - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/Classifier.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/Classifier.java deleted file mode 100644 index ec955870930..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/Classifier.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.convert; - -import static io.sentry.asyncprofiler.vendor.asyncprofiler.convert.Frame.*; - -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.StackTrace; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -@ApiStatus.Internal -abstract class Classifier { - - enum Category { - GC("[gc]", TYPE_CPP), - JIT("[jit]", TYPE_CPP), - VM("[vm]", TYPE_CPP), - VTABLE_STUBS("[vtable_stubs]", TYPE_NATIVE), - NATIVE("[native]", TYPE_NATIVE), - INTERPRETER("[Interpreter]", TYPE_NATIVE), - C1_COMP("[c1_comp]", TYPE_C1_COMPILED), - C2_COMP("[c2_comp]", TYPE_INLINED), - ADAPTER("[c2i_adapter]", TYPE_INLINED), - CLASS_INIT("[class_init]", TYPE_CPP), - CLASS_LOAD("[class_load]", TYPE_CPP), - CLASS_RESOLVE("[class_resolve]", TYPE_CPP), - CLASS_VERIFY("[class_verify]", TYPE_CPP), - LAMBDA_INIT("[lambda_init]", TYPE_CPP); - - final String title; - final byte type; - - Category(String title, byte type) { - this.title = title; - this.type = type; - } - } - - public @Nullable Category getCategory(@NotNull StackTrace stackTrace) { - long[] methods = stackTrace.methods; - byte[] types = stackTrace.types; - - Category category; - if ((category = detectGcJit(methods, types)) == null - && (category = detectClassLoading(methods, types)) == null) { - category = detectOther(methods, types); - } - return category; - } - - private @Nullable Category detectGcJit(long[] methods, byte[] types) { - boolean vmThread = false; - for (int i = types.length; --i >= 0; ) { - if (types[i] == TYPE_CPP) { - switch (getMethodName(methods[i], types[i])) { - case "CompileBroker::compiler_thread_loop": - return Category.JIT; - case "GCTaskThread::run": - case "WorkerThread::run": - return Category.GC; - case "java_start": - case "thread_native_entry": - vmThread = true; - break; - } - } else if (types[i] != TYPE_NATIVE) { - break; - } - } - return vmThread ? Category.VM : null; - } - - private @Nullable Category detectClassLoading(long[] methods, byte[] types) { - for (int i = 0; i < methods.length; i++) { - String methodName = getMethodName(methods[i], types[i]); - if (methodName.equals("Verifier::verify")) { - return Category.CLASS_VERIFY; - } else if (methodName.startsWith("InstanceKlass::initialize")) { - return Category.CLASS_INIT; - } else if (methodName.startsWith("LinkResolver::") - || methodName.startsWith("InterpreterRuntime::resolve") - || methodName.startsWith("SystemDictionary::resolve")) { - return Category.CLASS_RESOLVE; - } else if (methodName.endsWith("ClassLoader.loadClass")) { - return Category.CLASS_LOAD; - } else if (methodName.endsWith("LambdaMetafactory.metafactory") - || methodName.endsWith("LambdaMetafactory.altMetafactory")) { - return Category.LAMBDA_INIT; - } else if (methodName.endsWith("table stub")) { - return Category.VTABLE_STUBS; - } else if (methodName.equals("Interpreter")) { - return Category.INTERPRETER; - } else if (methodName.startsWith("I2C/C2I")) { - return i + 1 < types.length && types[i + 1] == TYPE_INTERPRETED - ? Category.INTERPRETER - : Category.ADAPTER; - } - } - return null; - } - - private @NotNull Category detectOther(long[] methods, byte[] types) { - boolean inJava = true; - for (int i = 0; i < types.length; i++) { - switch (types[i]) { - case TYPE_INTERPRETED: - return inJava ? Category.INTERPRETER : Category.NATIVE; - case TYPE_JIT_COMPILED: - return inJava ? Category.C2_COMP : Category.NATIVE; - case TYPE_INLINED: - inJava = true; - break; - case TYPE_NATIVE: - { - String methodName = getMethodName(methods[i], types[i]); - if (methodName.startsWith("JVM_") - || methodName.startsWith("Unsafe_") - || methodName.startsWith("MHN_") - || methodName.startsWith("jni_")) { - return Category.VM; - } - switch (methodName) { - case "call_stub": - case "deoptimization": - case "unknown_Java": - case "not_walkable_Java": - case "InlineCacheBuffer": - return Category.VM; - } - if (methodName.endsWith("_arraycopy") || methodName.contains("pthread_cond")) { - break; - } - inJava = false; - break; - } - case TYPE_CPP: - { - String methodName = getMethodName(methods[i], types[i]); - if (methodName.startsWith("Runtime1::")) { - return Category.C1_COMP; - } - break; - } - case TYPE_C1_COMPILED: - return inJava ? Category.C1_COMP : Category.NATIVE; - } - } - return Category.NATIVE; - } - - protected abstract @NotNull String getMethodName(long method, byte type); -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/Frame.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/Frame.java deleted file mode 100644 index bb9768442c4..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/Frame.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.convert; - -import java.util.HashMap; -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public final class Frame extends HashMap { - private static final long serialVersionUID = 1L; - public static final byte TYPE_INTERPRETED = 0; - public static final byte TYPE_JIT_COMPILED = 1; - public static final byte TYPE_INLINED = 2; - public static final byte TYPE_NATIVE = 3; - public static final byte TYPE_CPP = 4; - public static final byte TYPE_KERNEL = 5; - public static final byte TYPE_C1_COMPILED = 6; - - private static final int TYPE_SHIFT = 28; - - final int key; - long total; - long self; - long inlined, c1, interpreted; - - private Frame(int key) { - this.key = key; - } - - Frame(int titleIndex, byte type) { - this(titleIndex | type << TYPE_SHIFT); - } - - Frame getChild(int titleIndex, byte type) { - return super.computeIfAbsent(titleIndex | type << TYPE_SHIFT, Frame::new); - } - - int getTitleIndex() { - return key & ((1 << TYPE_SHIFT) - 1); - } - - byte getType() { - if (inlined * 3 >= total) { - return TYPE_INLINED; - } else if (c1 * 2 >= total) { - return TYPE_C1_COMPILED; - } else if (interpreted * 2 >= total) { - return TYPE_INTERPRETED; - } else { - return (byte) (key >>> TYPE_SHIFT); - } - } - - int depth(long cutoff) { - int depth = 0; - if (size() > 0) { - for (Frame child : values()) { - if (child.total >= cutoff) { - depth = Math.max(depth, child.depth(cutoff)); - } - } - } - return depth + 1; - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/JfrConverter.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/JfrConverter.java deleted file mode 100644 index 006bce7e03c..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/convert/JfrConverter.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.convert; - -import static io.sentry.asyncprofiler.vendor.asyncprofiler.convert.Frame.*; - -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.ClassRef; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.Dictionary; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.JfrReader; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.MethodRef; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.AllocationSample; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.ContendedLock; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.Event; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.EventAggregator; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.EventCollector; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.ExecutionSample; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.LiveObject; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.MallocEvent; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.MallocLeakAggregator; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.BitSet; -import java.util.Map; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -@ApiStatus.Internal -public abstract class JfrConverter extends Classifier { - protected final @NotNull JfrReader jfr; - protected final @NotNull Arguments args; - protected final @NotNull EventCollector collector; - protected @NotNull Dictionary methodNames; - - public JfrConverter(@NotNull JfrReader jfr, @NotNull Arguments args) { - this.jfr = jfr; - this.args = args; - this.methodNames = new Dictionary<>(); - - EventCollector collector = createCollector(args); - this.collector = args.nativemem && args.leak ? new MallocLeakAggregator(collector) : collector; - } - - public void convert() throws IOException { - jfr.stopAtNewChunk = true; - - while (jfr.hasMoreChunks()) { - // Reset method dictionary, since new chunk may have different IDs - methodNames = new Dictionary<>(); - - collector.beforeChunk(); - collectEvents(); - collector.afterChunk(); - - convertChunk(); - } - - if (collector.finish()) { - convertChunk(); - } - } - - protected EventCollector createCollector(Arguments args) { - return new EventAggregator(args.threads, args.grain); - } - - protected void collectEvents() throws IOException { - Class eventClass = - args.nativemem - ? MallocEvent.class - : args.live - ? LiveObject.class - : args.alloc - ? AllocationSample.class - : args.lock ? ContendedLock.class : ExecutionSample.class; - - BitSet threadStates = null; - if (args.state != null) { - threadStates = new BitSet(); - for (String state : args.state.toUpperCase().split(",", -1)) { - threadStates.set(toThreadState(state)); - } - } else if (args.cpu) { - threadStates = getThreadStates(true); - } else if (args.wall) { - threadStates = getThreadStates(false); - } - - long startTicks = args.from != 0 ? toTicks(args.from) : Long.MIN_VALUE; - long endTicks = args.to != 0 ? toTicks(args.to) : Long.MAX_VALUE; - - for (Event event; (event = jfr.readEvent(eventClass)) != null; ) { - if (event.time >= startTicks && event.time <= endTicks) { - if (threadStates == null || threadStates.get(((ExecutionSample) event).threadState)) { - collector.collect(event); - } - } - } - } - - protected void convertChunk() { - // To be overridden in subclasses - } - - protected int toThreadState(String name) { - Map threadStates = jfr.enums.get("jdk.types.ThreadState"); - if (threadStates != null) { - for (Map.Entry entry : threadStates.entrySet()) { - if (entry.getValue().startsWith(name, 6)) { - return entry.getKey(); - } - } - } - throw new IllegalArgumentException("Unknown thread state: " + name); - } - - protected BitSet getThreadStates(boolean cpu) { - BitSet set = new BitSet(); - Map threadStates = jfr.enums.get("jdk.types.ThreadState"); - if (threadStates != null) { - for (Map.Entry entry : threadStates.entrySet()) { - set.set(entry.getKey(), "STATE_DEFAULT".equals(entry.getValue()) == cpu); - } - } - return set; - } - - // millis can be an absolute timestamp or an offset from the beginning/end of the recording - protected long toTicks(long millis) { - long nanos = millis * 1_000_000; - if (millis < 0) { - nanos += jfr.endNanos; - } else if (millis < 1500000000000L) { - nanos += jfr.startNanos; - } - return (long) ((nanos - jfr.chunkStartNanos) * (jfr.ticksPerSec / 1e9)) + jfr.chunkStartTicks; - } - - @Override - public String getMethodName(long methodId, byte methodType) { - String result = methodNames.get(methodId); - if (result == null) { - methodNames.put(methodId, result = resolveMethodName(methodId, methodType)); - } - return result; - } - - private String resolveMethodName(long methodId, byte methodType) { - MethodRef method = jfr.methods.get(methodId); - if (method == null) { - return "unknown"; - } - - ClassRef cls = jfr.classes.get(method.cls); - byte[] className = jfr.symbols.get(cls.name); - byte[] methodName = jfr.symbols.get(method.name); - - if (className == null || className.length == 0 || isNativeFrame(methodType)) { - return new String(methodName, StandardCharsets.UTF_8); - } else { - String classStr = toJavaClassName(className, 0, args.dot); - if (methodName == null || methodName.length == 0) { - return classStr; - } - String methodStr = new String(methodName, StandardCharsets.UTF_8); - return classStr + '.' + methodStr; - } - } - - public String getClassName(long classId) { - ClassRef cls = jfr.classes.get(classId); - if (cls == null) { - return "null"; - } - byte[] className = jfr.symbols.get(cls.name); - - int arrayDepth = 0; - while (className[arrayDepth] == '[') { - arrayDepth++; - } - - String name = toJavaClassName(className, arrayDepth, true); - while (arrayDepth-- > 0) { - name = name.concat("[]"); - } - return name; - } - - private String toJavaClassName(byte[] symbol, int start, boolean dotted) { - int end = symbol.length; - if (start > 0) { - switch (symbol[start]) { - case 'B': - return "byte"; - case 'C': - return "char"; - case 'S': - return "short"; - case 'I': - return "int"; - case 'J': - return "long"; - case 'Z': - return "boolean"; - case 'F': - return "float"; - case 'D': - return "double"; - case 'L': - start++; - end--; - } - } - - if (args.norm) { - for (int i = end - 2; i > start; i--) { - if (symbol[i] == '/' || symbol[i] == '.') { - if (symbol[i + 1] >= '0' && symbol[i + 1] <= '9') { - end = i; - if (i > start + 19 && symbol[i - 19] == '+' && symbol[i - 18] == '0') { - // Original JFR transforms lambda names to something like - // pkg.ClassName$$Lambda+0x00007f8177090218/543846639 - end = i - 19; - } - } - break; - } - } - } - - if (args.simple) { - for (int i = end - 2; i >= start; i--) { - if (symbol[i] == '/' && (symbol[i + 1] < '0' || symbol[i + 1] > '9')) { - start = i + 1; - break; - } - } - } - - String s = new String(symbol, start, end - start, StandardCharsets.UTF_8); - return dotted ? s.replace('/', '.') : s; - } - - public StackTraceElement getStackTraceElement(long methodId, byte methodType, int location) { - MethodRef method = jfr.methods.get(methodId); - if (method == null) { - return new StackTraceElement("", "unknown", null, 0); - } - - ClassRef cls = jfr.classes.get(method.cls); - byte[] className = jfr.symbols.get(cls.name); - byte[] methodName = jfr.symbols.get(method.name); - - String classStr = - className == null || className.length == 0 || isNativeFrame(methodType) - ? "" - : toJavaClassName(className, 0, args.dot); - String methodStr = - methodName == null || methodName.length == 0 - ? "" - : new String(methodName, StandardCharsets.UTF_8); - return new StackTraceElement(classStr, methodStr, null, location >>> 16); - } - - public String getThreadName(int tid) { - String threadName = jfr.threads.get(tid); - return threadName == null - ? "[tid=" + tid + ']' - : threadName.startsWith("[tid=") ? threadName : '[' + threadName + " tid=" + tid + ']'; - } - - public String getPlainThreadName(int tid) { - String threadName = jfr.threads.get(tid); - return threadName == null ? "[tid=" + tid + ']' : threadName; - } - - protected boolean isNativeFrame(byte methodType) { - // In JDK Flight Recorder, TYPE_NATIVE denotes Java native methods, - // while in async-profiler, TYPE_NATIVE is for C methods - return (methodType == TYPE_NATIVE - && jfr.getEnumValue("jdk.types.FrameType", TYPE_KERNEL) != null) - || methodType == TYPE_CPP - || methodType == TYPE_KERNEL; - } - - // Select sum(samples) or sum(value) depending on the --total option. - // For lock events, convert lock duration from ticks to nanoseconds. - protected abstract class AggregatedEventVisitor implements EventCollector.Visitor { - final double factor = !args.total ? 0.0 : args.lock ? 1e9 / jfr.ticksPerSec : 1.0; - - @Override - public final void visit(Event event, long samples, long value) { - visit(event, factor == 0.0 ? samples : factor == 1.0 ? value : (long) (value * factor)); - } - - protected abstract void visit(Event event, long value); - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/ClassRef.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/ClassRef.java deleted file mode 100644 index 1727dc2156c..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/ClassRef.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public final class ClassRef { - public final long name; - - public ClassRef(long name) { - this.name = name; - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary.java deleted file mode 100644 index 5f3191a37e6..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Dictionary.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr; - -import java.util.Arrays; -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -/** Fast and compact long->Object map. */ -public final class Dictionary { - private static final int INITIAL_CAPACITY = 16; - - private long[] keys; - private Object[] values; - private int size; - - public Dictionary() { - this(INITIAL_CAPACITY); - } - - public Dictionary(int initialCapacity) { - this.keys = new long[initialCapacity]; - this.values = new Object[initialCapacity]; - } - - public void clear() { - Arrays.fill(keys, 0); - Arrays.fill(values, null); - size = 0; - } - - public int size() { - return size; - } - - public void put(long key, T value) { - if (key == 0) { - throw new IllegalArgumentException("Zero key not allowed"); - } - - int mask = keys.length - 1; - int i = hashCode(key) & mask; - while (keys[i] != 0) { - if (keys[i] == key) { - values[i] = value; - return; - } - i = (i + 1) & mask; - } - keys[i] = key; - values[i] = value; - - if (++size * 2 > keys.length) { - resize(keys.length * 2); - } - } - - @SuppressWarnings("unchecked") - public T get(long key) { - int mask = keys.length - 1; - int i = hashCode(key) & mask; - while (keys[i] != key && keys[i] != 0) { - i = (i + 1) & mask; - } - return (T) values[i]; - } - - @SuppressWarnings("unchecked") - public void forEach(Visitor visitor) { - for (int i = 0; i < keys.length; i++) { - if (keys[i] != 0) { - visitor.visit(keys[i], (T) values[i]); - } - } - } - - public int preallocate(int count) { - if (count * 2 > keys.length) { - resize(Integer.highestOneBit(count * 4 - 1)); - } - return count; - } - - private void resize(int newCapacity) { - long[] newKeys = new long[newCapacity]; - Object[] newValues = new Object[newCapacity]; - int mask = newKeys.length - 1; - - for (int i = 0; i < keys.length; i++) { - if (keys[i] != 0) { - for (int j = hashCode(keys[i]) & mask; ; j = (j + 1) & mask) { - if (newKeys[j] == 0) { - newKeys[j] = keys[i]; - newValues[j] = values[i]; - break; - } - } - } - } - - keys = newKeys; - values = newValues; - } - - private static int hashCode(long key) { - key *= 0xc6a4a7935bd1e995L; - return (int) (key ^ (key >>> 32)); - } - - public interface Visitor { - void visit(long key, T value); - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/DictionaryInt.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/DictionaryInt.java deleted file mode 100644 index 83d3a2772e1..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/DictionaryInt.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr; - -import java.util.Arrays; -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -/** Fast and compact long->int map. */ -public final class DictionaryInt { - private static final int INITIAL_CAPACITY = 16; - - private long[] keys; - private int[] values; - private int size; - - public DictionaryInt() { - this(INITIAL_CAPACITY); - } - - public DictionaryInt(int initialCapacity) { - this.keys = new long[initialCapacity]; - this.values = new int[initialCapacity]; - } - - public void clear() { - Arrays.fill(keys, 0); - Arrays.fill(values, 0); - size = 0; - } - - public void put(long key, int value) { - if (key == 0) { - throw new IllegalArgumentException("Zero key not allowed"); - } - - int mask = keys.length - 1; - int i = hashCode(key) & mask; - while (keys[i] != 0) { - if (keys[i] == key) { - values[i] = value; - return; - } - i = (i + 1) & mask; - } - keys[i] = key; - values[i] = value; - - if (++size * 2 > keys.length) { - resize(keys.length * 2); - } - } - - public int get(long key) { - int mask = keys.length - 1; - int i = hashCode(key) & mask; - while (keys[i] != key) { - if (keys[i] == 0) { - throw new IllegalArgumentException("No such key: " + key); - } - i = (i + 1) & mask; - } - return values[i]; - } - - public int get(long key, int notFound) { - int mask = keys.length - 1; - int i = hashCode(key) & mask; - while (keys[i] != key) { - if (keys[i] == 0) { - return notFound; - } - i = (i + 1) & mask; - } - return values[i]; - } - - public void forEach(Visitor visitor) { - for (int i = 0; i < keys.length; i++) { - if (keys[i] != 0) { - visitor.visit(keys[i], values[i]); - } - } - } - - public int preallocate(int count) { - if (count * 2 > keys.length) { - resize(Integer.highestOneBit(count * 4 - 1)); - } - return count; - } - - private void resize(int newCapacity) { - long[] newKeys = new long[newCapacity]; - int[] newValues = new int[newCapacity]; - int mask = newKeys.length - 1; - - for (int i = 0; i < keys.length; i++) { - if (keys[i] != 0) { - for (int j = hashCode(keys[i]) & mask; ; j = (j + 1) & mask) { - if (newKeys[j] == 0) { - newKeys[j] = keys[i]; - newValues[j] = values[i]; - break; - } - } - } - } - - keys = newKeys; - values = newValues; - } - - private static int hashCode(long key) { - key *= 0xc6a4a7935bd1e995L; - return (int) (key ^ (key >>> 32)); - } - - public interface Visitor { - void visit(long key, int value); - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Element.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Element.java deleted file mode 100644 index 0c12292106a..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/Element.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -abstract class Element { - - void addChild(Element e) {} - - static final class NoOpElement extends Element { - // Empty implementation for unhandled element types - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrClass.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrClass.java deleted file mode 100644 index eb85be46eb3..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrClass.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -@ApiStatus.Internal -public final class JfrClass extends Element { - final int id; - final boolean simpleType; - final @Nullable String name; - final List fields; - - JfrClass(@NotNull Map attributes) { - this.id = Integer.parseInt(attributes.get("id")); - this.simpleType = "true".equals(attributes.get("simpleType")); - this.name = attributes.get("name"); - this.fields = new ArrayList<>(2); - } - - @Override - void addChild(Element e) { - if (e instanceof JfrField) { - fields.add((JfrField) e); - } - } - - public @Nullable JfrField field(@NotNull String name) { - for (JfrField field : fields) { - if (field.name != null && field.name.equals(name)) { - return field; - } - } - return null; - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrField.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrField.java deleted file mode 100644 index 635b87fd0f3..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrField.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr; - -import java.util.Map; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -@ApiStatus.Internal -public final class JfrField extends Element { - final @Nullable String name; - final int type; - final boolean constantPool; - - JfrField(@NotNull Map attributes) { - this.name = attributes.get("name"); - this.type = Integer.parseInt(attributes.get("class")); - this.constantPool = "true".equals(attributes.get("constantPool")); - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrReader.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrReader.java deleted file mode 100644 index a0297d7afc1..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/JfrReader.java +++ /dev/null @@ -1,714 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr; - -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.AllocationSample; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.CPULoad; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.ContendedLock; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.Event; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.ExecutionSample; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.GCHeapSummary; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.LiveObject; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.MallocEvent; -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event.ObjectCount; -import java.io.Closeable; -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.channels.FileChannel; -import java.nio.charset.StandardCharsets; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** Parses JFR output produced by async-profiler. */ -public final class JfrReader implements Closeable { - private static final int BUFFER_SIZE = 2 * 1024 * 1024; - private static final int CHUNK_HEADER_SIZE = 68; - private static final int CHUNK_SIGNATURE = 0x464c5200; - - private static final byte STATE_NEW_CHUNK = 0; - private static final byte STATE_READING = 1; - private static final byte STATE_EOF = 2; - private static final byte STATE_INCOMPLETE = 3; - - private final @Nullable FileChannel ch; - private @NotNull ByteBuffer buf; - private final long fileSize; - private long filePosition; - private byte state; - - public long startNanos = Long.MAX_VALUE; - public long endNanos = Long.MIN_VALUE; - public long startTicks = Long.MAX_VALUE; - public long chunkStartNanos; - public long chunkEndNanos; - public long chunkStartTicks; - public long ticksPerSec; - public boolean stopAtNewChunk; - - public final Dictionary types = new Dictionary<>(); - public final Map typesByName = new HashMap<>(); - public final Dictionary threads = new Dictionary<>(); - // Maps thread IDs to Java thread IDs - // Change compared to original async-profiler JFR reader - public final Dictionary javaThreads = new Dictionary<>(); - public final Dictionary classes = new Dictionary<>(); - public final Dictionary strings = new Dictionary<>(); - public final Dictionary symbols = new Dictionary<>(); - public final Dictionary methods = new Dictionary<>(); - public final Dictionary stackTraces = new Dictionary<>(); - public final Map settings = new HashMap<>(); - public final Map> enums = new HashMap<>(); - - private final Dictionary> customEvents = new Dictionary<>(); - - private int executionSample; - private int nativeMethodSample; - private int wallClockSample; - private int allocationInNewTLAB; - private int allocationOutsideTLAB; - private int allocationSample; - private int liveObject; - private int monitorEnter; - private int threadPark; - private int activeSetting; - private int malloc; - private int free; - - @ApiStatus.Internal - public JfrReader(String fileName) throws IOException { - this.ch = FileChannel.open(Paths.get(fileName), StandardOpenOption.READ); - this.buf = ByteBuffer.allocateDirect(BUFFER_SIZE); - this.fileSize = ch.size(); - - buf.flip(); - ensureBytes(CHUNK_HEADER_SIZE); - if (!readChunk(0)) { - throw new IOException("Incomplete JFR file"); - } - } - - public JfrReader(@NotNull ByteBuffer buf) throws IOException { - this.ch = null; - this.buf = buf; - this.fileSize = buf.limit(); - - buf.order(ByteOrder.BIG_ENDIAN); - if (!readChunk(0)) { - throw new IOException("Incomplete JFR file"); - } - } - - @Override - public void close() throws IOException { - if (ch != null) { - ch.close(); - } - } - - public boolean eof() { - return state >= STATE_EOF; - } - - public boolean incomplete() { - return state == STATE_INCOMPLETE; - } - - public long durationNanos() { - return endNanos - startNanos; - } - - public void registerEvent(String name, Class eventClass) { - JfrClass type = typesByName.get(name); - if (type != null) { - try { - customEvents.put(type.id, eventClass.getConstructor(JfrReader.class)); - } catch (NoSuchMethodException e) { - throw new IllegalArgumentException("No suitable constructor found"); - } - } - } - - // Similar to eof(), but parses the next chunk header - public boolean hasMoreChunks() throws IOException { - return state == STATE_NEW_CHUNK ? readChunk(buf.position()) : state == STATE_READING; - } - - public List readAllEvents() throws IOException { - return readAllEvents(null); - } - - public List readAllEvents(@Nullable Class cls) throws IOException { - ArrayList events = new ArrayList<>(); - for (E event; (event = readEvent(cls)) != null; ) { - events.add(event); - } - Collections.sort(events); - return events; - } - - public @Nullable Event readEvent() throws IOException { - return readEvent(null); - } - - @SuppressWarnings("unchecked") - public @Nullable E readEvent(@Nullable Class cls) throws IOException { - while (ensureBytes(CHUNK_HEADER_SIZE)) { - int pos = buf.position(); - int size = getVarint(); - int type = getVarint(); - - if (type == 'L' && buf.getInt(pos) == CHUNK_SIGNATURE) { - if (state != STATE_NEW_CHUNK && stopAtNewChunk) { - buf.position(pos); - state = STATE_NEW_CHUNK; - } else if (readChunk(pos)) { - continue; - } - return null; - } - - if (type == executionSample || type == nativeMethodSample) { - if (cls == null || cls == ExecutionSample.class) return (E) readExecutionSample(false); - } else if (type == wallClockSample) { - if (cls == null || cls == ExecutionSample.class) return (E) readExecutionSample(true); - } else if (type == allocationInNewTLAB) { - if (cls == null || cls == AllocationSample.class) return (E) readAllocationSample(true); - } else if (type == allocationOutsideTLAB || type == allocationSample) { - if (cls == null || cls == AllocationSample.class) return (E) readAllocationSample(false); - } else if (type == malloc) { - if (cls == null || cls == MallocEvent.class) return (E) readMallocEvent(true); - } else if (type == free) { - if (cls == null || cls == MallocEvent.class) return (E) readMallocEvent(false); - } else if (type == liveObject) { - if (cls == null || cls == LiveObject.class) return (E) readLiveObject(); - } else if (type == monitorEnter) { - if (cls == null || cls == ContendedLock.class) return (E) readContendedLock(false); - } else if (type == threadPark) { - if (cls == null || cls == ContendedLock.class) return (E) readContendedLock(true); - } else if (type == activeSetting) { - readActiveSetting(); - } else { - Constructor customEvent = customEvents.get(type); - if (customEvent != null && (cls == null || cls == customEvent.getDeclaringClass())) { - try { - return (E) customEvent.newInstance(this); - } catch (ReflectiveOperationException e) { - throw new IllegalStateException(e); - } finally { - seek(filePosition + pos + size); - } - } - } - - seek(filePosition + pos + size); - } - - state = STATE_EOF; - return null; - } - - private ExecutionSample readExecutionSample(boolean hasSamples) { - long time = getVarlong(); - int tid = getVarint(); - int stackTraceId = getVarint(); - int threadState = getVarint(); - int samples = hasSamples ? getVarint() : 1; - return new ExecutionSample(time, tid, stackTraceId, threadState, samples); - } - - private AllocationSample readAllocationSample(boolean tlab) { - long time = getVarlong(); - int tid = getVarint(); - int stackTraceId = getVarint(); - int classId = getVarint(); - long allocationSize = getVarlong(); - long tlabSize = tlab ? getVarlong() : 0; - return new AllocationSample(time, tid, stackTraceId, classId, allocationSize, tlabSize); - } - - private MallocEvent readMallocEvent(boolean hasSize) { - long time = getVarlong(); - int tid = getVarint(); - int stackTraceId = getVarint(); - long address = getVarlong(); - long size = hasSize ? getVarlong() : 0; - return new MallocEvent(time, tid, stackTraceId, address, size); - } - - private LiveObject readLiveObject() { - long time = getVarlong(); - int tid = getVarint(); - int stackTraceId = getVarint(); - int classId = getVarint(); - long allocationSize = getVarlong(); - long allocatimeTime = getVarlong(); - return new LiveObject(time, tid, stackTraceId, classId, allocationSize, allocatimeTime); - } - - private ContendedLock readContendedLock(boolean hasTimeout) { - long time = getVarlong(); - long duration = getVarlong(); - int tid = getVarint(); - int stackTraceId = getVarint(); - int classId = getVarint(); - if (hasTimeout) getVarlong(); - getVarlong(); - getVarlong(); - return new ContendedLock(time, tid, stackTraceId, duration, classId); - } - - private void readActiveSetting() { - JfrClass activeSetting = typesByName.get("jdk.ActiveSetting"); - if (activeSetting == null) return; - for (JfrField field : activeSetting.fields) { - getVarlong(); - if ("id".equals(field.name)) { - break; - } - } - String name = getString(); - String value = getString(); - settings.put(name, value); - } - - private boolean readChunk(int pos) throws IOException { - if (pos + CHUNK_HEADER_SIZE > buf.limit() || buf.getInt(pos) != CHUNK_SIGNATURE) { - throw new IOException("Not a valid JFR file"); - } - - int version = buf.getInt(pos + 4); - if (version < 0x20000 || version > 0x2ffff) { - throw new IOException( - "Unsupported JFR version: " + (version >>> 16) + "." + (version & 0xffff)); - } - - long chunkStart = filePosition + pos; - long chunkSize = buf.getLong(pos + 8); - if (chunkStart + chunkSize > fileSize) { - state = STATE_INCOMPLETE; - return false; - } - - long cpOffset = buf.getLong(pos + 16); - long metaOffset = buf.getLong(pos + 24); - if (cpOffset == 0 || metaOffset == 0) { - state = STATE_INCOMPLETE; - return false; - } - - chunkStartNanos = buf.getLong(pos + 32); - chunkEndNanos = buf.getLong(pos + 32) + buf.getLong(pos + 40); - chunkStartTicks = buf.getLong(pos + 48); - ticksPerSec = buf.getLong(pos + 56); - - startNanos = Math.min(startNanos, chunkStartNanos); - endNanos = Math.max(endNanos, chunkEndNanos); - startTicks = Math.min(startTicks, chunkStartTicks); - - types.clear(); - typesByName.clear(); - - readMeta(chunkStart + metaOffset); - readConstantPool(chunkStart + cpOffset); - cacheEventTypes(); - - seek(chunkStart + CHUNK_HEADER_SIZE); - state = STATE_READING; - return true; - } - - private void readMeta(long metaOffset) throws IOException { - seek(metaOffset); - ensureBytes(5); - - int posBeforeSize = buf.position(); - ensureBytes(getVarint() - (buf.position() - posBeforeSize)); - getVarint(); - getVarlong(); - getVarlong(); - getVarlong(); - - String[] strings = new String[getVarint()]; - for (int i = 0; i < strings.length; i++) { - strings[i] = getString(); - } - readElement(strings); - } - - private Element readElement(String[] strings) { - String name = strings[getVarint()]; - - int attributeCount = getVarint(); - Map attributes = new HashMap<>(attributeCount); - for (int i = 0; i < attributeCount; i++) { - attributes.put(strings[getVarint()], strings[getVarint()]); - } - - Element e = createElement(name, attributes); - int childCount = getVarint(); - for (int i = 0; i < childCount; i++) { - e.addChild(readElement(strings)); - } - return e; - } - - private Element createElement(String name, Map attributes) { - switch (name) { - case "class": - { - JfrClass type = new JfrClass(attributes); - if (!attributes.containsKey("superType")) { - types.put(type.id, type); - } - typesByName.put(type.name, type); - return type; - } - case "field": - return new JfrField(attributes); - default: - return new Element.NoOpElement(); - } - } - - private void readConstantPool(long cpOffset) throws IOException { - long delta; - do { - seek(cpOffset); - ensureBytes(5); - - int posBeforeSize = buf.position(); - ensureBytes(getVarint() - (buf.position() - posBeforeSize)); - getVarint(); - getVarlong(); - getVarlong(); - delta = getVarlong(); - getVarint(); - - int poolCount = getVarint(); - for (int i = 0; i < poolCount; i++) { - int type = getVarint(); - readConstants(types.get(type)); - } - } while (delta != 0 && (cpOffset += delta) > 0); - } - - private void readConstants(JfrClass type) { - String typeName = type.name; - if (typeName == null) { - readOtherConstants(type.fields); - return; - } - switch (typeName) { - case "jdk.types.ChunkHeader": - buf.position(buf.position() + (CHUNK_HEADER_SIZE + 3)); - break; - case "java.lang.Thread": - readThreads(type.fields.size()); - break; - case "java.lang.Class": - readClasses(type.fields.size()); - break; - case "java.lang.String": - readStrings(); - break; - case "jdk.types.Symbol": - readSymbols(); - break; - case "jdk.types.Method": - readMethods(); - break; - case "jdk.types.StackTrace": - readStackTraces(); - break; - default: - if (type.simpleType && type.fields.size() == 1) { - readEnumValues(typeName); - } else { - readOtherConstants(type.fields); - } - } - } - - private void readThreads(int fieldCount) { - int count = threads.preallocate(getVarint()); - for (int i = 0; i < count; i++) { - long id = getVarlong(); - String osName = getString(); - getVarint(); // osThreadId - String javaName = getString(); - long javaThreadId = getVarlong(); - readFields(fieldCount - 4); - javaThreads.put(id, javaThreadId); - String threadName = javaName != null ? javaName : (osName != null ? osName : "Thread-" + id); - threads.put(id, threadName); - } - } - - private void readClasses(int fieldCount) { - int count = classes.preallocate(getVarint()); - for (int i = 0; i < count; i++) { - long id = getVarlong(); - getVarlong(); - long name = getVarlong(); - getVarlong(); - getVarint(); - readFields(fieldCount - 4); - classes.put(id, new ClassRef(name)); - } - } - - private void readMethods() { - int count = methods.preallocate(getVarint()); - for (int i = 0; i < count; i++) { - long id = getVarlong(); - long cls = getVarlong(); - long name = getVarlong(); - long sig = getVarlong(); - getVarint(); - getVarint(); - methods.put(id, new MethodRef(cls, name, sig)); - } - } - - private void readStackTraces() { - int count = stackTraces.preallocate(getVarint()); - for (int i = 0; i < count; i++) { - long id = getVarlong(); - getVarint(); // int truncated - StackTrace stackTrace = readStackTrace(); - stackTraces.put(id, stackTrace); - } - } - - private StackTrace readStackTrace() { - int depth = getVarint(); - long[] methods = new long[depth]; - byte[] types = new byte[depth]; - int[] locations = new int[depth]; - for (int i = 0; i < depth; i++) { - methods[i] = getVarlong(); - int line = getVarint(); - int bci = getVarint(); - locations[i] = line << 16 | (bci & 0xffff); - types[i] = buf.get(); - } - return new StackTrace(methods, types, locations); - } - - private void readStrings() { - int count = strings.preallocate(getVarint()); - for (int i = 0; i < count; i++) { - String str = getString(); - if (str == null) str = ""; - strings.put(getVarlong(), str); - } - } - - private void readSymbols() { - int count = symbols.preallocate(getVarint()); - for (int i = 0; i < count; i++) { - long id = getVarlong(); - if (buf.get() != 3) { - throw new IllegalArgumentException("Invalid symbol encoding"); - } - symbols.put(id, getBytes()); - } - } - - private void readEnumValues(@NotNull String typeName) { - HashMap map = new HashMap<>(); - int count = getVarint(); - for (int i = 0; i < count; i++) { - map.put((int) getVarlong(), getString()); - } - enums.put(typeName, map); - } - - private void readOtherConstants(List fields) { - int stringType = getTypeId("java.lang.String"); - - boolean[] numeric = new boolean[fields.size()]; - for (int i = 0; i < numeric.length; i++) { - JfrField f = fields.get(i); - numeric[i] = f.constantPool || f.type != stringType; - } - - int count = getVarint(); - for (int i = 0; i < count; i++) { - getVarlong(); - readFields(numeric); - } - } - - private void readFields(boolean[] numeric) { - for (boolean n : numeric) { - if (n) { - getVarlong(); - } else { - getString(); - } - } - } - - private void readFields(int count) { - while (count-- > 0) { - getVarlong(); - } - } - - private void cacheEventTypes() { - executionSample = getTypeId("jdk.ExecutionSample"); - nativeMethodSample = getTypeId("jdk.NativeMethodSample"); - wallClockSample = getTypeId("profiler.WallClockSample"); - allocationInNewTLAB = getTypeId("jdk.ObjectAllocationInNewTLAB"); - allocationOutsideTLAB = getTypeId("jdk.ObjectAllocationOutsideTLAB"); - allocationSample = getTypeId("jdk.ObjectAllocationSample"); - liveObject = getTypeId("profiler.LiveObject"); - monitorEnter = getTypeId("jdk.JavaMonitorEnter"); - threadPark = getTypeId("jdk.ThreadPark"); - activeSetting = getTypeId("jdk.ActiveSetting"); - malloc = getTypeId("profiler.Malloc"); - free = getTypeId("profiler.Free"); - - registerEvent("jdk.CPULoad", CPULoad.class); - registerEvent("jdk.GCHeapSummary", GCHeapSummary.class); - registerEvent("jdk.ObjectCount", ObjectCount.class); - registerEvent("jdk.ObjectCountAfterGC", ObjectCount.class); - } - - private int getTypeId(String typeName) { - JfrClass type = typesByName.get(typeName); - return type != null ? type.id : -1; - } - - public int getEnumKey(String typeName, String value) { - Map enumValues = enums.get(typeName); - if (enumValues != null) { - for (Map.Entry entry : enumValues.entrySet()) { - if (value.equals(entry.getValue())) { - return entry.getKey(); - } - } - } - return -1; - } - - public @Nullable String getEnumValue(String typeName, int key) { - Map enumMap = enums.get(typeName); - return enumMap != null ? enumMap.get(key) : null; - } - - public int getVarint() { - int result = 0; - for (int shift = 0; ; shift += 7) { - byte b = buf.get(); - result |= (b & 0x7f) << shift; - if (b >= 0) { - return result; - } - } - } - - public long getVarlong() { - long result = 0; - for (int shift = 0; shift < 56; shift += 7) { - byte b = buf.get(); - result |= (b & 0x7fL) << shift; - if (b >= 0) { - return result; - } - } - return result | (buf.get() & 0xffL) << 56; - } - - public float getFloat() { - return buf.getFloat(); - } - - public double getDouble() { - return buf.getDouble(); - } - - public @Nullable String getString() { - switch (buf.get()) { - case 0: - return null; - case 1: - return ""; - case 2: - return strings.get(getVarlong()); - case 3: - return new String(getBytes(), StandardCharsets.UTF_8); - case 4: - { - char[] chars = new char[getVarint()]; - for (int i = 0; i < chars.length; i++) { - chars[i] = (char) getVarint(); - } - return new String(chars); - } - case 5: - return new String(getBytes(), StandardCharsets.ISO_8859_1); - default: - throw new IllegalArgumentException("Invalid string encoding"); - } - } - - public byte[] getBytes() { - byte[] bytes = new byte[getVarint()]; - buf.get(bytes); - return bytes; - } - - private void seek(long pos) throws IOException { - long bufPosition = pos - filePosition; - if (bufPosition >= 0 && bufPosition <= buf.limit()) { - buf.position((int) bufPosition); - } else { - filePosition = pos; - if (ch != null) { - ch.position(pos); - } - buf.rewind().flip(); - } - } - - private boolean ensureBytes(int needed) throws IOException { - if (buf.remaining() >= needed) { - return true; - } - - if (ch == null) { - return false; - } - - filePosition += buf.position(); - - if (buf.capacity() < needed) { - ByteBuffer newBuf = ByteBuffer.allocateDirect(needed); - newBuf.put(buf); - buf = newBuf; - } else { - buf.compact(); - } - - while (ch.read(buf) > 0 && buf.position() < needed) { - // keep reading - } - buf.flip(); - return buf.limit() > 0; - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/MethodRef.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/MethodRef.java deleted file mode 100644 index 7790a492375..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/MethodRef.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public final class MethodRef { - public final long cls; - public final long name; - public final long sig; - - public MethodRef(long cls, long name, long sig) { - this.cls = cls; - this.name = name; - this.sig = sig; - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/StackTrace.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/StackTrace.java deleted file mode 100644 index 01e292f96f4..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/StackTrace.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public final class StackTrace { - public final long[] methods; - public final byte[] types; - public final int[] locations; - - public StackTrace(long[] methods, byte[] types, int[] locations) { - this.methods = methods; - this.types = types; - this.locations = locations; - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/AllocationSample.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/AllocationSample.java deleted file mode 100644 index 0f60086527d..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/AllocationSample.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public final class AllocationSample extends Event { - public final int classId; - public final long allocationSize; - public final long tlabSize; - - public AllocationSample( - long time, int tid, int stackTraceId, int classId, long allocationSize, long tlabSize) { - super(time, tid, stackTraceId); - this.classId = classId; - this.allocationSize = allocationSize; - this.tlabSize = tlabSize; - } - - @Override - public int hashCode() { - return classId * 127 + stackTraceId + (tlabSize == 0 ? 17 : 0); - } - - @Override - public boolean sameGroup(Event o) { - if (o instanceof AllocationSample) { - AllocationSample a = (AllocationSample) o; - return classId == a.classId && (tlabSize == 0) == (a.tlabSize == 0); - } - return false; - } - - @Override - public long classId() { - return classId; - } - - @Override - public long value() { - return tlabSize != 0 ? tlabSize : allocationSize; - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/CPULoad.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/CPULoad.java deleted file mode 100644 index 9134fe190ec..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/CPULoad.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event; - -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.JfrReader; -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public final class CPULoad extends Event { - public final float jvmUser; - public final float jvmSystem; - public final float machineTotal; - - public CPULoad(JfrReader jfr) { - super(jfr.getVarlong(), 0, 0); - this.jvmUser = jfr.getFloat(); - this.jvmSystem = jfr.getFloat(); - this.machineTotal = jfr.getFloat(); - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/ContendedLock.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/ContendedLock.java deleted file mode 100644 index e85595af4ce..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/ContendedLock.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public final class ContendedLock extends Event { - public final long duration; - public final int classId; - - public ContendedLock(long time, int tid, int stackTraceId, long duration, int classId) { - super(time, tid, stackTraceId); - this.duration = duration; - this.classId = classId; - } - - @Override - public int hashCode() { - return classId * 127 + stackTraceId; - } - - @Override - public boolean sameGroup(Event o) { - if (o instanceof ContendedLock) { - ContendedLock c = (ContendedLock) o; - return classId == c.classId; - } - return false; - } - - @Override - public long classId() { - return classId; - } - - @Override - public long value() { - return duration; - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event.java deleted file mode 100644 index 5612904e404..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/Event.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event; - -import java.lang.reflect.Field; -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public abstract class Event implements Comparable { - public final long time; - public final int tid; - public final int stackTraceId; - - protected Event(long time, int tid, int stackTraceId) { - this.time = time; - this.tid = tid; - this.stackTraceId = stackTraceId; - } - - @Override - public int compareTo(Event o) { - return Long.compare(time, o.time); - } - - @Override - public int hashCode() { - return stackTraceId; - } - - @Override - public String toString() { - StringBuilder sb = - new StringBuilder(getClass().getSimpleName()) - .append("{time=") - .append(time) - .append(",tid=") - .append(tid) - .append(",stackTraceId=") - .append(stackTraceId); - for (Field f : getClass().getDeclaredFields()) { - try { - sb.append(',').append(f.getName()).append('=').append(f.get(this)); - } catch (ReflectiveOperationException e) { - break; - } - } - return sb.append('}').toString(); - } - - public boolean sameGroup(Event o) { - return getClass() == o.getClass(); - } - - public long classId() { - return 0; - } - - public long samples() { - return 1; - } - - public long value() { - return 1; - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventAggregator.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventAggregator.java deleted file mode 100644 index a3b9c7dd17b..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventAggregator.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event; - -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -@ApiStatus.Internal -public final class EventAggregator implements EventCollector { - private static final int INITIAL_CAPACITY = 1024; - - private final boolean threads; - private final double grain; - private @NotNull Event[] keys; - private @NotNull long[] samples; - private @NotNull long[] values; - private int size; - private double fraction; - - public EventAggregator(boolean threads, double grain) { - this.threads = threads; - this.grain = grain; - this.keys = new Event[INITIAL_CAPACITY]; - this.samples = new long[INITIAL_CAPACITY]; - this.values = new long[INITIAL_CAPACITY]; - - beforeChunk(); - } - - public int size() { - return size; - } - - @Override - public void collect(Event e) { - collect(e, e.samples(), e.value()); - } - - public void collect(Event e, long samples, long value) { - int mask = keys.length - 1; - int i = hashCode(e) & mask; - while (keys[i] != null) { - if (sameGroup(keys[i], e)) { - this.samples[i] += samples; - this.values[i] += value; - return; - } - i = (i + 1) & mask; - } - - this.keys[i] = e; - this.samples[i] = samples; - this.values[i] = value; - - if (++size * 2 > keys.length) { - resize(keys.length * 2); - } - } - - @Override - public void beforeChunk() { - if (keys == null || size > 0) { - keys = new Event[INITIAL_CAPACITY]; - samples = new long[INITIAL_CAPACITY]; - values = new long[INITIAL_CAPACITY]; - size = 0; - } - } - - @Override - public void afterChunk() { - if (grain > 0) { - coarsen(grain); - } - } - - @Override - public boolean finish() { - // Don't set to null as it would break nullability contract - keys = new Event[0]; - samples = new long[0]; - values = new long[0]; - return false; - } - - @Override - public void forEach(Visitor visitor) { - if (size > 0) { - for (int i = 0; i < keys.length; i++) { - if (keys[i] != null) { - visitor.visit(keys[i], samples[i], values[i]); - } - } - } - } - - public void coarsen(double grain) { - fraction = 0; - - for (int i = 0; i < keys.length; i++) { - if (keys[i] != null) { - long s0 = samples[i]; - long s1 = round(s0 / grain); - if (s1 == 0) { - keys[i] = null; - size--; - } - samples[i] = s1; - values[i] = (long) (values[i] * ((double) s1 / s0)); - } - } - } - - private long round(double d) { - long r = (long) d; - if ((fraction += d - r) >= 1.0) { - fraction -= 1.0; - r++; - } - return r; - } - - private int hashCode(Event e) { - return e.hashCode() + (threads ? e.tid * 31 : 0); - } - - private boolean sameGroup(Event e1, Event e2) { - return e1.stackTraceId == e2.stackTraceId && (!threads || e1.tid == e2.tid) && e1.sameGroup(e2); - } - - private void resize(int newCapacity) { - Event[] newKeys = new Event[newCapacity]; - long[] newSamples = new long[newCapacity]; - long[] newValues = new long[newCapacity]; - int mask = newKeys.length - 1; - - for (int i = 0; i < keys.length; i++) { - if (keys[i] != null) { - for (int j = hashCode(keys[i]) & mask; ; j = (j + 1) & mask) { - if (newKeys[j] == null) { - newKeys[j] = keys[i]; - newSamples[j] = samples[i]; - newValues[j] = values[i]; - break; - } - } - } - } - - keys = newKeys; - samples = newSamples; - values = newValues; - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector.java deleted file mode 100644 index 639faa88778..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/EventCollector.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public interface EventCollector { - - void collect(Event e); - - void beforeChunk(); - - void afterChunk(); - - // Returns true if this collector has remaining data to process - boolean finish(); - - void forEach(Visitor visitor); - - interface Visitor { - void visit(Event event, long samples, long value); - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/ExecutionSample.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/ExecutionSample.java deleted file mode 100644 index d4db5c5e585..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/ExecutionSample.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public final class ExecutionSample extends Event { - public final int threadState; - public final int samples; - - public ExecutionSample(long time, int tid, int stackTraceId, int threadState, int samples) { - super(time, tid, stackTraceId); - this.threadState = threadState; - this.samples = samples; - } - - @Override - public long samples() { - return samples; - } - - @Override - public long value() { - return samples; - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/GCHeapSummary.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/GCHeapSummary.java deleted file mode 100644 index 68a8be94cf5..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/GCHeapSummary.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event; - -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.JfrReader; -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public final class GCHeapSummary extends Event { - public final int gcId; - public final boolean afterGC; - public final long committed; - public final long reserved; - public final long used; - - public GCHeapSummary(JfrReader jfr) { - super(jfr.getVarlong(), 0, 0); - this.gcId = jfr.getVarint(); - this.afterGC = jfr.getVarint() > 0; - jfr.getVarlong(); // long start - jfr.getVarlong(); // long committedEnd - this.committed = jfr.getVarlong(); - jfr.getVarlong(); // long reservedEnd - this.reserved = jfr.getVarlong(); - this.used = jfr.getVarlong(); - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/LiveObject.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/LiveObject.java deleted file mode 100644 index 6423d3b7f67..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/LiveObject.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public final class LiveObject extends Event { - public final int classId; - public final long allocationSize; - public final long allocationTime; - - public LiveObject( - long time, int tid, int stackTraceId, int classId, long allocationSize, long allocationTime) { - super(time, tid, stackTraceId); - this.classId = classId; - this.allocationSize = allocationSize; - this.allocationTime = allocationTime; - } - - @Override - public int hashCode() { - return classId * 127 + stackTraceId; - } - - @Override - public boolean sameGroup(Event o) { - if (o instanceof LiveObject) { - LiveObject a = (LiveObject) o; - return classId == a.classId; - } - return false; - } - - @Override - public long classId() { - return classId; - } - - @Override - public long value() { - return allocationSize; - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/MallocEvent.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/MallocEvent.java deleted file mode 100644 index 04aff9c71fe..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/MallocEvent.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public final class MallocEvent extends Event { - public final long address; - public final long size; - - public MallocEvent(long time, int tid, int stackTraceId, long address, long size) { - super(time, tid, stackTraceId); - this.address = address; - this.size = size; - } - - @Override - public long value() { - return size; - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/MallocLeakAggregator.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/MallocLeakAggregator.java deleted file mode 100644 index 6fc81957342..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/MallocLeakAggregator.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -@ApiStatus.Internal -public final class MallocLeakAggregator implements EventCollector { - private final EventCollector wrapped; - private final Map addresses; - private @NotNull List events; - - public MallocLeakAggregator(@NotNull EventCollector wrapped) { - this.wrapped = wrapped; - this.addresses = new HashMap<>(); - this.events = new ArrayList<>(); - } - - @Override - public void collect(Event e) { - events.add((MallocEvent) e); - } - - @Override - public void beforeChunk() { - events = new ArrayList<>(); - } - - @Override - public void afterChunk() { - events.sort(null); - - for (MallocEvent e : events) { - if (e.size > 0) { - addresses.put(e.address, e); - } else { - addresses.remove(e.address); - } - } - - events = new ArrayList<>(); - } - - @Override - public boolean finish() { - wrapped.beforeChunk(); - for (Event e : addresses.values()) { - wrapped.collect(e); - } - wrapped.afterChunk(); - - // Free memory before the final conversion - addresses.clear(); - return true; - } - - @Override - public void forEach(Visitor visitor) { - wrapped.forEach(visitor); - } -} diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/ObjectCount.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/ObjectCount.java deleted file mode 100644 index 202619272eb..00000000000 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/vendor/asyncprofiler/jfr/event/ObjectCount.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright The async-profiler authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.event; - -import io.sentry.asyncprofiler.vendor.asyncprofiler.jfr.JfrReader; -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public final class ObjectCount extends Event { - public final int gcId; - public final int classId; - public final long count; - public final long totalSize; - - public ObjectCount(JfrReader jfr) { - super(jfr.getVarlong(), 0, 0); - this.gcId = jfr.getVarint(); - this.classId = jfr.getVarint(); - this.count = jfr.getVarlong(); - this.totalSize = jfr.getVarlong(); - } -} From ddac02307ab65e1b1e6a3d06e0196bf7245af774 Mon Sep 17 00:00:00 2001 From: Lukas Bloder Date: Mon, 3 Nov 2025 09:41:53 +0100 Subject: [PATCH 2/3] add changelog entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed643ca30e4..daa9b87ba97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Features + +- Remove vendored code and upgrade to async profiler 4.2 ([#4856](https://github.com/getsentry/sentry-java/pull/4856)) + ### Improvements - Fallback to distinct-id as user.id logging attribute when user is not set ([#4847](https://github.com/getsentry/sentry-java/pull/4847)) From 0e85119cbe089e43e3e71214156124d1f8b0dc2d Mon Sep 17 00:00:00 2001 From: Lukas Bloder Date: Tue, 4 Nov 2025 11:56:00 +0100 Subject: [PATCH 3/3] cr changes --- CHANGELOG.md | 1 + .../sentry/asyncprofiler/profiling/JavaContinuousProfiler.java | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7e85d477e1..ed8f972a5e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Features - Remove vendored code and upgrade to async profiler 4.2 ([#4856](https://github.com/getsentry/sentry-java/pull/4856)) + - This adds support for JDK 23+ ### Improvements diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java index 8abd9a2d895..f5c314bf96c 100644 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java +++ b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java @@ -233,10 +233,7 @@ private void start() { "start,jfr,event=wall,nobatch,interval=%s,file=%s", profilingIntervalMicros, filename); - logger.log(SentryLevel.INFO, command); - profiler.execute(command); - } catch (Exception e) { logger.log(SentryLevel.ERROR, "Failed to start profiling: ", e); filename = "";