README.md
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