Skip to content

Commit 8cef052

Browse files
authored
Merge pull request #202 from mstange/precog-upstream
2 parents 6cc0ae7 + b31638e commit 8cef052

File tree

18 files changed

+619
-12
lines changed

18 files changed

+619
-12
lines changed

‎fxprof-processed-profile/src/frame_table.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl FrameTable {
3333
resource_table: &mut ResourceTable,
3434
func_table: &mut FuncTable,
3535
native_symbol_table: &mut NativeSymbols,
36-
global_libs: &GlobalLibTable,
36+
global_libs: &mut GlobalLibTable,
3737
frame: InternalFrame,
3838
) -> usize {
3939
let addresses = &mut self.addresses;
@@ -73,6 +73,9 @@ impl FrameTable {
7373
(Some(native_symbol), name_string_index)
7474
}
7575
None => {
76+
// This isn't in the pre-provided symbol table, and we know it's in a library.
77+
global_libs.add_lib_used_rva(lib_index, address);
78+
7679
let location_string = format!("0x{address:x}");
7780
(None, string_table.index_for_string(&location_string))
7881
}

‎fxprof-processed-profile/src/global_lib_table.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::collections::BTreeSet;
12
use std::sync::Arc;
23

34
use serde::ser::{Serialize, Serializer};
@@ -14,6 +15,12 @@ pub struct GlobalLibTable {
1415
used_libs: Vec<LibraryHandle>, // append-only for stable GlobalLibIndexes
1516
lib_map: FastHashMap<LibraryInfo, LibraryHandle>,
1617
used_lib_map: FastHashMap<LibraryHandle, GlobalLibIndex>,
18+
/// We keep track of RVA addresses that exist in frames that are assigned to this
19+
/// library, so that we can potentially provide symbolication info ahead of time.
20+
/// This is here instead of in `LibraryInfo` because we don't want to serialize it,
21+
/// and because it's currently a hack.
22+
/// Indexed by GlobalLibIndex.0, i.e. a parallel array to `used_libs`.
23+
used_libs_seen_rvas: Vec<BTreeSet<u32>>,
1724
}
1825

1926
impl GlobalLibTable {
@@ -23,6 +30,7 @@ impl GlobalLibTable {
2330
used_libs: Vec::new(),
2431
lib_map: FastHashMap::default(),
2532
used_lib_map: FastHashMap::default(),
33+
used_libs_seen_rvas: Vec::new(),
2634
}
2735
}
2836

@@ -44,6 +52,7 @@ impl GlobalLibTable {
4452
*self.used_lib_map.entry(lib_handle).or_insert_with(|| {
4553
let index = GlobalLibIndex(used_libs.len());
4654
used_libs.push(lib_handle);
55+
self.used_libs_seen_rvas.push(BTreeSet::new());
4756
index
4857
})
4958
}
@@ -52,6 +61,17 @@ impl GlobalLibTable {
5261
let handle = self.used_libs.get(index.0)?;
5362
self.all_libs.get(handle.0)
5463
}
64+
65+
pub fn add_lib_used_rva(&mut self, index: GlobalLibIndex, address: u32) {
66+
self.used_libs_seen_rvas[index.0].insert(address);
67+
}
68+
69+
pub fn lib_used_rva_iter(&self) -> UsedLibraryAddressesIterator {
70+
UsedLibraryAddressesIterator {
71+
next_used_lib_index: 0,
72+
global_lib_table: self,
73+
}
74+
}
5575
}
5676

