Skip to content

Commit c7cef77

Browse files
committed
Allow store bytecode indexes in addition to line numbers.
1 parent 27eb3e1 commit c7cef77

File tree

2 files changed

+59
-33
lines changed

2 files changed

+59
-33
lines changed

filpreload/src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![deny(unsafe_op_in_unsafe_fn)]
22
use parking_lot::Mutex;
3+
use pymemprofile_api::memorytracking::LineNumberInfo::LineNumber;
34
use pymemprofile_api::memorytracking::{
45
AllocationTracker, CallSiteId, Callstack, FunctionId, VecFunctionLocations, PARENT_PROCESS,
56
};
@@ -57,8 +58,10 @@ fn add_function(filename: String, function_name: String) -> FunctionId {
5758
/// Add to per-thread function stack:
5859
fn start_call(call_site: FunctionId, parent_line_number: u16, line_number: u16) {
5960
THREAD_CALLSTACK.with(|cs| {
60-
cs.borrow_mut()
61-
.start_call(parent_line_number, CallSiteId::new(call_site, line_number));
61+
cs.borrow_mut().start_call(
62+
parent_line_number as u32,
63+
CallSiteId::new(call_site, LineNumber(line_number as u32)),
64+
);
6265
});
6366
}
6467

@@ -136,7 +139,7 @@ fn add_allocation(
136139
// Will fail during thread shutdown, but not much we can do at that point.
137140
let callstack_id = THREAD_CALLSTACK.try_with(|tcs| {
138141
let mut callstack = tcs.borrow_mut();
139-
callstack.id_for_new_allocation(line_number, |callstack| {
142+
callstack.id_for_new_allocation(line_number as u32, |callstack| {
140143
allocations.get_callstack_id(callstack)
141144
})
142145
})?;

memapi/src/memorytracking.rs

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -82,19 +82,35 @@ impl FunctionLocations for VecFunctionLocations {
8282
}
8383
}
8484

85-
pub type LineNumber = u16; // TODO u32, newtype
85+
/// Either the line number, or the bytecode index needed to get it.
86+
#[derive(Copy, Clone, Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
87+
pub enum LineNumberInfo {
88+
LineNumber(u32),
89+
BytecodeIndex(i32),
90+
}
91+
92+
impl LineNumberInfo {
93+
fn get_line_number(&self) -> u32 {
94+
if let LineNumberInfo::LineNumber(lineno) = self {
95+
*lineno
96+
} else {
97+
debug_assert!(false, "This should never happen.");
98+
0
99+
}
100+
}
101+
}
86102

87103
/// A specific location: file + function + line number.
88104
#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Serialize, Deserialize)]
89105
pub struct CallSiteId {
90106
/// The function + filename. We use IDs for performance reasons (faster hashing).
91107
function: FunctionId,
92108
/// Line number within the _file_, 1-indexed.
93-
line_number: LineNumber,
109+
line_number: LineNumberInfo,
94110
}
95111

96112
impl CallSiteId {
97-
pub fn new(function: FunctionId, line_number: u16) -> CallSiteId {
113+
pub fn new(function: FunctionId, line_number: LineNumberInfo) -> CallSiteId {
98114
CallSiteId {
99115
function,
100116
line_number,
@@ -108,7 +124,7 @@ impl CallSiteId {
108124
pub struct Callstack {
109125
calls: Vec<CallSiteId>,
110126
#[derivative(Hash = "ignore", PartialEq = "ignore")]
111-
cached_callstack_id: Option<(u16, CallstackId)>, // first bit is line number
127+
cached_callstack_id: Option<(u32, CallstackId)>, // first bit is line number
112128
}
113129

114130
impl Callstack {
@@ -126,10 +142,10 @@ impl Callstack {
126142
}
127143
}
128144

129-
pub fn start_call(&mut self, parent_line_number: u16, callsite_id: CallSiteId) {
145+
pub fn start_call(&mut self, parent_line_number: u32, callsite_id: CallSiteId) {
130146
if parent_line_number != 0 {
131147
if let Some(mut call) = self.calls.last_mut() {
132-
call.line_number = parent_line_number;
148+
call.line_number = LineNumberInfo::LineNumber(parent_line_number);
133149
}
134150
}
135151
self.calls.push(callsite_id);
@@ -141,7 +157,7 @@ impl Callstack {
141157
self.cached_callstack_id = None;
142158
}
143159

144-
pub fn id_for_new_allocation<F>(&mut self, line_number: u16, get_callstack_id: F) -> CallstackId
160+
pub fn id_for_new_allocation<F>(&mut self, line_number: u32, get_callstack_id: F) -> CallstackId
145161
where
146162
F: FnOnce(&Callstack) -> CallstackId,
147163
{
@@ -156,7 +172,7 @@ impl Callstack {
156172
// Set the new line number:
157173
if line_number != 0 {
158174
if let Some(call) = self.calls.last_mut() {
159-
call.line_number = line_number;
175+
call.line_number = LineNumberInfo::LineNumber(line_number);
160176
}
161177
}
162178

@@ -194,7 +210,8 @@ impl Callstack {
194210
.map(|(id, (function, filename))| {
195211
if to_be_post_processed {
196212
// Get Python code.
197-
let code = linecache.get_source_line(filename, id.line_number as usize);
213+
let code = linecache
214+
.get_source_line(filename, id.line_number.get_line_number() as usize);
198215
// Leading whitespace is dropped by SVG, so we'd like to
199216
// replace it with non-breaking space. However, inferno
200217
// trims whitespace
@@ -215,15 +232,15 @@ impl Callstack {
215232
format!(
216233
"{filename}:{line} ({function});\u{2800}{code}",
217234
filename = filename,
218-
line = id.line_number,
235+
line = id.line_number.get_line_number(),
219236
function = function,
220237
code = &code.trim_end(),
221238
)
222239
} else {
223240
format!(
224241
"{filename}:{line} ({function})",
225242
filename = filename,
226-
line = id.line_number,
243+
line = id.line_number.get_line_number(),
227244
function = function,
228245
)
229246
}
@@ -748,6 +765,7 @@ impl<FL: FunctionLocations> AllocationTracker<FL> {
748765
mod tests {
749766
use crate::memorytracking::{ProcessUid, PARENT_PROCESS};
750767

768+
use super::LineNumberInfo::LineNumber;
751769
use super::{
752770
Allocation, AllocationTracker, CallSiteId, Callstack, CallstackInterner, FunctionId,
753771
FunctionLocations, VecFunctionLocations, HIGH_32BIT, MIB,
@@ -815,7 +833,7 @@ mod tests {
815833
let (process, allocation_size) = *allocated_sizes.get(i).unwrap();
816834
let process = ProcessUid(process);
817835
let mut cs = Callstack::new();
818-
cs.start_call(0, CallSiteId::new(FunctionId::new(i as u64), 0));
836+
cs.start_call(0, CallSiteId::new(FunctionId::new(i as u64), LineNumber(0)));
819837
let cs_id = tracker.get_callstack_id(&cs);
820838
tracker.add_allocation(process, i as usize, allocation_size, cs_id);
821839
expected_memory_usage.push_back(allocation_size);
@@ -854,7 +872,7 @@ mod tests {
854872
let (process, allocation_size) = *allocated_sizes.get(i).unwrap();
855873
let process = ProcessUid(process);
856874
let mut cs = Callstack::new();
857-
cs.start_call(0, CallSiteId::new(FunctionId::new(i as u64), 0));
875+
cs.start_call(0, CallSiteId::new(FunctionId::new(i as u64), LineNumber(0)));
858876
let csid = tracker.get_callstack_id(&cs);
859877
tracker.add_anon_mmap(process, addresses[i] as usize, allocation_size, csid);
860878
expected_memory_usage.push_back(allocation_size);
@@ -891,7 +909,7 @@ mod tests {
891909
let (process, allocation_size) = *allocated_sizes.get(i).unwrap();
892910
let process = ProcessUid(process);
893911
let mut cs = Callstack::new();
894-
cs.start_call(0, CallSiteId::new(FunctionId::new(i as u64), 0));
912+
cs.start_call(0, CallSiteId::new(FunctionId::new(i as u64), LineNumber(0)));
895913
let cs_id = tracker.get_callstack_id(&cs);
896914
tracker.add_allocation(process, i as usize, allocation_size, cs_id);
897915
expected_memory_usage += allocation_size;
@@ -900,7 +918,7 @@ mod tests {
900918
let (process, allocation_size) = *allocated_mmaps.get(i).unwrap();
901919
let process = ProcessUid(process);
902920
let mut cs = Callstack::new();
903-
cs.start_call(0, CallSiteId::new(FunctionId::new(i as u64), 0));
921+
cs.start_call(0, CallSiteId::new(FunctionId::new(i as u64), LineNumber(0)));
904922
let csid = tracker.get_callstack_id(&cs);
905923
tracker.add_anon_mmap(process, mmap_addresses[i] as usize, allocation_size, csid);
906924
expected_memory_usage += allocation_size;
@@ -933,9 +951,10 @@ mod tests {
933951

934952
// Parent line number does nothing if it's first call:
935953
let mut cs1 = Callstack::new();
936-
let id1 = CallSiteId::new(fid1, 2);
937-
let id2 = CallSiteId::new(fid3, 45);
938-
let id3 = CallSiteId::new(fid5, 6);
954+
// CallSiteId::new($a, $b) ==>> CallSiteId::new($a, LineNumber($b))
955+
let id1 = CallSiteId::new(fid1, LineNumber(2));
956+
let id2 = CallSiteId::new(fid3, LineNumber(45));
957+
let id3 = CallSiteId::new(fid5, LineNumber(6));
939958
cs1.start_call(123, id1);
940959
assert_eq!(cs1.calls, vec![id1]);
941960

@@ -950,7 +969,11 @@ mod tests {
950969
cs2.start_call(12, id3);
951970
assert_eq!(
952971
cs2.calls,
953-
vec![CallSiteId::new(fid1, 10), CallSiteId::new(fid3, 12), id3]
972+
vec![
973+
CallSiteId::new(fid1, LineNumber(10)),
974+
CallSiteId::new(fid3, LineNumber(12)),
975+
id3
976+
]
954977
);
955978
}
956979

@@ -960,10 +983,10 @@ mod tests {
960983
let fid3 = FunctionId::new(3u64);
961984

962985
let mut cs1 = Callstack::new();
963-
cs1.start_call(0, CallSiteId::new(fid1, 2));
986+
cs1.start_call(0, CallSiteId::new(fid1, LineNumber(2)));
964987
let cs1b = cs1.clone();
965988
let mut cs2 = Callstack::new();
966-
cs2.start_call(0, CallSiteId::new(fid3, 4));
989+
cs2.start_call(0, CallSiteId::new(fid3, LineNumber(4)));
967990
let cs3 = Callstack::new();
968991
let cs3b = Callstack::new();
969992

@@ -1014,7 +1037,7 @@ mod tests {
10141037

10151038
let fid1 = FunctionId::new(1u64);
10161039

1017-
cs1.start_call(0, CallSiteId::new(fid1, 2));
1040+
cs1.start_call(0, CallSiteId::new(fid1, LineNumber(2)));
10181041
let id1 =
10191042
cs1.id_for_new_allocation(1, |cs| interner.get_or_insert_id(Cow::Borrowed(&cs), || ()));
10201043
let id2 =
@@ -1025,7 +1048,7 @@ mod tests {
10251048
assert_ne!(id2, id0);
10261049
assert_ne!(id2, id1);
10271050

1028-
cs1.start_call(3, CallSiteId::new(fid1, 2));
1051+
cs1.start_call(3, CallSiteId::new(fid1, LineNumber(2)));
10291052
let id3 =
10301053
cs1.id_for_new_allocation(4, |cs| interner.get_or_insert_id(Cow::Borrowed(&cs), || ()));
10311054
assert_ne!(id3, id0);
@@ -1041,7 +1064,7 @@ mod tests {
10411064
assert_eq!(id1, id1c);
10421065

10431066
// Check for cache invalidation in start_call:
1044-
cs1.start_call(1, CallSiteId::new(fid1, 1));
1067+
cs1.start_call(1, CallSiteId::new(fid1, LineNumber(1)));
10451068
let id4 =
10461069
cs1.id_for_new_allocation(1, |cs| interner.get_or_insert_id(Cow::Borrowed(&cs), || ()));
10471070
assert_ne!(id4, id0);
@@ -1063,9 +1086,9 @@ mod tests {
10631086

10641087
let mut tracker = new_tracker();
10651088
let mut cs1 = Callstack::new();
1066-
cs1.start_call(0, CallSiteId::new(fid1, 2));
1089+
cs1.start_call(0, CallSiteId::new(fid1, LineNumber(2)));
10671090
let mut cs2 = Callstack::new();
1068-
cs2.start_call(0, CallSiteId::new(fid3, 4));
1091+
cs2.start_call(0, CallSiteId::new(fid3, LineNumber(4)));
10691092

10701093
let cs1_id = tracker.get_callstack_id(&cs1);
10711094

@@ -1156,12 +1179,12 @@ mod tests {
11561179
.functions
11571180
.add_function("c".to_string(), "cf".to_string());
11581181

1159-
let id1 = CallSiteId::new(fid1, 1);
1182+
let id1 = CallSiteId::new(fid1, LineNumber(1));
11601183
// Same function, different line number—should be different item:
1161-
let id1_different = CallSiteId::new(fid1, 7);
1162-
let id2 = CallSiteId::new(fid2, 2);
1184+
let id1_different = CallSiteId::new(fid1, LineNumber(7));
1185+
let id2 = CallSiteId::new(fid2, LineNumber(2));
11631186

1164-
let id3 = CallSiteId::new(fid3, 3);
1187+
let id3 = CallSiteId::new(fid3, LineNumber(3));
11651188
let mut cs1 = Callstack::new();
11661189
cs1.start_call(0, id1);
11671190
cs1.start_call(0, id2.clone());

0 commit comments

Comments
 (0)