Skip to content

Commit a1a651e

Browse files
authored
Some improvements to how frames and stacks are handled in fxprof-processed-profile (#540)
2 parents 02a7b37 + 561847d commit a1a651e

File tree

16 files changed

+219
-281
lines changed

16 files changed

+219
-281
lines changed

fxprof-processed-profile/src/category.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ pub trait IntoSubcategoryHandle {
2121
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
2222
pub struct Category<'a>(pub &'a str, pub CategoryColor);
2323

24+
impl Category<'_> {
25+
/// The "Other" category. All profiles have this category.
26+
pub const OTHER: Category<'static> = Category("Other", CategoryColor::Gray);
27+
}
28+
2429
impl IntoSubcategoryHandle for Category<'_> {
2530
fn into_subcategory_handle(self, profile: &mut Profile) -> SubcategoryHandle {
2631
let category_handle = profile.handle_for_category(self);

fxprof-processed-profile/src/frame_table.rs

Lines changed: 75 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
22

33
use crate::category::{CategoryHandle, SubcategoryHandle, SubcategoryIndex};
4-
use crate::fast_hash_map::FastHashMap;
4+
use crate::fast_hash_map::FastIndexSet;
55
use crate::frame::FrameFlags;
6-
use crate::func_table::{FuncIndex, FuncTable};
6+
use crate::func_table::{FuncIndex, FuncKey, FuncTable};
77
use crate::global_lib_table::{GlobalLibIndex, GlobalLibTable};
88
use crate::native_symbols::NativeSymbolIndex;
99
use crate::resource_table::ResourceTable;
@@ -12,19 +12,19 @@ use crate::thread_string_table::{ThreadInternalStringIndex, ThreadStringTable};
1212

1313
#[derive(Debug, Clone, Default)]
1414
pub struct FrameTable {
15-
name_col: Vec<ThreadInternalStringIndex>,
15+
func_table: FuncTable,
16+
resource_table: ResourceTable,
17+
18+
func_col: Vec<FuncIndex>,
1619
category_col: Vec<CategoryHandle>,
1720
subcategory_col: Vec<SubcategoryIndex>,
18-
flags_col: Vec<FrameFlags>,
19-
file_col: Vec<Option<ThreadInternalStringIndex>>,
2021
line_col: Vec<Option<u32>>,
2122
column_col: Vec<Option<u32>>,
22-
lib_col: Vec<Option<GlobalLibIndex>>,
2323
address_col: Vec<Option<u32>>,
2424
native_symbol_col: Vec<Option<NativeSymbolIndex>>,
2525
inline_depth_col: Vec<u16>,
26-
frame_key_to_frame_index: FastHashMap<InternalFrameKey, usize>,
27-
contains_js_frame: bool,
26+
27+
frame_key_set: FastIndexSet<InternalFrame>,
2828
}
2929

3030
impl FrameTable {
@@ -35,129 +35,88 @@ impl FrameTable {
3535
pub fn index_for_frame(
3636
&mut self,
3737
frame: InternalFrame,
38-
global_lib_index_to_thread_string_index: &mut FastHashMap<
39-
GlobalLibIndex,
40-
ThreadInternalStringIndex,
41-
>,
4238
global_libs: &mut GlobalLibTable,
4339
string_table: &mut ThreadStringTable,
4440
) -> usize {
45-
if let Some(index) = self.frame_key_to_frame_index.get(&frame.key) {
46-
return *index;
41+
let (frame_index, is_new) = self.frame_key_set.insert_full(frame);
42+
43+
if !is_new {
44+
return frame_index;
4745
}
4846

49-
let flags = frame.key.flags;
47+
let func_key = frame.func_key();
48+
let func = self.func_table.index_for_func(
49+
func_key,
50+
&mut self.resource_table,
51+
global_libs,
52+
string_table,
53+
);
5054

51-
let frame_index = self.name_col.len();
52-
let SubcategoryHandle(category, subcategory) = frame.key.subcategory;
53-
self.name_col.push(frame.name);
55+
self.func_col.push(func);
56+
let SubcategoryHandle(category, subcategory) = frame.subcategory;
5457
self.category_col.push(category);
5558
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);
59+
self.line_col.push(frame.line);
60+
self.column_col.push(frame.col);
61+
62+
match frame.variant {
63+
InternalFrameVariant::Label => {
6964
self.address_col.push(None);
7065
self.native_symbol_col.push(None);
7166
self.inline_depth_col.push(0);
7267
}
73-
InternalFrameKeyVariant::Native {
68+
InternalFrameVariant::Native(NativeFrameData {
7469
lib,
70+
native_symbol,
7571
relative_address,
7672
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-
73+
}) => {
8674
global_libs.add_lib_used_rva(lib, relative_address);
8775

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-
});
76+
self.address_col.push(Some(relative_address));
77+
self.native_symbol_col.push(native_symbol);
78+
self.inline_depth_col.push(inline_depth);
9479
}
9580
}
9681

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-
10382
frame_index
10483
}
10584

10685
pub fn contains_js_frame(&self) -> bool {
107-
self.contains_js_frame
86+
self.func_table.contains_js_func()
10887
}
10988

11089
pub fn get_serializable_tables(
11190
&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)
131-
})
132-
.collect();
91+
) -> (SerializableFrameTable<'_>, &'_ FuncTable, &'_ ResourceTable) {
13392
(
134-
SerializableFrameTable(self, func_col),
135-
func_table,
136-
resource_table,
93+
SerializableFrameTable(self),
94+
&self.func_table,
95+
&self.resource_table,
13796
)
13897
}
13998
}
14099

