Skip to content

Commit d5f15d1

Browse files
committed
Add perfetto tracing to host tooling
Example cvd create trace: https://ui.perfetto.dev/#!/?s=b1b38a42593f61ee34c230f344e62f8c883ec747 Example cvd fetch trace: https://ui.perfetto.dev/#!/?s=cd5028170d015f9dd026228c7fd7dd81027b680e Perfetto uses a shared memory buffer between producer processes and the traced consumer daemon. `fork()` is problematic for this as the parent and child processes would end up clobbering each other when the shared memory buffer is inherited by the child. To prevent this, we introduce a "perfetto forwarder" (see TracingSession) that runs in the top level `cvd` process and that forwards trace events from child processes. Bug: b/378560215
1 parent ecba083 commit d5f15d1

51 files changed

Lines changed: 1760 additions & 21 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

base/cvd/MODULE.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ bazel_dep(name = "nasm", version = "2.16.03.bcr.1")
3737
bazel_dep(name = "pcre2", version = "10.45")
3838
bazel_dep(name = "platforms", version = "1.0.0")
3939
bazel_dep(name = "protobuf", version = "31.1")
40+
bazel_dep(name = "re2")
4041
bazel_dep(name = "rootcanal")
4142
bazel_dep(name = "rules_cc", version = "0.2.16")
4243
bazel_dep(name = "rules_flex", version = "0.4")

base/cvd/build_external/build_external.MODULE.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ include("//build_external/mkbootimg:mkbootimg.MODULE.bazel")
4848
include("//build_external/ms-tpm-20-ref:ms-tpm-20-ref.MODULE.bazel")
4949
include("//build_external/mtools:mtools.MODULE.bazel")
5050
include("//build_external/opengl_headers:opengl_headers.MODULE.bazel")
51+
include("//build_external/perfetto:perfetto.MODULE.bazel")
5152
include("//build_external/pyyaml:pyyaml.MODULE.bazel")
5253
include("//build_external/re2:re2.MODULE.bazel")
5354
include("//build_external/rootcanal:rootcanal.MODULE.bazel")

base/cvd/build_external/perfetto/BUILD

