Skip to content
Merged
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
37 changes: 29 additions & 8 deletions Cargo.lock

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

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ object = "0.36.7"
linux-perf-data = "0.11.0"
debugid = "0.8.0"
memmap2 = "0.9.5"
nix = { version = "0.29.0", features = ["fs", "user"] }
nix = { version = "0.29.0", features = ["fs", "time", "user"] }
futures = "0.3.31"
runner-shared = { path = "crates/runner-shared" }

[target.'cfg(target_os = "linux")'.dependencies]
procfs = "0.17.0"
Expand All @@ -67,6 +68,9 @@ rstest = { version = "0.25.0", default-features = false }
rstest_reuse = "0.7.0"
shell-quote = "0.7.2"

[workspace]
members = ["crates/runner-shared"]

[workspace.metadata.release]
sign-tag = true
sign-commit = true
Expand Down
9 changes: 9 additions & 0 deletions crates/runner-shared/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "runner-shared"
version = "0.1.0"
edition = "2024"

[dependencies]
anyhow = "1.0.100"
serde = { version = "1.0.225", features = ["derive"] }
serde_json = "1.0.145"
33 changes: 33 additions & 0 deletions crates/runner-shared/src/fifo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//! WARNING: Has to be in sync with `instrument-hooks`.

pub const RUNNER_CTL_FIFO: &str = "/tmp/runner.ctl.fifo";
pub const RUNNER_ACK_FIFO: &str = "/tmp/runner.ack.fifo";

pub const CURRENT_PROTOCOL_VERSION: u64 = 1;

/// The different markers that can be set in the perf.data.
///
/// `SampleStart/End`: Marks the start and end of a sampling period. This is used to differentiate between benchmarks.
/// `BenchmarkStart/End`: Marks the start and end of a benchmark. This is used to measure the duration of a benchmark, without the benchmark harness code.
#[derive(
serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone,
)]
pub enum MarkerType {
SampleStart(u64),
SampleEnd(u64),
BenchmarkStart(u64),
BenchmarkEnd(u64),
}

#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
pub enum Command {
CurrentBenchmark { pid: i32, uri: String },
StartBenchmark,
StopBenchmark,
Ack,
PingPerf,
SetIntegration { name: String, version: String },
Err,
AddMarker { pid: i32, marker: MarkerType },
SetVersion(u64),
}
3 changes: 3 additions & 0 deletions crates/runner-shared/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod fifo;
pub mod metadata;
pub mod unwind_data;
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
// !!!!!!!!!!!!!!!!!!!!!!!!
// !! DO NOT TOUCH BELOW !!
// !!!!!!!!!!!!!!!!!!!!!!!!
// Has to be in sync with `perf-parser`.
//

use std::{collections::HashMap, path::Path};

use anyhow::Context;
use serde::{Deserialize, Serialize};
use std::path::Path;

use crate::fifo::MarkerType;

#[derive(Serialize, Deserialize)]
pub struct PerfMetadata {
/// The version of this metadata format.
pub version: u64,

/// Name and version of the integration
pub integration: (String, String),

/// The URIs of the benchmarks in the order they were executed.
pub bench_order_by_pid: HashMap<u32, Vec<String>>,
/// The URIs of the benchmarks with the timestamps they were executed at.
pub uri_by_ts: Vec<(u64, String)>,

/// Modules that should be ignored and removed from the folded trace and callgraph (e.g. python interpreter)
pub ignored_modules: Vec<(String, u64, u64)>,

/// Marker for certain regions in the profiling data
pub markers: Vec<MarkerType>,
}

impl PerfMetadata {
pub fn from_reader<R: std::io::Read>(reader: R) -> anyhow::Result<Self> {
serde_json::from_reader(reader).context("Could not parse perf metadata from JSON")
}

pub fn save_to<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
let file = std::fs::File::create(path.as_ref().join("perf.metadata"))?;
serde_json::to_writer(file, self)?;
Expand Down
49 changes: 49 additions & 0 deletions crates/runner-shared/src/unwind_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use core::{
fmt::Debug,
hash::{Hash, Hasher},
};
use serde::{Deserialize, Serialize};
use std::{hash::DefaultHasher, ops::Range};

/// Unwind data for a single module.
#[derive(Serialize, Deserialize)]
pub struct UnwindData {
pub path: String,

pub avma_range: Range<u64>,
pub base_avma: u64,

pub eh_frame_hdr: Vec<u8>,
pub eh_frame_hdr_svma: Range<u64>,

pub eh_frame: Vec<u8>,
pub eh_frame_svma: Range<u64>,
}

impl Debug for UnwindData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let eh_frame_hdr_hash = {
let mut hasher = DefaultHasher::new();
self.eh_frame_hdr.hash(&mut hasher);
hasher.finish()
};
let eh_frame_hash = {
let mut hasher = DefaultHasher::new();
self.eh_frame.hash(&mut hasher);
hasher.finish()
};

f.debug_struct("UnwindData")
.field("path", &self.path)
.field("avma_range", &format_args!("{:x?}", self.avma_range))
.field("base_avma", &format_args!("{:x}", self.base_avma))
.field(
"eh_frame_hdr_svma",
&format_args!("{:x?}", self.eh_frame_hdr_svma),
)
.field("eh_frame_hdr_hash", &format_args!("{eh_frame_hdr_hash:x}"))
.field("eh_frame_hash", &format_args!("{eh_frame_hash:x}"))
.field("eh_frame_svma", &format_args!("{:x?}", self.eh_frame_svma))
.finish()
}
}
6 changes: 3 additions & 3 deletions src/api_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ impl CodSpeedAPIClient {
.await;
match response {
Ok(response) => Ok(response.create_login_session),
Err(err) => bail!("Failed to create login session: {}", err),
Err(err) => bail!("Failed to create login session: {err}"),
}
}