141-
pub struct SerializableFrameTable<'a>(&'a FrameTable, Vec<FuncIndex>);
100+
pub struct SerializableFrameTable<'a>(&'a FrameTable);
142101

143102
impl Serialize for SerializableFrameTable<'_> {
144103
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
145-
let SerializableFrameTable(table, func_col) = self;
146-
let len = table.name_col.len();
104+
let SerializableFrameTable(table) = self;
105+
let len = table.func_col.len();
147106
let mut map = serializer.serialize_map(None)?;
148107
map.serialize_entry("length", &len)?;
108+
map.serialize_entry("func", &table.func_col)?;
109+
map.serialize_entry("category", &table.category_col)?;
110+
map.serialize_entry("subcategory", &table.subcategory_col)?;
111+
map.serialize_entry("line", &table.line_col)?;
112+
map.serialize_entry("column", &table.column_col)?;
149113
map.serialize_entry(
150114
"address",
151115
&SerializableFrameTableAddressColumn(&table.address_col),
152116
)?;
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)?;
157117
map.serialize_entry("nativeSymbol", &table.native_symbol_col)?;
118+
map.serialize_entry("inlineDepth", &table.inline_depth_col)?;
158119
map.serialize_entry("innerWindowID", &SerializableSingleValueColumn(0, len))?;
159-
map.serialize_entry("line", &table.line_col)?;
160-
map.serialize_entry("column", &table.column_col)?;
161120
map.end()
162121
}
163122
}
@@ -177,45 +136,49 @@ impl Serialize for SerializableFrameTableAddressColumn<'_> {
177136
}
178137
}
179138

180-
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
139+
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
181140
pub struct InternalFrame {
182-
pub key: InternalFrameKey,
183141
pub name: ThreadInternalStringIndex,
184-
pub native_symbol: Option<NativeSymbolIndex>, // only used when key.variant is InternalFrameKeyVariant::Native
142+
pub variant: InternalFrameVariant,
143+
pub subcategory: SubcategoryHandle,
185144
pub file_path: Option<ThreadInternalStringIndex>,
186145
pub line: Option<u32>,
187146
pub col: Option<u32>,
147+
pub flags: FrameFlags,
188148
}
189149

190150
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
191-
pub struct InternalFrameKey {
192-
pub variant: InternalFrameKeyVariant,
193-
pub subcategory: SubcategoryHandle,
194-
pub flags: FrameFlags,
151+
pub struct NativeFrameData {
152+
pub lib: GlobalLibIndex,
153+
pub native_symbol: Option<NativeSymbolIndex>,
154+
pub relative_address: u32,
155+
pub inline_depth: u16,
195156
}
196157

197158
#[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-
},
159+
pub enum InternalFrameVariant {
160+
Label,
161+
Native(NativeFrameData),
210162
}
211163

