Skip to content

Commit 2920aa3

Browse files
authored
simpleperf importer: Add categories for ART tiers (#544)
Example profiles: https://share.firefox.dev/4j434Y9 https://share.firefox.dev/44lvhVQ
2 parents 23d3e06 + d817472 commit 2920aa3

File tree

1 file changed

+138
-92
lines changed

1 file changed

+138
-92
lines changed

samply/src/linux_shared/converter.rs

+138-92
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,7 @@ where
7979
event_names: Vec<String>,
8080
kernel_symbols: Option<KernelSymbols>,
8181
kernel_image_mapping: Option<KernelImageMapping>,
82-
simpleperf_symbol_tables_user: HashMap<Vec<u8>, SymbolTableFromSimpleperf>,
83-
simpleperf_symbol_tables_jit: HashMap<Vec<u8>, Vec<SimpleperfSymbol>>,
84-
simpleperf_symbol_tables_kernel_image: Option<Vec<SimpleperfSymbol>>,
85-
simpleperf_symbol_tables_kernel_modules: HashMap<Vec<u8>, SymbolTableFromSimpleperf>,
86-
simpleperf_jit_app_cache_library: SyntheticJitLibrary,
82+
simpleperf: SimpleperfConverterData,
8783
pe_mappings: PeMappings,
8884
jit_category_manager: JitCategoryManager,
8985
arg_count_to_include_in_process_name: usize,
@@ -113,6 +109,19 @@ where
113109
should_emit_cswitch_markers: bool,
114110
}
115111

112+
struct SimpleperfConverterData {
113+
symbol_tables: SimpleperfSymbolTables,
114+
jit_app_cache_library: SyntheticJitLibrary,
115+
}
116+
117+
#[derive(Default)]
118+
struct SimpleperfSymbolTables {
119+
user: HashMap<Vec<u8>, SymbolTableFromSimpleperf>,
120+
jit: HashMap<Vec<u8>, Vec<SimpleperfSymbol>>,
121+
kernel_image: Option<Vec<SimpleperfSymbol>>,
122+
kernel_modules: HashMap<Vec<u8>, SymbolTableFromSimpleperf>,
123+
}
124+
116125
const DEFAULT_OFF_CPU_SAMPLING_INTERVAL_NS: u64 = 1_000_000; // 1ms
117126

118127
impl<U> Converter<U>
@@ -150,81 +159,6 @@ where
150159
};
151160
let kernel_symbols = KernelSymbols::new_for_running_kernel().ok();
152161

153-
let mut simpleperf_symbol_tables_user = HashMap::new();
154-
let mut simpleperf_symbol_tables_jit = HashMap::new();
155-
let mut simpleperf_symbol_tables_kernel_image = None;
156-
let mut simpleperf_symbol_tables_kernel_modules = HashMap::new();
157-
let simpleperf_jit_category: SubcategoryHandle = profile
158-
.handle_for_category(Category("JIT app cache", CategoryColor::Green))
159-
.into();
160-
let allow_jit_function_recycling = profile_creation_props.reuse_threads;
161-
let simpleperf_jit_app_cache_library = SyntheticJitLibrary::new(
162-
"JIT app cache".to_string(),
163-
simpleperf_jit_category,
164-
&mut profile,
165-
allow_jit_function_recycling,
166-
);
167-
if let Some(simpleperf_symbol_tables) = simpleperf_symbol_tables {
168-
let dex_category: SubcategoryHandle = profile
169-
.handle_for_category(Category("DEX", CategoryColor::Green))
170-
.into();
171-
let oat_category: SubcategoryHandle = profile
172-
.handle_for_category(Category("OAT", CategoryColor::Green))
173-
.into();
174-
for f in simpleperf_symbol_tables {
175-
if f.r#type == DSO_KERNEL {
176-
simpleperf_symbol_tables_kernel_image = Some(f.symbol);
177-
continue;
178-
}
179-
180-
let path = f.path.clone().into_bytes();
181-
if is_simpleperf_jit_path(&f.path) {
182-
simpleperf_symbol_tables_jit.insert(path, f.symbol);
183-
continue;
184-
}
185-
186-
let is_jit = false;
187-
let (category, art_info) = if f.path.ends_with(".oat") {
188-
(Some(oat_category), Some(AndroidArtInfo::JavaFrame))
189-
} else if f.r#type == DSO_DEX_FILE || f.path.ends_with(".odex") || is_jit {
190-
(Some(dex_category), Some(AndroidArtInfo::JavaFrame))
191-
} else if f.path.ends_with("libart.so") {
192-
(None, Some(AndroidArtInfo::LibArt))
193-
} else {
194-
(None, None)
195-
};
196-
197-
let (min_vaddr, file_offset_of_min_vaddr_in_elf_file) = match f.type_specific_msg {
198-
Some(SimpleperfTypeSpecificInfo::ElfFile(elf)) => {
199-
(f.min_vaddr, Some(elf.file_offset_of_min_vaddr))
200-
}
201-
_ => (f.min_vaddr, None),
202-
};
203-
let symbols: Vec<_> = f
204-
.symbol
205-
.iter()
206-
.map(|s| fxprof_processed_profile::Symbol {
207-
address: s.vaddr as u32,
208-
size: Some(s.len),
209-
name: demangle_any(&s.name),
210-
})
211-
.collect();
212-
let symbol_table = SymbolTable::new(symbols);
213-
let symbol_table = SymbolTableFromSimpleperf {
214-
file_offset_of_min_vaddr_in_elf_file,
215-
min_vaddr,
216-
symbol_table: Arc::new(symbol_table),
217-
category,
218-
art_info,
219-
};
220-
if f.r#type == DSO_KERNEL_MODULE {
221-
simpleperf_symbol_tables_kernel_modules.insert(path, symbol_table);
222-
} else {
223-
simpleperf_symbol_tables_user.insert(path, symbol_table);
224-
}
225-
}
226-
}
227-
228162
let timestamp_converter = TimestampConverter {
229163
reference_raw: first_sample_time,
230164
raw_to_ns_factor: 1,
@@ -237,6 +171,12 @@ where
237171
None
238172
};
239173

