diff options
author | 2023-11-15 13:30:48 +0000 | |
---|---|---|
committer | 2024-03-09 11:19:45 +0000 | |
commit | a0ae40f29a3a4d1b269ded4cda9d4f97d65d39fe (patch) | |
tree | 9059bd60a0d6675cb960d975200c3ab813d19cb2 | |
parent | 67cf0027b4f05681eae77ce60e443b86d8fd44c0 (diff) |
Add libtracing_perfetto for tracing using Perfetto SDK
libtracing_perfetto internally uses the Perfetto SDK or
libcutils based on an aconfig flag.
Test: atest libtracing_perfetto_tests
Bug: 303199244
Ignore-AOSP-First: Internal feature
Change-Id: I9922d11607051ff22777e3df12b8f877a765dfa7
-rw-r--r-- | libs/tracing_perfetto/.clang-format | 12 | ||||
-rw-r--r-- | libs/tracing_perfetto/Android.bp | 49 | ||||
-rw-r--r-- | libs/tracing_perfetto/OWNERS | 2 | ||||
-rw-r--r-- | libs/tracing_perfetto/include/trace_categories.h | 65 | ||||
-rw-r--r-- | libs/tracing_perfetto/include/trace_result.h | 30 | ||||
-rw-r--r-- | libs/tracing_perfetto/include/tracing_perfetto.h | 53 | ||||
-rw-r--r-- | libs/tracing_perfetto/tests/Android.bp | 45 | ||||
-rw-r--r-- | libs/tracing_perfetto/tests/tracing_perfetto_test.cpp | 111 | ||||
-rw-r--r-- | libs/tracing_perfetto/tests/utils.cpp | 219 | ||||
-rw-r--r-- | libs/tracing_perfetto/tests/utils.h | 452 | ||||
-rw-r--r-- | libs/tracing_perfetto/tracing_perfetto.cpp | 141 | ||||
-rw-r--r-- | libs/tracing_perfetto/tracing_perfetto_internal.cpp | 229 | ||||
-rw-r--r-- | libs/tracing_perfetto/tracing_perfetto_internal.h | 65 |
13 files changed, 1473 insertions, 0 deletions
diff --git a/libs/tracing_perfetto/.clang-format b/libs/tracing_perfetto/.clang-format new file mode 100644 index 0000000000..f3974548f6 --- /dev/null +++ b/libs/tracing_perfetto/.clang-format @@ -0,0 +1,12 @@ +BasedOnStyle: Google +AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: false + +ColumnLimit: 80 +ContinuationIndentWidth: 4 +CommentPragmas: NOLINT:.* +DerivePointerAlignment: false +IndentWidth: 2 +PointerAlignment: Left +UseTab: Never +PenaltyExcessCharacter: 32
\ No newline at end of file diff --git a/libs/tracing_perfetto/Android.bp b/libs/tracing_perfetto/Android.bp new file mode 100644 index 0000000000..3a4c869e46 --- /dev/null +++ b/libs/tracing_perfetto/Android.bp @@ -0,0 +1,49 @@ +// Copyright 2024 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. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_library_shared { + name: "libtracing_perfetto", + export_include_dirs: [ + "include", + ], + + cflags: [ + "-Wall", + "-Werror", + "-Wno-enum-compare", + "-Wno-unused-function", + ], + + srcs: [ + "tracing_perfetto.cpp", + "tracing_perfetto_internal.cpp", + ], + + shared_libs: [ + "libcutils", + "libperfetto_c", + "android.os.flags-aconfig-cc-host", + ], + + host_supported: true, +} diff --git a/libs/tracing_perfetto/OWNERS b/libs/tracing_perfetto/OWNERS new file mode 100644 index 0000000000..e2d4b4636a --- /dev/null +++ b/libs/tracing_perfetto/OWNERS @@ -0,0 +1,2 @@ +zezeozue@google.com +biswarupp@google.com
\ No newline at end of file diff --git a/libs/tracing_perfetto/include/trace_categories.h b/libs/tracing_perfetto/include/trace_categories.h new file mode 100644 index 0000000000..6d4168b772 --- /dev/null +++ b/libs/tracing_perfetto/include/trace_categories.h @@ -0,0 +1,65 @@ +/* + * Copyright 2024 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. + */ + +#ifndef TRACE_CATEGORIES_H +#define TRACE_CATEGORIES_H + +/** + * Keep these in sync with frameworks/base/core/java/android/os/Trace.java. + */ +#define TRACE_CATEGORY_ALWAYS (1 << 0) +#define TRACE_CATEGORY_GRAPHICS (1 << 1) +#define TRACE_CATEGORY_INPUT (1 << 2) +#define TRACE_CATEGORY_VIEW (1 << 3) +#define TRACE_CATEGORY_WEBVIEW (1 << 4) +#define TRACE_CATEGORY_WINDOW_MANAGER (1 << 5) +#define TRACE_CATEGORY_ACTIVITY_MANAGER (1 << 6) +#define TRACE_CATEGORY_SYNC_MANAGER (1 << 7) +#define TRACE_CATEGORY_AUDIO (1 << 8) +#define TRACE_CATEGORY_VIDEO (1 << 9) +#define TRACE_CATEGORY_CAMERA (1 << 10) +#define TRACE_CATEGORY_HAL (1 << 11) +#define TRACE_CATEGORY_APP (1 << 12) +#define TRACE_CATEGORY_RESOURCES (1 << 13) +#define TRACE_CATEGORY_DALVIK (1 << 14) +#define TRACE_CATEGORY_RS (1 << 15) +#define TRACE_CATEGORY_BIONIC (1 << 16) +#define TRACE_CATEGORY_POWER (1 << 17) +#define TRACE_CATEGORY_PACKAGE_MANAGER (1 << 18) +#define TRACE_CATEGORY_SYSTEM_SERVER (1 << 19) +#define TRACE_CATEGORY_DATABASE (1 << 20) +#define TRACE_CATEGORY_NETWORK (1 << 21) +#define TRACE_CATEGORY_ADB (1 << 22) +#define TRACE_CATEGORY_VIBRATOR (1 << 23) +#define TRACE_CATEGORY_AIDL (1 << 24) +#define TRACE_CATEGORY_NNAPI (1 << 25) +#define TRACE_CATEGORY_RRO (1 << 26) +#define TRACE_CATEGORY_THERMAL (1 << 27) + +// Allow all categories except TRACE_CATEGORY_APP +#define TRACE_CATEGORIES \ + TRACE_CATEGORY_ALWAYS | TRACE_CATEGORY_GRAPHICS | TRACE_CATEGORY_INPUT | \ + TRACE_CATEGORY_VIEW | TRACE_CATEGORY_WEBVIEW | \ + TRACE_CATEGORY_WINDOW_MANAGER | TRACE_CATEGORY_ACTIVITY_MANAGER | \ + TRACE_CATEGORY_SYNC_MANAGER | TRACE_CATEGORY_AUDIO | \ + TRACE_CATEGORY_VIDEO | TRACE_CATEGORY_CAMERA | TRACE_CATEGORY_HAL | \ + TRACE_CATEGORY_RESOURCES | TRACE_CATEGORY_DALVIK | TRACE_CATEGORY_RS | \ + TRACE_CATEGORY_BIONIC | TRACE_CATEGORY_POWER | \ + TRACE_CATEGORY_PACKAGE_MANAGER | TRACE_CATEGORY_SYSTEM_SERVER | \ + TRACE_CATEGORY_DATABASE | TRACE_CATEGORY_NETWORK | TRACE_CATEGORY_ADB | \ + TRACE_CATEGORY_VIBRATOR | TRACE_CATEGORY_AIDL | TRACE_CATEGORY_NNAPI | \ + TRACE_CATEGORY_RRO | TRACE_CATEGORY_THERMAL +#endif // TRACE_CATEGORIES_H diff --git a/libs/tracing_perfetto/include/trace_result.h b/libs/tracing_perfetto/include/trace_result.h new file mode 100644 index 0000000000..f7581fc0fb --- /dev/null +++ b/libs/tracing_perfetto/include/trace_result.h @@ -0,0 +1,30 @@ +/* + * Copyright 2024 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. + */ + +#ifndef TRACE_RESULT_H +#define TRACE_RESULT_H + +namespace tracing_perfetto { + +enum class Result { + SUCCESS, + NOT_SUPPORTED, + INVALID_INPUT, +}; + +} + +#endif // TRACE_RESULT_H diff --git a/libs/tracing_perfetto/include/tracing_perfetto.h b/libs/tracing_perfetto/include/tracing_perfetto.h new file mode 100644 index 0000000000..4e3c83fca3 --- /dev/null +++ b/libs/tracing_perfetto/include/tracing_perfetto.h @@ -0,0 +1,53 @@ +/* + * Copyright 2024 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. + */ + +#ifndef TRACING_PERFETTO_H +#define TRACING_PERFETTO_H + +#include <stdint.h> + +#include "trace_result.h" + +namespace tracing_perfetto { + +void registerWithPerfetto(bool test = false); + +Result traceBegin(uint64_t category, const char* name); + +Result traceEnd(uint64_t category); + +Result traceAsyncBegin(uint64_t category, const char* name, int32_t cookie); + +Result traceAsyncEnd(uint64_t category, const char* name, int32_t cookie); + +Result traceAsyncBeginForTrack(uint64_t category, const char* name, + const char* trackName, int32_t cookie); + +Result traceAsyncEndForTrack(uint64_t category, const char* trackName, + int32_t cookie); + +Result traceInstant(uint64_t category, const char* name); + +Result traceInstantForTrack(uint64_t category, const char* trackName, + const char* name); + +Result traceCounter(uint64_t category, const char* name, int64_t value); + +uint64_t getEnabledCategories(); + +} // namespace tracing_perfetto + +#endif // TRACING_PERFETTO_H diff --git a/libs/tracing_perfetto/tests/Android.bp b/libs/tracing_perfetto/tests/Android.bp new file mode 100644 index 0000000000..a35b0e0c83 --- /dev/null +++ b/libs/tracing_perfetto/tests/Android.bp @@ -0,0 +1,45 @@ +// Copyright 2024 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. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_test { + name: "libtracing_perfetto_tests", + static_libs: [ + "libflagtest", + "libgmock", + ], + cflags: [ + "-Wall", + "-Werror", + ], + shared_libs: [ + "android.os.flags-aconfig-cc-host", + "libbase", + "libperfetto_c", + "libtracing_perfetto", + ], + srcs: [ + "tracing_perfetto_test.cpp", + "utils.cpp", + ], + test_suites: ["device-tests"], +} diff --git a/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp b/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp new file mode 100644 index 0000000000..7716b9a316 --- /dev/null +++ b/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp @@ -0,0 +1,111 @@ +/* + * Copyright 2024 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 "tracing_perfetto.h" + +#include <thread> + +#include <android_os.h> +#include <flag_macros.h> + +#include "gtest/gtest.h" +#include "perfetto/public/abi/data_source_abi.h" +#include "perfetto/public/abi/heap_buffer.h" +#include "perfetto/public/abi/pb_decoder_abi.h" +#include "perfetto/public/abi/tracing_session_abi.h" +#include "perfetto/public/abi/track_event_abi.h" +#include "perfetto/public/data_source.h" +#include "perfetto/public/pb_decoder.h" +#include "perfetto/public/producer.h" +#include "perfetto/public/protos/config/trace_config.pzc.h" +#include "perfetto/public/protos/trace/interned_data/interned_data.pzc.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_descriptor.pzc.h" +#include "perfetto/public/protos/trace/track_event/track_event.pzc.h" +#include "perfetto/public/protos/trace/trigger.pzc.h" +#include "perfetto/public/te_category_macros.h" +#include "perfetto/public/te_macros.h" +#include "perfetto/public/track_event.h" +#include "trace_categories.h" +#include "utils.h" + +namespace tracing_perfetto { + +using ::perfetto::shlib::test_utils::AllFieldsWithId; +using ::perfetto::shlib::test_utils::FieldView; +using ::perfetto::shlib::test_utils::IdFieldView; +using ::perfetto::shlib::test_utils::MsgField; +using ::perfetto::shlib::test_utils::PbField; +using ::perfetto::shlib::test_utils::StringField; +using ::perfetto::shlib::test_utils::TracingSession; +using ::perfetto::shlib::test_utils::VarIntField; +using ::testing::_; +using ::testing::ElementsAre; +using ::testing::UnorderedElementsAre; + +const auto PERFETTO_SDK_TRACING = ACONFIG_FLAG(android::os, perfetto_sdk_tracing); + +class TracingPerfettoTest : public testing::Test { + protected: + void SetUp() override { + tracing_perfetto::registerWithPerfetto(true /* test */); + } +}; + +// TODO(b/303199244): Add tests for all the library functions. + +TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstant, + REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) { + TracingSession tracing_session = + TracingSession::Builder().set_data_source_name("track_event").Build(); + tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, ""); + + tracing_session.StopBlocking(); + std::vector<uint8_t> data = tracing_session.ReadBlocking(); + bool found = false; + for (struct PerfettoPbDecoderField trace_field : FieldView(data)) { + ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, + MsgField(_))); + IdFieldView track_event( + trace_field, perfetto_protos_TracePacket_track_event_field_number); + if (track_event.size() == 0) { + continue; + } + found = true; + IdFieldView cat_iid_fields( + track_event.front(), + perfetto_protos_TrackEvent_category_iids_field_number); + ASSERT_THAT(cat_iid_fields, ElementsAre(VarIntField(_))); + uint64_t cat_iid = cat_iid_fields.front().value.integer64; + EXPECT_THAT( + trace_field, + AllFieldsWithId( + perfetto_protos_TracePacket_interned_data_field_number, + ElementsAre(AllFieldsWithId( + perfetto_protos_InternedData_event_categories_field_number, + ElementsAre(MsgField(UnorderedElementsAre( + PbField(perfetto_protos_EventCategory_iid_field_number, + VarIntField(cat_iid)), + PbField(perfetto_protos_EventCategory_name_field_number, + StringField("input"))))))))); + } + EXPECT_TRUE(found); +} + +} // namespace tracing_perfetto
\ No newline at end of file diff --git a/libs/tracing_perfetto/tests/utils.cpp b/libs/tracing_perfetto/tests/utils.cpp new file mode 100644 index 0000000000..9c4202808a --- /dev/null +++ b/libs/tracing_perfetto/tests/utils.cpp @@ -0,0 +1,219 @@ +/* + * Copyright 2024 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. + */ + +// Copied from //external/perfetto/src/shared_lib/test/utils.cc + +#include "utils.h" + +#include "perfetto/public/abi/heap_buffer.h" +#include "perfetto/public/pb_msg.h" +#include "perfetto/public/pb_utils.h" +#include "perfetto/public/protos/config/data_source_config.pzc.h" +#include "perfetto/public/protos/config/trace_config.pzc.h" +#include "perfetto/public/protos/config/track_event/track_event_config.pzc.h" +#include "perfetto/public/tracing_session.h" + +namespace perfetto { +namespace shlib { +namespace test_utils { +namespace { + +std::string ToHexChars(uint8_t val) { + std::string ret; + uint8_t high_nibble = (val & 0xF0) >> 4; + uint8_t low_nibble = (val & 0xF); + static const char hex_chars[] = "0123456789ABCDEF"; + ret.push_back(hex_chars[high_nibble]); + ret.push_back(hex_chars[low_nibble]); + return ret; +} + +} // namespace + +TracingSession TracingSession::Builder::Build() { + struct PerfettoPbMsgWriter writer; + struct PerfettoHeapBuffer* hb = PerfettoHeapBufferCreate(&writer.writer); + + struct perfetto_protos_TraceConfig cfg; + PerfettoPbMsgInit(&cfg.msg, &writer); + + { + struct perfetto_protos_TraceConfig_BufferConfig buffers; + perfetto_protos_TraceConfig_begin_buffers(&cfg, &buffers); + + perfetto_protos_TraceConfig_BufferConfig_set_size_kb(&buffers, 1024); + + perfetto_protos_TraceConfig_end_buffers(&cfg, &buffers); + } + + { + struct perfetto_protos_TraceConfig_DataSource data_sources; + perfetto_protos_TraceConfig_begin_data_sources(&cfg, &data_sources); + + { + struct perfetto_protos_DataSourceConfig ds_cfg; + perfetto_protos_TraceConfig_DataSource_begin_config(&data_sources, + &ds_cfg); + + perfetto_protos_DataSourceConfig_set_cstr_name(&ds_cfg, + data_source_name_.c_str()); + if (!enabled_categories_.empty() && !disabled_categories_.empty()) { + perfetto_protos_TrackEventConfig te_cfg; + perfetto_protos_DataSourceConfig_begin_track_event_config(&ds_cfg, + &te_cfg); + for (const std::string& cat : enabled_categories_) { + perfetto_protos_TrackEventConfig_set_enabled_categories( + &te_cfg, cat.data(), cat.size()); + } + for (const std::string& cat : disabled_categories_) { + perfetto_protos_TrackEventConfig_set_disabled_categories( + &te_cfg, cat.data(), cat.size()); + } + perfetto_protos_DataSourceConfig_end_track_event_config(&ds_cfg, + &te_cfg); + } + + perfetto_protos_TraceConfig_DataSource_end_config(&data_sources, &ds_cfg); + } + + perfetto_protos_TraceConfig_end_data_sources(&cfg, &data_sources); + } + size_t cfg_size = PerfettoStreamWriterGetWrittenSize(&writer.writer); + std::unique_ptr<uint8_t[]> ser(new uint8_t[cfg_size]); + PerfettoHeapBufferCopyInto(hb, &writer.writer, ser.get(), cfg_size); + PerfettoHeapBufferDestroy(hb, &writer.writer); + + struct PerfettoTracingSessionImpl* ts = + PerfettoTracingSessionCreate(PERFETTO_BACKEND_IN_PROCESS); + + PerfettoTracingSessionSetup(ts, ser.get(), cfg_size); + + PerfettoTracingSessionStartBlocking(ts); + + return TracingSession::Adopt(ts); +} + +TracingSession TracingSession::Adopt(struct PerfettoTracingSessionImpl* session) { + TracingSession ret; + ret.session_ = session; + ret.stopped_ = std::make_unique<WaitableEvent>(); + PerfettoTracingSessionSetStopCb( + ret.session_, + [](struct PerfettoTracingSessionImpl*, void* arg) { + static_cast<WaitableEvent*>(arg)->Notify(); + }, + ret.stopped_.get()); + return ret; +} + +TracingSession::TracingSession(TracingSession&& other) noexcept { + session_ = other.session_; + other.session_ = nullptr; + stopped_ = std::move(other.stopped_); + other.stopped_ = nullptr; +} + +TracingSession::~TracingSession() { + if (!session_) { + return; + } + if (!stopped_->IsNotified()) { + PerfettoTracingSessionStopBlocking(session_); + stopped_->WaitForNotification(); + } + PerfettoTracingSessionDestroy(session_); +} + +bool TracingSession::FlushBlocking(uint32_t timeout_ms) { + WaitableEvent notification; + bool result; + auto* cb = new std::function<void(bool)>([&](bool success) { + result = success; + notification.Notify(); + }); + PerfettoTracingSessionFlushAsync( + session_, timeout_ms, + [](PerfettoTracingSessionImpl*, bool success, void* user_arg) { + auto* f = reinterpret_cast<std::function<void(bool)>*>(user_arg); + (*f)(success); + delete f; + }, + cb); + notification.WaitForNotification(); + return result; +} + +void TracingSession::WaitForStopped() { + stopped_->WaitForNotification(); +} + +void TracingSession::StopBlocking() { + PerfettoTracingSessionStopBlocking(session_); +} + +std::vector<uint8_t> TracingSession::ReadBlocking() { + std::vector<uint8_t> data; + PerfettoTracingSessionReadTraceBlocking( + session_, + [](struct PerfettoTracingSessionImpl*, const void* trace_data, + size_t size, bool, void* user_arg) { + auto& dst = *static_cast<std::vector<uint8_t>*>(user_arg); + auto* src = static_cast<const uint8_t*>(trace_data); + dst.insert(dst.end(), src, src + size); + }, + &data); + return data; +} + +} // namespace test_utils +} // namespace shlib +} // namespace perfetto + +void PrintTo(const PerfettoPbDecoderField& field, std::ostream* pos) { + std::ostream& os = *pos; + PerfettoPbDecoderStatus status = + static_cast<PerfettoPbDecoderStatus>(field.status); + switch (status) { + case PERFETTO_PB_DECODER_ERROR: + os << "MALFORMED PROTOBUF"; + break; + case PERFETTO_PB_DECODER_DONE: + os << "DECODER DONE"; + break; + case PERFETTO_PB_DECODER_OK: + switch (field.wire_type) { + case PERFETTO_PB_WIRE_TYPE_DELIMITED: + os << "\""; + for (size_t i = 0; i < field.value.delimited.len; i++) { + os << perfetto::shlib::test_utils::ToHexChars( + field.value.delimited.start[i]) + << " "; + } + os << "\""; + break; + case PERFETTO_PB_WIRE_TYPE_VARINT: + os << "varint: " << field.value.integer64; + break; + case PERFETTO_PB_WIRE_TYPE_FIXED32: + os << "fixed32: " << field.value.integer32; + break; + case PERFETTO_PB_WIRE_TYPE_FIXED64: + os << "fixed64: " << field.value.integer64; + break; + } + break; + } +} diff --git a/libs/tracing_perfetto/tests/utils.h b/libs/tracing_perfetto/tests/utils.h new file mode 100644 index 0000000000..4353554963 --- /dev/null +++ b/libs/tracing_perfetto/tests/utils.h @@ -0,0 +1,452 @@ +/* + * Copyright 2024 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. + */ + +// Copied from //external/perfetto/src/shared_lib/test/utils.h + +#ifndef UTILS_H +#define UTILS_H + +#include <cassert> +#include <condition_variable> +#include <cstdint> +#include <functional> +#include <iterator> +#include <memory> +#include <mutex> +#include <ostream> +#include <string> +#include <vector> + +#include "gmock/gmock-matchers.h" +#include "gmock/gmock-more-matchers.h" +#include "gtest/gtest-matchers.h" +#include "gtest/gtest.h" +#include "perfetto/public/abi/pb_decoder_abi.h" +#include "perfetto/public/pb_utils.h" +#include "perfetto/public/tracing_session.h" + +// Pretty printer for gtest +void PrintTo(const PerfettoPbDecoderField& field, std::ostream*); + +namespace perfetto { +namespace shlib { +namespace test_utils { + +class WaitableEvent { + public: + WaitableEvent() = default; + void Notify() { + std::unique_lock<std::mutex> lock(m_); + notified_ = true; + cv_.notify_one(); + } + bool WaitForNotification() { + std::unique_lock<std::mutex> lock(m_); + cv_.wait(lock, [this] { return notified_; }); + return notified_; + } + bool IsNotified() { + std::unique_lock<std::mutex> lock(m_); + return notified_; + } + + private: + std::mutex m_; + std::condition_variable cv_; + bool notified_ = false; +}; + +class TracingSession { + public: + class Builder { + public: + Builder() = default; + Builder& set_data_source_name(std::string data_source_name) { + data_source_name_ = std::move(data_source_name); + return *this; + } + Builder& add_enabled_category(std::string category) { + enabled_categories_.push_back(std::move(category)); + return *this; + } + Builder& add_disabled_category(std::string category) { + disabled_categories_.push_back(std::move(category)); + return *this; + } + TracingSession Build(); + + private: + std::string data_source_name_; + std::vector<std::string> enabled_categories_; + std::vector<std::string> disabled_categories_; + }; + + static TracingSession Adopt(struct PerfettoTracingSessionImpl*); + + TracingSession(TracingSession&&) noexcept; + + ~TracingSession(); + + struct PerfettoTracingSessionImpl* session() const { + return session_; + } + + bool FlushBlocking(uint32_t timeout_ms); + void WaitForStopped(); + void StopBlocking(); + std::vector<uint8_t> ReadBlocking(); + + private: + TracingSession() = default; + struct PerfettoTracingSessionImpl* session_; + std::unique_ptr<WaitableEvent> stopped_; +}; + +template <typename FieldSkipper> +class FieldViewBase { + public: + class Iterator { + public: + using iterator_category = std::input_iterator_tag; + using value_type = const PerfettoPbDecoderField; + using pointer = value_type; + using reference = value_type; + reference operator*() const { + struct PerfettoPbDecoder decoder; + decoder.read_ptr = read_ptr_; + decoder.end_ptr = end_ptr_; + struct PerfettoPbDecoderField field; + do { + field = PerfettoPbDecoderParseField(&decoder); + } while (field.status == PERFETTO_PB_DECODER_OK && + skipper_.ShouldSkip(field)); + return field; + } + Iterator& operator++() { + struct PerfettoPbDecoder decoder; + decoder.read_ptr = read_ptr_; + decoder.end_ptr = end_ptr_; + PerfettoPbDecoderSkipField(&decoder); + read_ptr_ = decoder.read_ptr; + AdvanceToFirstInterestingField(); + return *this; + } + Iterator operator++(int) { + Iterator tmp = *this; + ++(*this); + return tmp; + } + + friend bool operator==(const Iterator& a, const Iterator& b) { + return a.read_ptr_ == b.read_ptr_; + } + friend bool operator!=(const Iterator& a, const Iterator& b) { + return a.read_ptr_ != b.read_ptr_; + } + + private: + Iterator(const uint8_t* read_ptr, const uint8_t* end_ptr, + const FieldSkipper& skipper) + : read_ptr_(read_ptr), end_ptr_(end_ptr), skipper_(skipper) { + AdvanceToFirstInterestingField(); + } + void AdvanceToFirstInterestingField() { + struct PerfettoPbDecoder decoder; + decoder.read_ptr = read_ptr_; + decoder.end_ptr = end_ptr_; + struct PerfettoPbDecoderField field; + const uint8_t* prev_read_ptr; + do { + prev_read_ptr = decoder.read_ptr; + field = PerfettoPbDecoderParseField(&decoder); + } while (field.status == PERFETTO_PB_DECODER_OK && + skipper_.ShouldSkip(field)); + if (field.status == PERFETTO_PB_DECODER_OK) { + read_ptr_ = prev_read_ptr; + } else { + read_ptr_ = decoder.read_ptr; + } + } + friend class FieldViewBase<FieldSkipper>; + const uint8_t* read_ptr_; + const uint8_t* end_ptr_; + const FieldSkipper& skipper_; + }; + using value_type = const PerfettoPbDecoderField; + using const_iterator = Iterator; + template <typename... Args> + explicit FieldViewBase(const uint8_t* begin, const uint8_t* end, Args... args) + : begin_(begin), end_(end), s_(args...) { + } + template <typename... Args> + explicit FieldViewBase(const std::vector<uint8_t>& data, Args... args) + : FieldViewBase(data.data(), data.data() + data.size(), args...) { + } + template <typename... Args> + explicit FieldViewBase(const struct PerfettoPbDecoderField& field, + Args... args) + : s_(args...) { + if (field.wire_type != PERFETTO_PB_WIRE_TYPE_DELIMITED) { + abort(); + } + begin_ = field.value.delimited.start; + end_ = begin_ + field.value.delimited.len; + } + Iterator begin() const { + return Iterator(begin_, end_, s_); + } + Iterator end() const { + return Iterator(end_, end_, s_); + } + PerfettoPbDecoderField front() const { + return *begin(); + } + + size_t size() const { + size_t count = 0; + for (auto field : *this) { + (void)field; + count++; + } + return count; + } + + bool ok() const { + for (auto field : *this) { + if (field.status != PERFETTO_PB_DECODER_OK) { + return false; + } + } + return true; + } + + private: + const uint8_t* begin_; + const uint8_t* end_; + FieldSkipper s_; +}; + +// Pretty printer for gtest +template <typename FieldSkipper> +void PrintTo(const FieldViewBase<FieldSkipper>& field_view, std::ostream* pos) { + std::ostream& os = *pos; + os << "{"; + for (PerfettoPbDecoderField f : field_view) { + PrintTo(f, pos); + os << ", "; + } + os << "}"; +} + +class IdFieldSkipper { + public: + explicit IdFieldSkipper(uint32_t id) : id_(id) { + } + explicit IdFieldSkipper(int32_t id) : id_(static_cast<uint32_t>(id)) { + } + bool ShouldSkip(const struct PerfettoPbDecoderField& field) const { + return field.id != id_; + } + + private: + uint32_t id_; +}; + +class NoFieldSkipper { + public: + NoFieldSkipper() = default; + bool ShouldSkip(const struct PerfettoPbDecoderField&) const { + return false; + } +}; + +// View over all the fields of a contiguous serialized protobuf message. +// +// Examples: +// +// for (struct PerfettoPbDecoderField field : FieldView(msg_begin, msg_end)) { +// //... +// } +// FieldView fields2(/*PerfettoPbDecoderField*/ nested_field); +// FieldView fields3(/*std::vector<uint8_t>*/ data); +// size_t num = fields1.size(); // The number of fields. +// bool ok = fields1.ok(); // Checks that the message is not malformed. +using FieldView = FieldViewBase<NoFieldSkipper>; + +// Like `FieldView`, but only considers fields with a specific id. +// +// Examples: +// +// IdFieldView fields(msg_begin, msg_end, id) +using IdFieldView = FieldViewBase<IdFieldSkipper>; + +// Matches a PerfettoPbDecoderField with the specified id. Accepts another +// matcher to match the contents of the field. +// +// Example: +// PerfettoPbDecoderField field = ... +// EXPECT_THAT(field, PbField(900, VarIntField(5))); +template <typename M> +auto PbField(int32_t id, M m) { + return testing::AllOf( + testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK), + testing::Field(&PerfettoPbDecoderField::id, id), m); +} + +// Matches a PerfettoPbDecoderField submessage field. Accepts a container +// matcher for the subfields. +// +// Example: +// PerfettoPbDecoderField field = ... +// EXPECT_THAT(field, MsgField(ElementsAre(...))); +template <typename M> +auto MsgField(M m) { + auto f = [](const PerfettoPbDecoderField& field) { return FieldView(field); }; + return testing::AllOf( + testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK), + testing::Field(&PerfettoPbDecoderField::wire_type, + PERFETTO_PB_WIRE_TYPE_DELIMITED), + testing::ResultOf(f, m)); +} + +// Matches a PerfettoPbDecoderField length delimited field. Accepts a string +// matcher. +// +// Example: +// PerfettoPbDecoderField field = ... +// EXPECT_THAT(field, StringField("string")); +template <typename M> +auto StringField(M m) { + auto f = [](const PerfettoPbDecoderField& field) { + return std::string( + reinterpret_cast<const char*>(field.value.delimited.start), + field.value.delimited.len); + }; + return testing::AllOf( + testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK), + testing::Field(&PerfettoPbDecoderField::wire_type, + PERFETTO_PB_WIRE_TYPE_DELIMITED), + testing::ResultOf(f, m)); +} + +// Matches a PerfettoPbDecoderField VarInt field. Accepts an integer matcher +// +// Example: +// PerfettoPbDecoderField field = ... +// EXPECT_THAT(field, VarIntField(1))); +template <typename M> +auto VarIntField(M m) { + auto f = [](const PerfettoPbDecoderField& field) { + return field.value.integer64; + }; + return testing::AllOf( + testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK), + testing::Field(&PerfettoPbDecoderField::wire_type, + PERFETTO_PB_WIRE_TYPE_VARINT), + testing::ResultOf(f, m)); +} + +// Matches a PerfettoPbDecoderField fixed64 field. Accepts an integer matcher +// +// Example: +// PerfettoPbDecoderField field = ... +// EXPECT_THAT(field, Fixed64Field(1))); +template <typename M> +auto Fixed64Field(M m) { + auto f = [](const PerfettoPbDecoderField& field) { + return field.value.integer64; + }; + return testing::AllOf( + testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK), + testing::Field(&PerfettoPbDecoderField::wire_type, + PERFETTO_PB_WIRE_TYPE_FIXED64), + testing::ResultOf(f, m)); +} + +// Matches a PerfettoPbDecoderField fixed32 field. Accepts an integer matcher +// +// Example: +// PerfettoPbDecoderField field = ... +// EXPECT_THAT(field, Fixed32Field(1))); +template <typename M> +auto Fixed32Field(M m) { + auto f = [](const PerfettoPbDecoderField& field) { + return field.value.integer32; + }; + return testing::AllOf( + testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK), + testing::Field(&PerfettoPbDecoderField::wire_type, + PERFETTO_PB_WIRE_TYPE_FIXED32), + testing::ResultOf(f, m)); +} + +// Matches a PerfettoPbDecoderField double field. Accepts a double matcher +// +// Example: +// PerfettoPbDecoderField field = ... +// EXPECT_THAT(field, DoubleField(1.0))); +template <typename M> +auto DoubleField(M m) { + auto f = [](const PerfettoPbDecoderField& field) { + return field.value.double_val; + }; + return testing::AllOf( + testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK), + testing::Field(&PerfettoPbDecoderField::wire_type, + PERFETTO_PB_WIRE_TYPE_FIXED64), + testing::ResultOf(f, m)); +} + +// Matches a PerfettoPbDecoderField float field. Accepts a float matcher +// +// Example: +// PerfettoPbDecoderField field = ... +// EXPECT_THAT(field, FloatField(1.0))); +template <typename M> +auto FloatField(M m) { + auto f = [](const PerfettoPbDecoderField& field) { + return field.value.float_val; + }; + return testing::AllOf( + testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK), + testing::Field(&PerfettoPbDecoderField::wire_type, + PERFETTO_PB_WIRE_TYPE_FIXED32), + testing::ResultOf(f, m)); +} + +// Matches a PerfettoPbDecoderField submessage field. Accepts a container +// matcher for the subfields. +// +// Example: +// PerfettoPbDecoderField field = ... +// EXPECT_THAT(field, AllFieldsWithId(900, ElementsAre(...))); +template <typename M> +auto AllFieldsWithId(int32_t id, M m) { + auto f = [id](const PerfettoPbDecoderField& field) { + return IdFieldView(field, id); + }; + return testing::AllOf( + testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK), + testing::Field(&PerfettoPbDecoderField::wire_type, + PERFETTO_PB_WIRE_TYPE_DELIMITED), + testing::ResultOf(f, m)); +} + +} // namespace test_utils +} // namespace shlib +} // namespace perfetto + +#endif // UTILS_H diff --git a/libs/tracing_perfetto/tracing_perfetto.cpp b/libs/tracing_perfetto/tracing_perfetto.cpp new file mode 100644 index 0000000000..c7fb8bd9a8 --- /dev/null +++ b/libs/tracing_perfetto/tracing_perfetto.cpp @@ -0,0 +1,141 @@ +/* + * Copyright 2024 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 "tracing_perfetto.h" + +#include <cutils/trace.h> + +#include "perfetto/public/te_category_macros.h" +#include "trace_categories.h" +#include "tracing_perfetto_internal.h" + +namespace tracing_perfetto { + +void registerWithPerfetto(bool test) { + internal::registerWithPerfetto(test); +} + +Result traceBegin(uint64_t category, const char* name) { + struct PerfettoTeCategory* perfettoTeCategory = + internal::toPerfettoCategory(category); + if (perfettoTeCategory != nullptr) { + return internal::perfettoTraceBegin(*perfettoTeCategory, name); + } else { + atrace_begin(category, name); + return Result::SUCCESS; + } +} + +Result traceEnd(uint64_t category) { + struct PerfettoTeCategory* perfettoTeCategory = + internal::toPerfettoCategory(category); + if (perfettoTeCategory != nullptr) { + return internal::perfettoTraceEnd(*perfettoTeCategory); + } else { + atrace_end(category); + return Result::SUCCESS; + } +} + +Result traceAsyncBegin(uint64_t category, const char* name, int32_t cookie) { + struct PerfettoTeCategory* perfettoTeCategory = + internal::toPerfettoCategory(category); + if (perfettoTeCategory != nullptr) { + return internal::perfettoTraceAsyncBegin(*perfettoTeCategory, name, cookie); + } else { + atrace_async_begin(category, name, cookie); + return Result::SUCCESS; + } +} + +Result traceAsyncEnd(uint64_t category, const char* name, int32_t cookie) { + struct PerfettoTeCategory* perfettoTeCategory = + internal::toPerfettoCategory(category); + if (perfettoTeCategory != nullptr) { + return internal::perfettoTraceAsyncEnd(*perfettoTeCategory, name, cookie); + } else { + atrace_async_end(category, name, cookie); + return Result::SUCCESS; + } +} + +Result traceAsyncBeginForTrack(uint64_t category, const char* name, + const char* trackName, int32_t cookie) { + struct PerfettoTeCategory* perfettoTeCategory = + internal::toPerfettoCategory(category); + if (perfettoTeCategory != nullptr) { + return internal::perfettoTraceAsyncBeginForTrack(*perfettoTeCategory, name, trackName, cookie); + } else { + atrace_async_for_track_begin(category, trackName, name, cookie); + return Result::SUCCESS; + } +} + +Result traceAsyncEndForTrack(uint64_t category, const char* trackName, + int32_t cookie) { + struct PerfettoTeCategory* perfettoTeCategory = + internal::toPerfettoCategory(category); + if (perfettoTeCategory != nullptr) { + return internal::perfettoTraceAsyncEndForTrack(*perfettoTeCategory, trackName, cookie); + } else { + atrace_async_for_track_end(category, trackName, cookie); + return Result::SUCCESS; + } +} + +Result traceInstant(uint64_t category, const char* name) { + struct PerfettoTeCategory* perfettoTeCategory = + internal::toPerfettoCategory(category); + if (perfettoTeCategory != nullptr) { + return internal::perfettoTraceInstant(*perfettoTeCategory, name); + } else { + atrace_instant(category, name); + return Result::SUCCESS; + } +} + +Result traceInstantForTrack(uint64_t category, const char* trackName, + const char* name) { + struct PerfettoTeCategory* perfettoTeCategory = + internal::toPerfettoCategory(category); + if (perfettoTeCategory != nullptr) { + return internal::perfettoTraceInstantForTrack(*perfettoTeCategory, trackName, name); + } else { + atrace_instant_for_track(category, trackName, name); + return Result::SUCCESS; + } +} + +Result traceCounter(uint64_t category, const char* name, int64_t value) { + struct PerfettoTeCategory* perfettoTeCategory = + internal::toPerfettoCategory(category); + if (perfettoTeCategory != nullptr) { + return internal::perfettoTraceCounter(*perfettoTeCategory, name, value); + } else { + atrace_int64(category, name, value); + return Result::SUCCESS; + } +} + +uint64_t getEnabledCategories() { + if (internal::isPerfettoSdkTracingEnabled()) { + return internal::getDefaultCategories(); + } else { + return atrace_get_enabled_tags(); + } +} + +} // namespace tracing_perfetto diff --git a/libs/tracing_perfetto/tracing_perfetto_internal.cpp b/libs/tracing_perfetto/tracing_perfetto_internal.cpp new file mode 100644 index 0000000000..58ba428610 --- /dev/null +++ b/libs/tracing_perfetto/tracing_perfetto_internal.cpp @@ -0,0 +1,229 @@ +/* + * Copyright 2024 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. + */ + +#define FRAMEWORK_CATEGORIES(C) \ + C(always, "always", "Always category") \ + C(graphics, "graphics", "Graphics category") \ + C(input, "input", "Input category") \ + C(view, "view", "View category") \ + C(webview, "webview", "WebView category") \ + C(windowmanager, "wm", "WindowManager category") \ + C(activitymanager, "am", "ActivityManager category") \ + C(syncmanager, "syncmanager", "SyncManager category") \ + C(audio, "audio", "Audio category") \ + C(video, "video", "Video category") \ + C(camera, "camera", "Camera category") \ + C(hal, "hal", "HAL category") \ + C(app, "app", "App category") \ + C(resources, "res", "Resources category") \ + C(dalvik, "dalvik", "Dalvik category") \ + C(rs, "rs", "RS category") \ + C(bionic, "bionic", "Bionic category") \ + C(power, "power", "Power category") \ + C(packagemanager, "packagemanager", "PackageManager category") \ + C(systemserver, "ss", "System Server category") \ + C(database, "database", "Database category") \ + C(network, "network", "Network category") \ + C(adb, "adb", "ADB category") \ + C(vibrator, "vibrator", "Vibrator category") \ + C(aidl, "aidl", "AIDL category") \ + C(nnapi, "nnapi", "NNAPI category") \ + C(rro, "rro", "RRO category") \ + C(thermal, "thermal", "Thermal category") + +#include "tracing_perfetto_internal.h" + +#include <inttypes.h> + +#include <mutex> + +#include <android_os.h> + +#include "perfetto/public/compiler.h" +#include "perfetto/public/producer.h" +#include "perfetto/public/te_category_macros.h" +#include "perfetto/public/te_macros.h" +#include "perfetto/public/track_event.h" +#include "trace_categories.h" +#include "trace_result.h" + +namespace tracing_perfetto { + +namespace internal { + +namespace { + +PERFETTO_TE_CATEGORIES_DECLARE(FRAMEWORK_CATEGORIES); + +PERFETTO_TE_CATEGORIES_DEFINE(FRAMEWORK_CATEGORIES); + +struct PerfettoTeCategory* toCategory(uint64_t inCategory) { + switch (inCategory) { + case TRACE_CATEGORY_ALWAYS: + return &always; + case TRACE_CATEGORY_GRAPHICS: + return &graphics; + case TRACE_CATEGORY_INPUT: + return &input; + case TRACE_CATEGORY_VIEW: + return &view; + case TRACE_CATEGORY_WEBVIEW: + return &webview; + case TRACE_CATEGORY_WINDOW_MANAGER: + return &windowmanager; + case TRACE_CATEGORY_ACTIVITY_MANAGER: + return &activitymanager; + case TRACE_CATEGORY_SYNC_MANAGER: + return &syncmanager; + case TRACE_CATEGORY_AUDIO: + return &audio; + case TRACE_CATEGORY_VIDEO: + return &video; + case TRACE_CATEGORY_CAMERA: + return &camera; + case TRACE_CATEGORY_HAL: + return &hal; + case TRACE_CATEGORY_APP: + return &app; + case TRACE_CATEGORY_RESOURCES: + return &resources; + case TRACE_CATEGORY_DALVIK: + return &dalvik; + case TRACE_CATEGORY_RS: + return &rs; + case TRACE_CATEGORY_BIONIC: + return &bionic; + case TRACE_CATEGORY_POWER: + return &power; + case TRACE_CATEGORY_PACKAGE_MANAGER: + return &packagemanager; + case TRACE_CATEGORY_SYSTEM_SERVER: + return &systemserver; + case TRACE_CATEGORY_DATABASE: + return &database; + case TRACE_CATEGORY_NETWORK: + return &network; + case TRACE_CATEGORY_ADB: + return &adb; + case TRACE_CATEGORY_VIBRATOR: + return &vibrator; + case TRACE_CATEGORY_AIDL: + return &aidl; + case TRACE_CATEGORY_NNAPI: + return &nnapi; + case TRACE_CATEGORY_RRO: + return &rro; + case TRACE_CATEGORY_THERMAL: + return &thermal; + default: + return nullptr; + } +} + +} // namespace + +bool isPerfettoSdkTracingEnabled() { + return android::os::perfetto_sdk_tracing(); +} + +struct PerfettoTeCategory* toPerfettoCategory(uint64_t category) { + if (!isPerfettoSdkTracingEnabled()) { + return nullptr; + } + + struct PerfettoTeCategory* perfettoCategory = toCategory(category); + bool enabled = PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT( + (*perfettoCategory).enabled, PERFETTO_MEMORY_ORDER_RELAXED)); + return enabled ? perfettoCategory : nullptr; +} + +void registerWithPerfetto(bool test) { + if (!isPerfettoSdkTracingEnabled()) { + return; + } + static std::once_flag registration; + std::call_once(registration, [test]() { + struct PerfettoProducerInitArgs args = PERFETTO_PRODUCER_INIT_ARGS_INIT(); + args.backends = test ? PERFETTO_BACKEND_IN_PROCESS : PERFETTO_BACKEND_SYSTEM; + PerfettoProducerInit(args); + PerfettoTeInit(); + PERFETTO_TE_REGISTER_CATEGORIES(FRAMEWORK_CATEGORIES); + }); +} + +Result perfettoTraceBegin(const struct PerfettoTeCategory& category, const char* name) { + PERFETTO_TE(category, PERFETTO_TE_SLICE_BEGIN(name)); + return Result::SUCCESS; +} + +Result perfettoTraceEnd(const struct PerfettoTeCategory& category) { + PERFETTO_TE(category, PERFETTO_TE_SLICE_END()); + return Result::SUCCESS; +} + +Result perfettoTraceAsyncBeginForTrack(const struct PerfettoTeCategory& category, const char* name, + const char* trackName, uint64_t cookie) { + PERFETTO_TE( + category, PERFETTO_TE_SLICE_BEGIN(name), + PERFETTO_TE_NAMED_TRACK(trackName, cookie, PerfettoTeProcessTrackUuid())); + return Result::SUCCESS; +} + +Result perfettoTraceAsyncEndForTrack(const struct PerfettoTeCategory& category, + const char* trackName, uint64_t cookie) { + PERFETTO_TE( + category, PERFETTO_TE_SLICE_END(), + PERFETTO_TE_NAMED_TRACK(trackName, cookie, PerfettoTeProcessTrackUuid())); + return Result::SUCCESS; +} + +Result perfettoTraceAsyncBegin(const struct PerfettoTeCategory& category, const char* name, + uint64_t cookie) { + return perfettoTraceAsyncBeginForTrack(category, name, name, cookie); +} + +Result perfettoTraceAsyncEnd(const struct PerfettoTeCategory& category, const char* name, + uint64_t cookie) { + return perfettoTraceAsyncEndForTrack(category, name, cookie); +} + +Result perfettoTraceInstant(const struct PerfettoTeCategory& category, const char* name) { + PERFETTO_TE(category, PERFETTO_TE_INSTANT(name)); + return Result::SUCCESS; +} + +Result perfettoTraceInstantForTrack(const struct PerfettoTeCategory& category, + const char* trackName, const char* name) { + PERFETTO_TE( + category, PERFETTO_TE_INSTANT(name), + PERFETTO_TE_NAMED_TRACK(trackName, 1, PerfettoTeProcessTrackUuid())); + return Result::SUCCESS; +} + +Result perfettoTraceCounter(const struct PerfettoTeCategory& category, + [[maybe_unused]] const char* name, int64_t value) { + PERFETTO_TE(category, PERFETTO_TE_COUNTER(), + PERFETTO_TE_INT_COUNTER(value)); + return Result::SUCCESS; +} + +uint64_t getDefaultCategories() { + return TRACE_CATEGORIES; +} + +} // namespace internal + +} // namespace tracing_perfetto diff --git a/libs/tracing_perfetto/tracing_perfetto_internal.h b/libs/tracing_perfetto/tracing_perfetto_internal.h new file mode 100644 index 0000000000..9a579f162a --- /dev/null +++ b/libs/tracing_perfetto/tracing_perfetto_internal.h @@ -0,0 +1,65 @@ +/* + * Copyright 2024 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. + */ + +#ifndef TRACING_PERFETTO_INTERNAL_H +#define TRACING_PERFETTO_INTERNAL_H + +#include <stdint.h> + +#include "include/trace_result.h" +#include "perfetto/public/te_category_macros.h" + +namespace tracing_perfetto { + +namespace internal { + +bool isPerfettoSdkTracingEnabled(); + +struct PerfettoTeCategory* toPerfettoCategory(uint64_t category); + +void registerWithPerfetto(bool test = false); + +Result perfettoTraceBegin(const struct PerfettoTeCategory& category, const char* name); + +Result perfettoTraceEnd(const struct PerfettoTeCategory& category); + +Result perfettoTraceAsyncBegin(const struct PerfettoTeCategory& category, const char* name, + uint64_t cookie); + +Result perfettoTraceAsyncEnd(const struct PerfettoTeCategory& category, const char* name, + uint64_t cookie); + +Result perfettoTraceAsyncBeginForTrack(const struct PerfettoTeCategory& category, const char* name, + const char* trackName, uint64_t cookie); + +Result perfettoTraceAsyncEndForTrack(const struct PerfettoTeCategory& category, + const char* trackName, uint64_t cookie); + +Result perfettoTraceInstant(const struct PerfettoTeCategory& category, const char* name); + +Result perfettoTraceInstantForTrack(const struct PerfettoTeCategory& category, + const char* trackName, const char* name); + +Result perfettoTraceCounter(const struct PerfettoTeCategory& category, const char* name, + int64_t value); + +uint64_t getDefaultCategories(); + +} // namespace internal + +} // namespace tracing_perfetto + +#endif // TRACING_PERFETTO_INTERNAL_H |