Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: true
- uses: moonrepo/setup-rust@v1
with:
components: rustfmt, clippy
Expand All @@ -23,6 +25,7 @@ jobs:
- uses: actions/checkout@v3
with:
lfs: true
submodules: true

- name: "Install rust-toolchain.toml"
run: rustup toolchain install
Expand All @@ -45,6 +48,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: true
- uses: moonrepo/setup-rust@v1
- name: Run tests
run: cargo test -p exec-harness
Expand All @@ -55,6 +60,7 @@ jobs:
- uses: actions/checkout@v3
with:
lfs: true
submodules: true
- uses: moonrepo/setup-rust@v1
- name: Install dependencies required for libbpf-sys (vendored feature)
run: sudo apt-get update && sudo apt-get install -y autopoint bison flex
Expand All @@ -76,6 +82,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: true

- name: "Install rust-toolchain.toml"
run: rustup toolchain install
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "crates/instrument-hooks-bindings/instrument-hooks"]
path = crates/instrument-hooks-bindings/instrument-hooks
url = https://github.com/CodSpeedHQ/instrument-hooks.git
15 changes: 11 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,12 @@ rstest_reuse = "0.7.0"
shell-quote = "0.7.2"

[workspace]
members = ["crates/runner-shared", "crates/memtrack", "crates/exec-harness"]
members = [
"crates/runner-shared",
"crates/memtrack",
"crates/exec-harness",
"crates/instrument-hooks-bindings",
]

[workspace.dependencies]
anyhow = "1.0"
Expand Down
3 changes: 1 addition & 2 deletions crates/exec-harness/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ name = "exec-harness"
path = "src/main.rs"

[dependencies]
instrument-hooks-bindings = { path = "../instrument-hooks-bindings" }
anyhow = { workspace = true }
codspeed = "4.2.0"
log = { workspace = true }
env_logger = { workspace = true }
clap = { workspace = true }
Expand All @@ -23,7 +23,6 @@ tempfile = { workspace = true }
object = { workspace = true }

[build-dependencies]
cargo_metadata = "0.19"
cc = "1"

[package.metadata.dist]
Expand Down
58 changes: 11 additions & 47 deletions crates/exec-harness/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,9 @@
//! This script compiles the `libcodspeed_preload.so` shared library that is used
//! to inject instrumentation into child processes via LD_PRELOAD.
//!
//! The library is built using the `core.c` and headers from the `codspeed` crate's
//! `instrument-hooks` directory.
//!
//! # Environment Variables
//!
//! - `CODSPEED_INSTRUMENT_HOOKS_DIR`: Optional override for the instrument-hooks
//! source directory. If not set, the build script will locate it from the
//! `codspeed` crate in the cargo registry.
//! The library is built using the `core.c` and headers from the `instrument-hooks-bindings`
//! crate's `instrument-hooks` directory.

use cargo_metadata::MetadataCommand;
use std::env;
use std::path::PathBuf;

Expand All @@ -25,7 +18,6 @@ struct PreloadConstants {
/// Integration name reported to CodSpeed.
integration_name: &'static str,
/// Integration version reported to CodSpeed.
/// This should match the version of the `codspeed` crate dependency.
integration_version: &'static str,
/// Filename for the preload shared library.
preload_lib_filename: &'static str,
Expand Down Expand Up @@ -58,11 +50,11 @@ fn main() {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());

// Try to get the instrument-hooks directory from the environment variable first,
// otherwise locate it from the codspeed crate
let instrument_hooks_dir = match env::var("CODSPEED_INSTRUMENT_HOOKS_DIR") {
Ok(dir) => PathBuf::from(dir),
Err(_) => find_codspeed_instrument_hooks_dir(),
};
// otherwise use the one from the instrument-hooks-bindings crate
let instrument_hooks_dir = manifest_dir
.parent()
.unwrap()
.join("instrument-hooks-bindings/instrument-hooks");

// Build the preload shared library
let paths = PreloadBuildPaths {
Expand Down Expand Up @@ -130,40 +122,12 @@ fn build_shared_library(paths: &PreloadBuildPaths, constants: &PreloadConstants)
}
}

/// Find the instrument-hooks directory from the codspeed crate using cargo_metadata
fn find_codspeed_instrument_hooks_dir() -> PathBuf {
let metadata = MetadataCommand::new()
.exec()
.expect("Failed to run cargo metadata");

// Find the codspeed package in the resolved dependencies
let codspeed_pkg = metadata
.packages
.iter()
.find(|p| p.name == "codspeed")
.expect("codspeed crate not found in dependencies");

let codspeed_dir = codspeed_pkg
.manifest_path
.parent()
.expect("Failed to get codspeed crate directory");

let instrument_hooks_dir = codspeed_dir.join("instrument-hooks");

if !instrument_hooks_dir.exists() {
panic!("instrument-hooks directory not found at {instrument_hooks_dir}");
}

instrument_hooks_dir.into_std_path_buf()
}

