1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20
21 #include <memory>
22
23 #include <benchmark/benchmark.h>
24
25 #include "perfetto/public/abi/atomic.h"
26 #include "perfetto/public/data_source.h"
27 #include "perfetto/public/pb_utils.h"
28 #include "perfetto/public/producer.h"
29 #include "perfetto/public/protos/trace/test_event.pzc.h"
30 #include "perfetto/public/protos/trace/trace.pzc.h"
31 #include "perfetto/public/protos/trace/trace_packet.pzc.h"
32 #include "perfetto/public/protos/trace/track_event/debug_annotation.pzc.h"
33 #include "perfetto/public/protos/trace/track_event/track_event.pzc.h"
34 #include "perfetto/public/te_category_macros.h"
35 #include "perfetto/public/te_macros.h"
36 #include "perfetto/public/track_event.h"
37
38 #include "src/shared_lib/test/utils.h"
39
40 static struct PerfettoDs custom = PERFETTO_DS_INIT();
41
42 #define BENCHMARK_CATEGORIES(C) C(benchmark_cat, "benchmark", "")
43
44 PERFETTO_TE_CATEGORIES_DEFINE(BENCHMARK_CATEGORIES)
45
46 namespace {
47
48 using ::perfetto::shlib::test_utils::FieldView;
49 using ::perfetto::shlib::test_utils::IdFieldView;
50 using ::perfetto::shlib::test_utils::TracingSession;
51
52 constexpr char kDataSourceName[] = "com.example.custom_data_source";
53
Initialize()54 bool Initialize() {
55 struct PerfettoProducerInitArgs args = PERFETTO_PRODUCER_INIT_ARGS_INIT();
56 args.backends = PERFETTO_BACKEND_IN_PROCESS;
57 PerfettoProducerInit(args);
58 PerfettoDsRegister(&custom, kDataSourceName, PerfettoDsParamsDefault());
59 PerfettoTeInit();
60 PERFETTO_TE_REGISTER_CATEGORIES(BENCHMARK_CATEGORIES);
61 return true;
62 }
63
EnsureInitialized()64 void EnsureInitialized() {
65 static bool initialized = Initialize();
66 (void)initialized;
67 }
68
DecodePacketSizes(const std::vector<uint8_t> & data)69 size_t DecodePacketSizes(const std::vector<uint8_t>& data) {
70 for (struct PerfettoPbDecoderField field :
71 IdFieldView(data, perfetto_protos_Trace_packet_field_number)) {
72 if (field.status != PERFETTO_PB_DECODER_OK ||
73 field.wire_type != PERFETTO_PB_WIRE_TYPE_DELIMITED) {
74 abort();
75 }
76 IdFieldView for_testing_fields(
77 field, perfetto_protos_TracePacket_for_testing_field_number);
78 if (!for_testing_fields.ok()) {
79 abort();
80 }
81 if (for_testing_fields.size() == 0) {
82 continue;
83 }
84 if (for_testing_fields.size() > 1 || for_testing_fields.front().wire_type !=
85 PERFETTO_PB_WIRE_TYPE_DELIMITED) {
86 abort();
87 }
88 return field.value.delimited.len;
89 }
90
91 return 0;
92 }
93
BM_Shlib_DataSource_Disabled(benchmark::State & state)94 void BM_Shlib_DataSource_Disabled(benchmark::State& state) {
95 EnsureInitialized();
96 for (auto _ : state) {
97 PERFETTO_DS_TRACE(custom, ctx) {}
98 benchmark::ClobberMemory();
99 }
100 }
101
BM_Shlib_DataSource_DifferentPacketSize(benchmark::State & state)102 void BM_Shlib_DataSource_DifferentPacketSize(benchmark::State& state) {
103 EnsureInitialized();
104 TracingSession tracing_session =
105 TracingSession::Builder().set_data_source_name(kDataSourceName).Build();
106
107 // This controls the number of times a field is added in the trace packet.
108 // It controls the size of the trace packet. The PacketSize counter reports
109 // the exact number.
110 const size_t kNumFields = static_cast<size_t>(state.range(0));
111
112 for (auto _ : state) {
113 PERFETTO_DS_TRACE(custom, ctx) {
114 struct PerfettoDsRootTracePacket trace_packet;
115 PerfettoDsTracerPacketBegin(&ctx, &trace_packet);
116
117 {
118 struct perfetto_protos_TestEvent for_testing;
119 perfetto_protos_TracePacket_begin_for_testing(&trace_packet.msg,
120 &for_testing);
121 {
122 struct perfetto_protos_TestEvent_TestPayload payload;
123 perfetto_protos_TestEvent_begin_payload(&for_testing, &payload);
124 for (size_t i = 0; i < kNumFields; i++) {
125 perfetto_protos_TestEvent_TestPayload_set_cstr_str(&payload,
126 "ABCDEFGH");
127 }
128 perfetto_protos_TestEvent_end_payload(&for_testing, &payload);
129 }
130 perfetto_protos_TracePacket_end_for_testing(&trace_packet.msg,
131 &for_testing);
132 }
133 PerfettoDsTracerPacketEnd(&ctx, &trace_packet);
134 }
135 benchmark::ClobberMemory();
136 }
137
138 tracing_session.StopBlocking();
139 std::vector<uint8_t> data = tracing_session.ReadBlocking();
140
141 // Just compute the PacketSize counter.
142 state.counters["PacketSize"] = static_cast<double>(DecodePacketSizes(data));
143 }
144
BM_Shlib_TeDisabled(benchmark::State & state)145 void BM_Shlib_TeDisabled(benchmark::State& state) {
146 EnsureInitialized();
147 while (state.KeepRunning()) {
148 PERFETTO_TE(benchmark_cat, PERFETTO_TE_SLICE_BEGIN("DisabledEvent"));
149 benchmark::ClobberMemory();
150 }
151 }
152
BM_Shlib_TeBasic(benchmark::State & state)153 void BM_Shlib_TeBasic(benchmark::State& state) {
154 EnsureInitialized();
155 TracingSession tracing_session = TracingSession::Builder()
156 .set_data_source_name("track_event")
157 .add_enabled_category("*")
158 .Build();
159
160 while (state.KeepRunning()) {
161 PERFETTO_TE(benchmark_cat, PERFETTO_TE_SLICE_BEGIN("Event"));
162 benchmark::ClobberMemory();
163 }
164 }
165
BM_Shlib_TeBasicNoIntern(benchmark::State & state)166 void BM_Shlib_TeBasicNoIntern(benchmark::State& state) {
167 EnsureInitialized();
168 TracingSession tracing_session = TracingSession::Builder()
169 .set_data_source_name("track_event")
170 .add_enabled_category("*")
171 .Build();
172
173 while (state.KeepRunning()) {
174 PERFETTO_TE(benchmark_cat, PERFETTO_TE_SLICE_BEGIN("Event"),
175 PERFETTO_TE_NO_INTERN());
176 benchmark::ClobberMemory();
177 }
178 }
179
BM_Shlib_TeDebugAnnotations(benchmark::State & state)180 void BM_Shlib_TeDebugAnnotations(benchmark::State& state) {
181 EnsureInitialized();
182 TracingSession tracing_session = TracingSession::Builder()
183 .set_data_source_name("track_event")
184 .add_enabled_category("*")
185 .Build();
186
187 while (state.KeepRunning()) {
188 PERFETTO_TE(benchmark_cat, PERFETTO_TE_SLICE_BEGIN("Event"),
189 PERFETTO_TE_ARG_UINT64("value", 42));
190 benchmark::ClobberMemory();
191 }
192 }
193
BM_Shlib_TeLlBasic(benchmark::State & state)194 void BM_Shlib_TeLlBasic(benchmark::State& state) {
195 EnsureInitialized();
196 TracingSession tracing_session = TracingSession::Builder()
197 .set_data_source_name("track_event")
198 .add_enabled_category("*")
199 .Build();
200
201 while (state.KeepRunning()) {
202 if (PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT(
203 benchmark_cat.enabled, PERFETTO_MEMORY_ORDER_RELAXED))) {
204 struct PerfettoTeTimestamp timestamp = PerfettoTeGetTimestamp();
205 int32_t type = PERFETTO_TE_TYPE_SLICE_BEGIN;
206 const char* name = "Event";
207 for (struct PerfettoTeLlIterator ctx =
208 PerfettoTeLlBeginSlowPath(&benchmark_cat, timestamp);
209 ctx.impl.ds.tracer != nullptr;
210 PerfettoTeLlNext(&benchmark_cat, timestamp, &ctx)) {
211 uint64_t name_iid;
212 {
213 struct PerfettoDsRootTracePacket trace_packet;
214 PerfettoTeLlPacketBegin(&ctx, &trace_packet);
215 PerfettoTeLlWriteTimestamp(&trace_packet.msg, ×tamp);
216 perfetto_protos_TracePacket_set_sequence_flags(
217 &trace_packet.msg,
218 perfetto_protos_TracePacket_SEQ_NEEDS_INCREMENTAL_STATE);
219 {
220 struct PerfettoTeLlInternContext intern_ctx;
221 PerfettoTeLlInternContextInit(&intern_ctx, ctx.impl.incr,
222 &trace_packet.msg);
223 PerfettoTeLlInternRegisteredCat(&intern_ctx, &benchmark_cat);
224 name_iid = PerfettoTeLlInternEventName(&intern_ctx, name);
225 PerfettoTeLlInternContextDestroy(&intern_ctx);
226 }
227 {
228 struct perfetto_protos_TrackEvent te_msg;
229 perfetto_protos_TracePacket_begin_track_event(&trace_packet.msg,
230 &te_msg);
231 perfetto_protos_TrackEvent_set_type(
232 &te_msg,
233 static_cast<enum perfetto_protos_TrackEvent_Type>(type));
234 PerfettoTeLlWriteRegisteredCat(&te_msg, &benchmark_cat);
235 PerfettoTeLlWriteInternedEventName(&te_msg, name_iid);
236 perfetto_protos_TracePacket_end_track_event(&trace_packet.msg,
237 &te_msg);
238 }
239 PerfettoTeLlPacketEnd(&ctx, &trace_packet);
240 }
241 }
242 }
243
244 benchmark::ClobberMemory();
245 }
246 }
247
BM_Shlib_TeLlBasicNoIntern(benchmark::State & state)248 void BM_Shlib_TeLlBasicNoIntern(benchmark::State& state) {
249 EnsureInitialized();
250 TracingSession tracing_session = TracingSession::Builder()
251 .set_data_source_name("track_event")
252 .add_enabled_category("*")
253 .Build();
254
255 while (state.KeepRunning()) {
256 if (PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT(
257 benchmark_cat.enabled, PERFETTO_MEMORY_ORDER_RELAXED))) {
258 struct PerfettoTeTimestamp timestamp = PerfettoTeGetTimestamp();
259 int32_t type = PERFETTO_TE_TYPE_SLICE_BEGIN;
260 const char* name = "Event";
261 for (struct PerfettoTeLlIterator ctx =
262 PerfettoTeLlBeginSlowPath(&benchmark_cat, timestamp);
263 ctx.impl.ds.tracer != nullptr;
264 PerfettoTeLlNext(&benchmark_cat, timestamp, &ctx)) {
265 {
266 struct PerfettoDsRootTracePacket trace_packet;
267 PerfettoTeLlPacketBegin(&ctx, &trace_packet);
268 PerfettoTeLlWriteTimestamp(&trace_packet.msg, ×tamp);
269 perfetto_protos_TracePacket_set_sequence_flags(
270 &trace_packet.msg,
271 perfetto_protos_TracePacket_SEQ_NEEDS_INCREMENTAL_STATE);
272 {
273 struct PerfettoTeLlInternContext intern_ctx;
274 PerfettoTeLlInternContextInit(&intern_ctx, ctx.impl.incr,
275 &trace_packet.msg);
276 PerfettoTeLlInternRegisteredCat(&intern_ctx, &benchmark_cat);
277 PerfettoTeLlInternContextDestroy(&intern_ctx);
278 }
279 {
280 struct perfetto_protos_TrackEvent te_msg;
281 perfetto_protos_TracePacket_begin_track_event(&trace_packet.msg,
282 &te_msg);
283 perfetto_protos_TrackEvent_set_type(
284 &te_msg,
285 static_cast<enum perfetto_protos_TrackEvent_Type>(type));
286 PerfettoTeLlWriteRegisteredCat(&te_msg, &benchmark_cat);
287 PerfettoTeLlWriteEventName(&te_msg, name);
288 perfetto_protos_TracePacket_end_track_event(&trace_packet.msg,
289 &te_msg);
290 }
291 PerfettoTeLlPacketEnd(&ctx, &trace_packet);
292 }
293 }
294 }
295 benchmark::ClobberMemory();
296 }
297 }
298
BM_Shlib_TeLlDebugAnnotations(benchmark::State & state)299 void BM_Shlib_TeLlDebugAnnotations(benchmark::State& state) {
300 EnsureInitialized();
301 TracingSession tracing_session = TracingSession::Builder()
302 .set_data_source_name("track_event")
303 .add_enabled_category("*")
304 .Build();
305
306 while (state.KeepRunning()) {
307 if (PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT(
308 benchmark_cat.enabled, PERFETTO_MEMORY_ORDER_RELAXED))) {
309 struct PerfettoTeTimestamp timestamp = PerfettoTeGetTimestamp();
310 int32_t type = PERFETTO_TE_TYPE_SLICE_BEGIN;
311 const char* name = "Event";
312 for (struct PerfettoTeLlIterator ctx =
313 PerfettoTeLlBeginSlowPath(&benchmark_cat, timestamp);
314 ctx.impl.ds.tracer != nullptr;
315 PerfettoTeLlNext(&benchmark_cat, timestamp, &ctx)) {
316 uint64_t name_iid;
317 uint64_t dbg_arg_iid;
318 {
319 struct PerfettoDsRootTracePacket trace_packet;
320 PerfettoTeLlPacketBegin(&ctx, &trace_packet);
321 PerfettoTeLlWriteTimestamp(&trace_packet.msg, ×tamp);
322 perfetto_protos_TracePacket_set_sequence_flags(
323 &trace_packet.msg,
324 perfetto_protos_TracePacket_SEQ_NEEDS_INCREMENTAL_STATE);
325 {
326 struct PerfettoTeLlInternContext intern_ctx;
327 PerfettoTeLlInternContextInit(&intern_ctx, ctx.impl.incr,
328 &trace_packet.msg);
329 PerfettoTeLlInternRegisteredCat(&intern_ctx, &benchmark_cat);
330 name_iid = PerfettoTeLlInternEventName(&intern_ctx, name);
331 dbg_arg_iid = PerfettoTeLlInternDbgArgName(&intern_ctx, "value");
332 PerfettoTeLlInternContextDestroy(&intern_ctx);
333 }
334 {
335 struct perfetto_protos_TrackEvent te_msg;
336 perfetto_protos_TracePacket_begin_track_event(&trace_packet.msg,
337 &te_msg);
338 perfetto_protos_TrackEvent_set_type(
339 &te_msg,
340 static_cast<enum perfetto_protos_TrackEvent_Type>(type));
341 PerfettoTeLlWriteRegisteredCat(&te_msg, &benchmark_cat);
342 PerfettoTeLlWriteInternedEventName(&te_msg, name_iid);
343 {
344 struct perfetto_protos_DebugAnnotation dbg_arg;
345 perfetto_protos_TrackEvent_begin_debug_annotations(&te_msg,
346 &dbg_arg);
347 perfetto_protos_DebugAnnotation_set_name_iid(&dbg_arg,
348 dbg_arg_iid);
349 perfetto_protos_DebugAnnotation_set_uint_value(&dbg_arg, 42);
350 perfetto_protos_TrackEvent_end_debug_annotations(&te_msg,
351 &dbg_arg);
352 }
353 perfetto_protos_TracePacket_end_track_event(&trace_packet.msg,
354 &te_msg);
355 }
356 PerfettoTeLlPacketEnd(&ctx, &trace_packet);
357 }
358 }
359 }
360 benchmark::ClobberMemory();
361 }
362 }
363
364 } // namespace
365
366 BENCHMARK(BM_Shlib_DataSource_Disabled);
367 BENCHMARK(BM_Shlib_DataSource_DifferentPacketSize)->Range(1, 1000);
368 BENCHMARK(BM_Shlib_TeDisabled);
369 BENCHMARK(BM_Shlib_TeBasic);
370 BENCHMARK(BM_Shlib_TeBasicNoIntern);
371 BENCHMARK(BM_Shlib_TeDebugAnnotations);
372 BENCHMARK(BM_Shlib_TeLlBasic);
373 BENCHMARK(BM_Shlib_TeLlBasicNoIntern);
374 BENCHMARK(BM_Shlib_TeLlDebugAnnotations);
375