| # libatrace_rust - ATrace bindings for Rust |
| |
| Wrapper library for ATrace methods from libcutils. |
| |
| ## Quick start |
| |
| ### Using ATrace bindings directly |
| |
| Add the library to your `rustlibs` in `Android.bp`: |
| |
| ```text |
| rustlibs: [ |
| ... |
| "libatrace_rust", |
| ... |
| ], |
| ``` |
| |
| Call tracing methods: |
| |
| ```rust |
| fn important_function() { |
| // Use this macro to trace a function. |
| atrace::trace_method!(AtraceTag::App); |
| |
| if condition { |
| // Use a scoped event to trace inside a scope. |
| let _event = atrace::begin_scoped_event(AtraceTag::App, "Inside a scope"); |
| ... |
| } |
| |
| // Or just use the wrapped API directly. |
| atrace::atrace_begin(AtraceTag::App, "My event"); |
| ... |
| atrace::atrace_end(AtraceTag::App) |
| } |
| ``` |
| |
| See more in the [example](./example/src/main.rs). |
| |
| You're all set! Now you can collect a trace with your favorite tracing tool like |
| [Perfetto](https://perfetto.dev/docs/data-sources/atrace). |
| |
| ### Using the tracing crate |
| |
| You can use the ATrace layer for the [tracing](https://docs.rs/tracing/latest/tracing/) crate. |
| Compared to using the bindings directly, it has better instrumentation points and customizability. |
| The main drawback is lower performance. See the [Performance](#performance) section below for more |
| information. |
| |
| Add the tracing libraries to your `rustlibs` in `Android.bp`: |
| |
| ```text |
| rustlibs: [ |
| ... |
| "libatrace_tracing_subscriber", |
| "libtracing_subscriber", |
| "libtracing", |
| ... |
| ], |
| ``` |
| |
| [Initialize](https://docs.rs/tracing/latest/tracing/index.html#in-executables) the subscriber |
| before calling the tracing methods, usually somewhere in the beginning of `main()`. |
| |
| ```rust |
| // Initialize the subscriber, panic if it fails. |
| tracing_subscriber::registry() |
| .with(AtraceSubscriber::default().with_filter()) |
| .init(); |
| ``` |
| |
| The subscriber defaults to `AtraceTag::App`. Use other tags by creating the subscriber with |
| `AtraceSubscriber::new(tag: AtraceTag)`. |
| |
| You can combine the subscriber with other |
| [layers](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/layer/index.html). In |
| that case, omit `with_filter()` from the `AtraceSubscriber` initialization - it is an optimization |
| that disables instrumentation points when ATrace is disabled and it would affect other layers as |
| well. |
| |
| Now you can |
| [record spans and events](https://docs.rs/tracing/latest/tracing/index.html#recording-spans-and-events): |
| |
| ```rust |
| // This macro would automatically create and enter a span with function name and arguments. |
| #[tracing::instrument] |
| fn important_function() { |
| if condition { |
| // Use span! to trace inside a scope. |
| let _entered = tracing::span!(tracing::Level::TRACE, "Inside a scope").entered(); |
| ... |
| } |
| |
| // Use event! to record an instant event. |
| // You can annotate spans and events with fields. They will be appended to the end of |
| // the Atrace event. |
| tracing::info!(field="value", "My event"); |
| } |
| ``` |
| |
| See more in the [example](./example/src/tracing_subscriber_sample.rs) and check out the docs for |
| the [tracing](https://docs.rs/tracing/latest/tracing/index.html) and |
| [tracing-subscriber](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/index.html) |
| crates. |
| |
| ## Performance |
| |
| This section is an overview, you can find specific numbers in |
| [benchmark/README.md](./benchmark/README.md). |
| |
| ### ATrace bindings |
| |
| When tracing is enabled, you can expect 1-10 us per event - this is a significant cost that may |
| affect the performance of hot high-frequency methods. When the events are disabled, calling them is |
| cheap - on the order of 5-10 ns. There is a 10-20% overhead from the wrapper, mostly caused by |
| string conversion when tracing is enabled. |
| |
| ### Tracing subscriber |
| |
| The subscriber uses the bindings and adds its own overhead that depends on usage: |
| |
| * With tracing disabled and subscriber created `with_filter`, events cost around 30 ns. Not using |
| the filter brings the cost up to 100-400 ns per event. |
| * Instant events (`event!`) add roughly 200 ns to the bindings - 1.5 vs 1.3 us. |
| * Spans (`span!`) are roughly 400 ns slower - 2.8 vs 2.4 us. |
| * Using [fields](https://docs.rs/tracing/latest/tracing/index.html#recording-fields) adds time |
| that depends on the amount of the fields and the cost of converting them to strings. Typically |
| it is around an extra 500 ns per event and an extra 1 us for a span. |