impl Default for PreloadConstants {
// TODO(COD-1736): Stop impersonating codspeed-rust 🥸
fn default() -> Self {
Self {
uri_env: "CODSPEED_BENCH_URI",
integration_name: "codspeed-rust",
integration_version: "4.2.0",
integration_name: "exec-harness",
integration_version: env!("CARGO_PKG_VERSION"),
preload_lib_filename: "libcodspeed_preload.so",
}
}
Expand All @@ -185,13 +149,13 @@ impl PreloadBuildPaths {
fn check_sources_exist(&self) {
if !self.core_c.exists() {
panic!(
"core.c not found at {}. Make sure the codspeed crate is available.",
"core.c not found at {}. Make sure the instrument-hooks-bindings crate is available.",
self.core_c.display()
);
}
if !self.includes_dir.exists() {
panic!(
"includes directory not found at {}. Make sure the codspeed crate is available.",
"includes directory not found at {}. Make sure the instrument-hooks-bindings crate is available.",
self.includes_dir.display()
);
}
Expand Down
6 changes: 4 additions & 2 deletions crates/exec-harness/src/analysis/mod.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
use crate::constants::INTEGRATION_NAME;
use crate::constants::INTEGRATION_VERSION;
use crate::prelude::*;

use crate::BenchmarkCommand;
use crate::constants;
use crate::uri;
use codspeed::instrument_hooks::InstrumentHooks;
use instrument_hooks_bindings::InstrumentHooks;
use std::process::Command;

mod ld_preload_check;
mod preload_lib_file;

pub fn perform(commands: Vec<BenchmarkCommand>) -> Result<()> {
let hooks = InstrumentHooks::instance();
let hooks = InstrumentHooks::instance(INTEGRATION_NAME, INTEGRATION_VERSION);

for benchmark_cmd in commands {
let name_and_uri = uri::generate_name_and_uri(&benchmark_cmd.name, &benchmark_cmd.command);
Expand Down
5 changes: 3 additions & 2 deletions crates/exec-harness/src/walltime/benchmark_loop.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use super::ExecutionOptions;
use super::config::RoundOrTime;
use crate::constants::{INTEGRATION_NAME, INTEGRATION_VERSION};
use crate::prelude::*;
use codspeed::instrument_hooks::InstrumentHooks;
use instrument_hooks_bindings::InstrumentHooks;
use std::process::Command;
use std::time::Duration;

Expand All @@ -11,7 +12,7 @@ pub fn run_rounds(
config: &ExecutionOptions,
) -> Result<Vec<u128>> {
let warmup_time_ns = config.warmup_time_ns;
let hooks = InstrumentHooks::instance();
let hooks = InstrumentHooks::instance(INTEGRATION_NAME, INTEGRATION_VERSION);

let do_one_round = || -> Result<(u64, u64)> {
let mut child = Command::new(&command[0])
Expand Down
14 changes: 12 additions & 2 deletions crates/exec-harness/src/walltime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ mod config;

pub use config::ExecutionOptions;
pub use config::WalltimeExecutionArgs;
use runner_shared::walltime_results::Creator;
use runner_shared::walltime_results::WalltimeBenchmark;
pub use runner_shared::walltime_results::WalltimeResults;

use crate::BenchmarkCommand;
use crate::constants::INTEGRATION_NAME;
use crate::constants::INTEGRATION_VERSION;
use crate::prelude::*;
use crate::uri::NameAndUri;
use crate::uri::generate_name_and_uri;
Expand Down Expand Up @@ -42,8 +45,15 @@ pub fn perform(commands: Vec<BenchmarkCommand>) -> Result<()> {
walltime_benchmarks.push(walltime_benchmark);
}

let walltime_results = WalltimeResults::from_benchmarks(walltime_benchmarks)
.expect("Failed to create walltime results");
let walltime_results = WalltimeResults::new(
Creator {
name: INTEGRATION_NAME.to_string(),
version: INTEGRATION_VERSION.to_string(),
pid: std::process::id(),
},
walltime_benchmarks,
)
.expect("Failed to create walltime results");

walltime_results
.save_to_file(
Expand Down
10 changes: 10 additions & 0 deletions crates/instrument-hooks-bindings/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "instrument-hooks-bindings"
version = "0.1.0"
edition = "2024"

[dependencies]
nix = { version = "0.30.1", features = ["time"] }

[build-dependencies]
cc = "1.0"
50 changes: 50 additions & 0 deletions crates/instrument-hooks-bindings/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
fn main() {
println!("cargo:rustc-check-cfg=cfg(use_instrument_hooks)");

println!("cargo:rerun-if-changed=instrument-hooks/dist/core.c");
println!("cargo:rerun-if-changed=instrument-hooks/includes/core.h");
println!("cargo:rerun-if-changed=build.rs");

let mut build = cc::Build::new();
build
.flag("-std=c11")
.file("instrument-hooks/dist/core.c")
.include("instrument-hooks/includes")
// We generated the C code from Zig, which contains some warnings
// that can be safely ignored.
.flag("-Wno-format")
.flag("-Wno-format-security")
.flag("-Wno-unused-but-set-variable")
.flag("-Wno-unused-const-variable")
.flag("-Wno-type-limits")
.flag("-Wno-uninitialized")
// Ignore warnings when cross-compiling:
.flag("-Wno-overflow")
.flag("-Wno-unused-function")
.flag("-Wno-constant-conversion")
.flag("-Wno-incompatible-pointer-types")
// Disable warnings, as we will have lots of them
.warnings(false)
.extra_warnings(false)
.cargo_warnings(false)
.opt_level(3);

let result = build.try_compile("instrument_hooks");
match result {
Ok(_) => println!("cargo:rustc-cfg=use_instrument_hooks"),
Err(e) => {
let compiler = build.try_get_compiler().expect("Failed to get C compiler");

eprintln!("\n\nWARNING: Failed to compile instrument-hooks native library with cc-rs.");
eprintln!(
"The library will still compile, but instrument-hooks functionality will be disabled."
);
eprintln!("Compiler information: {compiler:?}");
eprintln!("Compilation error: {e}\n");

println!(
"cargo:warning=Failed to compile instrument-hooks native library with cc-rs. Continuing with noop implementation."
);
}
}
}
1 change: 1 addition & 0 deletions crates/instrument-hooks-bindings/instrument-hooks
Submodule instrument-hooks added at 89fb72
Loading
Loading