5777
impl Serialize for GlobalLibTable {
@@ -74,3 +94,26 @@ impl Serialize for GlobalLibIndex {
7494
/// The handle for a library, obtained from [`Profile::add_lib`](crate::Profile::add_lib).
7595
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
7696
pub struct LibraryHandle(usize);
97+
98+
pub struct UsedLibraryAddressesIterator<'a> {
99+
next_used_lib_index: usize,
100+
global_lib_table: &'a GlobalLibTable,
101+
}
102+
103+
impl<'a> Iterator for UsedLibraryAddressesIterator<'a> {
104+
type Item = (&'a LibraryInfo, &'a BTreeSet<u32>);
105+
106+
fn next(&mut self) -> Option<Self::Item> {
107+
let rvas = self
108+
.global_lib_table
109+
.used_libs_seen_rvas
110+
.get(self.next_used_lib_index)?;
111+
112+
let lib_handle = self.global_lib_table.used_libs[self.next_used_lib_index];
113+
let info = &self.global_lib_table.all_libs[lib_handle.0];
114+
115+
self.next_used_lib_index += 1;
116+
117+
Some((info, rvas))
118+
}
119+
}

‎fxprof-processed-profile/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pub use category_color::CategoryColor;
6363
pub use counters::CounterHandle;
6464
pub use cpu_delta::CpuDelta;
6565
pub use frame::{Frame, FrameFlags, FrameInfo};
66-
pub use global_lib_table::LibraryHandle;
66+
pub use global_lib_table::{LibraryHandle, UsedLibraryAddressesIterator};
6767
pub use lib_mappings::LibMappings;
6868
pub use library_info::{LibraryInfo, Symbol, SymbolTable};
6969
pub use markers::*;

‎fxprof-processed-profile/src/profile.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::cpu_delta::CpuDelta;
1111
use crate::fast_hash_map::FastHashMap;
1212
use crate::frame::{Frame, FrameInfo};
1313
use crate::frame_table::{InternalFrame, InternalFrameLocation};
14-
use crate::global_lib_table::{GlobalLibTable, LibraryHandle};
14+
use crate::global_lib_table::{GlobalLibTable, LibraryHandle, UsedLibraryAddressesIterator};
1515
use crate::lib_mappings::LibMappings;
1616
use crate::library_info::LibraryInfo;
1717
use crate::process::{Process, ThreadHandle};
@@ -601,7 +601,7 @@ impl Profile {
601601
flags: frame_info.flags,
602602
category_pair: frame_info.category_pair,
603603
};
604-
let frame_index = thread.frame_index_for_frame(internal_frame, &self.global_libs);
604+
let frame_index = thread.frame_index_for_frame(internal_frame, &mut self.global_libs);
605605
prefix =
606606
Some(thread.stack_index_for_stack(prefix, frame_index, frame_info.category_pair));
607607
}
@@ -665,6 +665,10 @@ impl Profile {
665665
fn contains_js_function(&self) -> bool {
666666
self.threads.iter().any(|t| t.contains_js_function())
667667
}
668+
669+
pub fn lib_used_rva_iter(&self) -> UsedLibraryAddressesIterator {
670+
self.global_libs.lib_used_rva_iter()
671+
}
668672
}
669673