212-
impl InternalFrameKeyVariant {
213-
pub fn new_label(name: ThreadInternalStringIndex) -> Self {
214-
InternalFrameKeyVariant::Label {
164+
impl InternalFrame {
165+
pub fn func_key(&self) -> FuncKey {
166+
let InternalFrame {
167+
name,
168+
variant,
169+
file_path,
170+
flags,
171+
..
172+
} = *self;
173+
let lib = match variant {
174+
InternalFrameVariant::Label => None,
175+
InternalFrameVariant::Native(NativeFrameData { lib, .. }) => Some(lib),
176+
};
177+
FuncKey {
215178
name,
216-
file_path: None,
217-
line: None,
218-
col: None,
179+
file_path,
180+
lib,
181+
flags,
219182
}
220183
}
221184
}

fxprof-processed-profile/src/func_table.rs

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,72 @@
11
use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
22

3-
use crate::fast_hash_map::FastHashMap;
3+
use crate::fast_hash_map::FastIndexSet;
44
use crate::frame::FrameFlags;
5-
use crate::resource_table::ResourceIndex;
5+
use crate::global_lib_table::{GlobalLibIndex, GlobalLibTable};
6+
use crate::resource_table::{ResourceIndex, ResourceTable};
67
use crate::serialization_helpers::SerializableSingleValueColumn;
7-
use crate::thread_string_table::ThreadInternalStringIndex;
8+
use crate::thread_string_table::{ThreadInternalStringIndex, ThreadStringTable};
89

910
#[derive(Debug, Clone, Default)]
1011
pub struct FuncTable {
1112
names: Vec<ThreadInternalStringIndex>,
1213
files: Vec<Option<ThreadInternalStringIndex>>,
1314
resources: Vec<Option<ResourceIndex>>,
1415
flags: Vec<FrameFlags>,
15-
func_key_to_func_index: FastHashMap<FuncKey, FuncIndex>,
16+
17+
func_key_set: FastIndexSet<FuncKey>,
18+
19+
contains_js_func: bool,
1620
}
1721

1822
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
19-
struct FuncKey {
20-
name: ThreadInternalStringIndex,
21-
file: Option<ThreadInternalStringIndex>,
22-
resource: Option<ResourceIndex>,
23-
flags: FrameFlags,
23+
pub struct FuncKey {
24+
pub name: ThreadInternalStringIndex,
25+
pub file_path: Option<ThreadInternalStringIndex>,
26+
pub lib: Option<GlobalLibIndex>,
27+
pub flags: FrameFlags,
2428
}
2529

2630
impl FuncTable {
27-
pub fn new() -> Self {
28-
Default::default()
29-
}
30-
3131
pub fn index_for_func(
3232
&mut self,
33-
name: ThreadInternalStringIndex,
34-
file: Option<ThreadInternalStringIndex>,
35-
resource: Option<ResourceIndex>,
36-
flags: FrameFlags,
33+
func_key: FuncKey,
34+
resource_table: &mut ResourceTable,
35+
global_libs: &mut GlobalLibTable,
36+
string_table: &mut ThreadStringTable,
3737
) -> FuncIndex {
38-
let key = FuncKey {
38+
let (index, is_new) = self.func_key_set.insert_full(func_key);
39+
40+
let func_index = FuncIndex(index.try_into().unwrap());
41+
if !is_new {
42+
return func_index;
43+
}
44+
45+
let FuncKey {
3946
name,
40-
file,
41-
resource,
47+
file_path,
48+
lib,
4249
flags,
43-
};
44-
if let Some(index) = self.func_key_to_func_index.get(&key) {
45-
return *index;
46-
}
50+
} = func_key;
51+
52+
let resource =
53+
lib.map(|lib| resource_table.resource_for_lib(lib, global_libs, string_table));
4754

48-
let func_index = FuncIndex(u32::try_from(self.names.len()).unwrap());
4955
self.names.push(name);
50-
self.files.push(file);
56+
self.files.push(file_path);
5157
self.resources.push(resource);
5258
self.flags.push(flags);
53-
self.func_key_to_func_index.insert(key, func_index);
59+
60+
if flags.intersects(FrameFlags::IS_JS | FrameFlags::IS_RELEVANT_FOR_JS) {
61+
self.contains_js_func = true;
62+
}
63+
5464
func_index
5565
}
66+
67+
pub fn contains_js_func(&self) -> bool {
68+
self.contains_js_func
69+
}
5670
}
5771

5872
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]

0 commit comments

Comments
 (0)