Skip to content

Commit b43c2f7

Browse files
authored
rust-sdk: Add proto extension support to Rust SDK codegen (#5444)
Adds extension code generation to the protozero Rust plugin. The plugin already collected proto extension declarations into an extensions_ map but never emitted code for them. Now it generates pb_msg_ext!() macro invocations that create extension traits with setter methods, matching the existing pb_msg_ext! runtime macro. The plugin also gains two new options for cross-crate imports: - external_crate: the crate name to use for types not found in the current proto set (e.g. "perfetto_sdk") - local_files: pipe-separated list of proto files belonging to the current crate, used to distinguish local vs external imports This enables gpu_track_event.proto to be fully auto-generated (not hand-written) in the GPU protos crate, with the correct cross-crate import for TrackEvent from perfetto_sdk. Also regenerates all Rust proto bindings, picking up: - event_wait_ids field on GpuRenderStageEvent - GpuCorrelation message and TrackEvent extension from gpu_track_event.proto - disable_extension_descriptors field on TraceConfig
1 parent 3ff13c2 commit b43c2f7

9 files changed

Lines changed: 107 additions & 6 deletions

File tree

contrib/rust-sdk/Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contrib/rust-sdk/perfetto-protos-gpu/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
edition = "2024"
33
name = "perfetto-sdk-protos-gpu"
4-
version = "0.3.3"
4+
version = "0.3.4"
55
authors = ["David Reveman <reveman@meta.com>"]
66
description = "Extra protobuf bindings for GPU events"
77
readme = "README.md"

contrib/rust-sdk/perfetto-protos-gpu/src/protos/trace/gpu/gpu_render_stage_event.pz.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pb_msg!(GpuRenderStageEvent {
6262
render_subpass_index_mask: u64, primitive, 15,
6363
command_buffer_handle: u64, primitive, 12,
6464
name: String, primitive, 17,
65+
event_wait_ids: u64, primitive, 18,
6566
specifications: GpuRenderStageEventSpecifications, msg, 7,
6667
hw_queue_id: i32, primitive, 3,
6768
stage_id: i32, primitive, 4,
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (C) 2025 Rivos Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Autogenerated by the ProtoZero Rust compiler plugin.
16+
// Invoked by contrib/rust-sdk/tools/gen_rust_protos
17+
// DO NOT EDIT.
18+
19+
use crate::pb_msg;
20+
use crate::pb_msg_ext;
21+
use perfetto_sdk::protos::trace::track_event::track_event::*;
22+
23+
pb_msg!(GpuCorrelation {
24+
render_stage_submission_event_ids: u64, primitive, 1,
25+
render_stage_wait_event_ids: u64, primitive, 2,
26+
});
27+
28+
pb_msg_ext!(TrackEvent {
29+
gpu_correlation: GpuCorrelation, msg, 3000,
30+
});

contrib/rust-sdk/perfetto-protos-gpu/src/protos/trace/gpu/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ pub mod gpu_log;
2727
#[path = "gpu_render_stage_event.pz.rs"]
2828
pub mod gpu_render_stage_event;
2929

30+
/// `gpu_track_event` protos.
31+
#[path = "gpu_track_event.pz.rs"]
32+
pub mod gpu_track_event;
33+
3034
/// `vulkan_api_event` protos.
3135
#[path = "vulkan_api_event.pz.rs"]
3236
pub mod vulkan_api_event;

contrib/rust-sdk/perfetto/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
edition = "2024"
33
name = "perfetto-sdk"
4-
version = "0.3.0"
4+
version = "0.3.1"
55
authors = ["David Reveman <reveman@meta.com>"]
66
description = "Bindings for the Perfetto tracing framework"
77
readme = "README.md"

contrib/rust-sdk/perfetto/src/protos/config/trace_config.pz.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ pb_msg!(TraceConfigBuiltinDataSource {
221221
snapshot_interval_ms: u32, primitive, 6,
222222
prefer_suspend_clock_for_snapshot: bool, primitive, 7,
223223
disable_chunk_usage_histograms: bool, primitive, 8,
224+
disable_extension_descriptors: bool, primitive, 9,
224225
});
225226

226227
pb_msg!(TraceConfigDataSource {

contrib/rust-sdk/tools/gen_rust_protos

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ SOURCE_FILES = [
8282
"protos/perfetto/trace/gpu/gpu_counter_event.proto",
8383
"protos/perfetto/trace/gpu/gpu_log.proto",
8484
"protos/perfetto/trace/gpu/gpu_render_stage_event.proto",
85+
"protos/perfetto/trace/gpu/gpu_track_event.proto",
8586
"protos/perfetto/trace/gpu/vulkan_api_event.proto",
8687
"protos/perfetto/trace/gpu/vulkan_memory_event.proto",
8788
"protos/perfetto/trace/system_info/gpu_info.proto",
@@ -92,6 +93,7 @@ SOURCE_FILES = [
9293
"protos/perfetto/trace/interned_data/interned_data.proto",
9394
"protos/perfetto/trace/trace_packet.proto",
9495
],
96+
"external_crate": "perfetto_sdk",
9597
"path_strip_prefix": "protos/perfetto",
9698
"path_add_prefix": "contrib/rust-sdk/perfetto-protos-gpu/src/protos",
9799
},
@@ -159,12 +161,18 @@ def generate(
159161
protozero_rust_plugin_path,
160162
path_strip_prefix,
161163
path_add_prefix,
164+
external_crate=None,
165+
local_files=None,
162166
):
163167
options = {
164168
"path_strip_prefix": path_strip_prefix,
165169
"path_add_prefix": path_add_prefix,
166170
"invoker": SCRIPT_PATH,
167171
}
172+
if external_crate:
173+
options["external_crate"] = external_crate
174+
if local_files:
175+
options["local_files"] = "|".join(local_files)
168176
serialized_options = ",".join(
169177
["{}={}".format(name, value) for name, value in options.items()])
170178
subprocess.check_call(
@@ -245,6 +253,7 @@ def main():
245253
try:
246254
with tempfile.TemporaryDirectory() as tmpdirname:
247255
for sources in SOURCE_FILES:
256+
all_files = sources["files"] + sources["custom_files"]
248257
for source in sources["files"]:
249258
generate(
250259
source,
@@ -253,6 +262,8 @@ def main():
253262
protozero_rust_plugin_path(out),
254263
path_strip_prefix=sources["path_strip_prefix"],
255264
path_add_prefix=sources["path_add_prefix"],
265+
external_crate=sources.get("external_crate"),
266+
local_files=all_files,
256267
)
257268

258269
tmpfilename = os.path.join(tmpdirname, transform_extension(source))

src/protozero/protoc_plugin/protozero_rust_plugin.cc

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ class GeneratorJob {
107107
GenerateEnumDescriptor(enumeration);
108108
for (const Descriptor* message : messages_)
109109
GenerateMessageDescriptor(message);
110+
for (const auto& key_value : extensions_)
111+
GenerateExtensionDescriptor(key_value.first, key_value.second);
110112
return error_.empty();
111113
}
112114

@@ -119,6 +121,12 @@ class GeneratorJob {
119121
path_add_prefix_ = value;
120122
} else if (name == "invoker") {
121123
invoker_ = value;
124+
} else if (name == "external_crate") {
125+
external_crate_ = value;
126+
} else if (name == "local_files") {
127+
for (const auto& f : SplitString(value, "|")) {
128+
local_files_.insert(std::string(f));
129+
}
122130
} else {
123131
Abort(std::string() + "Unknown plugin option '" + name + "'.");
124132
}
@@ -299,6 +307,27 @@ class GeneratorJob {
299307
}
300308
}
301309
}
310+
311+
// Collect dependencies for extension fields (base message and field types).
312+
for (const auto& key_value : extensions_) {
313+
for (const FieldDescriptor* field : key_value.second) {
314+
// The extended message type (e.g. TrackEvent).
315+
const Descriptor* extendee = field->containing_type();
316+
if (public_imports_.count(extendee->file()) == 0) {
317+
referenced_messages_.insert(extendee);
318+
}
319+
// Message/enum types used in extension fields.
320+
if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
321+
if (public_imports_.count(field->message_type()->file()) == 0) {
322+
referenced_messages_.insert(field->message_type());
323+
}
324+
} else if (field->type() == FieldDescriptor::TYPE_ENUM) {
325+
if (public_imports_.count(field->enum_type()->file()) == 0) {
326+
referenced_enums_.insert(field->enum_type());
327+
}
328+
}
329+
}
330+
}
302331
}
303332

304333
void Preprocess() {
@@ -350,6 +379,9 @@ class GeneratorJob {
350379
if (!messages_.empty()) {
351380
stub_rs_->Print("use crate::pb_msg;\n");
352381
}
382+
if (!extensions_.empty()) {
383+
stub_rs_->Print("use crate::pb_msg_ext;\n");
384+
}
353385

354386
// Print use statements for public imports, enums and messages.
355387
std::vector<std::string> imports;
@@ -378,8 +410,13 @@ class GeneratorJob {
378410
if (!path_strip_prefix_.empty()) {
379411
mod_path = StripPrefix(imp, path_strip_prefix_);
380412
}
381-
stub_rs_->Print("use crate::protos$mod$::*;\n", "mod",
382-
ReplaceAll(mod_path, "/", "::"));
413+
// When external_crate is set and this import is not a local file,
414+
// use the external crate path instead of crate::.
415+
bool is_external =
416+
!external_crate_.empty() && local_files_.count(imp + ".proto") == 0;
417+
std::string crate_prefix = is_external ? external_crate_ : "crate";
418+
stub_rs_->Print("use $crate$::protos$mod$::*;\n", "crate", crate_prefix,
419+
"mod", ReplaceAll(mod_path, "/", "::"));
383420
}
384421
}
385422

@@ -473,6 +510,21 @@ class GeneratorJob {
473510
}
474511
}
475512

513+
void GenerateExtensionDescriptor(
514+
const std::string& /*extension_name*/,
515+
const std::vector<const FieldDescriptor*>& fields) {
516+
// The extended message name (e.g. "TrackEvent").
517+
std::string base_name =
518+
GetFullRustMessageName(fields[0]->containing_type());
519+
520+
stub_rs_->Print("\npb_msg_ext!($base$ {\n", "base", base_name);
521+
for (const FieldDescriptor* field : fields) {
522+
stub_rs_->Print(" $field$\n", "field",
523+
GetFieldDescriptorContent(field));
524+
}
525+
stub_rs_->Print("});\n");
526+
}
527+
476528
const FileDescriptor* const source_;
477529
Printer* const stub_rs_;
478530
std::string error_;
@@ -481,6 +533,8 @@ class GeneratorJob {
481533
std::string wrapper_namespace_;
482534
std::string path_strip_prefix_;
483535
std::string path_add_prefix_;
536+
std::string external_crate_;
537+
std::set<std::string> local_files_;
484538
std::string invoker_;
485539
std::vector<std::string> namespaces_;
486540
std::string full_namespace_prefix_;

0 commit comments

Comments
 (0)