diff --git a/base/cvd/MODULE.bazel b/base/cvd/MODULE.bazel index efb02a91448..c15c327cbbd 100644 --- a/base/cvd/MODULE.bazel +++ b/base/cvd/MODULE.bazel @@ -37,6 +37,7 @@ bazel_dep(name = "nasm", version = "2.16.03.bcr.1") bazel_dep(name = "pcre2", version = "10.45") bazel_dep(name = "platforms", version = "1.0.0") bazel_dep(name = "protobuf", version = "31.1") +bazel_dep(name = "re2") bazel_dep(name = "rootcanal") bazel_dep(name = "rules_cc", version = "0.2.16") bazel_dep(name = "rules_flex", version = "0.4") diff --git a/base/cvd/build_external/build_external.MODULE.bazel b/base/cvd/build_external/build_external.MODULE.bazel index b657326b2fb..f273bb28efb 100644 --- a/base/cvd/build_external/build_external.MODULE.bazel +++ b/base/cvd/build_external/build_external.MODULE.bazel @@ -48,6 +48,7 @@ include("//build_external/mkbootimg:mkbootimg.MODULE.bazel") include("//build_external/ms-tpm-20-ref:ms-tpm-20-ref.MODULE.bazel") include("//build_external/mtools:mtools.MODULE.bazel") include("//build_external/opengl_headers:opengl_headers.MODULE.bazel") +include("//build_external/perfetto:perfetto.MODULE.bazel") include("//build_external/pyyaml:pyyaml.MODULE.bazel") include("//build_external/re2:re2.MODULE.bazel") include("//build_external/rootcanal:rootcanal.MODULE.bazel") diff --git a/base/cvd/build_external/perfetto/BUILD b/base/cvd/build_external/perfetto/BUILD new file mode 100644 index 00000000000..e69de29bb2d diff --git a/base/cvd/build_external/perfetto/PATCH.0001_disable_android_deps.patch b/base/cvd/build_external/perfetto/PATCH.0001_disable_android_deps.patch new file mode 100644 index 00000000000..f85ff89537d --- /dev/null +++ b/base/cvd/build_external/perfetto/PATCH.0001_disable_android_deps.patch @@ -0,0 +1,49 @@ +From 45c2b6299505b133fdce117649f457e36640d824 Mon Sep 17 00:00:00 2001 +From: Jason Macnak +Date: Fri, 15 May 2026 11:28:54 -0700 +Subject: [PATCH 1/4] Disable Android components to avoid extra dependencies + +--- + bazel/rules.bzl | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/bazel/rules.bzl b/bazel/rules.bzl +index 6195465a67..a3e367cde8 100644 +--- a/bazel/rules.bzl ++++ b/bazel/rules.bzl +@@ -13,9 +13,7 @@ + # limitations under the License. + + load("@perfetto//bazel:proto_gen.bzl", "proto_descriptor_gen", "proto_gen") +-load("@perfetto//bazel:run_ait_with_adb.bzl", "android_instrumentation_test") + load("@perfetto_cfg//:perfetto_cfg.bzl", "PERFETTO_CONFIG") +-load("@rules_android//android:rules.bzl", "android_binary", "android_library") + + # +----------------------------------------------------------------------------+ + # | Base C++ rules. | +@@ -113,11 +111,11 @@ def perfetto_jspb_proto_library(**kwargs): + # +----------------------------------------------------------------------------+ + def perfetto_android_binary(**kwargs): + if not _rule_override("android_binary", **kwargs): +- android_binary(**kwargs) ++ return + + def perfetto_android_library(**kwargs): + if not _rule_override("android_library", **kwargs): +- android_library(**kwargs) ++ return + + def perfetto_android_jni_library(**kwargs): + if not _rule_override("android_jni_library", **kwargs): +@@ -171,7 +169,7 @@ def _perfetto_android_jni_library( + + def perfetto_android_instrumentation_test(**kwargs): + if not _rule_override("android_instrumentation_test", **kwargs): +- android_instrumentation_test(**kwargs) ++ return + + # +----------------------------------------------------------------------------+ + # | Misc rules. | +-- +2.54.0.563.g4f69b47b94-goog + diff --git a/base/cvd/build_external/perfetto/PATCH.0002_add_load_statements.patch b/base/cvd/build_external/perfetto/PATCH.0002_add_load_statements.patch new file mode 100644 index 00000000000..5f9cb9a09a2 --- /dev/null +++ b/base/cvd/build_external/perfetto/PATCH.0002_add_load_statements.patch @@ -0,0 +1,131 @@ +From 5e991031fa757ade8a7be54e5bfab69ec627a432 Mon Sep 17 00:00:00 2001 +From: Jason Macnak +Date: Fri, 15 May 2026 11:29:26 -0700 +Subject: [PATCH 2/4] Add load statements for Bazel 9 + +--- + bazel/proto_gen.bzl | 2 ++ + bazel/rules.bzl | 30 ++++++++++++++++++------------ + 2 files changed, 20 insertions(+), 12 deletions(-) + +diff --git a/bazel/proto_gen.bzl b/bazel/proto_gen.bzl +index 74f91cad89..1764cb2d9a 100644 +--- a/bazel/proto_gen.bzl ++++ b/bazel/proto_gen.bzl +@@ -15,6 +15,8 @@ + # This file defines the proto_gen() rule that is used for generating protos + # with custom plugins (ipc and protozero). + ++load("@protobuf//bazel/common:proto_info.bzl", "ProtoInfo") ++ + def _proto_gen_impl(ctx): + proto_src = [ + f +diff --git a/bazel/rules.bzl b/bazel/rules.bzl +index a3e367cde8..15f6d52d5b 100644 +--- a/bazel/rules.bzl ++++ b/bazel/rules.bzl +@@ -14,6 +14,12 @@ + + load("@perfetto//bazel:proto_gen.bzl", "proto_descriptor_gen", "proto_gen") + load("@perfetto_cfg//:perfetto_cfg.bzl", "PERFETTO_CONFIG") ++load("@protobuf//bazel:cc_proto_library.bzl", "cc_proto_library") ++load("@protobuf//bazel:proto_library.bzl", "proto_library") ++load("@protobuf//bazel:java_lite_proto_library.bzl", "java_lite_proto_library") ++load("@rules_cc//cc:cc_binary.bzl", "cc_binary") ++load("@rules_cc//cc:cc_library.bzl", "cc_library") ++load("@rules_python//python:defs.bzl", "py_binary", "py_library") + + # +----------------------------------------------------------------------------+ + # | Base C++ rules. | +@@ -38,7 +44,7 @@ def default_cc_args(): + + def perfetto_build_config_cc_library(**kwargs): + if not _rule_override("cc_library", **kwargs): +- native.cc_library(**kwargs) ++ cc_library(**kwargs) + + def perfetto_filegroup(**kwargs): + if not _rule_override("filegroup", **kwargs): +@@ -51,20 +57,20 @@ def perfetto_genrule(**kwargs): + def perfetto_cc_library(**kwargs): + args = _merge_dicts(default_cc_args(), kwargs) + if not _rule_override("cc_library", **args): +- native.cc_library(**args) ++ cc_library(**args) + + def perfetto_cc_binary(**kwargs): + args = _merge_dicts(default_cc_args(), kwargs) + if not _rule_override("cc_binary", **args): +- native.cc_binary(**args) ++ cc_binary(**args) + + def perfetto_py_binary(**kwargs): + if not _rule_override("py_binary", **kwargs): +- native.py_binary(**kwargs) ++ py_binary(**kwargs) + + def perfetto_py_library(**kwargs): + if not _rule_override("py_library", **kwargs): +- native.py_library(**kwargs) ++ py_library(**kwargs) + + # +----------------------------------------------------------------------------+ + # | Proto-related rules | +@@ -72,11 +78,11 @@ def perfetto_py_library(**kwargs): + + def perfetto_proto_library(**kwargs): + if not _rule_override("proto_library", **kwargs): +- native.proto_library(**kwargs) ++ proto_library(**kwargs) + + def perfetto_cc_proto_library(**kwargs): + if not _rule_override("cc_proto_library", **kwargs): +- native.cc_proto_library(**kwargs) ++ cc_proto_library(**kwargs) + + def perfetto_java_proto_library(**kwargs): + if not _rule_override("java_proto_library", **kwargs): +@@ -84,7 +90,7 @@ def perfetto_java_proto_library(**kwargs): + + def perfetto_java_lite_proto_library(**kwargs): + if not _rule_override("java_lite_proto_library", **kwargs): +- native.java_lite_proto_library(**kwargs) ++ java_lite_proto_library(**kwargs) + + # Unlike the other rules, this is an noop by default because Bazel does not + # support Go proto libraries. +@@ -142,7 +148,7 @@ def _perfetto_android_jni_library( + if not (binary_name.startswith("lib") and binary_name.endswith(".so")): + fail("'binary_name' should sharts with 'lib' and ends with '.so'" + + ", got %s instead" % binary_name) +- # We strip the name, since `native.cc_binary` adds prefix and suffix ++ # We strip the name, since `cc_binary` adds prefix and suffix + # to the generated library name. + binary_target_name = binary_name.removeprefix("lib").removesuffix(".so") + input_cc_library_name = name + "_input" +@@ -150,18 +156,18 @@ def _perfetto_android_jni_library( + # exclude them from being build when invoke `bazel build :all`, + # since these targets won't be able to compile anyway, see + # https://bazel.build/docs/android-ndk#cclibrary-android. +- native.cc_library( ++ cc_library( + name = input_cc_library_name, + target_compatible_with = ["@platforms//os:android"], + **input_cc_library_kwargs + ) +- native.cc_binary( ++ cc_binary( + name = binary_target_name, + linkshared = True, + deps = [input_cc_library_name], + target_compatible_with = ["@platforms//os:android"], + ) +- native.cc_library( ++ cc_library( + name = name, + srcs = [binary_target_name], + target_compatible_with = ["@platforms//os:android"], +-- +2.54.0.563.g4f69b47b94-goog + diff --git a/base/cvd/build_external/perfetto/PATCH.0003_expose_shutdown.patch b/base/cvd/build_external/perfetto/PATCH.0003_expose_shutdown.patch new file mode 100644 index 00000000000..aabb557f912 --- /dev/null +++ b/base/cvd/build_external/perfetto/PATCH.0003_expose_shutdown.patch @@ -0,0 +1,39 @@ +From 8ae64deaf5cb13bcdfb87d576b6d207a2fef13df Mon Sep 17 00:00:00 2001 +From: Jason Macnak +Date: Fri, 15 May 2026 11:33:40 -0700 +Subject: [PATCH 3/4] Expose shutdown in perfetto_c + +--- + include/perfetto/public/abi/producer_abi.h | 3 +++ + src/shared_lib/producer.cc | 4 ++++ + 2 files changed, 7 insertions(+) + +diff --git a/include/perfetto/public/abi/producer_abi.h b/include/perfetto/public/abi/producer_abi.h +index 8899d0098e..e43da137c5 100644 +--- a/include/perfetto/public/abi/producer_abi.h ++++ b/include/perfetto/public/abi/producer_abi.h +@@ -79,6 +79,9 @@ PERFETTO_SDK_EXPORT void PerfettoProducerActivateTriggers( + const char* trigger_names[], + uint32_t ttl_ms); + ++ ++PERFETTO_SDK_EXPORT void PerfettoProducerShutdown(void); ++ + #ifdef __cplusplus + } + #endif +diff --git a/src/shared_lib/producer.cc b/src/shared_lib/producer.cc +index 06599f97e1..8f90bedb2d 100644 +--- a/src/shared_lib/producer.cc ++++ b/src/shared_lib/producer.cc +@@ -81,3 +81,7 @@ void PerfettoProducerActivateTriggers(const char* trigger_names[], + } + perfetto::Tracing::ActivateTriggers(triggers, ttl_ms); + } ++ ++void PerfettoProducerShutdown(void) { ++ perfetto::Tracing::Shutdown(); ++} +-- +2.54.0.563.g4f69b47b94-goog + diff --git a/base/cvd/build_external/perfetto/PATCH.0004_expose_flush.patch b/base/cvd/build_external/perfetto/PATCH.0004_expose_flush.patch new file mode 100644 index 00000000000..4e3710abcba --- /dev/null +++ b/base/cvd/build_external/perfetto/PATCH.0004_expose_flush.patch @@ -0,0 +1,54 @@ +From 3c24b5504feba80a1f48c22cf4bfaf27733aee34 Mon Sep 17 00:00:00 2001 +From: Jason Macnak +Date: Fri, 15 May 2026 11:37:20 -0700 +Subject: [PATCH 4/4] Expose flush in libperfetto_c + +--- + include/perfetto/public/abi/track_event_abi.h | 2 ++ + src/shared_lib/track_event/ds.h | 4 ++++ + src/shared_lib/track_event/track_event.cc | 4 ++++ + 3 files changed, 10 insertions(+) + +diff --git a/include/perfetto/public/abi/track_event_abi.h b/include/perfetto/public/abi/track_event_abi.h +index 6c07b30bd4..5c315ea942 100644 +--- a/include/perfetto/public/abi/track_event_abi.h ++++ b/include/perfetto/public/abi/track_event_abi.h +@@ -145,6 +145,8 @@ enum PerfettoTeType { + PERFETTO_TE_TYPE_COUNTER = 4, + }; + ++PERFETTO_SDK_EXPORT void PerfettoTeFlush(void); ++ + #ifdef __cplusplus + } + #endif +diff --git a/src/shared_lib/track_event/ds.h b/src/shared_lib/track_event/ds.h +index 199a1e3d6a..be13a0593b 100644 +--- a/src/shared_lib/track_event/ds.h ++++ b/src/shared_lib/track_event/ds.h +@@ -127,6 +127,10 @@ class TrackEvent + Register(dsd); + } + ++ static void Flush() { ++ TrackEvent::Trace([](TrackEvent::TraceContext ctx) { ctx.Flush(); }); ++ } ++ + static void UpdateDescriptorFromCategories(DataSourceDescriptor dsd) { + dsd.set_name("track_event"); + UpdateDescriptor(dsd); +diff --git a/src/shared_lib/track_event/track_event.cc b/src/shared_lib/track_event/track_event.cc +index b6f9000ad3..70dd68d61b 100644 +--- a/src/shared_lib/track_event/track_event.cc ++++ b/src/shared_lib/track_event/track_event.cc +@@ -86,3 +86,7 @@ void PerfettoTeCategoryImplDestroy(struct PerfettoTeCategoryImpl* cat) { + perfetto::shlib::GlobalState::Instance().UnregisterCategory(cat); + delete cat; + } ++ ++void PerfettoTeFlush(void) { ++ perfetto::shlib::TrackEvent::Flush(); ++} +-- +2.54.0.563.g4f69b47b94-goog + diff --git a/base/cvd/build_external/perfetto/perfetto.MODULE.bazel b/base/cvd/build_external/perfetto/perfetto.MODULE.bazel new file mode 100644 index 00000000000..b0b07b7ab36 --- /dev/null +++ b/base/cvd/build_external/perfetto/perfetto.MODULE.bazel @@ -0,0 +1,3 @@ +perfetto_ext = use_extension("//build_external/perfetto:repositories.bzl", "perfetto_extension") +use_repo(perfetto_ext, "perfetto") +use_repo(perfetto_ext, "perfetto_cfg") diff --git a/base/cvd/build_external/perfetto/repositories.bzl b/base/cvd/build_external/perfetto/repositories.bzl new file mode 100644 index 00000000000..e78f619c5c0 --- /dev/null +++ b/base/cvd/build_external/perfetto/repositories.bzl @@ -0,0 +1,32 @@ +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +# https://github.com/google/perfetto/issues/2787 for Perfetto getting into the +# Central Repository. +def _perfetto_extension_impl(_): + # From commit 877553985565ab10fe20ea844891aacabd0f70c7: + URL = "https://github.com/google/perfetto/archive/refs/tags/v55.2.tar.gz" + http_archive( + name = "perfetto", + url = URL, + strip_prefix = "perfetto-55.2", + patch_args = ["-p1"], + patches = [ + "@//build_external/perfetto:PATCH.0001_disable_android_deps.patch", + "@//build_external/perfetto:PATCH.0002_add_load_statements.patch", + "@//build_external/perfetto:PATCH.0003_expose_shutdown.patch", + "@//build_external/perfetto:PATCH.0004_expose_flush.patch", + ], + ) + http_archive( + name = "perfetto_cfg", + url = URL, + strip_prefix = "perfetto-55.2/bazel/standalone", + build_file_content = "# empty BUILD to make a bazel package", + patch_cmds = [ + "sed -i 's|@com_google_protobuf|@protobuf|g' perfetto_cfg.bzl", + ], + ) + +perfetto_extension = module_extension( + implementation = _perfetto_extension_impl, +) diff --git a/base/cvd/cuttlefish/host/commands/assemble_cvd/BUILD.bazel b/base/cvd/cuttlefish/host/commands/assemble_cvd/BUILD.bazel index 6dbcf8f4e3e..99648dee276 100644 --- a/base/cvd/cuttlefish/host/commands/assemble_cvd/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/assemble_cvd/BUILD.bazel @@ -72,6 +72,7 @@ cf_cc_binary( "//cuttlefish/host/libs/config/fastboot", "//cuttlefish/host/libs/feature:inject", "//cuttlefish/host/libs/log_names", + "//cuttlefish/host/libs/tracing", "//cuttlefish/posix:symlink", "//cuttlefish/pretty:vector", "//libbase", @@ -169,6 +170,7 @@ cf_cc_library( "//cuttlefish/common/libs/utils:subprocess", "//cuttlefish/common/libs/utils:subprocess_managed_stdio", "//cuttlefish/host/libs/config:config_utils", + "//cuttlefish/host/libs/tracing", "//cuttlefish/posix:strerror", "//cuttlefish/result", "//libbase", @@ -223,6 +225,7 @@ cf_cc_library( "//cuttlefish/host/libs/config:file_source", "//cuttlefish/host/libs/config:instance_nums", "//cuttlefish/host/libs/feature:inject", + "//cuttlefish/host/libs/tracing", "//cuttlefish/result", "//libbase", "@abseil-cpp//absl/log", @@ -240,6 +243,7 @@ cf_cc_library( "//cuttlefish/host/libs/config:vmm_mode", "//cuttlefish/host/libs/image_aggregator", "//cuttlefish/host/libs/image_aggregator:qcow2", + "//cuttlefish/host/libs/tracing", "//cuttlefish/result", "//libbase", "@abseil-cpp//absl/log", @@ -357,6 +361,7 @@ cf_cc_library( "//cuttlefish/host/libs/config:secure_hals", "//cuttlefish/host/libs/config:vmm_mode", "//cuttlefish/host/libs/config/defaults", + "//cuttlefish/host/libs/tracing", "//cuttlefish/host/libs/vhal_proxy_server", "//cuttlefish/host/libs/vm_manager", "//cuttlefish/result", @@ -405,6 +410,7 @@ cf_cc_library( "//cuttlefish/host/libs/config:config_utils", "//cuttlefish/host/libs/config:display", "//cuttlefish/host/libs/config:gpu_mode", + "//cuttlefish/host/libs/tracing", "//cuttlefish/pretty", "//cuttlefish/pretty:optional", "//cuttlefish/pretty:string", @@ -434,6 +440,7 @@ cf_cc_library( "//cuttlefish/host/libs/config:guest_hwui_renderer", "//cuttlefish/host/libs/config:guest_renderer_preload", "//cuttlefish/host/libs/config:vmm_mode", + "//cuttlefish/host/libs/tracing", "//cuttlefish/result", "//libbase", "@abseil-cpp//absl/log", diff --git a/base/cvd/cuttlefish/host/commands/assemble_cvd/assemble_cvd.cc b/base/cvd/cuttlefish/host/commands/assemble_cvd/assemble_cvd.cc index cdcde6afb71..eb828a035d1 100644 --- a/base/cvd/cuttlefish/host/commands/assemble_cvd/assemble_cvd.cc +++ b/base/cvd/cuttlefish/host/commands/assemble_cvd/assemble_cvd.cc @@ -68,8 +68,9 @@ #include "cuttlefish/host/libs/config/fastboot/fastboot.h" #include "cuttlefish/host/libs/config/fetcher_configs.h" #include "cuttlefish/host/libs/config/log_string_to_dir.h" -#include "cuttlefish/host/libs/log_names/log_names.h" #include "cuttlefish/host/libs/feature/inject.h" +#include "cuttlefish/host/libs/log_names/log_names.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/posix/symlink.h" #include "cuttlefish/pretty/vector.h" @@ -406,6 +407,8 @@ Result InitFilesystemAndCreateConfig( CF_EXPECT(CleanPriorFiles(preserving, clean_dirs), "Failed to clean prior files"); + CF_TRACE("SetupDirectories"); + std::string default_group = "cvdnetwork"; const mode_t default_mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH; @@ -574,6 +577,8 @@ Result AssembleCvdMain(int argc, char** argv) { CF_EXPECT(CheckNoTTY()); + CF_TRACE("AssembleCvd"); + // Read everything that cvd_internal_start writes, but ignore it since // fetcher_config.json will be searched for in the system image directory. (void) CF_EXPECT(ReadInputFiles()); @@ -637,10 +642,12 @@ Result AssembleCvdMain(int argc, char** argv) { "Failed to parse flags."); if (help || !help_str.empty()) { + CF_TRACE("Help"); LOG(WARNING) << "TODO(schuffelen): Implement `--help` for assemble_cvd."; LOG(WARNING) << "In the meantime, call `launch_cvd --help`"; return 1; } else if (helpxml) { + CF_TRACE("Help"); if (!FlagFeature::WriteGflagsHelpXml(flag_features, std::cout)) { LOG(ERROR) << "Failure in writing gflags helpxml output"; } diff --git a/base/cvd/cuttlefish/host/commands/assemble_cvd/clean.cc b/base/cvd/cuttlefish/host/commands/assemble_cvd/clean.cc index ab4e518d01f..388fb4ded52 100644 --- a/base/cvd/cuttlefish/host/commands/assemble_cvd/clean.cc +++ b/base/cvd/cuttlefish/host/commands/assemble_cvd/clean.cc @@ -33,6 +33,7 @@ #include "cuttlefish/common/libs/utils/subprocess.h" #include "cuttlefish/common/libs/utils/subprocess_managed_stdio.h" #include "cuttlefish/host/libs/config/config_utils.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/posix/strerror.h" #include "cuttlefish/result/result.h" @@ -177,6 +178,8 @@ Result CleanPriorFiles(const std::vector& paths, Result CleanPriorFiles(const std::set& preserving, const std::vector& clean_dirs) { + CF_TRACE("CleanPriorFiles"); + std::vector paths = { // The global link to the config file GetGlobalConfigFileLink(), diff --git a/base/cvd/cuttlefish/host/commands/assemble_cvd/create_dynamic_disk_files.cc b/base/cvd/cuttlefish/host/commands/assemble_cvd/create_dynamic_disk_files.cc index fa25fe0aa25..6d65d54fca3 100644 --- a/base/cvd/cuttlefish/host/commands/assemble_cvd/create_dynamic_disk_files.cc +++ b/base/cvd/cuttlefish/host/commands/assemble_cvd/create_dynamic_disk_files.cc @@ -59,6 +59,7 @@ #include "cuttlefish/host/libs/config/fetcher_config.h" #include "cuttlefish/host/libs/config/fetcher_configs.h" #include "cuttlefish/host/libs/config/file_source.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/result/result.h" namespace cuttlefish { @@ -98,6 +99,7 @@ Result CreateDynamicDiskFiles( const FetcherConfigs& fetcher_configs, const CuttlefishConfig& config, AndroidBuilds& android_builds, const BootImageFlag& boot_image, const SystemImageDirFlag& system_image_dirs) { + CF_TRACE("CreateDynamicDiskFiles"); std::vector>> image_files = InstanceImageFiles(config, boot_image); size_t instance_index = 0; diff --git a/base/cvd/cuttlefish/host/commands/assemble_cvd/disk_builder.cpp b/base/cvd/cuttlefish/host/commands/assemble_cvd/disk_builder.cpp index 6fdb6390210..5c2f898309f 100644 --- a/base/cvd/cuttlefish/host/commands/assemble_cvd/disk_builder.cpp +++ b/base/cvd/cuttlefish/host/commands/assemble_cvd/disk_builder.cpp @@ -26,6 +26,7 @@ #include "cuttlefish/host/libs/config/vmm_mode.h" #include "cuttlefish/host/libs/image_aggregator/image_aggregator.h" #include "cuttlefish/host/libs/image_aggregator/qcow2.h" +#include "cuttlefish/host/libs/tracing/tracing.h" namespace cuttlefish { @@ -199,6 +200,8 @@ Result DiskBuilder::WillRebuildCompositeDisk() { } Result DiskBuilder::BuildCompositeDiskIfNecessary() { + CF_TRACEF("BuildCompositeDisk: %s", composite_disk_path_.c_str()); + if (!entire_disk_.empty()) { VLOG(0) << "No composite disk to build"; return false; @@ -228,6 +231,8 @@ Result DiskBuilder::BuildCompositeDiskIfNecessary() { } Result DiskBuilder::BuildOverlayIfNecessary() { + CF_TRACEF("BuildOverlayIfNcessary: %s", overlay_path_.c_str()); + #ifdef __APPLE__ return false; #else diff --git a/base/cvd/cuttlefish/host/commands/assemble_cvd/flags.cc b/base/cvd/cuttlefish/host/commands/assemble_cvd/flags.cc index 507ada1063a..a6a6df7f921 100644 --- a/base/cvd/cuttlefish/host/commands/assemble_cvd/flags.cc +++ b/base/cvd/cuttlefish/host/commands/assemble_cvd/flags.cc @@ -90,6 +90,7 @@ #include "cuttlefish/host/libs/config/instance_nums.h" #include "cuttlefish/host/libs/config/secure_hals.h" #include "cuttlefish/host/libs/config/vmm_mode.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/host/libs/vhal_proxy_server/vhal_proxy_server_eth_addr.h" #include "cuttlefish/host/libs/vm_manager/gem5_manager.h" #include "cuttlefish/host/libs/vm_manager/qemu_manager.h" @@ -352,6 +353,8 @@ Result InitializeCuttlefishConfiguration( const SystemImageDirFlag& system_image_dir, const VendorBootImageFlag& vendor_boot_image, const VmManagerFlag& vm_manager_flag, const Defaults& defaults) { + CF_TRACE("InitializeCuttlefishConfiguration"); + CuttlefishConfig tmp_config_obj; // If a snapshot path is provided, do not read all flags to set up the config. // Instead, read the config that was saved at time of snapshot and restore diff --git a/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc b/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc index ba0e64866f5..0148a233f77 100644 --- a/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc +++ b/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc @@ -39,6 +39,7 @@ #include "cuttlefish/host/libs/config/guest_hwui_renderer.h" #include "cuttlefish/host/libs/config/guest_renderer_preload.h" #include "cuttlefish/host/libs/config/vmm_mode.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #ifdef __APPLE__ #define CF_UNUSED_ON_MACOS [[maybe_unused]] @@ -683,6 +684,8 @@ static std::unordered_set kSupportedGpuContexts{ gfxstream::proto::GraphicsAvailability GetGraphicsAvailabilityWithSubprocessCheck() { + CF_TRACE("GetGraphicsAvailability"); + #ifdef __APPLE__ return {}; #else @@ -736,6 +739,8 @@ Result ConfigureGpuSettings( const std::string& guest_renderer_preload_arg, VmmMode vmm, const GuestConfig& guest_config, CuttlefishConfig::MutableInstanceSpecific& instance) { + CF_TRACE("ConfigureGpuSettings"); + #ifdef __APPLE__ (void)graphics_availability; (void)gpu_vhost_user_mode_arg; diff --git a/base/cvd/cuttlefish/host/commands/assemble_cvd/guest_config.cc b/base/cvd/cuttlefish/host/commands/assemble_cvd/guest_config.cc index 808d709ec34..31b0c9197bb 100644 --- a/base/cvd/cuttlefish/host/commands/assemble_cvd/guest_config.cc +++ b/base/cvd/cuttlefish/host/commands/assemble_cvd/guest_config.cc @@ -46,6 +46,7 @@ #include "cuttlefish/host/libs/config/config_utils.h" #include "cuttlefish/host/libs/config/display.h" #include "cuttlefish/host/libs/config/gpu_mode.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/pretty/optional.h" #include "cuttlefish/pretty/string.h" @@ -309,6 +310,8 @@ PrettyStruct Pretty(const GuestConfig& config, PrettyAdlPlaceholder) { Result> ReadGuestConfig( const BootImageFlag& boot_image, const KernelPathFlag& kernel_path, const SystemImageDirFlag& system_image_dirs) { + CF_TRACE("ReadGuestConfig"); + std::vector guest_configs; const std::string env_path = fmt::format( diff --git a/base/cvd/cuttlefish/host/commands/cvd/BUILD.bazel b/base/cvd/cuttlefish/host/commands/cvd/BUILD.bazel index 46f8104fc74..b15e33656c1 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/cvd/BUILD.bazel @@ -39,6 +39,7 @@ cf_cc_binary( "//cuttlefish/host/commands/cvd/cli:log_files", "//cuttlefish/host/commands/cvd/utils", "//cuttlefish/host/commands/cvd/version", + "//cuttlefish/host/libs/tracing", "//cuttlefish/host/libs/vm_manager", "//cuttlefish/posix:strerror", "//libbase", diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/BUILD.bazel b/base/cvd/cuttlefish/host/commands/cvd/cli/BUILD.bazel index 91dc77cf573..4bfafb8beab 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/BUILD.bazel @@ -140,6 +140,7 @@ cf_cc_library( "//cuttlefish/host/commands/cvd/instances/lock", "//cuttlefish/host/commands/cvd/utils", "//cuttlefish/host/libs/metrics:device_metrics_orchestration", + "//cuttlefish/host/libs/tracing", "//cuttlefish/posix:strerror", "//cuttlefish/posix:symlink", "//cuttlefish/result", diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/BUILD.bazel b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/BUILD.bazel index 0f2f57c3cd4..afede0038a8 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/BUILD.bazel @@ -151,6 +151,7 @@ cf_cc_library( "//cuttlefish/host/commands/cvd/utils", "//cuttlefish/host/commands/cvd/utils:common", "//cuttlefish/host/libs/metrics:fetch_metrics_orchestration", + "//cuttlefish/host/libs/tracing", "//cuttlefish/result", "//libbase", "@abseil-cpp//absl/log", @@ -440,6 +441,7 @@ cf_cc_library( "//cuttlefish/host/libs/config:config_constants", "//cuttlefish/host/libs/config:cuttlefish_config", "//cuttlefish/host/libs/metrics:device_metrics_orchestration", + "//cuttlefish/host/libs/tracing", "//cuttlefish/posix:symlink", "//cuttlefish/result", "//libbase", diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/create.cpp b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/create.cpp index 6be0a93582e..3fecaa3087c 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/create.cpp +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/create.cpp @@ -51,6 +51,7 @@ #include "cuttlefish/host/commands/cvd/instances/instance_manager.h" #include "cuttlefish/host/commands/cvd/instances/local_instance_group.h" #include "cuttlefish/host/commands/cvd/utils/common.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/posix/strerror.h" #include "cuttlefish/posix/symlink.h" #include "cuttlefish/result/result.h" @@ -269,6 +270,8 @@ Result CreateSymlinks(const LocalInstanceGroup& group) { } // namespace Result CvdCreateCommandHandler::Handle(const CommandRequest& request) { + CF_TRACE("cvd create"); + std::vector subcmd_args = request.SubcommandArguments(); cvd_common::Envs envs = CF_EXPECT(GetEnvs(request)); @@ -279,7 +282,10 @@ Result CvdCreateCommandHandler::Handle(const CommandRequest& request) { CF_EXPECT(CreateLoadCommand(request, subcmd_args, flags.config_file)); std::unique_ptr load_handler = NewLoadConfigsCommand(instance_manager_); - CF_EXPECT(load_handler->Handle(subrequest)); + { + CF_TRACE("cvd load"); + CF_EXPECT(load_handler->Handle(subrequest)); + } return {}; } @@ -308,7 +314,10 @@ Result CvdCreateCommandHandler::Handle(const CommandRequest& request) { CF_EXPECT(CreateStartCommand(group, subcmd_args, envs)); std::unique_ptr start_handler = NewCvdStartCommandHandler(instance_manager_); - CF_EXPECT(start_handler->Handle(start_cmd)); + { + CF_TRACE("cvd start"); + CF_EXPECT(start_handler->Handle(start_cmd)); + } if (CF_EXPECT(IsDefaultGroup(request))) { // For backward compatibility, we add extra symlink in system wide home diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/fetch.cpp b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/fetch.cpp index 01877428b13..d664b141b25 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/fetch.cpp +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/fetch.cpp @@ -37,6 +37,7 @@ #include "cuttlefish/host/commands/cvd/fetch/fetch_cvd_parser.h" #include "cuttlefish/host/commands/cvd/utils/common.h" #include "cuttlefish/host/libs/metrics/fetch_metrics_orchestration.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/result/result.h" namespace cuttlefish { @@ -84,6 +85,8 @@ Result RunCacheCleanup(const BuildApiFlags& build_api_flags) { } // namespace Result CvdFetchCommandHandler::Handle(const CommandRequest& request) { + CF_TRACE("cvd fetch"); + std::vector args = request.SubcommandArguments(); const FetchFlags flags = CF_EXPECT(FetchFlags::Parse(args)); CF_EXPECT(EnsureDirectoryExists(flags.target_directory)); diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp index 51f87fd4794..fc45a8efc6b 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp @@ -68,6 +68,7 @@ #include "cuttlefish/host/libs/config/config_constants.h" #include "cuttlefish/host/libs/config/cuttlefish_config.h" #include "cuttlefish/host/libs/metrics/device_metrics_orchestration.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/posix/symlink.h" #include "cuttlefish/result/result.h" @@ -460,6 +461,7 @@ cvd_common::Args CvdStartCommandHandler::CmdList() const { Result CvdStartCommandHandler::LaunchDevice( Command launch_command, LocalInstanceGroup& group, const cvd_common::Envs& envs, const CommandRequest& request) { + CF_TRACE("LaunchDevice"); // Don't destroy the returned object until after the devices have started, it // holds a connection to the orchestrator that ensures the devices remain // pre-registered there. If the connection is lost before the devices register @@ -500,6 +502,7 @@ Result CvdStartCommandHandler::LaunchDevice( Result CvdStartCommandHandler::LaunchDeviceInterruptible( Command command, LocalInstanceGroup& group, const cvd_common::Envs& envs, const CommandRequest& request) { + CF_TRACE("LaunchDeviceInterruptible"); // cvd_internal_start uses the config from the previous invocation to // determine the default value for the -report_anonymous_usage_stats flag so // we symlink that to the group's home directory, this link will be @@ -522,6 +525,7 @@ Result CvdStartCommandHandler::LaunchDeviceInterruptible( Result CvdStartCommandHandler::DetailedHelp( const CommandRequest& request) { + CF_TRACE("cvd start help"); cvd_common::Args args = request.SubcommandArguments(); std::vector own_flags = BuildOwnFlags(); CF_EXPECT(ConsumeFlags(own_flags, args)); diff --git a/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel b/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel index 9d109db3dbe..776be46c038 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel @@ -181,6 +181,7 @@ cf_cc_library( "//cuttlefish/host/commands/cvd/fetch:target_directories", "//cuttlefish/host/libs/config:fetcher_config", "//cuttlefish/host/libs/config:file_source", + "//cuttlefish/host/libs/tracing", "//cuttlefish/host/libs/web:android_build", "//cuttlefish/host/libs/web:android_build_api", "//cuttlefish/host/libs/web:build_api", @@ -220,6 +221,7 @@ cf_cc_library( "//cuttlefish/host/libs/config:file_source", "//cuttlefish/host/libs/image_aggregator:sparse_image", "//cuttlefish/host/libs/log_names", + "//cuttlefish/host/libs/tracing", "//cuttlefish/host/libs/web:android_build", "//cuttlefish/host/libs/web:android_build_string", "//cuttlefish/host/libs/web:chrome_os_build_string", diff --git a/base/cvd/cuttlefish/host/commands/cvd/fetch/fetch_context.cc b/base/cvd/cuttlefish/host/commands/cvd/fetch/fetch_context.cc index f46e4bbe54f..49e51fcad9f 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/fetch/fetch_context.cc +++ b/base/cvd/cuttlefish/host/commands/cvd/fetch/fetch_context.cc @@ -37,6 +37,7 @@ #include "cuttlefish/host/commands/cvd/fetch/target_directories.h" #include "cuttlefish/host/libs/config/fetcher_config.h" #include "cuttlefish/host/libs/config/file_source.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/host/libs/web/android_build_api.h" #include "cuttlefish/host/libs/web/build_api.h" #include "cuttlefish/host/libs/web/build_api_zip.h" @@ -64,10 +65,15 @@ Result FetchArtifact::DownloadTo(std::string local_path) { fmt::format("{}/{}", fetch_build_context_.target_directory_, local_path); if (downloaded_path_.empty()) { - std::string downloaded = - CF_EXPECT(fetch_build_context_.fetch_context_.build_api_.DownloadFile( - fetch_build_context_.build_, fetch_build_context_.target_directory_, - artifact_name_)); + std::string downloaded; + + { + CF_TRACEF("Download: %s", artifact_name_.c_str()); + downloaded = + CF_EXPECT(fetch_build_context_.fetch_context_.build_api_.DownloadFile( + fetch_build_context_.build_, + fetch_build_context_.target_directory_, artifact_name_)); + } size_t size = FileSize(downloaded); std::string download_phase = fmt::format("Downloaded '{}'", artifact_name_); fetch_build_context_.trace_.CompletePhase(download_phase, size); @@ -104,6 +110,8 @@ Result FetchArtifact::ExtractAll() { } Result FetchArtifact::ExtractAll(const std::string& local_path) { + CF_TRACEF("ExtractAll: %s", artifact_name_.c_str()); + ReadableZip* zip = CF_EXPECT(AsZip()); size_t entries = CF_EXPECT(zip->NumEntries()); for (uint64_t i = 0; i < entries; i++) { diff --git a/base/cvd/cuttlefish/host/commands/cvd/fetch/fetch_cvd.cc b/base/cvd/cuttlefish/host/commands/cvd/fetch/fetch_cvd.cc index fc8ea5f9185..938b914448e 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/fetch/fetch_cvd.cc +++ b/base/cvd/cuttlefish/host/commands/cvd/fetch/fetch_cvd.cc @@ -47,8 +47,9 @@ #include "cuttlefish/host/commands/cvd/utils/common.h" #include "cuttlefish/host/libs/config/fetcher_config.h" #include "cuttlefish/host/libs/config/file_source.h" -#include "cuttlefish/host/libs/log_names/log_names.h" #include "cuttlefish/host/libs/image_aggregator/sparse_image.h" +#include "cuttlefish/host/libs/log_names/log_names.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/host/libs/web/android_build.h" #include "cuttlefish/host/libs/web/android_build_string.h" #include "cuttlefish/host/libs/web/chrome_os_build_string.h" @@ -102,6 +103,8 @@ std::vector GetFetchTargets(const FetchFlags& flags, Result EnsureDirectoriesExist(const std::string& host_tools_directory, const std::string& cache_base_path, const std::vector& targets) { + CF_TRACE("EnsureDirectoriesExist"); + CF_EXPECT(EnsureDirectoryExists(host_tools_directory)); CF_EXPECT(EnsureDirectoryExists(cache_base_path)); for (const auto& target : targets) { @@ -126,6 +129,7 @@ Result> GetBuildHelper( Result GetBuilds(BuildApi& build_api, const BuildStrings& build_sources) { + CF_TRACE("GetBuilds"); Builds result = Builds{ .default_build = CF_EXPECT(GetBuildHelper( build_api, build_sources.default_build, kDefaultBuildTarget)), @@ -204,6 +208,8 @@ Result FetchDefaultTarget(FetchBuildContext& context, bool keep_downloaded_archives, const DownloadFlags& flags, bool has_system_build) { + CF_TRACE("FetchDefaultTarget"); + constexpr char kSignedPrefix[] = "signed/signed-"; // Some older builds might not have misc_info.txt, so permit errors on // fetching misc_info.txt @@ -263,6 +269,8 @@ Result FetchDefaultTarget(FetchBuildContext& context, Result FetchSystemTarget(FetchBuildContext& context, bool download_img_zip, const bool keep_downloaded_archives) { + CF_TRACE("FetchSystemTarget"); + std::string target_files_name = context.GetBuildZipName("target_files"); FetchArtifact target_files = context.Artifact(target_files_name); @@ -304,6 +312,8 @@ Result FetchSystemTarget(FetchBuildContext& context, } Result FetchKernelTarget(FetchBuildContext context) { + CF_TRACE("FetchKernelTarget"); + // If the kernel is from an arm/aarch64 build, the artifact will be called // Image. if (!context.Artifact("bzImage").DownloadTo("kernel").ok()) { @@ -319,6 +329,8 @@ Result FetchKernelTarget(FetchBuildContext context) { Result FetchBootTarget(FetchBuildContext& context, bool keep_downloaded_archives) { + CF_TRACE("FetchBootTarget"); + std::string img_zip = context.GetBuildZipName("img"); std::string to_download = context.GetFilepath().value_or(img_zip); FetchArtifact artifact = context.Artifact(to_download); @@ -336,6 +348,8 @@ Result FetchBootTarget(FetchBuildContext& context, } Result FetchBootloaderTarget(FetchBuildContext& context) { + CF_TRACE("FetchBootloaderTarget"); + // If the bootloader is from an arm/aarch64 build, the artifact will be of // filetype bin. if (!context.Artifact("u-boot.rom").DownloadTo("bootloader").ok()) { @@ -345,6 +359,8 @@ Result FetchBootloaderTarget(FetchBuildContext& context) { } Result FetchAndroidEfiLoaderTarget(FetchBuildContext& context) { + CF_TRACE("FetchAndroidEfiLoaderTarget"); + std::string filename = context.GetFilepath().value_or("gbl_x86_64.efi"); CF_EXPECT(context.Artifact(filename).DownloadTo("android_efi_loader.efi")); return {}; @@ -352,6 +368,8 @@ Result FetchAndroidEfiLoaderTarget(FetchBuildContext& context) { Result FetchOtaToolsTarget(FetchBuildContext& context, bool keep_downloaded_archives) { + CF_TRACE("FetchOtaToolsTarget"); + FetchArtifact otatools = context.Artifact("otatools.zip"); CF_EXPECT(otatools.Download()); CF_EXPECT(otatools.ExtractAll()); @@ -363,6 +381,8 @@ Result FetchOtaToolsTarget(FetchBuildContext& context, Result FetchTestSuitesTarget(FetchBuildContext& context, bool keep_downloaded_archives) { + CF_TRACE("FetchTestSuitesTarget"); + FetchArtifact android_cts = context.Artifact("android-cts.zip"); // TODO(b/468074996): determine what tradefed actually needs and potentially // expose a flag to allow downloading specific parts of the entire zip. @@ -380,6 +400,8 @@ Result FetchChromeOsTarget( const TargetDirectories& target_directories, const bool keep_downloaded_archives, FetcherConfig& config, FetchTracer::Trace trace) { + CF_TRACE("FetchChromeOsTarget"); + auto artifacts_opt = CF_EXPECT(luci_build_api.GetBuildArtifacts(chrome_os_build_string)); auto artifacts = CF_EXPECT(std::move(artifacts_opt)); @@ -405,6 +427,8 @@ Result FetchChromeOsTarget( Result FetchTarget(FetchContext& fetch_context, const DownloadFlags& flags, const bool keep_downloaded_archives) { + CF_TRACE("FetchTarget"); + if (std::optional context = fetch_context.DefaultBuild()) { bool has_system_build = fetch_context.SystemBuild().has_value(); CF_EXPECT(FetchDefaultTarget(*context, keep_downloaded_archives, flags, @@ -448,6 +472,8 @@ Result Fetch(const FetchFlags& flags, const std::string& cache_base_path, const HostToolsTarget& host_target, std::vector& targets) { + CF_TRACE("Fetch"); + #ifdef __BIONIC__ // TODO(schuffelen): Find a better way to deal with tzdata setenv("ANDROID_TZDATA_ROOT", "/", /* overwrite */ 0); diff --git a/base/cvd/cuttlefish/host/commands/cvd/main.cc b/base/cvd/cuttlefish/host/commands/cvd/main.cc index 55d25fd49e0..8f6ae3fcaf0 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/main.cc +++ b/base/cvd/cuttlefish/host/commands/cvd/main.cc @@ -41,6 +41,7 @@ #include "cuttlefish/host/commands/cvd/cvd.h" #include "cuttlefish/host/commands/cvd/utils/common.h" #include "cuttlefish/host/commands/cvd/version/version.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/posix/strerror.h" // TODO(315772518) Re-enable once metrics send is reenabled // #include "cuttlefish/host/commands/cvd/metrics/cvd_metrics_api.h" @@ -124,6 +125,8 @@ void IncreaseFileLimit() { } Result CvdMain(cvd_common::Args all_args) { + CF_TRACE("CvdMain"); + if (!isatty(0)) { LOG(INFO) << GetVersionIds().ToString(); } diff --git a/base/cvd/cuttlefish/host/commands/run_cvd/BUILD.bazel b/base/cvd/cuttlefish/host/commands/run_cvd/BUILD.bazel index 1a78c5cae0f..52e3fe43c67 100644 --- a/base/cvd/cuttlefish/host/commands/run_cvd/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/run_cvd/BUILD.bazel @@ -26,6 +26,7 @@ cf_cc_library( "//cuttlefish/host/libs/config:config_utils", "//cuttlefish/host/libs/config:cuttlefish_config", "//cuttlefish/host/libs/feature", + "//cuttlefish/host/libs/tracing", "//cuttlefish/host/libs/vm_manager", "//cuttlefish/posix:strerror", "//cuttlefish/result", @@ -107,6 +108,7 @@ cf_cc_binary( "//cuttlefish/host/libs/feature:inject", "//cuttlefish/host/libs/log_names", "//cuttlefish/host/libs/metrics", + "//cuttlefish/host/libs/tracing", "//cuttlefish/host/libs/version", "//cuttlefish/host/libs/vm_manager", "//cuttlefish/result", @@ -147,6 +149,7 @@ cf_cc_library( "//cuttlefish/host/libs/feature", "//cuttlefish/host/libs/feature:inject", "//cuttlefish/host/libs/process_monitor", + "//cuttlefish/host/libs/tracing", "//cuttlefish/host/libs/vm_manager", "//cuttlefish/posix:strerror", "//cuttlefish/result", diff --git a/base/cvd/cuttlefish/host/commands/run_cvd/boot_state_machine.cc b/base/cvd/cuttlefish/host/commands/run_cvd/boot_state_machine.cc index 029e9225e7d..cf56b1baded 100644 --- a/base/cvd/cuttlefish/host/commands/run_cvd/boot_state_machine.cc +++ b/base/cvd/cuttlefish/host/commands/run_cvd/boot_state_machine.cc @@ -62,6 +62,7 @@ #include "cuttlefish/host/libs/config/cuttlefish_config.h" #include "cuttlefish/host/libs/feature/feature.h" #include "cuttlefish/host/libs/feature/kernel_log_pipe_provider.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/host/libs/vm_manager/vm_manager.h" #include "cuttlefish/posix/strerror.h" #include "cuttlefish/result/result.h" @@ -164,6 +165,9 @@ Result DaemonizeLauncher(const CuttlefishConfig& config) { // Explicitly close here, otherwise we may end up reading forever if the // child process dies. write_end->Close(); + + CF_TRACE("Waiting for Guest to Boot"); + RunnerExitCodes exit_code; auto bytes_read = read_end->Read(&exit_code, sizeof(exit_code)); if (bytes_read != sizeof(exit_code)) { diff --git a/base/cvd/cuttlefish/host/commands/run_cvd/main.cc b/base/cvd/cuttlefish/host/commands/run_cvd/main.cc index dc676f4115a..52015e43d3e 100644 --- a/base/cvd/cuttlefish/host/commands/run_cvd/main.cc +++ b/base/cvd/cuttlefish/host/commands/run_cvd/main.cc @@ -80,6 +80,7 @@ #include "cuttlefish/host/libs/feature/inject.h" #include "cuttlefish/host/libs/log_names/log_names.h" #include "cuttlefish/host/libs/metrics/metrics_receiver.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/host/libs/version/version.h" #include "cuttlefish/host/libs/vm_manager/vm_manager.h" #include "cuttlefish/result/result.h" @@ -126,9 +127,15 @@ class InstanceLifecycle : public LateInjected { // One of the setup features can consume most output, so print this early. DiagnosticInformation::PrintAll(diagnostics_); - CF_EXPECT(SetupFeature::RunSetup(setup_features_)); + { + CF_TRACE("RunFeatureSetup"); + CF_EXPECT(SetupFeature::RunSetup(setup_features_)); + } - CF_EXPECT(server_loop_.Run()); + { + CF_TRACE("RunServerLoop"); + CF_EXPECT(server_loop_.Run()); + } return {}; } diff --git a/base/cvd/cuttlefish/host/commands/run_cvd/server_loop_impl.cpp b/base/cvd/cuttlefish/host/commands/run_cvd/server_loop_impl.cpp index f06a13766af..aad40501edb 100644 --- a/base/cvd/cuttlefish/host/commands/run_cvd/server_loop_impl.cpp +++ b/base/cvd/cuttlefish/host/commands/run_cvd/server_loop_impl.cpp @@ -50,6 +50,7 @@ #include "cuttlefish/host/libs/config/vmm_mode.h" #include "cuttlefish/host/libs/feature/command_source.h" #include "cuttlefish/host/libs/process_monitor/process_monitor.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/posix/strerror.h" #include "cuttlefish/result/result.h" @@ -110,8 +111,10 @@ Result ServerLoopImpl::Run() { snapshot_control_files_->run_cvd_to_secure_env_fd; ProcessMonitor process_monitor(std::move(process_monitor_properties), channel_to_secure_env); - - CF_EXPECT(process_monitor.StartAndMonitorProcesses()); + { + CF_TRACE("StartAndMonitorProcesses"); + CF_EXPECT(process_monitor.StartAndMonitorProcesses()); + } device_status_ = DeviceStatus::kActive; while (true) { @@ -323,6 +326,8 @@ void ServerLoopImpl::HandleActionWithNoData(const LauncherAction action, } void ServerLoopImpl::DeleteFifos() { + CF_TRACE("DeleteFifos"); + // TODO(schuffelen): Create these FIFOs in assemble_cvd instead of run_cvd. std::vector pipes = { KernelLogPipeName(instance_), @@ -360,6 +365,8 @@ void ServerLoopImpl::DeleteFifos() { } bool ServerLoopImpl::PowerwashFiles() { + CF_TRACE("PowerwashFiles"); + DeleteFifos(); // TODO(b/269669405): Figure out why this file is not being deleted diff --git a/base/cvd/cuttlefish/host/commands/start/BUILD.bazel b/base/cvd/cuttlefish/host/commands/start/BUILD.bazel index 7ab232d6e97..da53524da5a 100644 --- a/base/cvd/cuttlefish/host/commands/start/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/start/BUILD.bazel @@ -34,6 +34,7 @@ cf_cc_binary( "//cuttlefish/host/libs/config:host_tools_version", "//cuttlefish/host/libs/config:instance_nums", "//cuttlefish/host/libs/log_names", + "//cuttlefish/host/libs/tracing", "//cuttlefish/host/libs/vm_manager", "//libbase", "@abseil-cpp//absl/base:no_destructor", diff --git a/base/cvd/cuttlefish/host/commands/start/main.cc b/base/cvd/cuttlefish/host/commands/start/main.cc index 8c7428576e7..f53c2847dbf 100644 --- a/base/cvd/cuttlefish/host/commands/start/main.cc +++ b/base/cvd/cuttlefish/host/commands/start/main.cc @@ -46,6 +46,7 @@ #include "cuttlefish/host/libs/config/host_tools_version.h" #include "cuttlefish/host/libs/config/instance_nums.h" #include "cuttlefish/host/libs/log_names/log_names.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/posix/symlink.h" namespace cuttlefish { @@ -207,6 +208,9 @@ Result LinkLogs2InstanceDir( int CvdInternalStartMain(int argc, char** argv) { LogToStderr(); + + CF_TRACE("cvd_internal_start"); + std::vector args(argv + 1, argv + argc); std::vector assemble_args; @@ -293,15 +297,18 @@ int CvdInternalStartMain(int argc, char** argv) { auto assembler_input = WriteFiles(AvailableFilesReport()); std::string assembler_output; - auto assemble_ret = - InvokeAssembler(assembler_input, assembler_output, - forwarder.ArgvForSubprocess(AssemblerPath(), args)); - - if (assemble_ret != 0) { - LOG(ERROR) << "assemble_cvd returned " << assemble_ret; - return assemble_ret; - } else { - VLOG(0) << "assemble_cvd exited successfully."; + { + CF_TRACE("Running assemble_cvd"); + auto assemble_ret = + InvokeAssembler(assembler_input, assembler_output, + forwarder.ArgvForSubprocess(AssemblerPath(), args)); + + if (assemble_ret != 0) { + LOG(ERROR) << "assemble_cvd returned " << assemble_ret; + return assemble_ret; + } else { + VLOG(0) << "assemble_cvd exited successfully."; + } } std::string conf_path; @@ -327,11 +334,13 @@ int CvdInternalStartMain(int argc, char** argv) { setenv(kCuttlefishInstanceEnvVarName, instance.id().c_str(), /* overwrite */ 1); + CF_TRACEF("Running run_cvd: %s", instance.instance_name().c_str()); auto run_proc = StartRunner(std::move(runner_stdin), instance, forwarder.ArgvForSubprocess(RunnerPath())); runners.push_back(std::move(run_proc)); } + CF_TRACE("WaitForRunCvd"); bool run_cvd_failure = false; for (auto& run_proc : runners) { auto run_ret = run_proc.Wait(); diff --git a/base/cvd/cuttlefish/host/libs/feature/BUILD.bazel b/base/cvd/cuttlefish/host/libs/feature/BUILD.bazel index 1b9d0276300..825178a6659 100644 --- a/base/cvd/cuttlefish/host/libs/feature/BUILD.bazel +++ b/base/cvd/cuttlefish/host/libs/feature/BUILD.bazel @@ -18,6 +18,7 @@ cf_cc_library( "//cuttlefish/common/libs/fs", "//cuttlefish/common/libs/utils:subprocess", "//cuttlefish/common/libs/utils:type_name", + "//cuttlefish/host/libs/tracing", "//cuttlefish/result", "//libbase", "@abseil-cpp//absl/log", diff --git a/base/cvd/cuttlefish/host/libs/feature/feature.cpp b/base/cvd/cuttlefish/host/libs/feature/feature.cpp index 611e62800ac..10564b464c7 100644 --- a/base/cvd/cuttlefish/host/libs/feature/feature.cpp +++ b/base/cvd/cuttlefish/host/libs/feature/feature.cpp @@ -23,6 +23,7 @@ #include "absl/log/log.h" +#include "cuttlefish/host/libs/tracing/tracing.h" #include "cuttlefish/result/result.h" namespace cuttlefish { @@ -49,6 +50,7 @@ SetupFeature::~SetupFeature() {} "Dependency issue detected, not performing any setup."); // TODO(b/189153501): This can potentially be parallelized. for (auto& feature : ordered_features) { + CF_TRACEF("FeatureSetup %s", feature->Name().c_str()); VLOG(0) << "Running setup for " << feature->Name(); CF_EXPECT(feature->ResultSetup(), "Setup failed for " << feature->Name()); } diff --git a/base/cvd/cuttlefish/host/libs/tracing/BUILD.bazel b/base/cvd/cuttlefish/host/libs/tracing/BUILD.bazel new file mode 100644 index 00000000000..0dcf27c222e --- /dev/null +++ b/base/cvd/cuttlefish/host/libs/tracing/BUILD.bazel @@ -0,0 +1,38 @@ +load("@rules_cc//cc:cc_shared_library.bzl", "cc_shared_library") +load("//cuttlefish/bazel:rules.bzl", "cf_cc_library") + +package( + default_visibility = ["//:android_cuttlefish"], +) + +cc_shared_library( + name = "perfetto_c", + deps = [ + "@perfetto//:libperfetto_c", + ], +) + +cf_cc_library( + name = "tracing", + srcs = [ + "perfetto.h", + "perfetto_functions.cpp", + "perfetto_functions.h", + "perfetto_worker_thread.cpp", + "perfetto_worker_thread.h", + "tracing.cpp", + "tracing_state.cpp", + "tracing_state.h", + ], + hdrs = [ + "tracing.h", + ], + deps = [ + "//cuttlefish/common/libs/utils:environment", + "//cuttlefish/host/libs/config:config_utils", + "//cuttlefish/result", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/strings:str_format", + "@abseil-cpp//absl/synchronization", + ], +) diff --git a/base/cvd/cuttlefish/host/libs/tracing/README.md b/base/cvd/cuttlefish/host/libs/tracing/README.md new file mode 100644 index 00000000000..71b22f1f48c --- /dev/null +++ b/base/cvd/cuttlefish/host/libs/tracing/README.md @@ -0,0 +1,52 @@ +# Cuttlefish Tracing + +Cuttlefish host tooling supports [Perfetto](http://perfetto.dev) for tracing. + +## Setup + +Please see the +[Perfetto Quickstart](https://perfetto.dev/docs/getting-started/system-tracing) +instructions, or follow these potentially out of date instructions below: + +``` +curl -LO https://get.perfetto.dev/tracebox +chmod +x tracebox +``` + +and add `tracebox` to your `$PATH`. + +## Usage + +``` +tracebox --system-sockets -o cuttlefish_trace.ptrace --txt -c cuttlefish_trace.cfg +``` + +with `cuttlefish_trace.cfg` containing the following or similar: + +``` +buffers { + size_kb: 4096 +} +data_sources: { + config { + name: "track_event" + track_event_config { + disabled_categories: "*" + enabled_categories: "cuttlefish" + } + } +} +``` + +Next, run Cuttlefish: + +``` +CVD_TRACE=1 cvd create +``` + +TODO(b/324031921): revisit the need for `CVD_TRACE=1` after fixed. + +Finally, end the trace capture with Ctrl + C. + +You can open https://ui.perfetto.dev/ in your webbrowser and use "Open trace +file" to view the trace. \ No newline at end of file diff --git a/base/cvd/cuttlefish/host/libs/tracing/perfetto.h b/base/cvd/cuttlefish/host/libs/tracing/perfetto.h new file mode 100644 index 00000000000..4b9e9c87043 --- /dev/null +++ b/base/cvd/cuttlefish/host/libs/tracing/perfetto.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2026 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. + */ + +#pragma once + +#include +#include +#include + +// TODO: see if Perfetto can add a header only library to their build. + +enum PerfettoTeHlExtraType { + PERFETTO_TE_HL_EXTRA_TYPE_REGISTERED_TRACK = 1, + PERFETTO_TE_HL_EXTRA_TYPE_NAMED_TRACK = 2, + PERFETTO_TE_HL_EXTRA_TYPE_TIMESTAMP = 3, + PERFETTO_TE_HL_EXTRA_TYPE_DYNAMIC_CATEGORY = 4, + PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_INT64 = 5, + PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_DOUBLE = 6, + PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_BOOL = 7, + PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_UINT64 = 8, + PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_INT64 = 9, + PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_DOUBLE = 10, + PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_STRING = 11, + PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_POINTER = 12, + PERFETTO_TE_HL_EXTRA_TYPE_FLOW = 13, + PERFETTO_TE_HL_EXTRA_TYPE_TERMINATING_FLOW = 14, + PERFETTO_TE_HL_EXTRA_TYPE_FLUSH = 15, + PERFETTO_TE_HL_EXTRA_TYPE_NO_INTERN = 16, + PERFETTO_TE_HL_EXTRA_TYPE_PROTO_FIELDS = 17, + PERFETTO_TE_HL_EXTRA_TYPE_PROTO_TRACK = 18, + PERFETTO_TE_HL_EXTRA_TYPE_NESTED_TRACKS = 19, +}; + +enum PerfettoTeType { + PERFETTO_TE_TYPE_SLICE_BEGIN = 1, + PERFETTO_TE_TYPE_SLICE_END = 2, + PERFETTO_TE_TYPE_INSTANT = 3, + PERFETTO_TE_TYPE_COUNTER = 4, +}; + +struct PerfettoTeHlExtra { + uint32_t type; +}; + +struct PerfettoTeHlExtraNamedTrack { + struct PerfettoTeHlExtra header; + const char* name; + uint64_t id; + uint64_t parent_uuid; + bool is_name_static; +}; + +struct PerfettoTeTimestamp { + // PerfettoTeTimestampType + uint32_t clock_id; + uint64_t value; +}; + +struct PerfettoTeHlExtraTimestamp { + struct PerfettoTeHlExtra header; + // The timestamp for this event. + struct PerfettoTeTimestamp timestamp; +}; + +struct PerfettoTeHlExtraFlow { + struct PerfettoTeHlExtra header; + // Specifies that this event starts (or terminates) a flow (i.e. a link + // between two events) identified by this id. + uint64_t id; +}; + +// Perfetto does not have a header only bazel target. +struct PerfettoProducerBackendInitArgs; +struct PerfettoTeCategoryImpl; +struct PerfettoTeCategoryDescriptor { + const char* name; + const char* desc; + const char** tags; + size_t num_tags; +}; + +using PFN_PerfettoProducerBackendInitArgsCreate = + struct PerfettoProducerBackendInitArgs* (*)(void); +using PFN_PerfettoProducerBackendInitArgsDestroy = + void (*)(struct PerfettoProducerBackendInitArgs*); +using PFN_PerfettoProducerShutdown = void (*)(void); +using PFN_PerfettoProducerSystemInit = + void (*)(const struct PerfettoProducerBackendInitArgs*); +using PFN_PerfettoTeCategoryImplCreate = + struct PerfettoTeCategoryImpl* (*)(struct PerfettoTeCategoryDescriptor*); +using PFN_PerfettoTeCategoryImplDestroy = + void (*)(struct PerfettoTeCategoryImpl*); +using PFN_PerfettoTeCategoryImplGetEnabled = + std::atomic* (*)(struct PerfettoTeCategoryImpl*); +using PFN_PerfettoTeFlush = void (*)(void); +using PFN_PerfettoTeHlEmitImpl = void (*)(struct PerfettoTeCategoryImpl*, + int32_t, const char*, + struct PerfettoTeHlExtra* const*); +using PFN_PerfettoTeInit = void (*)(void); +using PFN_PerfettoTePublishCategories = void (*)(void); diff --git a/base/cvd/cuttlefish/host/libs/tracing/perfetto_functions.cpp b/base/cvd/cuttlefish/host/libs/tracing/perfetto_functions.cpp new file mode 100644 index 00000000000..ec33bd51562 --- /dev/null +++ b/base/cvd/cuttlefish/host/libs/tracing/perfetto_functions.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2026 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 "cuttlefish/host/libs/tracing/perfetto_functions.h" + +#include + +#include "cuttlefish/host/libs/config/config_utils.h" + +namespace cuttlefish { + +void PerfettoFunctions::LibraryCloser::operator()(void* handle) const { + if (handle != nullptr) { + dlclose(handle); + } +} + +/*static*/ Result PerfettoFunctions::Load() { + const std::string libperfetto_path = HostBinaryPath("libperfetto_c.so"); + + PerfettoFunctions funcs; + funcs.handle.reset(dlopen(libperfetto_path.c_str(), RTLD_NOW | RTLD_LOCAL)); + CF_EXPECT(funcs.handle.get() != nullptr, + "Failed to load " << libperfetto_path); + +#define LOAD_SYMBOL(name) \ + funcs.name = reinterpret_cast( \ + dlsym(funcs.handle.get(), #name)); \ + CF_EXPECT(funcs.name != nullptr, \ + "Failed to resolve symbol " << #name << ": " << dlerror()); + + LOAD_SYMBOL(PerfettoProducerBackendInitArgsCreate); + LOAD_SYMBOL(PerfettoProducerBackendInitArgsDestroy); + LOAD_SYMBOL(PerfettoProducerShutdown); + LOAD_SYMBOL(PerfettoProducerSystemInit); + LOAD_SYMBOL(PerfettoTeCategoryImplCreate); + LOAD_SYMBOL(PerfettoTeCategoryImplDestroy); + LOAD_SYMBOL(PerfettoTeCategoryImplGetEnabled); + LOAD_SYMBOL(PerfettoTeFlush); + LOAD_SYMBOL(PerfettoTeHlEmitImpl); + LOAD_SYMBOL(PerfettoTeInit); + LOAD_SYMBOL(PerfettoTePublishCategories); + +#undef LOAD_SYMBOL + + funcs.perfetto_te_process_track_uuid_ptr = reinterpret_cast( + dlsym(funcs.handle.get(), "perfetto_te_process_track_uuid")); + CF_EXPECT( + funcs.perfetto_te_process_track_uuid_ptr != nullptr, + "Failed to resolve symbol perfetto_te_process_track_uuid: " << dlerror()); + + return funcs; +} + +} // namespace cuttlefish \ No newline at end of file diff --git a/base/cvd/cuttlefish/host/libs/tracing/perfetto_functions.h b/base/cvd/cuttlefish/host/libs/tracing/perfetto_functions.h new file mode 100644 index 00000000000..82e3ce750b2 --- /dev/null +++ b/base/cvd/cuttlefish/host/libs/tracing/perfetto_functions.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2026 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. + */ + +#pragma once + +#include +#include + +#include "cuttlefish/host/libs/tracing/perfetto.h" +#include "cuttlefish/result/result.h" + +namespace cuttlefish { + +struct PerfettoFunctions { + struct LibraryCloser { + void operator()(void* handle) const; + }; + std::unique_ptr handle; + + PFN_PerfettoProducerBackendInitArgsCreate + PerfettoProducerBackendInitArgsCreate = nullptr; + PFN_PerfettoProducerBackendInitArgsDestroy + PerfettoProducerBackendInitArgsDestroy = nullptr; + PFN_PerfettoProducerShutdown PerfettoProducerShutdown = nullptr; + PFN_PerfettoProducerSystemInit PerfettoProducerSystemInit = nullptr; + PFN_PerfettoTeCategoryImplCreate PerfettoTeCategoryImplCreate = nullptr; + PFN_PerfettoTeCategoryImplDestroy PerfettoTeCategoryImplDestroy = nullptr; + PFN_PerfettoTeCategoryImplGetEnabled PerfettoTeCategoryImplGetEnabled = + nullptr; + PFN_PerfettoTeFlush PerfettoTeFlush = nullptr; + PFN_PerfettoTeHlEmitImpl PerfettoTeHlEmitImpl = nullptr; + PFN_PerfettoTeInit PerfettoTeInit = nullptr; + PFN_PerfettoTePublishCategories PerfettoTePublishCategories = nullptr; + uint64_t* perfetto_te_process_track_uuid_ptr = nullptr; + + static Result Load(); +}; + +} // namespace cuttlefish diff --git a/base/cvd/cuttlefish/host/libs/tracing/perfetto_worker_thread.cpp b/base/cvd/cuttlefish/host/libs/tracing/perfetto_worker_thread.cpp new file mode 100644 index 00000000000..33d6302789a --- /dev/null +++ b/base/cvd/cuttlefish/host/libs/tracing/perfetto_worker_thread.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2026 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, express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cuttlefish/host/libs/tracing/perfetto_worker_thread.h" + +#include "absl/log/log.h" + +namespace cuttlefish { + +PerfettoWorkerThread::PerfettoWorkerThread() { + thread_ = std::thread(&PerfettoWorkerThread::WorkerThreadLoop, this); +} + +PerfettoWorkerThread::~PerfettoWorkerThread() { + { + absl::MutexLock lock(mutex_); + shutting_down_ = true; + } + thread_.join(); +} + +void PerfettoWorkerThread::EnqueueTraceEvent(TraceEvent event) { + absl::MutexLock lock(mutex_); + trace_events_.push_back(event); +} + +bool PerfettoWorkerThread::LoadPerfetto() { + auto result = PerfettoFunctions::Load(); + if (!result.ok()) { + LOG(ERROR) << result.error(); + return false; + } + perfetto_ = std::move(*result); + return true; +} + +bool PerfettoWorkerThread::InitializeProducer() { + struct PerfettoProducerBackendInitArgs* args = + perfetto_.PerfettoProducerBackendInitArgsCreate(); + if (!args) { + LOG(ERROR) << "Failed to create Perfetto backend init args."; + return false; + } + perfetto_.PerfettoProducerSystemInit(args); + perfetto_.PerfettoProducerBackendInitArgsDestroy(args); + + static struct PerfettoTeCategoryDescriptor desc = { + .name = "cuttlefish", + .desc = "Cuttlefish Events", + }; + category_ = perfetto_.PerfettoTeCategoryImplCreate(&desc); + if (!category_) { + LOG(ERROR) << "Failed to create Perfetto category."; + return false; + } + + perfetto_.PerfettoTeInit(); + perfetto_.PerfettoTePublishCategories(); + + // Perfetto's original expected usage was to have a long running service + // that is initialized before a trace session starts. + // + // Cuttlefish wants to be able to trace the launch procedure where many + // processes are connecting to an already running trace session. + // + // b/324031921 tracks adding a way to synchronize with traced during init + // and to wait for a connection is traced is reachable. For now, tracing + // will require explicit opt-in via a flag/envvar. + std::atomic* category_enabled = + perfetto_.PerfettoTeCategoryImplGetEnabled(category_); + while (!category_enabled->load()) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + return true; +} + +void PerfettoWorkerThread::ShutdownProducer() { + perfetto_.PerfettoTeFlush(); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + perfetto_.PerfettoTeCategoryImplDestroy(category_); + perfetto_.PerfettoProducerShutdown(); +} + +bool PerfettoWorkerThread::HasWorkOrIsShuttingDown() { + return !trace_events_.empty() || shutting_down_; +} + +void PerfettoWorkerThread::WorkerThreadLoop() { + if (!LoadPerfetto()) { + LOG(WARNING) << "Failed to initialize tracing: failed to load Perfetto."; + return; + } + + if (!InitializeProducer()) { + LOG(WARNING) << "Failed to initialize tracing: failed to init Perfetto."; + return; + } + + while (true) { + std::vector events_to_process; + + { + absl::MutexLock lock(mutex_); + absl::Condition condition(this, + &PerfettoWorkerThread::HasWorkOrIsShuttingDown); + mutex_.Await(condition); + + if (shutting_down_ && trace_events_.empty()) { + break; + } + + events_to_process.swap(trace_events_); + } + + for (auto& event : events_to_process) { + WorkerProcessTraceEvent(event); + } + } + + ShutdownProducer(); +} + +uint64_t PerfettoWorkerThread::ProcessTrackUuid() const { + return *perfetto_.perfetto_te_process_track_uuid_ptr; +} + +void PerfettoWorkerThread::WorkerProcessTraceEvent(TraceEvent& event) { + struct PerfettoTeHlExtraTimestamp timestamp_extra = { + .header = + { + .type = PERFETTO_TE_HL_EXTRA_TYPE_TIMESTAMP, + }, + .timestamp = + { + .clock_id = 6, // BOOTTIME + .value = event.timestamp, + }, + }; + + const std::string thread_name = "Thread " + std::to_string(event.thread_id); + struct PerfettoTeHlExtraNamedTrack track_extra = { + .header = + { + .type = PERFETTO_TE_HL_EXTRA_TYPE_NAMED_TRACK, + }, + .name = thread_name.c_str(), + .id = event.thread_id, + .parent_uuid = ProcessTrackUuid(), + .is_name_static = false, + }; + + struct PerfettoTeHlExtraFlow flow_extra = { + .header = + { + .type = PERFETTO_TE_HL_EXTRA_TYPE_FLOW, + }, + .id = event.flow ? *event.flow : 0, + }; + + std::vector extras; + extras.push_back(×tamp_extra.header); + extras.push_back(&track_extra.header); + if (event.flow) { + extras.push_back(&flow_extra.header); + } + extras.push_back(nullptr); + + const char* event_str = event.str.has_value() ? event.str->c_str() : nullptr; + perfetto_.PerfettoTeHlEmitImpl(category_, event.type, event_str, + extras.data()); +} + +} // namespace cuttlefish \ No newline at end of file diff --git a/base/cvd/cuttlefish/host/libs/tracing/perfetto_worker_thread.h b/base/cvd/cuttlefish/host/libs/tracing/perfetto_worker_thread.h new file mode 100644 index 00000000000..9a11bb42846 --- /dev/null +++ b/base/cvd/cuttlefish/host/libs/tracing/perfetto_worker_thread.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2026 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "absl/synchronization/mutex.h" +#include "cuttlefish/host/libs/tracing/perfetto_functions.h" + +namespace cuttlefish { + +// A dedicated helper thread for interacting with the Perfetto library. +// +// Perfetto makes use of static global data. The Perfetto library is +// loaded via dlopen() and unloaded via dlclose() so that the static +// global data can be reset. +// +// Perfetto also makes use of thread local data. When thread locals +// are used, the c runtime registers destructors for thread exit. One +// must ensure that all threads using these thread locals are destroyed +// before dlclose() from above. Otherwise, the thread local destructors +// might try to use destructor code that was already unloaded. +// +// With all of this, we restrict all interaction with the Perfetto library +// into a dedicated worker thread. +class PerfettoWorkerThread { + public: + PerfettoWorkerThread(); + ~PerfettoWorkerThread(); + + struct TraceEvent { + int type = 0; + uint64_t timestamp = 0; + uint64_t thread_id = 0; + std::optional str; + std::optional flow; + }; + + void EnqueueTraceEvent(TraceEvent event) ABSL_LOCKS_EXCLUDED(mutex_); + + private: + bool LoadPerfetto(); + + bool InitializeProducer(); + void ShutdownProducer(); + + bool HasWorkOrIsShuttingDown() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + void WorkerThreadLoop(); + void WorkerProcessTraceEvent(TraceEvent& event) ABSL_LOCKS_EXCLUDED(mutex_); + + uint64_t ProcessTrackUuid() const; + + std::thread thread_; + + absl::Mutex mutex_; + bool shutting_down_ ABSL_GUARDED_BY(mutex_) = false; + std::vector trace_events_ ABSL_GUARDED_BY(mutex_); + + PerfettoFunctions perfetto_; + struct PerfettoTeCategoryImpl* category_ = nullptr; +}; + +} // namespace cuttlefish \ No newline at end of file diff --git a/base/cvd/cuttlefish/host/libs/tracing/tracing.cpp b/base/cvd/cuttlefish/host/libs/tracing/tracing.cpp new file mode 100644 index 00000000000..4c89c87ab15 --- /dev/null +++ b/base/cvd/cuttlefish/host/libs/tracing/tracing.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2026 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 "cuttlefish/host/libs/tracing/tracing.h" + +#include + +#include "absl/log/log.h" +#include "cuttlefish/host/libs/tracing/tracing_state.h" + +namespace cuttlefish { +namespace { + +void TracingAtExit() { TracingState::Get().Shutdown(); } + +void TracingBeforeFork() { TracingState::Get().BeforeFork(); } + +void TracingAfterForkChild() { + TracingState::Get().AfterFork(/*is_child=*/true); +} + +void TracingAfterForkParent() { + TracingState::Get().AfterFork(/*is_child=*/false); +} + +} // namespace + +void TraceEventBegin(std::string_view str) { + static std::once_flag sInitializeOnceFlag; + std::call_once(sInitializeOnceFlag, []() { + int res = pthread_atfork(TracingBeforeFork, TracingAfterForkParent, + TracingAfterForkChild); + if (res != 0) { + LOG(ERROR) << "Failed to register pthread fork callbacks."; + } + std::atexit(TracingAtExit); + }); + + TracingState::Get().TraceBegin(str); +} + +void TraceEventEnd() { TracingState::Get().TraceEnd(); } + +} // namespace cuttlefish diff --git a/base/cvd/cuttlefish/host/libs/tracing/tracing.h b/base/cvd/cuttlefish/host/libs/tracing/tracing.h new file mode 100644 index 00000000000..7429fa925de --- /dev/null +++ b/base/cvd/cuttlefish/host/libs/tracing/tracing.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2026 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. + */ + +#pragma once + +#include +#include + +#include "absl/strings/str_format.h" + +namespace cuttlefish { + +void TraceEventBegin(std::string_view str); +void TraceEventEnd(); + +class ScopedTrace { + public: + inline ScopedTrace(std::string_view str) { TraceEventBegin(str); } + + ~ScopedTrace() { TraceEventEnd(); } +}; + +#define CF_SCOPED_TRACE_VAR_NAME2(x, y) x##y +#define CF_SCOPED_TRACE_VAR_NAME(x, y) CF_SCOPED_TRACE_VAR_NAME2(x, y) + +#define CF_TRACE(str) \ + ::cuttlefish::ScopedTrace CF_SCOPED_TRACE_VAR_NAME(cf_internal_tracer_line_, \ + __LINE__)(str) + +#define CF_TRACEF(format, ...) \ + ::cuttlefish::ScopedTrace CF_SCOPED_TRACE_VAR_NAME( \ + cf_internal_tracer_line_, \ + __LINE__)(absl::StrFormat(format, ##__VA_ARGS__)) + +} // namespace cuttlefish \ No newline at end of file diff --git a/base/cvd/cuttlefish/host/libs/tracing/tracing_state.cpp b/base/cvd/cuttlefish/host/libs/tracing/tracing_state.cpp new file mode 100644 index 00000000000..17ea7297064 --- /dev/null +++ b/base/cvd/cuttlefish/host/libs/tracing/tracing_state.cpp @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2026 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 "cuttlefish/host/libs/tracing/tracing_state.h" + +#include + +#include +#include + +#include "cuttlefish/common/libs/utils/environment.h" + +namespace cuttlefish { +namespace { + +thread_local std::shared_ptr tlThreadTraceState = nullptr; + +uint64_t GetNewFlowId() { + thread_local std::mt19937 generator(std::random_device{}()); + std::uniform_int_distribution distribution( + 0, std::numeric_limits::max()); + return distribution(generator); +} + +uint64_t GetThreadId() { return static_cast(gettid()); } + +uint64_t GetTimestamp() { + struct timespec ts; + clock_gettime(CLOCK_BOOTTIME, &ts); + return (uint64_t)ts.tv_sec * 1000000000ULL + ts.tv_nsec; +} + +} // namespace + +/*static*/ TracingState& TracingState::Get() { + static TracingState* sInstance = new TracingState(); + return *sInstance; +} + +void TracingState::Shutdown() { + if (!enabled_) return; + + absl::MutexLock lock(mutex_); + ShutdownLocked(); +} + +void TracingState::TraceBegin(std::string_view str) { + if (!enabled_) return; + + PerfettoWorkerThread::TraceEvent trace_event = { + .type = PERFETTO_TE_TYPE_SLICE_BEGIN, + .timestamp = GetTimestamp(), + .str = {std::string(str)}, + }; + SendTraceEventToWorker(trace_event, /* modify_trace_stack=*/true); +} + +void TracingState::TraceEnd() { + if (!enabled_) return; + + PerfettoWorkerThread::TraceEvent trace_event = { + .type = PERFETTO_TE_TYPE_SLICE_END, + .timestamp = GetTimestamp(), + }; + SendTraceEventToWorker(trace_event, /* modify_trace_stack=*/true); +} + +void TracingState::BeforeFork() { + if (!enabled_) return; + + const uint64_t parent_to_child_flow_id = GetNewFlowId(); + + // NOTE: This is held until the end of AfterFork(). + mutex_.lock(); + + prefork_data_ = PreForkData{ + .parent_to_child_flow_id = parent_to_child_flow_id, + }; + + if (tlThreadTraceState) { + PerfettoWorkerThread::TraceEvent trace_event = { + .type = PERFETTO_TE_TYPE_INSTANT, + .timestamp = GetTimestamp(), + .str = {"(Forking)"}, + .flow = {parent_to_child_flow_id}, + }; + SendTraceEventToWorkerLocked(trace_event, /* modify_trace_stack=*/false); + + prefork_data_->forked_threads_trace_stack = tlThreadTraceState->trace_stack; + } + + ShutdownLocked(); +} + +void TracingState::AfterFork(const bool is_child) { + if (!enabled_) return; + + // NOTE: mutex_.lock() still held from BeforeFork(). + + const uint64_t timestamp = GetTimestamp(); + + if (is_child) { + // In the child process, only the thread that called fork() survives. + // Clean up trace events from all other threads. + thread_states_.clear(); + + // If the parent process had active trace events, copy them into the + // new child process. The thread local state is recreated as the + // thread id will be changed after the fork. + if (prefork_data_->forked_threads_trace_stack) { + tlThreadTraceState = CreateThreadStateLocked(); + tlThreadTraceState->trace_stack = + *prefork_data_->forked_threads_trace_stack; + } + } + + PerfettoWorkerThread::TraceEvent after_fork_event = { + .type = PERFETTO_TE_TYPE_INSTANT, + .timestamp = timestamp, + }; + if (is_child) { + after_fork_event.str = "(Child Resuming After Fork)"; + after_fork_event.flow = prefork_data_->parent_to_child_flow_id; + } else { + after_fork_event.str = "(Parent Resuming After Fork)"; + } + + for (auto& [_, thread_state] : thread_states_) { + // After the fork, emit the "Resuming After Fork" trace event + thread_state->after_fork_event = after_fork_event; + thread_state->after_fork_event->thread_id = thread_state->thread_id; + + // Update the timestamp to the post fork timestamp so that the "restarted" + // trace begin events show up as starting after the fork. + for (auto& trace_event : thread_state->trace_stack) { + trace_event.timestamp = timestamp; + } + } + + prefork_data_.reset(); + + mutex_.unlock(); +} + +void TracingState::AtExit() { + if (!enabled_) return; + + Shutdown(); +} + +TracingState::TracingState() + : enabled_(StringFromEnv("CVD_TRACE").has_value()) {} + +void TracingState::ShutdownLocked() { + // Emit trace end events for all of the active traces. If we are forking, + // the trace begin events will be re-emitted after the fork. + const uint64_t shutdown_timestamp = GetTimestamp(); + for (auto& [_, thread_state] : thread_states_) { + for (auto it = thread_state->trace_stack.rbegin(); + it != thread_state->trace_stack.rend(); ++it) { + PerfettoWorkerThread::TraceEvent trace_event = { + .type = PERFETTO_TE_TYPE_SLICE_END, + .timestamp = shutdown_timestamp, + }; + SendTraceEventToWorkerForThreadLocked(*thread_state, trace_event, + /* modify_trace_stack=*/false); + } + } + + worker_.reset(); +} + +void TracingState::EnsureWorkerInitializedLocked() { + if (worker_.has_value()) { + return; + } + worker_.emplace(); +} + +std::shared_ptr TracingState::GetOrCreateThreadStateLocked() { + if (tlThreadTraceState == nullptr) { + tlThreadTraceState = CreateThreadStateLocked(); + } + return tlThreadTraceState; +} + +std::shared_ptr TracingState::CreateThreadStateLocked() { + auto state = std::make_shared(); + state->thread_id = GetThreadId(); + state->thread_name = "Thread " + std::to_string(state->thread_id); + thread_states_[state->thread_id] = state; + return state; +} + +void TracingState::RemoveThreadState(uint64_t thread_id) { + absl::MutexLock lock(mutex_); + thread_states_.erase(thread_id); +} + +void TracingState::SendTraceEventToWorker( + PerfettoWorkerThread::TraceEvent trace_event, + const bool modify_trace_stack) { + absl::MutexLock lock(mutex_); + SendTraceEventToWorkerLocked(trace_event, modify_trace_stack); +} + +void TracingState::SendTraceEventToWorkerLocked( + PerfettoWorkerThread::TraceEvent trace_event, + const bool modify_trace_stack) { + EnsureWorkerInitializedLocked(); + + auto thread_state = GetOrCreateThreadStateLocked(); + SendTraceEventToWorkerForThreadLocked(*thread_state, trace_event, + modify_trace_stack); +} + +void TracingState::SendTraceEventToWorkerForThreadLocked( + ThreadTraceState& thread_state, + PerfettoWorkerThread::TraceEvent trace_event, + const bool modify_trace_stack) { + if (thread_state.after_fork_event) { + for (const PerfettoWorkerThread::TraceEvent& event : + thread_state.trace_stack) { + worker_->EnqueueTraceEvent(event); + } + worker_->EnqueueTraceEvent(*thread_state.after_fork_event); + + thread_state.after_fork_event.reset(); + } + + trace_event.thread_id = thread_state.thread_id; + + worker_->EnqueueTraceEvent(trace_event); + + if (modify_trace_stack) { + if (trace_event.type == PERFETTO_TE_TYPE_SLICE_BEGIN) { + thread_state.trace_stack.push_back(trace_event); + } else if (trace_event.type == PERFETTO_TE_TYPE_SLICE_END) { + thread_state.trace_stack.pop_back(); + } + } +} + +} // namespace cuttlefish diff --git a/base/cvd/cuttlefish/host/libs/tracing/tracing_state.h b/base/cvd/cuttlefish/host/libs/tracing/tracing_state.h new file mode 100644 index 00000000000..ba35dbb5078 --- /dev/null +++ b/base/cvd/cuttlefish/host/libs/tracing/tracing_state.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2026 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "absl/synchronization/mutex.h" +#include "cuttlefish/host/libs/tracing/perfetto_worker_thread.h" + +namespace cuttlefish { + +struct ThreadTraceState { + uint64_t thread_id; + std::string thread_name; + std::vector trace_stack; + std::optional after_fork_event; +}; + +class TracingState { + public: + static TracingState& Get(); + + ~TracingState() = default; + + TracingState(const TracingState&) = delete; + TracingState& operator=(const TracingState&) = delete; + + void Shutdown() ABSL_LOCKS_EXCLUDED(mutex_); + + void TraceBegin(std::string_view str) ABSL_LOCKS_EXCLUDED(mutex_); + void TraceEnd() ABSL_LOCKS_EXCLUDED(mutex_); + + // If tracing is enabled, `mutex_` is held until the end of `AfterFork()`. + void BeforeFork() ABSL_NO_THREAD_SAFETY_ANALYSIS; + + // If tracing is enabled, `mutex_` is already looked from `BeforeFork()`. + void AfterFork(const bool is_child) ABSL_NO_THREAD_SAFETY_ANALYSIS; + + void AtExit() ABSL_LOCKS_EXCLUDED(mutex_); + + private: + TracingState(); + + void ShutdownLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + void EnsureWorkerInitializedLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + std::shared_ptr GetOrCreateThreadStateLocked() + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + std::shared_ptr CreateThreadStateLocked() + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + void RemoveThreadState(uint64_t thread_id) ABSL_LOCKS_EXCLUDED(mutex_); + + void SendTraceEventToWorker(PerfettoWorkerThread::TraceEvent trace_event, + const bool modify_trace_stack = true) + ABSL_LOCKS_EXCLUDED(mutex_); + + void SendTraceEventToWorkerLocked( + PerfettoWorkerThread::TraceEvent trace_event, + const bool modify_trace_stack = true) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + void SendTraceEventToWorkerForThreadLocked( + ThreadTraceState& thread_state, + PerfettoWorkerThread::TraceEvent trace_event, + const bool modify_trace_stack = true) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + const bool enabled_ = false; + + absl::Mutex mutex_; + std::optional worker_ ABSL_GUARDED_BY(mutex_); + std::unordered_map> thread_states_ + ABSL_GUARDED_BY(mutex_); + + struct PreForkData { + uint64_t parent_to_child_flow_id = 0; + std::optional> + forked_threads_trace_stack; + }; + std::optional prefork_data_ ABSL_GUARDED_BY(mutex_); +}; + +} // namespace cuttlefish \ No newline at end of file diff --git a/base/cvd/cuttlefish/package/BUILD.bazel b/base/cvd/cuttlefish/package/BUILD.bazel index fe988b2d5fc..df35b34b6ab 100644 --- a/base/cvd/cuttlefish/package/BUILD.bazel +++ b/base/cvd/cuttlefish/package/BUILD.bazel @@ -57,6 +57,7 @@ package_files( "cuttlefish-common/bin/libgfxstream_backend.so": "@gfxstream//host:gfxstream_backend", "cuttlefish-common/bin/libvk_lavapipe.so": "@mesa//:vk_lavapipe", "cuttlefish-common/bin/libvk_swiftshader.so": "@swiftshader//:vk_swiftshader", + "cuttlefish-common/bin/libperfetto_c.so": "//cuttlefish/host/libs/tracing:perfetto_c", "cuttlefish-common/bin/log_tee": "//cuttlefish/host/commands/log_tee", "cuttlefish-common/bin/logcat_receiver": "//cuttlefish/host/commands/logcat_receiver", "cuttlefish-common/bin/lpadd": "@android_system_extras//:lpadd",