diff --git a/crates/codspeed/build.rs b/crates/codspeed/build.rs index bb3a42ea..77f06f09 100644 --- a/crates/codspeed/build.rs +++ b/crates/codspeed/build.rs @@ -7,6 +7,7 @@ fn main() { collect_rustc_info(); collect_cargo_info(); + collect_build_profile_info(); let mut build = cc::Build::new(); build @@ -48,6 +49,41 @@ fn main() { } } +/// Collect build profile and performance-relevant compiler options at build time. +/// These env var names must be kept in sync with `src/instrument_hooks/mod.rs`. +/// +/// Reference: +fn collect_build_profile_info() { + // PROFILE is set by Cargo to the name of the profile being built (e.g. "release", "bench", "debug"). + if let Ok(profile) = std::env::var("PROFILE") { + println!("cargo:rustc-env=CODSPEED_BUILD_PROFILE={profile}"); + } + + // OPT_LEVEL is set by Cargo to the optimization level (0, 1, 2, 3, s, z). + if let Ok(opt_level) = std::env::var("OPT_LEVEL") { + println!("cargo:rustc-env=CODSPEED_BUILD_OPT_LEVEL={opt_level}"); + } + + // Extract performance-relevant codegen flags from rustflags. + // + // Cargo uses two mutually exclusive sources for rustflags (see + // ): + // - RUSTFLAGS env var (space-separated, takes priority) + // - CARGO_ENCODED_RUSTFLAGS env var (0x1f-separated, used when RUSTFLAGS is not set) + // We check both in priority order to accurately represent the flags used to build. + let rustflags: Vec = if let Ok(raw) = std::env::var("RUSTFLAGS") { + raw.split_whitespace().map(String::from).collect() + } else if let Ok(encoded) = std::env::var("CARGO_ENCODED_RUSTFLAGS") { + encoded.split('\x1f').map(String::from).collect() + } else { + Vec::new() + }; + + if let Some(target_cpu) = extract_codegen_flag(&rustflags, "target-cpu") { + println!("cargo:rustc-env=CODSPEED_BUILD_TARGET_CPU={target_cpu}"); + } +} + /// Collect rustc toolchain info at build time and expose as env vars. /// These env var names must be kept in sync with `src/instrument_hooks/mod.rs`. fn collect_rustc_info() { @@ -98,3 +134,35 @@ fn collect_cargo_info() { println!("cargo:rustc-env=CODSPEED_CARGO_VERSION={rest}"); } } + +/// Extract a codegen option value from a list of rustc flags. +/// +/// Handles all three forms that rustc accepts: +/// - `-Ckey=value` (no space) +/// - `-C` `key=value` (space between -C and the option, split into two entries) +/// - `-C` `key` `value` (space between key and value, split into three entries) — only for flags that accept it +/// +/// Returns the value for the first match of `key`. +fn extract_codegen_flag(flags: &[String], key: &str) -> Option { + let mut iter = flags.iter(); + while let Some(flag) = iter.next() { + // Form: -Ckey=value + if let Some(rest) = flag.strip_prefix("-C") { + if let Some(value) = rest.strip_prefix(key).and_then(|s| s.strip_prefix('=')) { + return Some(value.to_string()); + } + // rest is not our key, skip + continue; + } + + // Form: -C key=value or -C key value + if flag == "-C" { + if let Some(next) = iter.next() { + if let Some(value) = next.strip_prefix(key).and_then(|s| s.strip_prefix('=')) { + return Some(value.to_string()); + } + } + } + } + None +} diff --git a/crates/codspeed/instrument-hooks b/crates/codspeed/instrument-hooks index e86719c7..0c971823 160000 --- a/crates/codspeed/instrument-hooks +++ b/crates/codspeed/instrument-hooks @@ -1 +1 @@ -Subproject commit e86719c70c9c0b1646db182a7c748230e243dace +Subproject commit 0c971823b17cb5a3bbd0cce4411cbee2c6fe4317 diff --git a/crates/codspeed/src/instrument_hooks/bindings.rs b/crates/codspeed/src/instrument_hooks/bindings.rs index 692b8501..428a2e69 100644 --- a/crates/codspeed/src/instrument_hooks/bindings.rs +++ b/crates/codspeed/src/instrument_hooks/bindings.rs @@ -66,6 +66,15 @@ extern "C" { value: *const ::std::os::raw::c_char, ) -> u8; } +extern "C" { + pub fn instrument_hooks_set_environment_list( + arg1: *mut InstrumentHooks, + section_name: *const ::std::os::raw::c_char, + key: *const ::std::os::raw::c_char, + values: *const *const ::std::os::raw::c_char, + count: u32, + ) -> u8; +} extern "C" { pub fn instrument_hooks_write_environment(arg1: *mut InstrumentHooks, pid: u32) -> u8; } diff --git a/crates/codspeed/src/instrument_hooks/mod.rs b/crates/codspeed/src/instrument_hooks/mod.rs index a6e44260..cebe9b3d 100644 --- a/crates/codspeed/src/instrument_hooks/mod.rs +++ b/crates/codspeed/src/instrument_hooks/mod.rs @@ -59,6 +59,15 @@ mod linux_impl { if let Some(v) = option_env!("CODSPEED_CARGO_VERSION") { let _ = self.set_environment(SECTION, "cargo", v); } + if let Some(v) = option_env!("CODSPEED_BUILD_PROFILE") { + let _ = self.set_environment(SECTION, "profile", v); + } + if let Some(v) = option_env!("CODSPEED_BUILD_OPT_LEVEL") { + let _ = self.set_environment(SECTION, "opt-level", v); + } + if let Some(v) = option_env!("CODSPEED_BUILD_TARGET_CPU") { + let _ = self.set_environment(SECTION, "target-cpu", v); + } if let Err(e) = self.write_environment() { eprintln!("Warning: failed to write environment info: {e}"); diff --git a/crates/codspeed/src/instrument_hooks/update-bindings.sh b/crates/codspeed/src/instrument_hooks/update-bindings.sh index 0b7beed4..0dd97f93 100755 --- a/crates/codspeed/src/instrument_hooks/update-bindings.sh +++ b/crates/codspeed/src/instrument_hooks/update-bindings.sh @@ -1,8 +1,10 @@ #!/usr/bin/env bash set -euo pipefail -bindgen ../../instrument-hooks/includes/core.h \ - -o bindings.rs \ +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +bindgen "$SCRIPT_DIR/../../instrument-hooks/includes/core.h" \ + -o "$SCRIPT_DIR/bindings.rs" \ --rust-target 1.74 \ --allowlist-function "instrument_hooks_.*" \ --allowlist-var "MARKER_TYPE_.*"