1## Tracing Driver 2 3An experimental tracing backend that supports extremely low overhead tracing for JVM and Android 4apps; with the goal of supporting more platforms supported by the Kotlin Multiplatform ecosystem. 5 6The traces are captured using standard trace format defined by 7[Perfetto](https://perfetto.dev/docs/reference/trace-packet-proto). All tools that consume 8perfetto traces can continue being used. [ui.perfetto.dev](https://ui.perfetto.dev) can be used 9to visualize traces. Tools like 10[TraceProcessor](https://perfetto.dev/docs/analysis/trace-processor-python) can be used for 11analysing traces. 12 13## Usage 14 15To start recording traces, you need to create an instance of a 16[`TraceDriver`](src/commonMain/kotlin/androidx/tracing/driver/TraceDriver.kt). 17 18```kotlin 19val driver = TraceDriver( 20 // The trace sink. Determines where traces are stored. 21 // The library provides an implementation to a tracing sink out of the box. 22 // You can also write your own implementation of a TraceSink. 23 sink = JvmTraceSink(sequenceId = 1, baseDir = File("/path/to/trace/directory")), 24 // If injecting an instance of Driver, setting this to `false` means that no traces will be 25 // emitted to the sink. You don't have to change all the call sites where traces are captured. 26 isEnabled = true 27) 28``` 29 30The `TraceDriver` provides a `context` which is of type 31[`TraceContext`](src/commonMain/kotlin/androidx/tracing/driver/TraceContext.kt). 32 33### Trace Context 34 35The `TraceContext` provides a way to create process and thread tracks. For more context on what 36tracks are, please refer 37to [the documentation](https://perfetto.dev/docs/instrumentation/track-events#tracks). 38 39### Process Tracks 40 41To create a [ProcessTrack](src/commonMain/kotlin/androidx/tracing/driver/ProcessTrack.kt) you can 42use the following API: 43 44```kotlin 45// driver.ProcessTrack(...) is an alias for driver.context.ProcessTrack(...) 46val process = driver.context.getOrCreateProcessTrack( 47 // The process id 48 id = 1, 49 // The name of the process 50 name = "processName" 51) 52``` 53 54### Thread Tracks 55 56To create a [ThreadTrack](src/commonMain/kotlin/androidx/tracing/driver/ThreadTrack.kt), you can 57use a `ProcessTrack` instance : 58 59```kotlin 60val threadTrack = process.getOrCreateThreadTrack( 61 // The thread id 62 id = 10, 63 // The name of the thread 64 name = "threadName" 65) 66``` 67 68### Tracing 69 70Once you have a track that you want to attach traces to, you can do: 71 72#### Basic 73 74```kotlin 75track.trace("traceSectionName") { 76 // The code that is being instrumented 77 doSomethingExpensive() 78} 79``` 80 81#### Context Propagation 82 83The library also provides an implementation for tracing APIs that make use of Kotlin Coroutines 84to propagate the tracing context across multiple coroutines. 85 86```kotlin 87track.traceFlow("traceSectionName") { 88 // suspend block 89 // propagates flowId to inner coroutines automatically to do context propagation. 90} 91``` 92 93For e.g. 94 95```kotlin 96suspend fun ProcessTrack.forkJoin(input: List<Int>) { 97 coroutineScope { 98 val batches = input.chunked(CHUNK_SIZE) 99 val jobs = mutableListOf<Deferred<List<Int>>() 100 batches.forEachIndexed { index, batch -> 101 jobs += async { 102 traceFlow("batch-$index") { fork(batch) } 103 } 104 } 105 val results = jobs.awaitAll() 106 return traceFlow("merge") { 107 merge(results) 108 } 109 } 110} 111``` 112 113 114 115#### Counters 116 117You can also create tracks that emit counters as metrics. To create a counter you can use: 118 119```kotlin 120// The name of the counter. 121val counter = process.getOrCreateCounterTrack("MemoryUsage") 122``` 123 124To emit metrics you can: 125 126```kotlin 127counter.setCounter(longValue) 128// Or 129counter.setCounter(doubleValue) 130``` 131 132 133 134For an end to end tracing example app, look at 135[`TracingDemoTest.kt`](src/jvmTest/kotlin/androidx/tracing/driver/TracingDemoTest.kt). 136 137### Flushing Traces 138 139Traces are flushed to the sink asynchronously. To force a flush, you can always call `context.flush()`. 140 141Prior to termination of the program, call `traceContext.close()` to finalize all traces to the sink. 142(A [TraceContext](src/commonMain/kotlin/androidx/tracing/driver/TraceContext.kt) is a `Closeable`). 143