Skip to content

Commit 296b78a

Browse files
committed
Store symbol tables separately from fxprof_processed_profile::LibraryInfo.
We already have a separate Profile::set_lib_symbol_table method so just use that always. Most consumers just specify None, and now they don't have to do that anymore. But the main motivation for this change was performance: We were hashing the symbol table during calls to handle_for_lib. This fixes that.
1 parent 6a5dd4c commit 296b78a

File tree

10 files changed

+45
-61
lines changed

10 files changed

+45
-61
lines changed

fxprof-processed-profile/src/global_lib_table.rs

+15-14
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,18 @@ use std::sync::Arc;
33

44
use serde::ser::{Serialize, Serializer};
55

6-
use crate::fast_hash_map::FastHashMap;
6+
use crate::fast_hash_map::{FastHashMap, FastIndexSet};
77
use crate::{LibraryInfo, SymbolTable};
88

99
#[derive(Debug)]
1010
pub struct GlobalLibTable {
11-
/// All libraries added via `Profile::add_lib`. May or may not be used.
11+
/// All libraries added via `Profile::handle_for_lib`. May or may not be used.
1212
/// Indexed by `LibraryHandle.0`.
13-
all_libs: Vec<LibraryInfo>, // append-only for stable LibraryHandles
13+
all_libs: FastIndexSet<LibraryInfo>, // append-only for stable LibraryHandles
14+
/// Any symbol tables for libraries in all_libs
15+
symbol_tables: FastHashMap<LibraryHandle, Arc<SymbolTable>>,
1416
/// Indexed by `GlobalLibIndex.0`.
1517
used_libs: Vec<LibraryHandle>, // append-only for stable GlobalLibIndexes
16-
lib_map: FastHashMap<LibraryInfo, LibraryHandle>,
1718
used_lib_map: FastHashMap<LibraryHandle, GlobalLibIndex>,
1819
/// We keep track of RVA addresses that exist in frames that are assigned to this
1920
/// library, so that we can potentially provide symbolication info ahead of time.
@@ -26,25 +27,20 @@ pub struct GlobalLibTable {
2627
impl GlobalLibTable {
2728
pub fn new() -> Self {
2829
Self {
29-
all_libs: Vec::new(),
30+
all_libs: FastIndexSet::default(),
31+
symbol_tables: FastHashMap::default(),
3032
used_libs: Vec::new(),
31-
lib_map: FastHashMap::default(),
3233
used_lib_map: FastHashMap::default(),
3334
used_libs_seen_rvas: Vec::new(),
3435
}
3536
}
3637

3738
pub fn handle_for_lib(&mut self, lib: LibraryInfo) -> LibraryHandle {
38-
let all_libs = &mut self.all_libs;
39-
*self.lib_map.entry(lib.clone()).or_insert_with(|| {
40-
let handle = LibraryHandle(all_libs.len());
41-
all_libs.push(lib);
42-
handle
43-
})
39+
LibraryHandle(self.all_libs.insert_full(lib).0)
4440
}
4541

4642
pub fn set_lib_symbol_table(&mut self, library: LibraryHandle, symbol_table: Arc<SymbolTable>) {
47-
self.all_libs[library.0].symbol_table = Some(symbol_table);
43+
self.symbol_tables.insert(library, symbol_table);
4844
}
4945

5046
pub fn index_for_used_lib(&mut self, lib_handle: LibraryHandle) -> GlobalLibIndex {
@@ -59,7 +55,12 @@ impl GlobalLibTable {
5955

6056
pub fn get_lib(&self, index: GlobalLibIndex) -> Option<&LibraryInfo> {
6157
let handle = self.used_libs.get(index.0)?;
62-
self.all_libs.get(handle.0)
58+
self.all_libs.get_index(handle.0)
59+
}
60+
61+
pub fn get_lib_symbol_table(&self, index: GlobalLibIndex) -> Option<&SymbolTable> {
62+
let handle = self.used_libs.get(index.0)?;
63+
self.symbol_tables.get(handle).map(|v| &**v)
6364
}
6465

6566
pub fn add_lib_used_rva(&mut self, index: GlobalLibIndex, address: u32) {

fxprof-processed-profile/src/library_info.rs

-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::sync::Arc;
2-
31
use debugid::DebugId;
42
use serde::ser::{Serialize, SerializeMap, Serializer};
53

@@ -40,24 +38,6 @@ pub struct LibraryInfo {
4038
/// correct sub-binary in a mach-O fat binary. But we now use the debug_id for that
4139
/// purpose.
4240
pub arch: Option<String>,
43-
/// An optional symbol table, for "pre-symbolicating" stack frames.
44-
///
45-
/// Usually, symbolication is something that should happen asynchronously,
46-
/// because it can be very slow, so the regular way to use the profiler is to
47-
/// store only frame addresses and no symbols in the profile JSON, and perform
48-
/// symbolication only once the profile is loaded in the Firefox Profiler UI.
49-
///
50-
/// However, sometimes symbols are only available during recording and are not
51-
/// easily accessible afterwards. One such example the symbol table of the
52-
/// Linux kernel: Users with root privileges can access the symbol table of the
53-
/// currently-running kernel via `/proc/kallsyms`, but we don't want to have
54-
/// to run the local symbol server with root privileges. So it's easier to
55-
/// resolve kernel symbols when generating the profile JSON.
56-
///
57-
/// This way of symbolicating does not support file names, line numbers, or
58-
/// inline frames. It is intended for relatively "small" symbol tables for which
59-
/// an address lookup is fast.
60-
pub symbol_table: Option<Arc<SymbolTable>>,
6141
}
6242

6343
impl Serialize for LibraryInfo {

fxprof-processed-profile/src/profile.rs

+19-14
Original file line numberDiff line numberDiff line change
@@ -382,15 +382,23 @@ impl Profile {
382382
self.global_libs.handle_for_lib(library)
383383
}
384384

385-
/// Set the symbol table for a library.
386-
///
387-
/// This symbol table can also be specified in the [`LibraryInfo`] which is given to
388-
/// [`Profile::add_lib`]. However, sometimes you may want to have the [`LibraryHandle`]
389-
/// for a library before you know about all its symbols. In those cases, you can call
390-
/// [`Profile::add_lib`] with `symbol_table` set to `None`, and then supply the symbol
391-
/// table afterwards.
392-
///
393-
/// Symbol tables are optional.
385+
/// Set an optional symbol table for a library, for "pre-symbolicating" stack frames.
386+
///
387+
/// Usually, symbolication is something that should happen asynchronously,
388+
/// because it can be very slow, so the regular way to use the profiler is to
389+
/// store only frame addresses and no symbols in the profile JSON, and perform
390+
/// symbolication only once the profile is loaded in the Firefox Profiler UI.
391+
///
392+
/// However, sometimes symbols are only available during recording and are not
393+
/// easily accessible afterwards. One such example the symbol table of the
394+
/// Linux kernel: Users with root privileges can access the symbol table of the
395+
/// currently-running kernel via `/proc/kallsyms`, but we don't want to have
396+
/// to run the local symbol server with root privileges. So it's easier to
397+
/// resolve kernel symbols when generating the profile JSON.
398+
///
399+
/// This form of symbolicating does not support file names, line numbers, or
400+
/// inline frames. It is intended for relatively "small" symbol tables for which
401+
/// an address lookup is fast.
394402
pub fn set_lib_symbol_table(&mut self, library: LibraryHandle, symbol_table: Arc<SymbolTable>) {
395403
self.global_libs.set_lib_symbol_table(library, symbol_table);
396404
}
@@ -598,11 +606,8 @@ impl Profile {
598606
(InternalFrameVariant::Label, name)
599607
}
600608
InternalFrameAddress::InLib(address, lib_index) => {
601-
let lib = self.global_libs.get_lib(lib_index).unwrap();
602-
let symbol = lib
603-
.symbol_table
604-
.as_deref()
605-
.and_then(|symbol_table| symbol_table.lookup(address));
609+
let lib_symbol_table = self.global_libs.get_lib_symbol_table(lib_index);
610+
let symbol = lib_symbol_table.and_then(|symbol_table| symbol_table.lookup(address));
606611
let (native_symbol, name) = match symbol {
607612
Some(symbol) => {
608613
let (native_symbol, name) = thread

fxprof-processed-profile/tests/integration_tests/main.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,10 @@ fn profile_without_js() {
142142
debug_path: "/usr/lib/x86_64-linux-gnu/libc.so.6".to_string(),
143143
debug_id: DebugId::from_breakpad("1629FCF0BE5C8860C0E1ADF03B0048FB0").unwrap(),
144144
arch: None,
145-
symbol_table: Some(Arc::new(SymbolTable::new(vec![
145+
});
146+
profile.set_lib_symbol_table(
147+
libc_handle,
148+
Arc::new(SymbolTable::new(vec![
146149
Symbol {
147150
address: 1700001,
148151
size: Some(180),
@@ -158,8 +161,8 @@ fn profile_without_js() {
158161
size: Some(20),
159162
name: "libc_symbol_2".to_string(),
160163
},
161-
]))),
162-
});
164+
])),
165+
);
163166
profile.add_lib_mapping(
164167
process,
165168
libc_handle,
@@ -175,7 +178,6 @@ fn profile_without_js() {
175178
debug_path: "/home/mstange/code/dump_syms/target/release/dump_syms".to_string(),
176179
debug_id: DebugId::from_breakpad("5C0A0D51EA1980DF43F203B4525BE9BE0").unwrap(),
177180
arch: None,
178-
symbol_table: None,
179181
});
180182
profile.add_lib_mapping(
181183
process,

samply/src/linux_shared/converter.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1220,8 +1220,10 @@ where
12201220
name: dso_key.name().to_string(),
12211221
debug_name: dso_key.name().to_string(),
12221222
arch: None,
1223-
symbol_table,
12241223
});
1224+
if let Some(symbol_table) = symbol_table {
1225+
self.profile.set_lib_symbol_table(lib_handle, symbol_table);
1226+
}
12251227
let end_address = base_address + len;
12261228
self.profile
12271229
.add_kernel_lib_mapping(lib_handle, base_address, end_address, 0);
@@ -1390,8 +1392,9 @@ where
13901392
debug_name: name.clone(),
13911393
name,
13921394
arch: None,
1393-
symbol_table: Some(symbol_table.symbol_table.clone()),
13941395
});
1396+
self.profile
1397+
.set_lib_symbol_table(lib_handle, symbol_table.symbol_table.clone());
13951398
let info = match symbol_table.art_info {
13961399
Some(AndroidArtInfo::LibArt) => LibMappingInfo::new_libart_mapping(lib_handle),
13971400
Some(AndroidArtInfo::JavaFrame) => {
@@ -1556,7 +1559,6 @@ where
15561559
debug_name: name.clone(),
15571560
name,
15581561
arch: None,
1559-
symbol_table: None,
15601562
});
15611563
process.add_regular_lib_mapping(
15621564
timestamp,
@@ -1607,7 +1609,6 @@ where
16071609
debug_name: name.to_owned(),
16081610
name: name.to_owned(),
16091611
arch: None,
1610-
symbol_table: None,
16111612
})
16121613
}
16131614

samply/src/mac/task_profiler.rs

-1
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,6 @@ impl TaskProfiler {
462462
debug_id: lib.debug_id.unwrap(),
463463
code_id: lib.code_id.map(|ci| ci.to_string()),
464464
arch: lib.arch.map(ToOwned::to_owned),
465-
symbol_table: None,
466465
});
467466
self.lib_mapping_ops.push(
468467
now_mono,

samply/src/shared/perf_map.rs

-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ pub fn try_load_perf_map(
6262
debug_id: DebugId::nil(),
6363
code_id: None,
6464
arch: None,
65-
symbol_table: None,
6665
});
6766

6867
let mut symbols = Vec::new();

samply/src/shared/synthetic_jit_library.rs

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ impl SyntheticJitLibrary {
3131
debug_id: DebugId::nil(),
3232
code_id: None,
3333
arch: None,
34-
symbol_table: None,
3534
});
3635
let recycler = if allow_recycling {
3736
Some(FastHashMap::default())

samply/src/shared/utils.rs

-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,5 @@ pub fn lib_handle_for_jitdump(
4949
debug_id,
5050
code_id: Some(code_id.to_string()),
5151
arch: None,
52-
symbol_table: None,
5352
})
5453
}

samply/src/windows/profile_context.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1476,7 +1476,6 @@ impl ProfileContext {
14761476
debug_id,
14771477
code_id: code_id.map(|ci| ci.to_string()),
14781478
arch: Some(self.arch.to_owned()),
1479-
symbol_table: None,
14801479
});
14811480

14821481
// attempt to categorize the library based on the path

0 commit comments

Comments
 (0)