Skip to content

Commit f4c670f

Browse files
committed
feat: add unwind data v2 format with base_svma
1 parent 02cfa8b commit f4c670f

10 files changed

+79
-51
lines changed

Cargo.lock

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

crates/runner-shared/Cargo.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ version = "0.1.0"
44
edition = "2024"
55

66
[dependencies]
7-
anyhow = "1.0.100"
8-
serde = { version = "1.0.225", features = ["derive"] }
9-
serde_json = "1.0.145"
7+
anyhow = "1.0"
8+
serde = { version = "1.0", features = ["derive"] }
9+
serde_json = "1.0"
10+
bincode = "1.3"
11+
log = "0.4"

crates/runner-shared/src/unwind_data.rs

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,43 @@ use core::{
55
use serde::{Deserialize, Serialize};
66
use std::{hash::DefaultHasher, ops::Range};
77

8-
/// Unwind data for a single module.
9-
#[derive(Serialize, Deserialize)]
10-
pub struct UnwindData {
11-
pub path: String,
8+
pub const UNWIND_FILE_EXT: &str = "unwind_data";
129

13-
pub avma_range: Range<u64>,
14-
pub base_avma: u64,
10+
pub type UnwindData = UnwindDataV1;
1511

16-
pub eh_frame_hdr: Vec<u8>,
17-
pub eh_frame_hdr_svma: Range<u64>,
12+
impl UnwindData {
13+
pub fn parse(reader: &[u8]) -> anyhow::Result<Self> {
14+
let compat: UnwindDataCompat = bincode::deserialize(reader)?;
1815

19-
pub eh_frame: Vec<u8>,
20-
pub eh_frame_svma: Range<u64>,
16+
match compat {
17+
UnwindDataCompat::V1(v1) => Ok(v1),
18+
}
19+
}
20+
21+
pub fn save_to<P: AsRef<std::path::Path>>(&self, folder: P, pid: i32) -> anyhow::Result<()> {
22+
let unwind_data_path = folder.as_ref().join(format!(
23+
"{}_{:x}_{:x}.{UNWIND_FILE_EXT}",
24+
pid, self.avma_range.start, self.avma_range.end
25+
));
26+
self.to_file(unwind_data_path)?;
27+
28+
Ok(())
29+
}
30+
31+
pub fn to_file<P: AsRef<std::path::Path>>(&self, path: P) -> anyhow::Result<()> {
32+
if let Ok(true) = std::fs::exists(path.as_ref()) {
33+
log::warn!(
34+
"{} already exists, file will be truncated",
35+
path.as_ref().display()
36+
);
37+
log::warn!("{} {:x?}", self.path, self.avma_range);
38+
}
39+
40+
let mut writer = std::fs::File::create(path.as_ref())?;
41+
let compat = UnwindDataCompat::V1(self.clone());
42+
bincode::serialize_into(&mut writer, &compat)?;
43+
Ok(())
44+
}
2145
}
2246

2347
impl Debug for UnwindData {
@@ -37,6 +61,7 @@ impl Debug for UnwindData {
3761
.field("path", &self.path)
3862
.field("avma_range", &format_args!("{:x?}", self.avma_range))
3963
.field("base_avma", &format_args!("{:x}", self.base_avma))
64+
.field("base_svma", &format_args!("{:x}", self.base_svma))
4065
.field(
4166
"eh_frame_hdr_svma",
4267
&format_args!("{:x?}", self.eh_frame_hdr_svma),
@@ -47,3 +72,25 @@ impl Debug for UnwindData {
4772
.finish()
4873
}
4974
}
75+
76+
/// A versioned enum for `UnwindData` to allow for future extensions while maintaining backward compatibility.
77+
#[derive(Serialize, Deserialize)]
78+
enum UnwindDataCompat {
79+
V1(UnwindDataV1),
80+
}
81+
82+
#[doc(hidden)]
83+
#[derive(Serialize, Deserialize, Clone)]
84+
pub struct UnwindDataV1 {
85+
pub path: String,
86+
87+
pub avma_range: Range<u64>,
88+
pub base_avma: u64,
89+
pub base_svma: u64,
90+
91+
pub eh_frame_hdr: Vec<u8>,
92+
pub eh_frame_hdr_svma: Range<u64>,
93+
94+
pub eh_frame: Vec<u8>,
95+
pub eh_frame_svma: Range<u64>,
96+
}

src/run/runner/wall_time/perf/jit_dump.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
use crate::{
22
prelude::*,
3-
run::runner::wall_time::perf::{
4-
perf_map::{ModuleSymbols, Symbol},
5-
unwind_data::UnwindDataExt,
6-
},
3+
run::runner::wall_time::perf::perf_map::{ModuleSymbols, Symbol},
74
};
85
use linux_perf_data::jitdump::{JitDumpReader, JitDumpRecord};
96
use runner_shared::unwind_data::UnwindData;
@@ -83,6 +80,7 @@ impl JitDump {
8380
eh_frame_hdr_svma: 0..0,
8481
eh_frame,
8582
eh_frame_svma: 0..0,
83+
base_svma: 0,
8684
});
8785
}
8886
JitDumpRecord::CodeUnwindingInfo(record) => {

src/run/runner/wall_time/perf/snapshots/codspeed__run__runner__wall_time__perf__unwind_data__tests__cpp_unwind_data.snap

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
---
22
source: src/run/runner/wall_time/perf/unwind_data.rs
3-
expression: "UnwindData::new(MODULE_PATH.as_bytes(), 0x0, start_addr, size, None)"
3+
expression: "UnwindData::new(MODULE_PATH.as_bytes(), file_offset, start_addr, end_addr,\nNone,)"
44
---
55
Ok(
66
UnwindData {
77
path: "testdata/perf_map/cpp_my_benchmark.bin",
88
avma_range: 400000..459000,
99
base_avma: 400000,
10+
base_svma: 400000,
1011
eh_frame_hdr_svma: 4577bc..458b30,
1112
eh_frame_hdr_hash: 4b4eac90f7f5e60d,
1213
eh_frame_hash: 233bdd4ae9fe4ba4,

src/run/runner/wall_time/perf/snapshots/codspeed__run__runner__wall_time__perf__unwind_data__tests__golang_unwind_data.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Ok(
77
path: "testdata/perf_map/go_fib.bin",
88
avma_range: 402000..50f000,
99
base_avma: 400000,
10+
base_svma: 400000,
1011
eh_frame_hdr_svma: 6498b0..649b94,
1112
eh_frame_hdr_hash: f1f69beb959a08d7,
1213
eh_frame_hash: a8727039dd21b51c,

src/run/runner/wall_time/perf/snapshots/codspeed__run__runner__wall_time__perf__unwind_data__tests__ruff_unwind_data.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Ok(
77
path: "testdata/perf_map/ty_walltime",
88
avma_range: 555555e6d000..555556813000,
99
base_avma: 555555554000,
10+
base_svma: 0,
1011
eh_frame_hdr_svma: 7ec298..80f67c,
1112
eh_frame_hdr_hash: 6d6dd1e2c782318a,
1213
eh_frame_hash: ee27244db791265a,

src/run/runner/wall_time/perf/snapshots/codspeed__run__runner__wall_time__perf__unwind_data__tests__rust_divan_unwind_data.snap

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
---
22
source: src/run/runner/wall_time/perf/unwind_data.rs
3-
expression: "UnwindData::new(MODULE_PATH.as_bytes(), 0x4d000, start_addr, end_addr, None)"
3+
expression: "UnwindData::new(MODULE_PATH.as_bytes(), file_offset, start_addr, end_addr,\nNone)"
44
---
55
Ok(
66
UnwindData {
77
path: "testdata/perf_map/divan_sleep_benches.bin",
88
avma_range: 5555555a2000..555555692000,
99
base_avma: 555555554000,
10+
base_svma: 0,
1011
eh_frame_hdr_svma: 2ac74..2ea60,
1112
eh_frame_hdr_hash: f579da4368e627c1,
1213
eh_frame_hash: 791501d5a9c438d,

src/run/runner/wall_time/perf/snapshots/codspeed__run__runner__wall_time__perf__unwind_data__tests__the_algorithms_unwind_data.snap

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
---
22
source: src/run/runner/wall_time/perf/unwind_data.rs
3-
expression: "UnwindData::new(MODULE_PATH.as_bytes(), file_offset, start_addr, end_addr,\nNone)"
3+
expression: "UnwindData::new(MODULE_PATH.as_bytes(), 0x52efc, 0x00005555555a7000, 0x00005555556b0000,\nNone)"
44
---
55
Ok(
66
UnwindData {
77
path: "testdata/perf_map/the_algorithms.bin",
88
avma_range: 5555555a7000..5555556b0000,
99
base_avma: 555555554000,
10+
base_svma: 0,
1011
eh_frame_hdr_svma: 2f0ec..33590,
1112
eh_frame_hdr_hash: 277fbdb59e6decaa,
1213
eh_frame_hash: 21d8b0c8da0d1029,

src/run/runner/wall_time/perf/unwind_data.rs

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
use crate::run::runner::wall_time::perf::elf_helper;
44
use anyhow::{Context, bail};
55
use debugid::CodeId;
6-
use libc::pid_t;
76
use object::Object;
87
use object::ObjectSection;
98
use runner_shared::unwind_data::UnwindData;
@@ -19,9 +18,6 @@ pub trait UnwindDataExt {
1918
) -> anyhow::Result<Self>
2019
where
2120
Self: Sized;
22-
23-
fn save_to<P: AsRef<std::path::Path>>(&self, folder: P, pid: pid_t) -> anyhow::Result<()>;
24-
fn to_file<P: AsRef<std::path::Path>>(&self, path: P) -> anyhow::Result<()>;
2521
}
2622

2723
impl UnwindDataExt for UnwindData {
@@ -68,6 +64,7 @@ impl UnwindDataExt for UnwindData {
6864
runtime_file_offset,
6965
&file,
7066
)?;
67+
let base_svma = elf_helper::relative_address_base(&file);
7168
let eh_frame = file.section_by_name(".eh_frame");
7269
let eh_frame_hdr = file.section_by_name(".eh_frame_hdr");
7370

@@ -82,10 +79,11 @@ impl UnwindDataExt for UnwindData {
8279
section.address()..section.address() + section.size()
8380
}
8481

85-
Ok(Self {
82+
Ok(UnwindData {
8683
path,
8784
avma_range,
8885
base_avma,
86+
base_svma,
8987
eh_frame_hdr: eh_frame_hdr_data.context("Failed to find eh_frame hdr data")?,
9088
eh_frame_hdr_svma: eh_frame_hdr
9189
.as_ref()
@@ -98,30 +96,6 @@ impl UnwindDataExt for UnwindData {
9896
.context("Failed to find eh_frame section")?,
9997
})
10098
}
101-
102-
fn save_to<P: AsRef<std::path::Path>>(&self, folder: P, pid: pid_t) -> anyhow::Result<()> {
103-
let unwind_data_path = folder.as_ref().join(format!(
104-
"{}_{:x}_{:x}.unwind",
105-
pid, self.avma_range.start, self.avma_range.end
106-
));
107-
self.to_file(unwind_data_path)?;
108-
109-
Ok(())
110-
}
111-
112-
fn to_file<P: AsRef<std::path::Path>>(&self, path: P) -> anyhow::Result<()> {
113-
if let Ok(true) = std::fs::exists(path.as_ref()) {
114-
log::warn!(
115-
"{} already exists, file will be truncated",
116-
path.as_ref().display()
117-
);
118-
log::warn!("{} {:x?}", self.path, self.avma_range);
119-
}
120-
121-
let mut writer = std::fs::File::create(path.as_ref())?;
122-
bincode::serialize_into(&mut writer, self)?;
123-
Ok(())
124-
}
12599
}
126100

127101
#[cfg(test)]

0 commit comments

Comments
 (0)