Expand All @@ -189,7 +189,7 @@ impl CodSpeedAPIClient {
.await;
match response {
Ok(response) => Ok(response.consume_login_session),
Err(err) => bail!("Failed to use login session: {}", err),
Err(err) => bail!("Failed to use login session: {err}"),
}
}

Expand All @@ -212,7 +212,7 @@ impl CodSpeedAPIClient {
Err(err) if err.contains_error_code("UNAUTHENTICATED") => {
bail!("Your session has expired, please login again using `codspeed auth login`")
}
Err(err) => bail!("Failed to fetch local run report: {}", err),
Err(err) => bail!("Failed to fetch local run report: {err}"),
}
}
}
2 changes: 1 addition & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl CodSpeedConfig {
debug!("Config file not found at {}", config_path.display());
CodSpeedConfig::default()
}
Err(e) => bail!("Failed to load config: {}", e),
Err(e) => bail!("Failed to load config: {e}"),
};

if let Some(oauth_token) = oauth_token_override {
Expand Down
2 changes: 1 addition & 1 deletion src/run/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl TryFrom<RunArgs> for Config {
let instruments = Instruments::try_from(&args)?;
let raw_upload_url = args.upload_url.unwrap_or_else(|| DEFAULT_UPLOAD_URL.into());
let upload_url = Url::parse(&raw_upload_url)
.map_err(|e| anyhow!("Invalid upload URL: {}, {}", raw_upload_url, e))?;
.map_err(|e| anyhow!("Invalid upload URL: {raw_upload_url}, {e}"))?;

Ok(Self {
upload_url,
Expand Down
13 changes: 4 additions & 9 deletions src/run/helpers/download_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub async fn download_file(url: &Url, path: &Path) -> Result<()> {
.get(url.clone())
.send()
.await
.map_err(|e| anyhow!("Failed to download file: {}", e))?;
.map_err(|e| anyhow!("Failed to download file: {e}"))?;
if !response.status().is_success() {
bail!("Failed to download file: {}", response.status());
}
Expand All @@ -18,13 +18,8 @@ pub async fn download_file(url: &Url, path: &Path) -> Result<()> {
let content = response
.bytes()
.await
.map_err(|e| anyhow!("Failed to read response: {}", e))?;
std::io::copy(&mut content.as_ref(), &mut file).map_err(|e| {
anyhow!(
"Failed to write to file: {}, {}",
path.display(),
e.to_string()
)
})?;
.map_err(|e| anyhow!("Failed to read response: {e}"))?;
std::io::copy(&mut content.as_ref(), &mut file)
.map_err(|e| anyhow!("Failed to write to file: {}, {}", path.display(), e))?;
Ok(())
}
2 changes: 1 addition & 1 deletion src/run/helpers/get_env_var.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use anyhow::anyhow;
use std::env;

pub fn get_env_variable(name: &str) -> Result<String> {
env::var(name).map_err(|_| anyhow!("{} environment variable not found", name))
env::var(name).map_err(|_| anyhow!("{name} environment variable not found"))
}

#[cfg(test)]
Expand Down
5 changes: 1 addition & 4 deletions src/run/helpers/parse_git_remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ pub struct GitRemote {

pub fn parse_git_remote(remote: &str) -> Result<GitRemote> {
let captures = REMOTE_REGEX.captures(remote).ok_or_else(|| {
anyhow!(
"Could not extract owner and repository from remote url: {}",
remote
)
anyhow!("Could not extract owner and repository from remote url: {remote}")
})?;

let domain = captures.name("domain").unwrap().as_str();
Expand Down
2 changes: 1 addition & 1 deletion src/run/instruments/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl TryFrom<&RunArgs> for Instruments {
for instrument_name in &args.instruments {
match instrument_name.as_str() {
"mongodb" => validated_instrument_names.insert(InstrumentName::MongoDB),
_ => bail!("Invalid instrument name: {}", instrument_name),
_ => bail!("Invalid instrument name: {instrument_name}"),
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/run/run_environment/gitlab_ci/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ impl TryFrom<&Config> for GitLabCIProvider {
None,
),

_ => bail!("Event {} is not supported by CodSpeed", ci_pipeline_source),
_ => bail!("Event {ci_pipeline_source} is not supported by CodSpeed"),
};

let run_id = get_env_variable("CI_JOB_ID")?;
Expand Down
5 changes: 1 addition & 4 deletions src/run/run_environment/local/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,7 @@ fn extract_provider_owner_and_repository_from_remote_url(
let repository_provider = match domain.as_str() {
"github.com" => RepositoryProvider::GitHub,
"gitlab.com" => RepositoryProvider::GitLab,
domain => bail!(
"Repository provider {} is not supported by CodSpeed",
domain
),
domain => bail!("Repository provider {domain} is not supported by CodSpeed"),
};

Ok((
Expand Down
5 changes: 4 additions & 1 deletion src/run/runner/valgrind/helpers/perf_maps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ pub async fn harvest_perf_maps(profile_folder: &Path) -> Result<()> {
harvest_perf_maps_for_pids(profile_folder, &pids).await
}

pub async fn harvest_perf_maps_for_pids(profile_folder: &Path, pids: &HashSet<i32>) -> Result<()> {
pub async fn harvest_perf_maps_for_pids(
profile_folder: &Path,
pids: &HashSet<libc::pid_t>,
) -> Result<()> {
let perf_maps = pids
.iter()
.map(|pid| format!("perf-{pid}.map"))
Expand Down
Loading