Skip to content

Commit 02a7b37

Browse files
authored
Support richer frame information in fxprof-processed-profile (#525)
Inline depth, both address and symbol name, file / line / column info
2 parents 884da76 + a865212 commit 02a7b37

24 files changed

+1093
-685
lines changed

fxprof-processed-profile/src/frame.rs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
use bitflags::bitflags;
22

3-
use crate::category::SubcategoryHandle;
43
use crate::global_lib_table::LibraryHandle;
5-
use crate::profile::StringHandle;
64

7-
/// A part of the information about a single stack frame.
5+
/// The address information of a stack frame.
86
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
9-
pub enum Frame {
7+
pub enum FrameAddress {
108
/// A code address taken from the instruction pointer.
119
///
1210
/// This code address will be resolved to a library-relative address using
@@ -45,20 +43,6 @@ pub enum Frame {
4543
/// A relative address taken from an adjusted return address which
4644
/// has already been resolved to a `LibraryHandle`.
4745
RelativeAddressFromAdjustedReturnAddress(LibraryHandle, u32),
48-
/// A string, containing an index returned by
49-
/// [`Profile::handle_for_string`](crate::Profile::handle_for_string).
50-
Label(StringHandle),
51-
}
52-
53-
/// All the information about a single stack frame.
54-
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
55-
pub struct FrameInfo {
56-
/// The absolute address or label of this frame.
57-
pub frame: Frame,
58-
/// The subcategory of this frame.
59-
pub subcategory: SubcategoryHandle,
60-
/// The flags of this frame. Use `FrameFlags::empty()` if unsure.
61-
pub flags: FrameFlags,
6246
}
6347

6448
bitflags! {

fxprof-processed-profile/src/frame_table.rs

Lines changed: 165 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,26 @@ use crate::fast_hash_map::FastHashMap;
55
use crate::frame::FrameFlags;
66
use crate::func_table::{FuncIndex, FuncTable};
77
use crate::global_lib_table::{GlobalLibIndex, GlobalLibTable};
8-
use crate::native_symbols::{NativeSymbolIndex, NativeSymbols};
8+
use crate::native_symbols::NativeSymbolIndex;
99
use crate::resource_table::ResourceTable;
1010
use crate::serialization_helpers::SerializableSingleValueColumn;
1111
use crate::thread_string_table::{ThreadInternalStringIndex, ThreadStringTable};
1212

1313
#[derive(Debug, Clone, Default)]
1414
pub struct FrameTable {
15-
addresses: Vec<Option<u32>>,
16-
categories: Vec<CategoryHandle>,
17-
subcategories: Vec<SubcategoryIndex>,
18-
funcs: Vec<FuncIndex>,
19-
native_symbols: Vec<Option<NativeSymbolIndex>>,
20-
internal_frame_to_frame_index: FastHashMap<InternalFrame, usize>,
15+
name_col: Vec<ThreadInternalStringIndex>,
16+
category_col: Vec<CategoryHandle>,
17+
subcategory_col: Vec<SubcategoryIndex>,
18+
flags_col: Vec<FrameFlags>,
19+
file_col: Vec<Option<ThreadInternalStringIndex>>,
20+
line_col: Vec<Option<u32>>,
21+
column_col: Vec<Option<u32>>,
22+
lib_col: Vec<Option<GlobalLibIndex>>,
23+
address_col: Vec<Option<u32>>,
24+
native_symbol_col: Vec<Option<NativeSymbolIndex>>,
25+
inline_depth_col: Vec<u16>,
26+
frame_key_to_frame_index: FastHashMap<InternalFrameKey, usize>,
27+
contains_js_frame: bool,
2128
}
2229

2330
impl FrameTable {
@@ -27,91 +34,130 @@ impl FrameTable {
2734

2835
pub fn index_for_frame(
2936
&mut self,
30-
string_table: &mut ThreadStringTable,
31-
resource_table: &mut ResourceTable,
32-
func_table: &mut FuncTable,
33-
native_symbol_table: &mut NativeSymbols,
34-
global_libs: &mut GlobalLibTable,
3537
frame: InternalFrame,
38+
global_lib_index_to_thread_string_index: &mut FastHashMap<
39+
GlobalLibIndex,
40+
ThreadInternalStringIndex,
41+
>,
42+
global_libs: &mut GlobalLibTable,
43+
string_table: &mut ThreadStringTable,
3644
) -> usize {
37-
let addresses = &mut self.addresses;
38-
let funcs = &mut self.funcs;
39-
let native_symbols = &mut self.native_symbols;
40-
let categories = &mut self.categories;
41-
let subcategories = &mut self.subcategories;
42-
*self
43-
.internal_frame_to_frame_index
44-
.entry(frame.clone())
45-
.or_insert_with(|| {
46-
let frame_index = addresses.len();
47-
let (address, location_string_index, native_symbol, resource) = match frame.location
48-
{
49-
InternalFrameLocation::UnknownAddress(address) => {
50-
let location_string = format!("0x{address:x}");
51-
let s = string_table.index_for_string(&location_string);
52-
(None, s, None, None)
53-
}
54-
InternalFrameLocation::AddressInLib(address, lib_index) => {
55-
let res =
56-
resource_table.resource_for_lib(lib_index, global_libs, string_table);
57-
let lib = global_libs.get_lib(lib_index).unwrap();
58-
let native_symbol_and_name =
59-
lib.symbol_table.as_deref().and_then(|symbol_table| {
60-
let symbol = symbol_table.lookup(address)?;
61-
Some(
62-
native_symbol_table.symbol_index_and_string_index_for_symbol(
63-
lib_index,
64-
symbol,
65-
string_table,
66-
),
67-
)
68-
});
69-
let (native_symbol, s) = match native_symbol_and_name {
70-
Some((native_symbol, name_string_index)) => {
71-
(Some(native_symbol), name_string_index)
72-
}
73-
None => {
74-
// This isn't in the pre-provided symbol table, and we know it's in a library.
75-
global_libs.add_lib_used_rva(lib_index, address);
76-
77-
let location_string = format!("0x{address:x}");
78-
(None, string_table.index_for_string(&location_string))
79-
}
80-
};
81-
(Some(address), s, native_symbol, Some(res))
82-
}
83-
InternalFrameLocation::Label(string_index) => (None, string_index, None, None),
84-
};
85-
let func_index =
86-
func_table.index_for_func(location_string_index, resource, frame.flags);
87-
let SubcategoryHandle(category, subcategory) = frame.subcategory;
88-
addresses.push(address);
89-
categories.push(category);
90-
subcategories.push(subcategory);
91-
funcs.push(func_index);
92-
native_symbols.push(native_symbol);
93-
frame_index
45+
if let Some(index) = self.frame_key_to_frame_index.get(&frame.key) {
46+
return *index;
47+
}
48+
49+
let flags = frame.key.flags;
50+
51+
let frame_index = self.name_col.len();
52+
let SubcategoryHandle(category, subcategory) = frame.key.subcategory;
53+
self.name_col.push(frame.name);
54+
self.category_col.push(category);
55+
self.subcategory_col.push(subcategory);
56+
self.flags_col.push(flags);
57+
58+
match frame.key.variant {
59+
InternalFrameKeyVariant::Label {
60+
file_path,
61+
line,
62+
col,
63+
..
64+
} => {
65+
self.file_col.push(file_path);
66+
self.line_col.push(line);
67+
self.column_col.push(col);
68+
self.lib_col.push(None);
69+
self.address_col.push(None);
70+
self.native_symbol_col.push(None);
71+
self.inline_depth_col.push(0);
72+
}
73+
InternalFrameKeyVariant::Native {
74+
lib,
75+
relative_address,
76+
inline_depth,
77+
} => {
78+
self.file_col.push(None);
79+
self.line_col.push(None);
80+
self.column_col.push(None);
81+
self.lib_col.push(Some(lib));
82+
self.address_col.push(Some(relative_address));
83+
self.native_symbol_col.push(frame.native_symbol);
84+
self.inline_depth_col.push(inline_depth);
85+
86+
global_libs.add_lib_used_rva(lib, relative_address);
87+
88+
global_lib_index_to_thread_string_index
89+
.entry(lib)
90+
.or_insert_with(|| {
91+
let lib_name = &global_libs.get_lib(lib).unwrap().name;
92+
string_table.index_for_string(lib_name)
93+
});
94+
}
95+
}
96+
97+
self.frame_key_to_frame_index.insert(frame.key, frame_index);
98+
99+
if flags.intersects(FrameFlags::IS_JS | FrameFlags::IS_RELEVANT_FOR_JS) {
100+
self.contains_js_frame = true;
101+
}
102+
103+
frame_index
104+
}
105+
106+
pub fn contains_js_frame(&self) -> bool {
107+
self.contains_js_frame
108+
}
109+
110+
pub fn get_serializable_tables(
111+
&self,
112+
global_lib_index_to_thread_string_index: &FastHashMap<
113+
GlobalLibIndex,
114+
ThreadInternalStringIndex,
115+
>,
116+
) -> (SerializableFrameTable<'_>, FuncTable, ResourceTable) {
117+
let mut func_table = FuncTable::new();
118+
let mut resource_table = ResourceTable::new();
119+
let func_col = self
120+
.name_col
121+
.iter()
122+
.cloned()
123+
.zip(self.flags_col.iter().cloned())
124+
.zip(self.lib_col.iter().cloned())
125+
.zip(self.file_col.iter().cloned())
126+
.map(|(((name, flags), lib), file)| {
127+
let resource = lib.map(|lib| {
128+
resource_table.resource_for_lib(lib, global_lib_index_to_thread_string_index)
129+
});
130+
func_table.index_for_func(name, file, resource, flags)
94131
})
132+
.collect();
133+
(
134+
SerializableFrameTable(self, func_col),
135+
func_table,
136+
resource_table,
137+
)
95138
}
96139
}
97140

98-
impl Serialize for FrameTable {
141+
pub struct SerializableFrameTable<'a>(&'a FrameTable, Vec<FuncIndex>);
142+
143+
impl Serialize for SerializableFrameTable<'_> {
99144
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
100-
let len = self.addresses.len();
145+
let SerializableFrameTable(table, func_col) = self;
146+
let len = table.name_col.len();
101147
let mut map = serializer.serialize_map(None)?;
102148
map.serialize_entry("length", &len)?;
103149
map.serialize_entry(
104150
"address",
105-
&SerializableFrameTableAddressColumn(&self.addresses),
151+
&SerializableFrameTableAddressColumn(&table.address_col),
106152
)?;
107-
map.serialize_entry("inlineDepth", &SerializableSingleValueColumn(0u32, len))?;
108-
map.serialize_entry("category", &self.categories)?;
109-
map.serialize_entry("subcategory", &self.subcategories)?;
110-
map.serialize_entry("func", &self.funcs)?;
111-
map.serialize_entry("nativeSymbol", &self.native_symbols)?;
153+
map.serialize_entry("inlineDepth", &table.inline_depth_col)?;
154+
map.serialize_entry("category", &table.category_col)?;
155+
map.serialize_entry("subcategory", &table.subcategory_col)?;
156+
map.serialize_entry("func", func_col)?;
157+
map.serialize_entry("nativeSymbol", &table.native_symbol_col)?;
112158
map.serialize_entry("innerWindowID", &SerializableSingleValueColumn(0, len))?;
113-
map.serialize_entry("line", &SerializableSingleValueColumn((), len))?;
114-
map.serialize_entry("column", &SerializableSingleValueColumn((), len))?;
159+
map.serialize_entry("line", &table.line_col)?;
160+
map.serialize_entry("column", &table.column_col)?;
115161
map.end()
116162
}
117163
}
@@ -133,14 +179,49 @@ impl Serialize for SerializableFrameTableAddressColumn<'_> {
133179

134180
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
135181
pub struct InternalFrame {
136-
pub location: InternalFrameLocation,
182+
pub key: InternalFrameKey,
183+
pub name: ThreadInternalStringIndex,
184+
pub native_symbol: Option<NativeSymbolIndex>, // only used when key.variant is InternalFrameKeyVariant::Native
185+
pub file_path: Option<ThreadInternalStringIndex>,
186+
pub line: Option<u32>,
187+
pub col: Option<u32>,
188+
}
189+
190+
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
191+
pub struct InternalFrameKey {
192+
pub variant: InternalFrameKeyVariant,
137193
pub subcategory: SubcategoryHandle,
138194
pub flags: FrameFlags,
139195
}
140196

197+
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
198+
pub enum InternalFrameKeyVariant {
199+
Label {
200+
name: ThreadInternalStringIndex,
201+
file_path: Option<ThreadInternalStringIndex>,
202+
line: Option<u32>,
203+
col: Option<u32>,
204+
},
205+
Native {
206+
lib: GlobalLibIndex,
207+
relative_address: u32,
208+
inline_depth: u16,
209+
},
210+
}
211+
212+
impl InternalFrameKeyVariant {
213+
pub fn new_label(name: ThreadInternalStringIndex) -> Self {
214+
InternalFrameKeyVariant::Label {
215+
name,
216+
file_path: None,
217+
line: None,
218+
col: None,
219+
}
220+
}
221+
}
222+
141223
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
142-
pub enum InternalFrameLocation {
143-
UnknownAddress(u64),
144-
AddressInLib(u32, GlobalLibIndex),
145-
Label(ThreadInternalStringIndex),
224+
pub enum InternalFrameAddress {
225+
Unknown(u64),
226+
InLib(u32, GlobalLibIndex),
146227
}

0 commit comments

Comments
 (0)