670674
impl Serialize for Profile {

‎fxprof-processed-profile/src/thread.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ impl Thread {
9797
pub fn frame_index_for_frame(
9898
&mut self,
9999
frame: InternalFrame,
100-
global_libs: &GlobalLibTable,
100+
global_libs: &mut GlobalLibTable,
101101
) -> usize {
102102
self.frame_table.index_for_frame(
103103
&mut self.string_table,

‎samply-symbols/src/lib.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ pub use crate::shared::{
256256
MultiArchDisambiguator, OptionallySendFuture, PeCodeId, SourceFilePath, SymbolInfo,
257257
SyncAddressInfo,
258258
};
259-
pub use crate::symbol_map::SymbolMap;
259+
pub use crate::symbol_map::{SymbolMap, SymbolMapTrait};
260260

261261
pub struct SymbolManager<H: FileAndPathHelper> {
262262
helper: Arc<H>,
@@ -304,6 +304,14 @@ where
304304
/// Obtain a symbol map for the library, given the (partial) `LibraryInfo`.
305305
/// At least the debug_id has to be given.
306306
pub async fn load_symbol_map(&self, library_info: &LibraryInfo) -> Result<SymbolMap<H>, Error> {
307+
if let Some((fl, symbol_map)) = self
308+
.helper()
309+
.as_ref()
310+
.get_symbol_map_for_library(library_info)
311+
{
312+
return Ok(SymbolMap::with_symbol_map_trait(fl, symbol_map));
313+
}
314+
307315
let debug_id = match library_info.debug_id {
308316
Some(debug_id) => debug_id,
309317
None => return Err(Error::NotEnoughInformationToIdentifySymbolMap),

‎samply-symbols/src/shared.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::future::Future;
55
use std::marker::PhantomData;
66
use std::ops::{Deref, Range};
77
use std::str::FromStr;
8+
use std::sync::Arc;
89

910
#[cfg(feature = "partial_read_stats")]
1011
use bitvec::{bitvec, prelude::BitVec};
@@ -14,6 +15,7 @@ use object::FileFlags;
1415
use uuid::Uuid;
1516

1617
use crate::mapped_path::MappedPath;
18+
use crate::symbol_map::SymbolMapTrait;
1719

1820
pub type FileAndPathHelperError = Box<dyn std::error::Error + Send + Sync + 'static>;
1921
pub type FileAndPathHelperResult<T> = std::result::Result<T, FileAndPathHelperError>;
@@ -402,6 +404,14 @@ pub trait FileAndPathHelper {
402404
&self,
403405
location: Self::FL,
404406
) -> std::pin::Pin<Box<dyn OptionallySendFuture<Output = FileAndPathHelperResult<Self::F>> + '_>>;
407+
408+
/// Ask the helper to return a SymbolMap if it happens to have one available already.
409+
fn get_symbol_map_for_library(
410+
&self,
411+
_info: &LibraryInfo,
412+
) -> Option<(Self::FL, Arc<dyn SymbolMapTrait + Send + Sync>)> {
413+
None
414+
}
405415
}
406416

407417
/// Provides synchronous access to the raw bytes of a file.

‎samply-symbols/src/symbol_map.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub trait GetInnerSymbolMapWithLookupFramesExt<FC> {
4242
enum InnerSymbolMap<FC> {
4343
WithoutAddFile(Box<dyn GetInnerSymbolMap + Send + Sync>),
4444
WithAddFile(Box<dyn GetInnerSymbolMapWithLookupFramesExt<FC> + Send + Sync>),
45+
Direct(Arc<dyn SymbolMapTrait + Send + Sync>),
4546
}
4647

4748
pub struct SymbolMap<H: FileAndPathHelper> {
@@ -74,10 +75,22 @@ impl<H: FileAndPathHelper> SymbolMap<H> {
7475
}
7576
}
7677

78+
pub fn with_symbol_map_trait(
79+
debug_file_location: H::FL,
80+
inner: Arc<dyn SymbolMapTrait + Send + Sync>,
81+
) -> Self {
82+
Self {
83+
debug_file_location,
84+
inner: InnerSymbolMap::Direct(inner),
85+
helper: None,
86+
}
87+
}
88+
7789
fn inner(&self) -> &dyn SymbolMapTrait {
7890
match &self.inner {
7991
InnerSymbolMap::WithoutAddFile(inner) => inner.get_inner_symbol_map(),
8092
InnerSymbolMap::WithAddFile(inner) => inner.get_inner_symbol_map().get_as_symbol_map(),
93+
InnerSymbolMap::Direct(inner) => inner.as_ref(),
8194
}
8295
}
8396

@@ -111,7 +124,7 @@ impl<H: FileAndPathHelper> SymbolMap<H> {
111124
frames: Some(frames),
112125
});
113126
}
114-
(None, _) | (_, InnerSymbolMap::WithoutAddFile(_)) => {
127+
(None, _) | (_, InnerSymbolMap::WithoutAddFile(_)) | (_, InnerSymbolMap::Direct(_)) => {
115128
return Some(AddressInfo {
116129
symbol,
117130
frames: None,
@@ -168,7 +181,7 @@ impl<H: FileAndPathHelper> SymbolMap<H> {
168181
) -> Option<Vec<FrameDebugInfo>> {
169182
let helper = self.helper.as_deref()?;
170183
let inner = match &self.inner {
171-
InnerSymbolMap::WithoutAddFile(_) => return None,
184+
InnerSymbolMap::WithoutAddFile(_) | InnerSymbolMap::Direct(_) => return None,
172185
InnerSymbolMap::WithAddFile(inner) => inner.get_inner_symbol_map(),
173186
};
174187

‎samply/src/linux/profiler.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ pub fn start_recording(
9797
let interval = recording_props.interval;
9898
let time_limit = recording_props.time_limit;
9999
let observer_thread = thread::spawn(move || {
100+
let unstable_presymbolicate = profile_creation_props.unstable_presymbolicate;
100101
let mut converter = make_converter(interval, profile_creation_props);
101102

102103
// Wait for the initial pid to profile.
@@ -128,6 +129,7 @@ pub fn start_recording(
128129
profile_another_pid_request_receiver,
129130
profile_another_pid_reply_sender,
130131
stop_receiver,
132+
unstable_presymbolicate,
131133
);
132134
});
133135

@@ -265,6 +267,7 @@ fn start_profiling_pid(
265267
move || {
266268
let interval = recording_props.interval;
267269
let time_limit = recording_props.time_limit;
270+
let unstable_presymbolicate = profile_creation_props.unstable_presymbolicate;
268271
let mut converter = make_converter(interval, profile_creation_props);
269272
let SamplerRequest::StartProfilingAnotherProcess(pid, attach_mode) =
270273
profile_another_pid_request_receiver.recv().unwrap()
@@ -285,6 +288,7 @@ fn start_profiling_pid(
285288
profile_another_pid_request_receiver,
286289
profile_another_pid_reply_sender,
287290
ctrl_c_receiver,
291+
unstable_presymbolicate,
288292
)
289293
}
290294
});
@@ -532,6 +536,7 @@ enum SamplerRequest {
532536
StopProfilingOncePerfEventsExhausted,
533537
}
534538

539+
#[allow(clippy::too_many_arguments)]
535540
fn run_profiler(
536541
mut perf: PerfGroup,
537542
mut converter: Converter<
@@ -542,6 +547,7 @@ fn run_profiler(
542547
more_processes_request_receiver: Receiver<SamplerRequest>,
543548
more_processes_reply_sender: Sender<bool>,
544549
mut stop_receiver: oneshot::Receiver<()>,
550+
unstable_presymbolicate: bool,
545551
) {
546552
// eprintln!("Running...");
547553

@@ -667,9 +673,18 @@ fn run_profiler(
667673

668674
let profile = converter.finish();
669675

670-
let output_file = File::create(output_filename).unwrap();
671-
let writer = BufWriter::new(output_file);
672-
serde_json::to_writer(writer, &profile).expect("Couldn't write JSON");
676+
{
677+
let output_file = File::create(output_filename).unwrap();
678+
let writer = BufWriter::new(output_file);
679+
serde_json::to_writer(writer, &profile).expect("Couldn't write JSON");
680+
}
681+
682+
if unstable_presymbolicate {
683+
crate::shared::symbol_precog::presymbolicate(
684+
&profile,
685+
&output_filename.with_extension("syms.json"),
686+
);
687+
}
673688
}
674689

675690
pub fn read_string_lossy<P: AsRef<Path>>(path: P) -> std::io::Result<String> {

‎samply/src/mac/profiler.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ pub fn start_recording(
8585
..profile_creation_props
8686
};
8787

88+
let unstable_presymbolicate = profile_creation_props.unstable_presymbolicate;
89+
8890
let (task_sender, task_receiver) = unbounded();
8991

9092
let sampler_thread = thread::spawn(move || {
@@ -210,6 +212,13 @@ pub fn start_recording(
210212
to_writer(writer, &profile).expect("Couldn't write JSON");
211213
}
212214

215+
if unstable_presymbolicate {
216+
crate::shared::symbol_precog::presymbolicate(
217+
&profile,
218+
&output_file.with_extension("syms.json"),
219+
);
220+
}
221+
213222
if let Some(server_props) = server_props {
214223
let libinfo_map = crate::profile_json_preparse::parse_libinfo_map_from_profile_file(
215224
File::open(&output_file).expect("Couldn't open file we just wrote"),

0 commit comments

Comments
 (0)