From 57c7902c60b4b1d665b40ab5e19a869716acac1f Mon Sep 17 00:00:00 2001 From: Dmitry Khalanskiy Date: Tue, 17 Feb 2026 14:29:28 +0100 Subject: [PATCH 1/2] Optimize attaching the debug probes I see a notable speed improvement even without any benchmarks, simply by running `DebugProbes.withDebugProbes { }` in a loop. --- kotlinx-coroutines-debug/src/Attach.kt | 37 +++++++++++++++----------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/kotlinx-coroutines-debug/src/Attach.kt b/kotlinx-coroutines-debug/src/Attach.kt index 291d913f3e..8d79daba10 100644 --- a/kotlinx-coroutines-debug/src/Attach.kt +++ b/kotlinx-coroutines-debug/src/Attach.kt @@ -16,23 +16,30 @@ internal class ByteBuddyDynamicAttach : Function1 { private fun attach() { ByteBuddyAgent.install(ByteBuddyAgent.AttachmentProvider.ForEmulatedAttachment.INSTANCE) - val cl = Class.forName("kotlin.coroutines.jvm.internal.DebugProbesKt") - val cl2 = Class.forName("kotlinx.coroutines.debug.internal.DebugProbesKt") - - ByteBuddy() - .redefine(cl2) - .name(cl.name) - .make() - .load(cl.classLoader, ClassReloadingStrategy.fromInstalledAgent()) + dynamicTypeWithProbes.load(targetClassLoader, ClassReloadingStrategy.fromInstalledAgent()) } private fun detach() { - val cl = Class.forName("kotlin.coroutines.jvm.internal.DebugProbesKt") - val cl2 = Class.forName("kotlinx.coroutines.debug.NoOpProbesKt") - ByteBuddy() - .redefine(cl2) - .name(cl.name) - .make() - .load(cl.classLoader, ClassReloadingStrategy.fromInstalledAgent()) + dynamicTypeWithoutProbes.load(targetClassLoader, ClassReloadingStrategy.fromInstalledAgent()) } } + +private val targetClassLoader = Class.forName(classNameToOverride).classLoader + +private const val classNameToOverride = "kotlin.coroutines.jvm.internal.DebugProbesKt" + +private val dynamicTypeWithProbes by lazy { + val classWithProbes = Class.forName("kotlinx.coroutines.debug.internal.DebugProbesKt") + ByteBuddy() + .redefine(classWithProbes) + .name(classNameToOverride) + .make() +} + +private val dynamicTypeWithoutProbes by lazy { + val classWithoutProbes = Class.forName("kotlinx.coroutines.debug.NoOpProbesKt") + ByteBuddy() + .redefine(classWithoutProbes) + .name(classNameToOverride) + .make() +} From fb0981099976c5285cbdc27eaa3f232f4f5189a7 Mon Sep 17 00:00:00 2001 From: Dmitry Khalanskiy Date: Fri, 10 Jul 2026 14:40:57 +0200 Subject: [PATCH 2/2] Move the top-level cache variables into the companion object --- kotlinx-coroutines-debug/src/Attach.kt | 42 ++++++++++++++------------ 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/kotlinx-coroutines-debug/src/Attach.kt b/kotlinx-coroutines-debug/src/Attach.kt index 8d79daba10..102f8cf372 100644 --- a/kotlinx-coroutines-debug/src/Attach.kt +++ b/kotlinx-coroutines-debug/src/Attach.kt @@ -22,24 +22,28 @@ internal class ByteBuddyDynamicAttach : Function1 { private fun detach() { dynamicTypeWithoutProbes.load(targetClassLoader, ClassReloadingStrategy.fromInstalledAgent()) } -} - -private val targetClassLoader = Class.forName(classNameToOverride).classLoader - -private const val classNameToOverride = "kotlin.coroutines.jvm.internal.DebugProbesKt" -private val dynamicTypeWithProbes by lazy { - val classWithProbes = Class.forName("kotlinx.coroutines.debug.internal.DebugProbesKt") - ByteBuddy() - .redefine(classWithProbes) - .name(classNameToOverride) - .make() -} - -private val dynamicTypeWithoutProbes by lazy { - val classWithoutProbes = Class.forName("kotlinx.coroutines.debug.NoOpProbesKt") - ByteBuddy() - .redefine(classWithoutProbes) - .name(classNameToOverride) - .make() + private companion object { + private const val classNameToOverride = "kotlin.coroutines.jvm.internal.DebugProbesKt" + + private val targetClassLoader by lazy { + Class.forName(classNameToOverride).classLoader + } + + private val dynamicTypeWithProbes by lazy { + val classWithProbes = Class.forName("kotlinx.coroutines.debug.internal.DebugProbesKt") + ByteBuddy() + .redefine(classWithProbes) + .name(classNameToOverride) + .make() + } + + private val dynamicTypeWithoutProbes by lazy { + val classWithoutProbes = Class.forName("kotlinx.coroutines.debug.NoOpProbesKt") + ByteBuddy() + .redefine(classWithoutProbes) + .name(classNameToOverride) + .make() + } + } }