Whitespace-only changes.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
From 45c2b6299505b133fdce117649f457e36640d824 Mon Sep 17 00:00:00 2001
2+
From: Jason Macnak <natsu@google.com>
3+
Date: Fri, 15 May 2026 11:28:54 -0700
4+
Subject: [PATCH 1/4] Disable Android components to avoid extra dependencies
5+
6+
---
7+
bazel/rules.bzl | 8 +++-----
8+
1 file changed, 3 insertions(+), 5 deletions(-)
9+
10+
diff --git a/bazel/rules.bzl b/bazel/rules.bzl
11+
index 6195465a67..a3e367cde8 100644
12+
--- a/bazel/rules.bzl
13+
+++ b/bazel/rules.bzl
14+
@@ -13,9 +13,7 @@
15+
# limitations under the License.
16+
17+
load("@perfetto//bazel:proto_gen.bzl", "proto_descriptor_gen", "proto_gen")
18+
-load("@perfetto//bazel:run_ait_with_adb.bzl", "android_instrumentation_test")
19+
load("@perfetto_cfg//:perfetto_cfg.bzl", "PERFETTO_CONFIG")
20+
-load("@rules_android//android:rules.bzl", "android_binary", "android_library")
21+
22+
# +----------------------------------------------------------------------------+
23+
# | Base C++ rules. |
24+
@@ -113,11 +111,11 @@ def perfetto_jspb_proto_library(**kwargs):
25+
# +----------------------------------------------------------------------------+
26+
def perfetto_android_binary(**kwargs):
27+
if not _rule_override("android_binary", **kwargs):
28+
- android_binary(**kwargs)
29+
+ return
30+
31+
def perfetto_android_library(**kwargs):
32+
if not _rule_override("android_library", **kwargs):
33+
- android_library(**kwargs)
34+
+ return
35+
36+
def perfetto_android_jni_library(**kwargs):
37+
if not _rule_override("android_jni_library", **kwargs):
38+
@@ -171,7 +169,7 @@ def _perfetto_android_jni_library(
39+
40+
def perfetto_android_instrumentation_test(**kwargs):
41+
if not _rule_override("android_instrumentation_test", **kwargs):
42+
- android_instrumentation_test(**kwargs)
43+
+ return
44+
45+
# +----------------------------------------------------------------------------+
46+
# | Misc rules. |
47+
--
48+
2.54.0.563.g4f69b47b94-goog
49+
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
From 5e991031fa757ade8a7be54e5bfab69ec627a432 Mon Sep 17 00:00:00 2001
2+
From: Jason Macnak <natsu@google.com>
3+
Date: Fri, 15 May 2026 11:29:26 -0700
4+
Subject: [PATCH 2/4] Add load statements for Bazel 9
5+
6+
---
7+
bazel/proto_gen.bzl | 2 ++
8+
bazel/rules.bzl | 30 ++++++++++++++++++------------
9+
2 files changed, 20 insertions(+), 12 deletions(-)
10+
11+
diff --git a/bazel/proto_gen.bzl b/bazel/proto_gen.bzl
12+
index 74f91cad89..1764cb2d9a 100644
13+
--- a/bazel/proto_gen.bzl
14+
+++ b/bazel/proto_gen.bzl
15+
@@ -15,6 +15,8 @@
16+
# This file defines the proto_gen() rule that is used for generating protos
17+
# with custom plugins (ipc and protozero).
18+
19+
+load("@protobuf//bazel/common:proto_info.bzl", "ProtoInfo")
20+
+
21+
def _proto_gen_impl(ctx):
22+
proto_src = [
23+
f
24+
diff --git a/bazel/rules.bzl b/bazel/rules.bzl
25+
index a3e367cde8..15f6d52d5b 100644
26+
--- a/bazel/rules.bzl
27+
+++ b/bazel/rules.bzl
28+
@@ -14,6 +14,12 @@
29+
30+
load("@perfetto//bazel:proto_gen.bzl", "proto_descriptor_gen", "proto_gen")
31+
load("@perfetto_cfg//:perfetto_cfg.bzl", "PERFETTO_CONFIG")
32+
+load("@protobuf//bazel:cc_proto_library.bzl", "cc_proto_library")
33+
+load("@protobuf//bazel:proto_library.bzl", "proto_library")
34+
+load("@protobuf//bazel:java_lite_proto_library.bzl", "java_lite_proto_library")
35+
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
36+
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
37+
+load("@rules_python//python:defs.bzl", "py_binary", "py_library")
38+
39+
# +----------------------------------------------------------------------------+
40+
# | Base C++ rules. |
41+
@@ -38,7 +44,7 @@ def default_cc_args():
42+
43+
def perfetto_build_config_cc_library(**kwargs):
44+
if not _rule_override("cc_library", **kwargs):
45+
- native.cc_library(**kwargs)
46+
+ cc_library(**kwargs)
47+
48+
def perfetto_filegroup(**kwargs):
49+
if not _rule_override("filegroup", **kwargs):
50+
@@ -51,20 +57,20 @@ def perfetto_genrule(**kwargs):
51+
def perfetto_cc_library(**kwargs):
52+
args = _merge_dicts(default_cc_args(), kwargs)
53+
if not _rule_override("cc_library", **args):
54+
- native.cc_library(**args)
55+
+ cc_library(**args)
56+
57+
def perfetto_cc_binary(**kwargs):
58+
args = _merge_dicts(default_cc_args(), kwargs)
59+
if not _rule_override("cc_binary", **args):
60+
- native.cc_binary(**args)
61+
+ cc_binary(**args)
62+
63+
def perfetto_py_binary(**kwargs):
64+
if not _rule_override("py_binary", **kwargs):
65+
- native.py_binary(**kwargs)
66+
+ py_binary(**kwargs)
67+
68+
def perfetto_py_library(**kwargs):
69+
if not _rule_override("py_library", **kwargs):
70+
- native.py_library(**kwargs)
71+
+ py_library(**kwargs)
72+
73+
# +----------------------------------------------------------------------------+
74+
# | Proto-related rules |
75+
@@ -72,11 +78,11 @@ def perfetto_py_library(**kwargs):
76+
77+
def perfetto_proto_library(**kwargs):
78+
if not _rule_override("proto_library", **kwargs):
79+
- native.proto_library(**kwargs)
80+
+ proto_library(**kwargs)
81+
82+
def perfetto_cc_proto_library(**kwargs):
83+
if not _rule_override("cc_proto_library", **kwargs):
84+
- native.cc_proto_library(**kwargs)
85+
+ cc_proto_library(**kwargs)
86+
87+
def perfetto_java_proto_library(**kwargs):
88+
if not _rule_override("java_proto_library", **kwargs):
89+
@@ -84,7 +90,7 @@ def perfetto_java_proto_library(**kwargs):
90+
91+
def perfetto_java_lite_proto_library(**kwargs):
92+
if not _rule_override("java_lite_proto_library", **kwargs):
93+
- native.java_lite_proto_library(**kwargs)
94+
+ java_lite_proto_library(**kwargs)
95+
96+
# Unlike the other rules, this is an noop by default because Bazel does not
97+
# support Go proto libraries.
98+
@@ -142,7 +148,7 @@ def _perfetto_android_jni_library(
99+
if not (binary_name.startswith("lib") and binary_name.endswith(".so")):
100+
fail("'binary_name' should sharts with 'lib' and ends with '.so'" +
101+
", got %s instead" % binary_name)
102+
- # We strip the name, since `native.cc_binary` adds prefix and suffix
103+
+ # We strip the name, since `cc_binary` adds prefix and suffix
104+
# to the generated library name.
105+
binary_target_name = binary_name.removeprefix("lib").removesuffix(".so")
106+
input_cc_library_name = name + "_input"
107+
@@ -150,18 +156,18 @@ def _perfetto_android_jni_library(
108+
# exclude them from being build when invoke `bazel build :all`,
109+
# since these targets won't be able to compile anyway, see
110+
# https://bazel.build/docs/android-ndk#cclibrary-android.
111+
- native.cc_library(
112+
+ cc_library(
113+
name = input_cc_library_name,
114+
target_compatible_with = ["@platforms//os:android"],
115+
**input_cc_library_kwargs
116+
)
117+
- native.cc_binary(
118+
+ cc_binary(
119+
name = binary_target_name,
120+
linkshared = True,
121+
deps = [input_cc_library_name],
122+
target_compatible_with = ["@platforms//os:android"],
123+
)
124+
- native.cc_library(
125+
+ cc_library(
126+
name = name,
127+
srcs = [binary_target_name],
128+
target_compatible_with = ["@platforms//os:android"],
129+
--
130+
2.54.0.563.g4f69b47b94-goog
131+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
perfetto_ext = use_extension("//build_external/perfetto:repositories.bzl", "perfetto_extension")
2+
use_repo(perfetto_ext, "perfetto")
3+
use_repo(perfetto_ext, "perfetto_cfg")
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
2+
3+
# https://github.com/google/perfetto/issues/2787 for Perfetto getting into the
4+
# Central Repository.
5+
def _perfetto_extension_impl(_):
6+
# From commit 877553985565ab10fe20ea844891aacabd0f70c7:
7+
URL = "https://github.com/google/perfetto/archive/refs/tags/v55.2.tar.gz"
8+
http_archive(
9+
name = "perfetto",
10+
url = URL,
11+
strip_prefix = "perfetto-55.2",
12+
patch_args = ["-p1"],
13+
patches = [
14+
"@//build_external/perfetto:PATCH.0001_disable_android_deps.patch",
15+
"@//build_external/perfetto:PATCH.0002_add_load_statements.patch",
16+
],
17+
)
18+
http_archive(
19+
name = "perfetto_cfg",
20+
url = URL,
21+
strip_prefix = "perfetto-55.2/bazel/standalone",
22+
build_file_content = "# empty BUILD to make a bazel package",
23+
patch_cmds = [
24+
"sed -i 's|@com_google_protobuf|@protobuf|g' perfetto_cfg.bzl",
25+
],
26+
)
27+
28+
perfetto_extension = module_extension(
29+
implementation = _perfetto_extension_impl,
30+
)

base/cvd/cuttlefish/host/commands/assemble_cvd/BUILD.bazel

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ cf_cc_binary(
7272
"//cuttlefish/host/libs/config/fastboot",
7373
"//cuttlefish/host/libs/feature:inject",
7474
"//cuttlefish/host/libs/log_names",
75+
"//cuttlefish/host/libs/tracing",
7576
"//cuttlefish/posix:symlink",
7677
"//cuttlefish/pretty:vector",
7778
"//libbase",
@@ -169,6 +170,7 @@ cf_cc_library(
169170
"//cuttlefish/common/libs/utils:subprocess",
170171
"//cuttlefish/common/libs/utils:subprocess_managed_stdio",
171172
"//cuttlefish/host/libs/config:config_utils",
173+
"//cuttlefish/host/libs/tracing",
172174
"//cuttlefish/posix:strerror",
173175
"//cuttlefish/result",
174176
"//libbase",
@@ -223,6 +225,7 @@ cf_cc_library(
223225
"//cuttlefish/host/libs/config:file_source",
224226
"//cuttlefish/host/libs/config:instance_nums",
225227
"//cuttlefish/host/libs/feature:inject",
228+
"//cuttlefish/host/libs/tracing",
226229
"//cuttlefish/result",
227230
"//libbase",
228231
"@abseil-cpp//absl/log",
@@ -240,6 +243,7 @@ cf_cc_library(
240243
"//cuttlefish/host/libs/config:vmm_mode",
241244
"//cuttlefish/host/libs/image_aggregator",
242245
"//cuttlefish/host/libs/image_aggregator:qcow2",
246+
"//cuttlefish/host/libs/tracing",
243247
"//cuttlefish/result",
244248
"//libbase",
245249
"@abseil-cpp//absl/log",
@@ -357,6 +361,7 @@ cf_cc_library(
357361
"//cuttlefish/host/libs/config:secure_hals",
358362
"//cuttlefish/host/libs/config:vmm_mode",
359363
"//cuttlefish/host/libs/config/defaults",
364+
"//cuttlefish/host/libs/tracing",
360365
"//cuttlefish/host/libs/vhal_proxy_server",
361366
"//cuttlefish/host/libs/vm_manager",
362367
"//cuttlefish/result",
@@ -405,6 +410,7 @@ cf_cc_library(
405410
"//cuttlefish/host/libs/config:config_utils",
406411
"//cuttlefish/host/libs/config:display",
407412
"//cuttlefish/host/libs/config:gpu_mode",
413+
"//cuttlefish/host/libs/tracing",
408414
"//cuttlefish/pretty",
409415
"//cuttlefish/pretty:optional",
410416
"//cuttlefish/pretty:string",
@@ -436,6 +442,7 @@ cf_cc_library(
436442
"//cuttlefish/host/libs/config:guest_hwui_renderer",
437443
"//cuttlefish/host/libs/config:guest_renderer_preload",
438444
"//cuttlefish/host/libs/config:vmm_mode",
445+
"//cuttlefish/host/libs/tracing",
439446
"//cuttlefish/result",
440447
"//libbase",
441448
"@abseil-cpp//absl/log",

base/cvd/cuttlefish/host/commands/assemble_cvd/assemble_cvd.cc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,9 @@
6868
#include "cuttlefish/host/libs/config/fastboot/fastboot.h"
6969
#include "cuttlefish/host/libs/config/fetcher_configs.h"
7070
#include "cuttlefish/host/libs/config/log_string_to_dir.h"
71-
#include "cuttlefish/host/libs/log_names/log_names.h"
7271
#include "cuttlefish/host/libs/feature/inject.h"
72+
#include "cuttlefish/host/libs/log_names/log_names.h"
73+
#include "cuttlefish/host/libs/tracing/tracing.h"
7374
#include "cuttlefish/posix/symlink.h"
7475
#include "cuttlefish/pretty/vector.h"
7576

@@ -406,6 +407,8 @@ Result<const CuttlefishConfig*> InitFilesystemAndCreateConfig(
406407
CF_EXPECT(CleanPriorFiles(preserving, clean_dirs),
407408
"Failed to clean prior files");
408409

410+
CF_TRACE("SetupDirectories");
411+
409412
std::string default_group = "cvdnetwork";
410413
const mode_t default_mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
411414

@@ -574,6 +577,8 @@ Result<int> AssembleCvdMain(int argc, char** argv) {
574577

575578
CF_EXPECT(CheckNoTTY());
576579

580+
CF_TRACE("AssembleCvd");
581+
577582
// Read everything that cvd_internal_start writes, but ignore it since
578583
// fetcher_config.json will be searched for in the system image directory.
579584
(void) CF_EXPECT(ReadInputFiles());
@@ -637,10 +642,12 @@ Result<int> AssembleCvdMain(int argc, char** argv) {
637642
"Failed to parse flags.");
638643

639644
if (help || !help_str.empty()) {
645+
CF_TRACE("Help");
640646
LOG(WARNING) << "TODO(schuffelen): Implement `--help` for assemble_cvd.";
641647
LOG(WARNING) << "In the meantime, call `launch_cvd --help`";
642648
return 1;
643649
} else if (helpxml) {
650+
CF_TRACE("Help");
644651
if (!FlagFeature::WriteGflagsHelpXml(flag_features, std::cout)) {
645652
LOG(ERROR) << "Failure in writing gflags helpxml output";
646653
}

base/cvd/cuttlefish/host/commands/assemble_cvd/clean.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "cuttlefish/common/libs/utils/subprocess.h"
3434
#include "cuttlefish/common/libs/utils/subprocess_managed_stdio.h"
3535
#include "cuttlefish/host/libs/config/config_utils.h"
36+
#include "cuttlefish/host/libs/tracing/tracing.h"
3637
#include "cuttlefish/posix/strerror.h"
3738
#include "cuttlefish/result/result.h"
3839

@@ -177,6 +178,8 @@ Result<void> CleanPriorFiles(const std::vector<std::string>& paths,
177178

178179
Result<void> CleanPriorFiles(const std::set<std::string>& preserving,
179180
const std::vector<std::string>& clean_dirs) {
181+
CF_TRACE("CleanPriorFiles");
182+
180183
std::vector<std::string> paths = {
181184
// The global link to the config file
182185
GetGlobalConfigFileLink(),

0 commit comments

Comments
 (0)