1# libatrace_rust - ATrace bindings for Rust 2 3Wrapper library for ATrace methods from libcutils. 4 5## Quick start 6 7### Using ATrace bindings directly 8 9Add the library to your `rustlibs` in `Android.bp`: 10 11```text 12rustlibs: [ 13 ... 14 "libatrace_rust", 15 ... 16], 17``` 18 19Call tracing methods: 20 21```rust 22fn important_function() { 23 // Use this macro to trace a function. 24 atrace::trace_method!(AtraceTag::App); 25 26 if condition { 27 // Use a scoped event to trace inside a scope. 28 let _event = atrace::begin_scoped_event(AtraceTag::App, "Inside a scope"); 29 ... 30 } 31 32 // Or just use the wrapped API directly. 33 atrace::atrace_begin(AtraceTag::App, "My event"); 34 ... 35 atrace::atrace_end(AtraceTag::App) 36} 37``` 38 39See more in the [example](./example/src/main.rs). 40 41You're all set! Now you can collect a trace with your favorite tracing tool like 42[Perfetto](https://perfetto.dev/docs/data-sources/atrace). 43 44### Using the tracing crate 45 46You can use the ATrace layer for the [tracing](https://docs.rs/tracing/latest/tracing/) crate. 47Compared to using the bindings directly, it has better instrumentation points and customizability. 48The main drawback is lower performance. See the [Performance](#performance) section below for more 49information. 50 51Add the tracing libraries to your `rustlibs` in `Android.bp`: 52 53```text 54 rustlibs: [ 55 ... 56 "libatrace_tracing_subscriber", 57 "libtracing_subscriber", 58 "libtracing", 59 ... 60 ], 61``` 62 63[Initialize](https://docs.rs/tracing/latest/tracing/index.html#in-executables) the subscriber 64before calling the tracing methods, usually somewhere in the beginning of `main()`. 65 66```rust 67// Initialize the subscriber, panic if it fails. 68tracing_subscriber::registry() 69 .with(AtraceSubscriber::default().with_filter()) 70 .init(); 71``` 72 73The subscriber defaults to `AtraceTag::App`. Use other tags by creating the subscriber with 74`AtraceSubscriber::new(tag: AtraceTag)`. 75 76You can combine the subscriber with other 77[layers](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/layer/index.html). In 78that case, omit `with_filter()` from the `AtraceSubscriber` initialization - it is an optimization 79that disables instrumentation points when ATrace is disabled and it would affect other layers as 80well. 81 82Now you can 83[record spans and events](https://docs.rs/tracing/latest/tracing/index.html#recording-spans-and-events): 84 85```rust 86// This macro would automatically create and enter a span with function name and arguments. 87#[tracing::instrument] 88fn important_function() { 89 if condition { 90 // Use span! to trace inside a scope. 91 let _entered = tracing::span!(tracing::Level::TRACE, "Inside a scope").entered(); 92 ... 93 } 94 95 // Use event! to record an instant event. 96 // You can annotate spans and events with fields. They will be appended to the end of 97 // the Atrace event. 98 tracing::info!(field="value", "My event"); 99} 100``` 101 102See more in the [example](./example/src/tracing_subscriber_sample.rs) and check out the docs for 103the [tracing](https://docs.rs/tracing/latest/tracing/index.html) and 104[tracing-subscriber](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/index.html) 105crates. 106 107## Performance 108 109This section is an overview, you can find specific numbers in 110[benchmark/README.md](./benchmark/README.md). 111 112### ATrace bindings 113 114When tracing is enabled, you can expect 1-10 us per event - this is a significant cost that may 115affect the performance of hot high-frequency methods. When the events are disabled, calling them is 116cheap - on the order of 5-10 ns. There is a 10-20% overhead from the wrapper, mostly caused by 117string conversion when tracing is enabled. 118 119### Tracing subscriber 120 121The subscriber uses the bindings and adds its own overhead that depends on usage: 122 123* With tracing disabled and subscriber created `with_filter`, events cost around 30 ns. Not using 124 the filter brings the cost up to 100-400 ns per event. 125* Instant events (`event!`) add roughly 200 ns to the bindings - 1.5 vs 1.3 us. 126* Spans (`span!`) are roughly 400 ns slower - 2.8 vs 2.4 us. 127* Using [fields](https://docs.rs/tracing/latest/tracing/index.html#recording-fields) adds time 128 that depends on the amount of the fields and the cost of converting them to strings. Typically 129 it is around an extra 500 ns per event and an extra 1 us for a span. 130