Educational tool for visualizing Kotlin Coroutine execution.
This project is designed as an educational resource, specifically targeted at coroutine-related talks, workshops, and for anyone wanting to build a deeper mental model of how coroutines behave. It provides a real-time GUI that visualizes coroutine call trees, tracking function calls, exceptions, and cancellations across coroutines.
- Real-time Visualization: Watch the call tree grow and shrink as your coroutines execute.
- Coroutine-aware Tracking: Correctly handles suspension points and unstructured concurrency.
- Exception & Cancellation Tracking: Visualizes where exceptions are thrown and where coroutines are cancelled.
- Customizable UI: Support for Dark and Light themes.
This tool is especially useful for live demonstrations during talks or workshops. By visualizing the call tree, you can:
- Demystify Structured Concurrency: Show how child coroutines are tied to their parents.
- Visualize Cancellation: Demonstrate how cancellation propagates through the tree.
- Explain Suspension: See exactly when a coroutine suspends and resumes.
- Debug Complex Flows: Use it to explain complex asynchronous logic that is hard to follow in code alone.
:compiler-plugin: The Kotlin compiler plugin that instruments code for tracking.:gradle-plugin: A Gradle plugin to easily apply the compiler plugin to your projects.:stack-tracking-core-api: The runtime API used by instrumented code.:tracked-call-tree-as-flow: Integration layer that converts tracking events into a Kotlin Flow.:call-tree-visualizer-gui: A Compose Multiplatform desktop application for visualizing the call tree.:examples: Example project demonstrating how to use the visualizer.
The compiler plugin transforms every suspend function (unless marked with @NonTracked) to wrap its body with a call to stackTracked. This function uses a StackTrackingContext from the CoroutineContext to report when a function is entered, exited, or when it throws an exception.
Add the plugin to your settings.gradle.kts:
pluginManagement {
repositories {
gradlePluginPortal()
mavenCentral()
}
}And in your build.gradle.kts:
plugins {
id("com.woutwerkman.calltreevisualizer") version "0.0.1-2.2.20"
}By default, all suspend functions are instrumented. You can opt-out of tracking for specific functions using the @NonTracked annotation:
@NonTracked
suspend fun internalWork() {
// This function won't appear in the call tree
}You can use the trackingCallStacks function to collect events as a Flow:
// Will print:
// Event type: CallStackPushType of function named fully.qualified.name.of.foo
// Event type: CallStackPopType of function named fully.qualified.name.of.foo
suspend fun main() {
trackingCallStacks {
foo()
}.collect {
println("Event type: ${it.eventType} of function named ${it.node.functionFqn}")
}
}For more advanced usage, see the detailed READMEs in the subprojects:
- Compiler Plugin - Details on how the code is transformed.
- Core API - Information about annotations and the tracking interface.
- GUI Visualizer - How to use the real-time visualization tool.
You can use the trackingCallStacks function from the :tracked-call-tree-as-flow module to collect events and display them in the CallTreeUI provided by the :call-tree-visualizer-gui module.
See examples/src/main/kotlin/com/woutwerkman/calltreevisualizer/Main.kt for a complete example.
./gradlew buildThe project uses the Kotlin compiler test framework.
- Codegen tests:
compiler-plugin/testData/box - Diagnostic tests:
compiler-plugin/testData/diagnostics
Run tests with:
./gradlew :compiler-plugin:testNote: This is an educational project and is not intended for production use. It is optimized for clarity and visualization during presentations rather than performance.
Developed as a tool to better understand and explain complex Kotlin Coroutine interactions.