174+
let simpleperf = SimpleperfConverterData::new(
175+
simpleperf_symbol_tables,
176+
profile_creation_props,
177+
&mut profile,
178+
);
179+
240180
Self {
241181
profile,
242182
cache,
@@ -259,11 +199,7 @@ where
259199
event_names: interpretation.event_names,
260200
kernel_symbols,
261201
kernel_image_mapping: None,
262-
simpleperf_symbol_tables_user,
263-
simpleperf_symbol_tables_jit,
264-
simpleperf_symbol_tables_kernel_image,
265-
simpleperf_symbol_tables_kernel_modules,
266-
simpleperf_jit_app_cache_library,
202+
simpleperf,
267203
pe_mappings: PeMappings::new(),
268204
jit_category_manager: JitCategoryManager::new(),
269205
fold_recursive_prefix: profile_creation_props.fold_recursive_prefix,
@@ -279,7 +215,8 @@ where
279215

280216
pub fn finish(mut self) -> Profile {
281217
let mut profile = self.profile;
282-
self.simpleperf_jit_app_cache_library
218+
self.simpleperf
219+
.jit_app_cache_library
283220
.finish_and_set_symbol_table(&mut profile);
284221
self.processes.finish(
285222
&mut profile,
@@ -823,7 +760,7 @@ where
823760
}
824761

825762
const PROT_EXEC: u32 = 0b100;
826-
if e.protection & PROT_EXEC == 0 && !self.simpleperf_symbol_tables_user.contains_key(&*path)
763+
if e.protection & PROT_EXEC == 0 && !self.simpleperf.symbol_tables.user.contains_key(&*path)
827764
{
828765
// Ignore non-executable mappings.
829766
// Don't ignore mappings that simpleperf found symbols for, even if they're
@@ -1246,7 +1183,7 @@ where
12461183
Some(kernel_symbols.symbol_table.clone())
12471184
}
12481185
_ => {
1249-
if let Some(symbols) = self.simpleperf_symbol_tables_kernel_image.take() {
1186+
if let Some(symbols) = self.simpleperf.symbol_tables.kernel_image.take() {
12501187
let symbols: Vec<_> = symbols
12511188
.into_iter()
12521189
.filter_map(|s| {
@@ -1267,7 +1204,9 @@ where
12671204
}
12681205
}
12691206
} else {
1270-
self.simpleperf_symbol_tables_kernel_modules
1207+
self.simpleperf
1208+
.symbol_tables
1209+
.kernel_modules
12711210
.get(path_slice)
12721211
.map(|s| s.symbol_table.clone())
12731212
};
@@ -1335,7 +1274,7 @@ where
13351274
.unwrap_or_else(|| (format!("jit_fun_{address:x}"), mapping_size as u32));
13361275

13371276
let process = self.processes.get_by_pid(e.pid, &mut self.profile);
1338-
let synthetic_lib = &mut self.simpleperf_jit_app_cache_library;
1277+
let synthetic_lib = &mut self.simpleperf.jit_app_cache_library;
13391278
let info = LibMappingInfo::new_java_mapping(
13401279
synthetic_lib.lib_handle(),
13411280
Some(synthetic_lib.default_category()),
@@ -1348,7 +1287,7 @@ where
13481287
path_slice: &[u8],
13491288
start_avma: u64,
13501289
) -> Option<(String, u32)> {
1351-
let symbols = self.simpleperf_symbol_tables_jit.get(path_slice)?;
1290+
let symbols = self.simpleperf.symbol_tables.jit.get(path_slice)?;
13521291
let index = symbols
13531292
.binary_search_by_key(&start_avma, |sym| sym.vaddr)
13541293
.ok()?;
@@ -1413,7 +1352,7 @@ where
14131352

14141353
// Case 1: There are symbols in the file, if we are importing a perf.data file
14151354
// that was recorded with simpleperf.
1416-
if let Some(symbol_table) = self.simpleperf_symbol_tables_user.get(original_path) {
1355+
if let Some(symbol_table) = self.simpleperf.symbol_tables.user.get(original_path) {
14171356
let relative_address_at_start = if let Some(file_offset_of_min_vaddr) =
14181357
&symbol_table.file_offset_of_min_vaddr_in_elf_file
14191358
{
@@ -1754,6 +1693,113 @@ where
17541693
}
17551694
}
17561695

1696+
impl SimpleperfConverterData {
1697+
pub fn new(
1698+
symbol_tables: Option<Vec<SimpleperfFileRecord>>,
1699+
profile_creation_props: &ProfileCreationProps,
1700+
profile: &mut Profile,
1701+
) -> Self {
1702+
// See https://source.android.com/docs/core/runtime/jit-compiler#architectural-overview for the
1703+
// ART JIT architecture and the tiers.
1704+
1705+
let jit_category: SubcategoryHandle = profile
1706+
.handle_for_category(Category("ART JIT", CategoryColor::Blue))
1707+
.into();
1708+
let allow_jit_function_recycling = profile_creation_props.reuse_threads;
1709+
let jit_app_cache_library = SyntheticJitLibrary::new(
1710+
"JIT app cache".to_string(),
1711+
jit_category,
1712+
profile,
1713+
allow_jit_function_recycling,
1714+
);
1715+
1716+
Self {
1717+
symbol_tables: symbol_tables
1718+
.map(|st| SimpleperfSymbolTables::new(st, profile))
1719+
.unwrap_or_default(),
1720+
jit_app_cache_library,
1721+
}
1722+
}
1723+
}
1724+
1725+
impl SimpleperfSymbolTables {
1726+
pub fn new(symbol_tables: Vec<SimpleperfFileRecord>, profile: &mut Profile) -> Self {
1727+
let interpreter_category: SubcategoryHandle = profile
1728+
.handle_for_category(Category("ART Interpreter", CategoryColor::Red))
1729+
.into();
1730+
let oat_category: SubcategoryHandle = profile
1731+
.handle_for_category(Category(
1732+
"ART ahead-of-time compiled DEX (OAT)",
1733+
CategoryColor::Green,
1734+
))
1735+
.into();
1736+
1737+
let mut symbol_tables_user = HashMap::new();
1738+
let mut symbol_tables_jit = HashMap::new();
1739+
let mut symbol_tables_kernel_image = None;
1740+
let mut symbol_tables_kernel_modules = HashMap::new();
1741+
1742+
for f in symbol_tables {
1743+
if f.r#type == DSO_KERNEL {
1744+
symbol_tables_kernel_image = Some(f.symbol);
1745+
continue;
1746+
}
1747+
1748+
let path = f.path.clone().into_bytes();
1749+
if is_simpleperf_jit_path(&f.path) {
1750+
symbol_tables_jit.insert(path, f.symbol);
1751+
continue;
1752+
}
1753+
1754+
let (category, art_info) = if f.path.ends_with(".oat") || f.path.ends_with(".odex") {
1755+
(Some(oat_category), Some(AndroidArtInfo::JavaFrame))
1756+
} else if f.r#type == DSO_DEX_FILE {
1757+
(Some(interpreter_category), Some(AndroidArtInfo::JavaFrame))
1758+
} else if f.path.ends_with("libart.so") {
1759+
(None, Some(AndroidArtInfo::LibArt))
1760+
} else {
1761+
(None, None)
1762+
};
1763+
1764+
let (min_vaddr, file_offset_of_min_vaddr_in_elf_file) = match f.type_specific_msg {
1765+
Some(SimpleperfTypeSpecificInfo::ElfFile(elf)) => {
1766+
(f.min_vaddr, Some(elf.file_offset_of_min_vaddr))
1767+
}
1768+
_ => (f.min_vaddr, None),
1769+
};
1770+
let symbols: Vec<_> = f
1771+
.symbol
1772+
.iter()
1773+
.map(|s| fxprof_processed_profile::Symbol {
1774+
address: s.vaddr as u32,
1775+
size: Some(s.len),
1776+
name: demangle_any(&s.name),
1777+
})
1778+
.collect();
1779+
let symbol_table = SymbolTable::new(symbols);
1780+
let symbol_table = SymbolTableFromSimpleperf {
1781+
file_offset_of_min_vaddr_in_elf_file,
1782+
min_vaddr,
1783+
symbol_table: Arc::new(symbol_table),
1784+
category,
1785+
art_info,
1786+
};
1787+
if f.r#type == DSO_KERNEL_MODULE {
1788+
symbol_tables_kernel_modules.insert(path, symbol_table);
1789+
} else {
1790+
symbol_tables_user.insert(path, symbol_table);
1791+
}
1792+
}
1793+
1794+
Self {
1795+
user: symbol_tables_user,
1796+
jit: symbol_tables_jit,
1797+
kernel_image: symbol_tables_kernel_image,
1798+
kernel_modules: symbol_tables_kernel_modules,
1799+
}
1800+
}
1801+
}
1802+
17571803
// #[test]
17581804
// fn test_my_jit() {
17591805
// let data = std::fs::read("/Users/mstange/Downloads/jitted-123175-0-fixed.so").unwrap();

0 commit comments

Comments
 (0)