Skip to content

Commit 04eaff7

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

10 files changed

Lines changed: 150 additions & 60 deletions

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: 124 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,153 @@ use core::{
55
use serde::{Deserialize, Serialize};
66
use std::{hash::DefaultHasher, ops::Range};
77

8-
/// Unwind data for a single module.
8+
/// A versioned enum for `UnwindData` to allow for future extensions while maintaining backward compatibility.
99
#[derive(Serialize, Deserialize)]
10-
pub struct UnwindData {
11-
pub path: String,
10+
pub enum UnwindData {
11+
V1(UnwindDataV1),
12+
V2(UnwindDataV2),
13+
}
1214

13-
pub avma_range: Range<u64>,
14-
pub base_avma: u64,
15+
impl UnwindData {
16+
pub fn path(&self) -> &str {
17+
match self {
18+
UnwindData::V1(data) => &data.path,
19+
UnwindData::V2(data) => &data.path,
20+
}
21+
}
1522

16-
pub eh_frame_hdr: Vec<u8>,
17-
pub eh_frame_hdr_svma: Range<u64>,
23+
pub fn avma_range(&self) -> &Range<u64> {
24+
match self {
25+
UnwindData::V1(data) => &data.avma_range,
26+
UnwindData::V2(data) => &data.avma_range,
27+
}
28+
}
1829

19-
pub eh_frame: Vec<u8>,
20-
pub eh_frame_svma: Range<u64>,
30+
pub fn base_avma(&self) -> u64 {
31+
match self {
32+
UnwindData::V1(data) => data.base_avma,
33+
UnwindData::V2(data) => data.base_avma,
34+
}
35+
}
36+
37+
pub fn base_svma(&self) -> u64 {
38+
match self {
39+
UnwindData::V1(_) => 0,
40+
UnwindData::V2(data) => data.base_svma,
41+
}
42+
}
43+
44+
pub fn eh_frame_hdr(&self) -> &Vec<u8> {
45+
match self {
46+
UnwindData::V1(data) => &data.eh_frame_hdr,
47+
UnwindData::V2(data) => &data.eh_frame_hdr,
48+
}
49+
}
50+
51+
pub fn eh_frame_hdr_svma(&self) -> &Range<u64> {
52+
match self {
53+
UnwindData::V1(data) => &data.eh_frame_hdr_svma,
54+
UnwindData::V2(data) => &data.eh_frame_hdr_svma,
55+
}
56+
}
57+
58+
pub fn eh_frame(&self) -> &Vec<u8> {
59+
match self {
60+
UnwindData::V1(data) => &data.eh_frame,
61+
UnwindData::V2(data) => &data.eh_frame,
62+
}
63+
}
64+
65+
pub fn eh_frame_svma(&self) -> &Range<u64> {
66+
match self {
67+
UnwindData::V1(data) => &data.eh_frame_svma,
68+
UnwindData::V2(data) => &data.eh_frame_svma,
69+
}
70+
}
71+
72+
pub fn save_to<P: AsRef<std::path::Path>>(&self, folder: P, pid: i32) -> anyhow::Result<()> {
73+
let unwind_data_path = folder.as_ref().join(format!(
74+
"{}_{:x}_{:x}.unwind2",
75+
pid,
76+
self.avma_range().start,
77+
self.avma_range().end
78+
));
79+
self.to_file(unwind_data_path)?;
80+
81+
Ok(())
82+
}
83+
84+
pub fn to_file<P: AsRef<std::path::Path>>(&self, path: P) -> anyhow::Result<()> {
85+
if let Ok(true) = std::fs::exists(path.as_ref()) {
86+
log::warn!(
87+
"{} already exists, file will be truncated",
88+
path.as_ref().display()
89+
);
90+
log::warn!("{} {:x?}", self.path(), self.avma_range());
91+
}
92+
93+
let mut writer = std::fs::File::create(path.as_ref())?;
94+
bincode::serialize_into(&mut writer, self)?;
95+
Ok(())
96+
}
2197
}
2298

2399
impl Debug for UnwindData {
24100
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25101
let eh_frame_hdr_hash = {
26102
let mut hasher = DefaultHasher::new();
27-
self.eh_frame_hdr.hash(&mut hasher);
103+
self.eh_frame_hdr().hash(&mut hasher);
28104
hasher.finish()
29105
};
30106
let eh_frame_hash = {
31107
let mut hasher = DefaultHasher::new();
32-
self.eh_frame.hash(&mut hasher);
108+
self.eh_frame().hash(&mut hasher);
33109
hasher.finish()
34110
};
35111

36112
f.debug_struct("UnwindData")
37-
.field("path", &self.path)
38-
.field("avma_range", &format_args!("{:x?}", self.avma_range))
39-
.field("base_avma", &format_args!("{:x}", self.base_avma))
113+
.field("path", &self.path())
114+
.field("avma_range", &format_args!("{:x?}", self.avma_range()))
115+
.field("base_avma", &format_args!("{:x}", self.base_avma()))
116+
.field("base_svma", &format_args!("{:x}", self.base_svma()))
40117
.field(
41118
"eh_frame_hdr_svma",
42-
&format_args!("{:x?}", self.eh_frame_hdr_svma),
119+
&format_args!("{:x?}", self.eh_frame_hdr_svma()),
43120
)
44121
.field("eh_frame_hdr_hash", &format_args!("{eh_frame_hdr_hash:x}"))
45122
.field("eh_frame_hash", &format_args!("{eh_frame_hash:x}"))
46-
.field("eh_frame_svma", &format_args!("{:x?}", self.eh_frame_svma))
123+
.field(
124+
"eh_frame_svma",
125+
&format_args!("{:x?}", self.eh_frame_svma()),
126+
)
47127
.finish()
48128
}
49129
}
130+
131+
#[derive(Serialize, Deserialize)]
132+
pub struct UnwindDataV1 {
133+
pub path: String,
134+
135+
pub avma_range: Range<u64>,
136+
pub base_avma: u64,
137+
pub eh_frame_hdr: Vec<u8>,
138+
pub eh_frame_hdr_svma: Range<u64>,
139+
140+
pub eh_frame: Vec<u8>,
141+
pub eh_frame_svma: Range<u64>,
142+
}
143+
144+
#[derive(Serialize, Deserialize, Clone)]
145+
pub struct UnwindDataV2 {
146+
pub path: String,
147+
148+
pub avma_range: Range<u64>,
149+
pub base_avma: u64,
150+
pub base_svma: u64,
151+
152+
pub eh_frame_hdr: Vec<u8>,
153+
pub eh_frame_hdr_svma: Range<u64>,
154+
155+
pub eh_frame: Vec<u8>,
156+
pub eh_frame_svma: Range<u64>,
157+
}

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

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
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};
9-
use runner_shared::unwind_data::UnwindData;
6+
use runner_shared::unwind_data::{UnwindData, UnwindDataV2};
107
use std::{
118
collections::HashSet,
129
path::{Path, PathBuf},
@@ -75,15 +72,16 @@ impl JitDump {
7572
continue;
7673
};
7774

78-
jit_unwind_data.push(UnwindData {
75+
jit_unwind_data.push(UnwindData::V2(UnwindDataV2 {
7976
path: format!("jit_{name}"),
8077
avma_range: avma_start..avma_end,
8178
base_avma: 0,
8279
eh_frame_hdr,
8380
eh_frame_hdr_svma: 0..0,
8481
eh_frame,
8582
eh_frame_svma: 0..0,
86-
});
83+
base_svma: 0,
84+
}));
8785
}
8886
JitDumpRecord::CodeUnwindingInfo(record) => {
8987
// Store unwind info for the next code loads

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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Ok(
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: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
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;
9+
use runner_shared::unwind_data::UnwindDataV2;
1010
use std::ops::Range;
1111

1212
pub trait UnwindDataExt {
@@ -19,9 +19,6 @@ pub trait UnwindDataExt {
1919
) -> anyhow::Result<Self>
2020
where
2121
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<()>;
2522
}
2623

2724
impl UnwindDataExt for UnwindData {
@@ -68,6 +65,7 @@ impl UnwindDataExt for UnwindData {
6865
runtime_file_offset,
6966
&file,
7067
)?;
68+
let base_svma = elf_helper::relative_address_base(&file);
7169
let eh_frame = file.section_by_name(".eh_frame");
7270
let eh_frame_hdr = file.section_by_name(".eh_frame_hdr");
7371

@@ -82,10 +80,11 @@ impl UnwindDataExt for UnwindData {
8280
section.address()..section.address() + section.size()
8381
}
8482

85-
Ok(Self {
83+
Ok(UnwindData::V2(UnwindDataV2 {
8684
path,
8785
avma_range,
8886
base_avma,
87+
base_svma,
8988
eh_frame_hdr: eh_frame_hdr_data.context("Failed to find eh_frame hdr data")?,
9089
eh_frame_hdr_svma: eh_frame_hdr
9190
.as_ref()
@@ -96,31 +95,7 @@ impl UnwindDataExt for UnwindData {
9695
.as_ref()
9796
.map(svma_range)
9897
.context("Failed to find eh_frame section")?,
99-
})
100-
}
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(())
98+
}))
12499
}
125100
}
126101

0 commit comments

Comments
 (0)