| /* | 
 |  * Copyright (C) 2023 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <unistd.h> | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include <benchmark/benchmark.h> | 
 |  | 
 | #include "perfetto/public/abi/atomic.h" | 
 | #include "perfetto/public/data_source.h" | 
 | #include "perfetto/public/pb_utils.h" | 
 | #include "perfetto/public/producer.h" | 
 | #include "perfetto/public/protos/trace/test_event.pzc.h" | 
 | #include "perfetto/public/protos/trace/trace.pzc.h" | 
 | #include "perfetto/public/protos/trace/trace_packet.pzc.h" | 
 | #include "perfetto/public/protos/trace/track_event/debug_annotation.pzc.h" | 
 | #include "perfetto/public/protos/trace/track_event/track_event.pzc.h" | 
 | #include "perfetto/public/te_category_macros.h" | 
 | #include "perfetto/public/te_macros.h" | 
 | #include "perfetto/public/track_event.h" | 
 |  | 
 | #include "src/shared_lib/test/utils.h" | 
 |  | 
 | static struct PerfettoDs custom = PERFETTO_DS_INIT(); | 
 |  | 
 | #define BENCHMARK_CATEGORIES(C) C(benchmark_cat, "benchmark", "") | 
 |  | 
 | PERFETTO_TE_CATEGORIES_DEFINE(BENCHMARK_CATEGORIES) | 
 |  | 
 | namespace { | 
 |  | 
 | using ::perfetto::shlib::test_utils::FieldView; | 
 | using ::perfetto::shlib::test_utils::IdFieldView; | 
 | using ::perfetto::shlib::test_utils::TracingSession; | 
 |  | 
 | constexpr char kDataSourceName[] = "com.example.custom_data_source"; | 
 |  | 
 | bool Initialize() { | 
 |   struct PerfettoProducerInitArgs args = PERFETTO_PRODUCER_INIT_ARGS_INIT(); | 
 |   args.backends = PERFETTO_BACKEND_IN_PROCESS; | 
 |   PerfettoProducerInit(args); | 
 |   PerfettoDsRegister(&custom, kDataSourceName, PerfettoDsParamsDefault()); | 
 |   PerfettoTeInit(); | 
 |   PERFETTO_TE_REGISTER_CATEGORIES(BENCHMARK_CATEGORIES); | 
 |   return true; | 
 | } | 
 |  | 
 | void EnsureInitialized() { | 
 |   static bool initialized = Initialize(); | 
 |   (void)initialized; | 
 | } | 
 |  | 
 | size_t DecodePacketSizes(const std::vector<uint8_t>& data) { | 
 |   for (struct PerfettoPbDecoderField field : | 
 |        IdFieldView(data, perfetto_protos_Trace_packet_field_number)) { | 
 |     if (field.status != PERFETTO_PB_DECODER_OK || | 
 |         field.wire_type != PERFETTO_PB_WIRE_TYPE_DELIMITED) { | 
 |       abort(); | 
 |     } | 
 |     IdFieldView for_testing_fields( | 
 |         field, perfetto_protos_TracePacket_for_testing_field_number); | 
 |     if (!for_testing_fields.ok()) { | 
 |       abort(); | 
 |     } | 
 |     if (for_testing_fields.size() == 0) { | 
 |       continue; | 
 |     } | 
 |     if (for_testing_fields.size() > 1 || for_testing_fields.front().wire_type != | 
 |                                              PERFETTO_PB_WIRE_TYPE_DELIMITED) { | 
 |       abort(); | 
 |     } | 
 |     return field.value.delimited.len; | 
 |   } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | void BM_Shlib_DataSource_Disabled(benchmark::State& state) { | 
 |   EnsureInitialized(); | 
 |   for (auto _ : state) { | 
 |     PERFETTO_DS_TRACE(custom, ctx) {} | 
 |     benchmark::ClobberMemory(); | 
 |   } | 
 | } | 
 |  | 
 | void BM_Shlib_DataSource_DifferentPacketSize(benchmark::State& state) { | 
 |   EnsureInitialized(); | 
 |   TracingSession tracing_session = | 
 |       TracingSession::Builder().set_data_source_name(kDataSourceName).Build(); | 
 |  | 
 |   // This controls the number of times a field is added in the trace packet. | 
 |   // It controls the size of the trace packet. The PacketSize counter reports | 
 |   // the exact number. | 
 |   const size_t kNumFields = static_cast<size_t>(state.range(0)); | 
 |  | 
 |   for (auto _ : state) { | 
 |     PERFETTO_DS_TRACE(custom, ctx) { | 
 |       struct PerfettoDsRootTracePacket trace_packet; | 
 |       PerfettoDsTracerPacketBegin(&ctx, &trace_packet); | 
 |  | 
 |       { | 
 |         struct perfetto_protos_TestEvent for_testing; | 
 |         perfetto_protos_TracePacket_begin_for_testing(&trace_packet.msg, | 
 |                                                       &for_testing); | 
 |         { | 
 |           struct perfetto_protos_TestEvent_TestPayload payload; | 
 |           perfetto_protos_TestEvent_begin_payload(&for_testing, &payload); | 
 |           for (size_t i = 0; i < kNumFields; i++) { | 
 |             perfetto_protos_TestEvent_TestPayload_set_cstr_str(&payload, | 
 |                                                                "ABCDEFGH"); | 
 |           } | 
 |           perfetto_protos_TestEvent_end_payload(&for_testing, &payload); | 
 |         } | 
 |         perfetto_protos_TracePacket_end_for_testing(&trace_packet.msg, | 
 |                                                     &for_testing); | 
 |       } | 
 |       PerfettoDsTracerPacketEnd(&ctx, &trace_packet); | 
 |     } | 
 |     benchmark::ClobberMemory(); | 
 |   } | 
 |  | 
 |   tracing_session.StopBlocking(); | 
 |   std::vector<uint8_t> data = tracing_session.ReadBlocking(); | 
 |  | 
 |   // Just compute the PacketSize counter. | 
 |   state.counters["PacketSize"] = static_cast<double>(DecodePacketSizes(data)); | 
 | } | 
 |  | 
 | void BM_Shlib_TeDisabled(benchmark::State& state) { | 
 |   EnsureInitialized(); | 
 |   while (state.KeepRunning()) { | 
 |     PERFETTO_TE(benchmark_cat, PERFETTO_TE_SLICE_BEGIN("DisabledEvent")); | 
 |     benchmark::ClobberMemory(); | 
 |   } | 
 | } | 
 |  | 
 | void BM_Shlib_TeBasic(benchmark::State& state) { | 
 |   EnsureInitialized(); | 
 |   TracingSession tracing_session = | 
 |       TracingSession::Builder().set_data_source_name("track_event").Build(); | 
 |  | 
 |   while (state.KeepRunning()) { | 
 |     PERFETTO_TE(benchmark_cat, PERFETTO_TE_SLICE_BEGIN("Event")); | 
 |     benchmark::ClobberMemory(); | 
 |   } | 
 | } | 
 |  | 
 | void BM_Shlib_TeBasicNoIntern(benchmark::State& state) { | 
 |   EnsureInitialized(); | 
 |   TracingSession tracing_session = | 
 |       TracingSession::Builder().set_data_source_name("track_event").Build(); | 
 |  | 
 |   while (state.KeepRunning()) { | 
 |     PERFETTO_TE(benchmark_cat, PERFETTO_TE_SLICE_BEGIN("Event"), | 
 |                 PERFETTO_TE_NO_INTERN()); | 
 |     benchmark::ClobberMemory(); | 
 |   } | 
 | } | 
 |  | 
 | void BM_Shlib_TeDebugAnnotations(benchmark::State& state) { | 
 |   EnsureInitialized(); | 
 |   TracingSession tracing_session = | 
 |       TracingSession::Builder().set_data_source_name("track_event").Build(); | 
 |  | 
 |   while (state.KeepRunning()) { | 
 |     PERFETTO_TE(benchmark_cat, PERFETTO_TE_SLICE_BEGIN("Event"), | 
 |                 PERFETTO_TE_ARG_UINT64("value", 42)); | 
 |     benchmark::ClobberMemory(); | 
 |   } | 
 | } | 
 |  | 
 | void BM_Shlib_TeLlBasic(benchmark::State& state) { | 
 |   EnsureInitialized(); | 
 |   TracingSession tracing_session = | 
 |       TracingSession::Builder().set_data_source_name("track_event").Build(); | 
 |  | 
 |   while (state.KeepRunning()) { | 
 |     if (PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT( | 
 |             benchmark_cat.enabled, PERFETTO_MEMORY_ORDER_RELAXED))) { | 
 |       struct PerfettoTeTimestamp timestamp = PerfettoTeGetTimestamp(); | 
 |       int32_t type = PERFETTO_TE_TYPE_SLICE_BEGIN; | 
 |       const char* name = "Event"; | 
 |       for (struct PerfettoTeLlIterator ctx = | 
 |                PerfettoTeLlBeginSlowPath(&benchmark_cat, timestamp); | 
 |            ctx.impl.ds.tracer != nullptr; | 
 |            PerfettoTeLlNext(&benchmark_cat, timestamp, &ctx)) { | 
 |         uint64_t name_iid; | 
 |         { | 
 |           struct PerfettoDsRootTracePacket trace_packet; | 
 |           PerfettoTeLlPacketBegin(&ctx, &trace_packet); | 
 |           PerfettoTeLlWriteTimestamp(&trace_packet.msg, ×tamp); | 
 |           perfetto_protos_TracePacket_set_sequence_flags( | 
 |               &trace_packet.msg, | 
 |               perfetto_protos_TracePacket_SEQ_NEEDS_INCREMENTAL_STATE); | 
 |           { | 
 |             struct PerfettoTeLlInternContext intern_ctx; | 
 |             PerfettoTeLlInternContextInit(&intern_ctx, ctx.impl.incr, | 
 |                                           &trace_packet.msg); | 
 |             PerfettoTeLlInternRegisteredCat(&intern_ctx, &benchmark_cat); | 
 |             name_iid = PerfettoTeLlInternEventName(&intern_ctx, name); | 
 |             PerfettoTeLlInternContextDestroy(&intern_ctx); | 
 |           } | 
 |           { | 
 |             struct perfetto_protos_TrackEvent te_msg; | 
 |             perfetto_protos_TracePacket_begin_track_event(&trace_packet.msg, | 
 |                                                           &te_msg); | 
 |             perfetto_protos_TrackEvent_set_type( | 
 |                 &te_msg, | 
 |                 static_cast<enum perfetto_protos_TrackEvent_Type>(type)); | 
 |             PerfettoTeLlWriteRegisteredCat(&te_msg, &benchmark_cat); | 
 |             PerfettoTeLlWriteInternedEventName(&te_msg, name_iid); | 
 |             perfetto_protos_TracePacket_end_track_event(&trace_packet.msg, | 
 |                                                         &te_msg); | 
 |           } | 
 |           PerfettoTeLlPacketEnd(&ctx, &trace_packet); | 
 |         } | 
 |       } | 
 |     } | 
 |  | 
 |     benchmark::ClobberMemory(); | 
 |   } | 
 | } | 
 |  | 
 | void BM_Shlib_TeLlBasicNoIntern(benchmark::State& state) { | 
 |   EnsureInitialized(); | 
 |   TracingSession tracing_session = | 
 |       TracingSession::Builder().set_data_source_name("track_event").Build(); | 
 |  | 
 |   while (state.KeepRunning()) { | 
 |     if (PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT( | 
 |             benchmark_cat.enabled, PERFETTO_MEMORY_ORDER_RELAXED))) { | 
 |       struct PerfettoTeTimestamp timestamp = PerfettoTeGetTimestamp(); | 
 |       int32_t type = PERFETTO_TE_TYPE_SLICE_BEGIN; | 
 |       const char* name = "Event"; | 
 |       for (struct PerfettoTeLlIterator ctx = | 
 |                PerfettoTeLlBeginSlowPath(&benchmark_cat, timestamp); | 
 |            ctx.impl.ds.tracer != nullptr; | 
 |            PerfettoTeLlNext(&benchmark_cat, timestamp, &ctx)) { | 
 |         { | 
 |           struct PerfettoDsRootTracePacket trace_packet; | 
 |           PerfettoTeLlPacketBegin(&ctx, &trace_packet); | 
 |           PerfettoTeLlWriteTimestamp(&trace_packet.msg, ×tamp); | 
 |           perfetto_protos_TracePacket_set_sequence_flags( | 
 |               &trace_packet.msg, | 
 |               perfetto_protos_TracePacket_SEQ_NEEDS_INCREMENTAL_STATE); | 
 |           { | 
 |             struct PerfettoTeLlInternContext intern_ctx; | 
 |             PerfettoTeLlInternContextInit(&intern_ctx, ctx.impl.incr, | 
 |                                           &trace_packet.msg); | 
 |             PerfettoTeLlInternRegisteredCat(&intern_ctx, &benchmark_cat); | 
 |             PerfettoTeLlInternContextDestroy(&intern_ctx); | 
 |           } | 
 |           { | 
 |             struct perfetto_protos_TrackEvent te_msg; | 
 |             perfetto_protos_TracePacket_begin_track_event(&trace_packet.msg, | 
 |                                                           &te_msg); | 
 |             perfetto_protos_TrackEvent_set_type( | 
 |                 &te_msg, | 
 |                 static_cast<enum perfetto_protos_TrackEvent_Type>(type)); | 
 |             PerfettoTeLlWriteRegisteredCat(&te_msg, &benchmark_cat); | 
 |             PerfettoTeLlWriteEventName(&te_msg, name); | 
 |             perfetto_protos_TracePacket_end_track_event(&trace_packet.msg, | 
 |                                                         &te_msg); | 
 |           } | 
 |           PerfettoTeLlPacketEnd(&ctx, &trace_packet); | 
 |         } | 
 |       } | 
 |     } | 
 |     benchmark::ClobberMemory(); | 
 |   } | 
 | } | 
 |  | 
 | void BM_Shlib_TeLlDebugAnnotations(benchmark::State& state) { | 
 |   EnsureInitialized(); | 
 |   TracingSession tracing_session = | 
 |       TracingSession::Builder().set_data_source_name("track_event").Build(); | 
 |  | 
 |   while (state.KeepRunning()) { | 
 |     if (PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT( | 
 |             benchmark_cat.enabled, PERFETTO_MEMORY_ORDER_RELAXED))) { | 
 |       struct PerfettoTeTimestamp timestamp = PerfettoTeGetTimestamp(); | 
 |       int32_t type = PERFETTO_TE_TYPE_SLICE_BEGIN; | 
 |       const char* name = "Event"; | 
 |       for (struct PerfettoTeLlIterator ctx = | 
 |                PerfettoTeLlBeginSlowPath(&benchmark_cat, timestamp); | 
 |            ctx.impl.ds.tracer != nullptr; | 
 |            PerfettoTeLlNext(&benchmark_cat, timestamp, &ctx)) { | 
 |         uint64_t name_iid; | 
 |         uint64_t dbg_arg_iid; | 
 |         { | 
 |           struct PerfettoDsRootTracePacket trace_packet; | 
 |           PerfettoTeLlPacketBegin(&ctx, &trace_packet); | 
 |           PerfettoTeLlWriteTimestamp(&trace_packet.msg, ×tamp); | 
 |           perfetto_protos_TracePacket_set_sequence_flags( | 
 |               &trace_packet.msg, | 
 |               perfetto_protos_TracePacket_SEQ_NEEDS_INCREMENTAL_STATE); | 
 |           { | 
 |             struct PerfettoTeLlInternContext intern_ctx; | 
 |             PerfettoTeLlInternContextInit(&intern_ctx, ctx.impl.incr, | 
 |                                           &trace_packet.msg); | 
 |             PerfettoTeLlInternRegisteredCat(&intern_ctx, &benchmark_cat); | 
 |             name_iid = PerfettoTeLlInternEventName(&intern_ctx, name); | 
 |             dbg_arg_iid = PerfettoTeLlInternDbgArgName(&intern_ctx, "value"); | 
 |             PerfettoTeLlInternContextDestroy(&intern_ctx); | 
 |           } | 
 |           { | 
 |             struct perfetto_protos_TrackEvent te_msg; | 
 |             perfetto_protos_TracePacket_begin_track_event(&trace_packet.msg, | 
 |                                                           &te_msg); | 
 |             perfetto_protos_TrackEvent_set_type( | 
 |                 &te_msg, | 
 |                 static_cast<enum perfetto_protos_TrackEvent_Type>(type)); | 
 |             PerfettoTeLlWriteRegisteredCat(&te_msg, &benchmark_cat); | 
 |             PerfettoTeLlWriteInternedEventName(&te_msg, name_iid); | 
 |             { | 
 |               struct perfetto_protos_DebugAnnotation dbg_arg; | 
 |               perfetto_protos_TrackEvent_begin_debug_annotations(&te_msg, | 
 |                                                                  &dbg_arg); | 
 |               perfetto_protos_DebugAnnotation_set_name_iid(&dbg_arg, | 
 |                                                            dbg_arg_iid); | 
 |               perfetto_protos_DebugAnnotation_set_uint_value(&dbg_arg, 42); | 
 |               perfetto_protos_TrackEvent_end_debug_annotations(&te_msg, | 
 |                                                                &dbg_arg); | 
 |             } | 
 |             perfetto_protos_TracePacket_end_track_event(&trace_packet.msg, | 
 |                                                         &te_msg); | 
 |           } | 
 |           PerfettoTeLlPacketEnd(&ctx, &trace_packet); | 
 |         } | 
 |       } | 
 |     } | 
 |     benchmark::ClobberMemory(); | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | BENCHMARK(BM_Shlib_DataSource_Disabled); | 
 | BENCHMARK(BM_Shlib_DataSource_DifferentPacketSize)->Range(1, 1000); | 
 | BENCHMARK(BM_Shlib_TeDisabled); | 
 | BENCHMARK(BM_Shlib_TeBasic); | 
 | BENCHMARK(BM_Shlib_TeBasicNoIntern); | 
 | BENCHMARK(BM_Shlib_TeDebugAnnotations); | 
 | BENCHMARK(BM_Shlib_TeLlBasic); | 
 | BENCHMARK(BM_Shlib_TeLlBasicNoIntern); | 
 | BENCHMARK(BM_Shlib_TeLlDebugAnnotations); |