From ada2c5063d5c98ae6234d218052cbfc7b22e2b22 Mon Sep 17 00:00:00 2001 From: Yilin Chen Date: Tue, 25 Oct 2022 14:14:08 +0800 Subject: [PATCH] update prost 0.11 (#166) Signed-off-by: Yilin Chen Signed-off-by: Yilin Chen --- .github/workflows/rust.yml | 9 ++ Cargo.toml | 9 +- build.rs | 44 ++++++- proto/perftools.profiles.rs | 236 ++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 +- 5 files changed, 297 insertions(+), 6 deletions(-) create mode 100644 proto/perftools.profiles.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d0c370b6..c050d5b2 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -22,6 +22,9 @@ jobs: toolchain: stable override: true components: rustfmt, clippy + + - name: Install protobuf compiler + run: sudo apt-get install -y protobuf-compiler - name: Run cargo fmt uses: actions-rs/cargo@v1.0.3 @@ -29,12 +32,18 @@ jobs: command: fmt args: --all -- --check + - name: Remove pre-generated prost files to force regeneration + run: rm proto/*.rs + - name: Run cargo clippy prost uses: actions-rs/cargo@v1.0.3 with: command: clippy args: --all-targets --features flamegraph,prost-codec -- -D warnings + - name: Check if the prost file committed to git is up-to-date + run: git diff --no-ext-diff --exit-code + - name: Run cargo clippy protobuf uses: actions-rs/cargo@v1.0.3 with: diff --git a/Cargo.toml b/Cargo.toml index 6a172105..fae4141b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ frame-pointer = [] # A private feature to indicate either prost-codec or protobuf-codec is enabled. _protobuf = [] -prost-codec = ["prost", "prost-derive", "prost-build", "_protobuf"] +prost-codec = ["prost", "prost-derive", "prost-build", "sha2", "_protobuf"] protobuf-codec = ["protobuf", "protobuf-codegen-pure", "_protobuf"] [dependencies] @@ -34,8 +34,8 @@ cfg-if = "1.0" smallvec = "1.7" inferno = { version = "0.11", default-features = false, features = ["nameattr"], optional = true } -prost = { version = "0.10", optional = true } -prost-derive = { version = "0.10", optional = true } +prost = { version = "0.11", optional = true } +prost-derive = { version = "0.11", optional = true } protobuf = { version = "2.0", optional = true } criterion = {version = "0.4", optional = true} @@ -49,7 +49,8 @@ criterion = "0.4" rand = "0.8.0" [build-dependencies] -prost-build = { version = "0.10", optional = true } +prost-build = { version = "0.11", optional = true } +sha2 = { version = "0.10", optional = true } protobuf-codegen-pure = { version = "2.0", optional = true } [[example]] diff --git a/build.rs b/build.rs index 6db69bb8..829274f4 100644 --- a/build.rs +++ b/build.rs @@ -22,9 +22,51 @@ fn generate_protobuf() { write!(f, "pub mod profile;").unwrap(); } +#[cfg(feature = "prost-codec")] +fn generate_prost() { + use sha2::{Digest, Sha256}; + use std::{ + fmt::Write, + fs::{self, File}, + io::{self, BufRead, BufReader}, + }; + + const PRE_GENERATED_PATH: &str = "proto/perftools.profiles.rs"; + + // Calculate the SHA256 of the proto file + let mut hasher = Sha256::new(); + let mut proto_file = BufReader::new(File::open("proto/profile.proto").unwrap()); + io::copy(&mut proto_file, &mut hasher).unwrap(); + let mut hex = String::new(); + for b in hasher.finalize() { + write!(&mut hex, "{:x}", b).unwrap(); + } + let hash_comment = format!("// {} proto/profile.proto", hex); + + let first_line = File::open(PRE_GENERATED_PATH) + .and_then(|f| { + let mut reader = BufReader::new(f); + let mut first_line = String::new(); + reader.read_line(&mut first_line)?; + Ok(first_line) + }) + .unwrap_or_default(); + // If the hash of the proto file changes, regenerate the prost file. + if first_line.trim() != hash_comment { + prost_build::Config::new() + .out_dir("proto/") + .compile_protos(&["proto/profile.proto"], &["proto/"]) + .unwrap(); + // Prepend the hash comment to the generated file. + let generated = fs::read_to_string(PRE_GENERATED_PATH).unwrap(); + let with_hex = format!("{}\n\n{}", hash_comment, generated); + fs::write(PRE_GENERATED_PATH, with_hex).unwrap(); + } +} + fn main() { #[cfg(feature = "prost-codec")] - prost_build::compile_protos(&["proto/profile.proto"], &["proto/"]).unwrap(); + generate_prost(); #[cfg(feature = "protobuf-codec")] generate_protobuf(); } diff --git a/proto/perftools.profiles.rs b/proto/perftools.profiles.rs new file mode 100644 index 00000000..c46c6ebc --- /dev/null +++ b/proto/perftools.profiles.rs @@ -0,0 +1,236 @@ +// f9f855b960d01b292a3c2642e263e6156d52631e78e0177fe51416ed5bbecc81 proto/profile.proto + +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Profile { + /// A description of the samples associated with each Sample.value. + /// For a cpu profile this might be: + /// \[["cpu","nanoseconds"]\] or \[["wall","seconds"]\] or \[["syscall","count"]\] + /// For a heap profile, this might be: + /// \[["allocations","count"\], \["space","bytes"]\], + /// If one of the values represents the number of events represented + /// by the sample, by convention it should be at index 0 and use + /// sample_type.unit == "count". + #[prost(message, repeated, tag="1")] + pub sample_type: ::prost::alloc::vec::Vec, + /// The set of samples recorded in this profile. + #[prost(message, repeated, tag="2")] + pub sample: ::prost::alloc::vec::Vec, + /// Mapping from address ranges to the image/binary/library mapped + /// into that address range. mapping\[0\] will be the main binary. + #[prost(message, repeated, tag="3")] + pub mapping: ::prost::alloc::vec::Vec, + /// Useful program location + #[prost(message, repeated, tag="4")] + pub location: ::prost::alloc::vec::Vec, + /// Functions referenced by locations + #[prost(message, repeated, tag="5")] + pub function: ::prost::alloc::vec::Vec, + /// A common table for strings referenced by various messages. + /// string_table\[0\] must always be "". + #[prost(string, repeated, tag="6")] + pub string_table: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + /// frames with Function.function_name fully matching the following + /// regexp will be dropped from the samples, along with their successors. + /// + /// Index into string table. + #[prost(int64, tag="7")] + pub drop_frames: i64, + /// frames with Function.function_name fully matching the following + /// regexp will be kept, even if it matches drop_functions. + /// + /// Index into string table. + #[prost(int64, tag="8")] + pub keep_frames: i64, + // The following fields are informational, do not affect + // interpretation of results. + + /// Time of collection (UTC) represented as nanoseconds past the epoch. + #[prost(int64, tag="9")] + pub time_nanos: i64, + /// Duration of the profile, if a duration makes sense. + #[prost(int64, tag="10")] + pub duration_nanos: i64, + /// The kind of events between sampled ocurrences. + /// e.g [ "cpu","cycles" ] or [ "heap","bytes" ] + #[prost(message, optional, tag="11")] + pub period_type: ::core::option::Option, + /// The number of events between sampled occurrences. + #[prost(int64, tag="12")] + pub period: i64, + /// Freeform text associated to the profile. + /// + /// Indices into string table. + #[prost(int64, repeated, tag="13")] + pub comment: ::prost::alloc::vec::Vec, + /// Index into the string table of the type of the preferred sample + /// value. If unset, clients should default to the last sample value. + #[prost(int64, tag="14")] + pub default_sample_type: i64, +} +/// ValueType describes the semantics and measurement units of a value. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ValueType { + /// Rename it from type to ty to avoid using keyword in Rust. + /// + /// Index into string table. + #[prost(int64, tag="1")] + pub ty: i64, + /// Index into string table. + #[prost(int64, tag="2")] + pub unit: i64, +} +/// Each Sample records values encountered in some program +/// context. The program context is typically a stack trace, perhaps +/// augmented with auxiliary information like the thread-id, some +/// indicator of a higher level request being handled etc. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Sample { + /// The ids recorded here correspond to a Profile.location.id. + /// The leaf is at location_id\[0\]. + #[prost(uint64, repeated, tag="1")] + pub location_id: ::prost::alloc::vec::Vec, + /// The type and unit of each value is defined by the corresponding + /// entry in Profile.sample_type. All samples must have the same + /// number of values, the same as the length of Profile.sample_type. + /// When aggregating multiple samples into a single sample, the + /// result has a list of values that is the elemntwise sum of the + /// lists of the originals. + #[prost(int64, repeated, tag="2")] + pub value: ::prost::alloc::vec::Vec, + /// label includes additional context for this sample. It can include + /// things like a thread id, allocation size, etc + #[prost(message, repeated, tag="3")] + pub label: ::prost::alloc::vec::Vec