Skip to content

Commit 6161b8f

Browse files
authored
feat: bump MAX_UNWIND_SHARDS from 64 to 512, widen shard_id u8 → u16 (#79)
1 parent 52cacc9 commit 6161b8f

File tree

6 files changed

+23
-23
lines changed

6 files changed

+23
-23
lines changed

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ sudo tests/run_e2e.sh --filter dwarf
301301
|---|---|---|
302302
| Max frame depth | 165 (tail-call) / 21 (legacy) | Kernel 33 tail-call limit; legacy for kprobe/uprobe |
303303
| Mappings per process | 8 (`MAX_PROC_MAPS`) | eBPF array size limit |
304-
| Unwind shards | 8 (`MAX_UNWIND_SHARDS`) | Max 8 unique binaries with tables loaded |
304+
| Unwind shards | 512 (`MAX_UNWIND_SHARDS`) | Max unique binaries with DWARF tables loaded |
305305
| Entries per shard | 65,536 (`MAX_SHARD_ENTRIES`) | Very large binaries truncated |
306306
| CFA registers | RSP, RBP only | Other registers skipped |
307307
| DWARF expressions | Unsupported | Except PLT-stub and signal-frame patterns |

profile-bee-common/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,15 @@ pub const MAX_PROC_MAPS: usize = 8;
122122

123123
/// Maximum number of inner shard maps in the outer ArrayOfMaps.
124124
/// With array-of-maps, unused slots cost nothing (no pre-allocated kernel memory).
125-
pub const MAX_UNWIND_SHARDS: usize = 64;
125+
pub const MAX_UNWIND_SHARDS: usize = 512;
126126
/// Maximum unwind entries per inner shard map.
127127
/// With array-of-maps, each inner map is sized to the actual binary's table,
128128
/// but we need an upper bound for the binary search depth (17 iterations covers 2^17 = 128K).
129129
pub const MAX_SHARD_ENTRIES: u32 = 131_072;
130130
/// Binary search iterations needed: ceil(log2(MAX_SHARD_ENTRIES)) = 17
131131
pub const MAX_BIN_SEARCH_DEPTH: u32 = 17;
132132
/// Sentinel value: no shard assigned to this mapping
133-
pub const SHARD_NONE: u8 = 0xFF;
133+
pub const SHARD_NONE: u16 = 0xFFFF;
134134

135135
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
136136
#[repr(C)]
@@ -145,8 +145,8 @@ pub struct ExecMapping {
145145
pub begin: u64,
146146
pub end: u64,
147147
pub load_bias: u64,
148-
pub shard_id: u8, // Which shard Array to search (0..MAX_UNWIND_SHARDS-1, or SHARD_NONE)
149-
pub _pad1: [u8; 3],
148+
pub shard_id: u16, // Which shard Array to search (0..MAX_UNWIND_SHARDS-1, or SHARD_NONE)
149+
pub _pad1: [u8; 2],
150150
pub table_count: u32, // Number of entries in this shard for this binary
151151
}
152152

profile-bee-ebpf/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ unsafe fn dwarf_unwind_one_frame(state: &mut DwarfUnwindState, proc_info: &ProcI
619619

620620
// Find the mapping that contains current_ip
621621
let mut found_mapping = false;
622-
let mut shard_id: u8 = SHARD_NONE;
622+
let mut shard_id: u16 = SHARD_NONE;
623623
let mut table_count: u32 = 0;
624624
let mut load_bias: u64 = 0;
625625

@@ -780,7 +780,7 @@ unsafe fn dwarf_copy_stack_regs(
780780

781781
// Find the mapping that contains current_ip
782782
let mut found_mapping = false;
783-
let mut shard_id: u8 = SHARD_NONE;
783+
let mut shard_id: u16 = SHARD_NONE;
784784
let mut table_count: u32 = 0;
785785
let mut load_bias: u64 = 0;
786786

@@ -1091,14 +1091,14 @@ unsafe fn try_fp_step(bp: u64) -> Option<(u64, u64)> {
10911091
/// This avoids verifier state explosion that occurs when the two lookups
10921092
/// are separated by typed wrapper code (MapDef::as_ptr() on the inner map).
10931093
#[inline(always)]
1094-
unsafe fn shard_lookup(shard_id: u8, idx: u32) -> Option<UnwindEntry> {
1094+
unsafe fn shard_lookup(shard_id: u16, idx: u32) -> Option<UnwindEntry> {
10951095
let entry: &UnwindEntry = UNWIND_SHARDS.get_value(shard_id as u32, &idx)?;
10961096
Some(*entry)
10971097
}
10981098

10991099
#[inline(always)]
11001100
unsafe fn binary_search_unwind_entry(
1101-
shard_id: u8,
1101+
shard_id: u16,
11021102
table_count: u32,
11031103
relative_pc: u32,
11041104
) -> Option<UnwindEntry> {

profile-bee/bin/profile-bee.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ enum PerfWork {
3838
/// Incremental DWARF unwind table update
3939
/// Each shard update is a (shard_id, entries) pair for a newly-loaded binary.
4040
struct DwarfRefreshUpdate {
41-
shard_updates: Vec<(u8, Arc<Vec<UnwindEntry>>)>, // (shard_id, entries) for new shards
41+
shard_updates: Vec<(u16, Arc<Vec<UnwindEntry>>)>, // (shard_id, entries) for new shards
4242
proc_info: Vec<(u32, ProcInfo)>,
4343
}
4444

@@ -1137,7 +1137,7 @@ fn dwarf_refresh_loop(
11371137
fn send_refresh(
11381138
manager: &DwarfUnwindManager,
11391139
tx: &mpsc::Sender<PerfWork>,
1140-
new_shard_ids: Vec<u8>,
1140+
new_shard_ids: Vec<u16>,
11411141
) -> Result<(), ()> {
11421142
// Only clone the new shards (not the entire binary_tables)
11431143
let mut shard_updates = Vec::new();

profile-bee/src/dwarf_unwind.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -392,14 +392,14 @@ pub struct DwarfUnwindManager {
392392
/// Per-process mapping information
393393
pub proc_info: HashMap<u32, ProcInfo>,
394394
/// Next shard_id to assign to a new binary
395-
next_shard_id: u8,
395+
next_shard_id: u16,
396396
/// Fast metadata-based cache for hot path lookups (stat-based)
397-
metadata_cache: HashMap<FileMetadata, u8>, // metadata -> shard_id
397+
metadata_cache: HashMap<FileMetadata, u16>, // metadata -> shard_id
398398
/// Cache of parsed ELF binary shard IDs, keyed by build ID
399399
/// Falls back to path-based caching for binaries without build IDs
400-
binary_cache: HashMap<BuildId, u8>, // build_id -> shard_id
400+
binary_cache: HashMap<BuildId, u16>, // build_id -> shard_id
401401
/// Fallback cache for binaries without build IDs (keyed by path)
402-
path_cache: HashMap<std::path::PathBuf, u8>, // path -> shard_id
402+
path_cache: HashMap<std::path::PathBuf, u16>, // path -> shard_id
403403
}
404404

405405
impl Default for DwarfUnwindManager {
@@ -445,12 +445,12 @@ impl DwarfUnwindManager {
445445

446446
/// Rescan a process's memory mappings and load any new ones.
447447
/// Returns the list of new shard IDs added (for incremental eBPF updates).
448-
pub fn refresh_process(&mut self, tgid: u32) -> Result<Vec<u8>, String> {
448+
pub fn refresh_process(&mut self, tgid: u32) -> Result<Vec<u16>, String> {
449449
// Track number of shards before update
450450
let old_len = self.binary_tables.len();
451451
self.scan_and_update(tgid)?;
452452
// Find new shards: those added after old_len
453-
let new_shard_ids: Vec<u8> = (old_len as u8..self.binary_tables.len() as u8).collect();
453+
let new_shard_ids: Vec<u16> = (old_len as u16..self.binary_tables.len() as u16).collect();
454454
Ok(new_shard_ids)
455455
}
456456

@@ -498,7 +498,7 @@ impl DwarfUnwindManager {
498498
end: 0,
499499
load_bias: 0,
500500
shard_id: SHARD_NONE,
501-
_pad1: [0; 3],
501+
_pad1: [0; 2],
502502
table_count: 0,
503503
}; MAX_PROC_MAPS],
504504
});
@@ -714,7 +714,7 @@ impl DwarfUnwindManager {
714714
end: end_addr,
715715
load_bias,
716716
shard_id,
717-
_pad1: [0; 3],
717+
_pad1: [0; 2],
718718
table_count,
719719
};
720720
proc_info.mapping_count += 1;

profile-bee/src/ebpf.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -497,13 +497,13 @@ impl EbpfProfiler {
497497
manager: &crate::dwarf_unwind::DwarfUnwindManager,
498498
) -> Result<(), anyhow::Error> {
499499
// Load all shards - using array indexing pattern
500-
let all_shard_ids: Vec<u8> = (0..manager.binary_tables.len() as u8).collect();
500+
let all_shard_ids: Vec<u16> = (0..manager.binary_tables.len() as u16).collect();
501501
self.update_dwarf_tables(manager, &all_shard_ids)
502502
}
503503

504504
/// Load a single shard's unwind entries by creating a new inner Array map
505505
/// and inserting it into the outer ArrayOfMaps at `shard_id`.
506-
fn load_shard(&mut self, shard_id: u8, entries: &[UnwindEntry]) -> Result<(), anyhow::Error> {
506+
fn load_shard(&mut self, shard_id: u16, entries: &[UnwindEntry]) -> Result<(), anyhow::Error> {
507507
if entries.is_empty() {
508508
return Ok(());
509509
}
@@ -540,7 +540,7 @@ impl EbpfProfiler {
540540
pub fn update_dwarf_tables(
541541
&mut self,
542542
manager: &crate::dwarf_unwind::DwarfUnwindManager,
543-
new_shard_ids: &[u8],
543+
new_shard_ids: &[u16],
544544
) -> Result<(), anyhow::Error> {
545545
if !new_shard_ids.is_empty() {
546546
let mut total_entries = 0usize;
@@ -695,7 +695,7 @@ fn batch_populate_inner_map(
695695
/// referenced from the outer ArrayOfMaps; once inserted there, the returned
696696
/// Array handle (and its FD) can be dropped (the kernel holds its own reference).
697697
pub fn create_and_populate_inner_map(
698-
shard_id: u8,
698+
shard_id: u16,
699699
entries: &[UnwindEntry],
700700
) -> Result<aya::maps::Array<MapData, UnwindEntryPod>, anyhow::Error> {
701701
if entries.is_empty() {

0 commit comments

Comments
 (0)