From 8e6703e606164c4d7532aaaa2a62a5ab34d5cb81 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Sun, 4 Oct 2026 22:55:06 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=87=87=E6=A0=B7=E6=A0=B7=E6=9C=AC?= =?UTF-8?q?=E8=AE=B0=E8=A1=A8=E4=BB=A3=E9=99=85=EF=BC=8C=E7=9B=B4=E6=96=B9?= =?UTF-8?q?=E5=9B=BE=E6=8C=89=E4=BB=A3=E9=99=85=E8=A7=A3=E6=9E=90=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E5=90=8D=E5=B9=B6=E8=AE=A2=E6=AD=A3=E5=B9=B6=E5=88=97?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_vm/src/vm/dispatch_loop.rs | 14 +++++--- crates/oxide_vm/src/vm_runtime.rs | 44 +++++++++++++------------ crates/oxide_vm/src/vm_state.rs | 8 ++--- 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/crates/oxide_vm/src/vm/dispatch_loop.rs b/crates/oxide_vm/src/vm/dispatch_loop.rs index 00ee2d3f..671c38c3 100644 --- a/crates/oxide_vm/src/vm/dispatch_loop.rs +++ b/crates/oxide_vm/src/vm/dispatch_loop.rs @@ -235,12 +235,16 @@ impl Vm { } // 指令周期采样:开启时(周期为 2 的幂)每 period 条指令记一条样本 - // (flat_id, pc, opcode, frames 深度),run 末聚合成 top-K 直方图; - // 关闭时仅这一条可预测分支,零写零分配。 + // (flat_id, pc, opcode, frames 深度, 表代际),run 末聚合成 top-K + // 直方图;关闭时仅这一条可预测分支,零写零分配。 if self.sampling.period != 0 && (steps & (self.sampling.period - 1)) == 0 { - self.sampling - .records - .push((self.active_flat_id, pc as u32, op as u8, self.frames.len() as u32)); + self.sampling.records.push(( + self.active_flat_id, + pc as u32, + op as u8, + self.frames.len() as u32, + self.active_table_gen, + )); } match op { diff --git a/crates/oxide_vm/src/vm_runtime.rs b/crates/oxide_vm/src/vm_runtime.rs index 90464cd9..f06de05f 100644 --- a/crates/oxide_vm/src/vm_runtime.rs +++ b/crates/oxide_vm/src/vm_runtime.rs @@ -711,11 +711,11 @@ impl Vm { result } - /// 按 flat_id 聚合采样记录并向 stderr 输出 top-K 热点直方图。 + /// 按 (flat_id, 表代际) 聚合采样记录并向 stderr 输出 top-K 热点直方图。 /// - /// 聚合键取 (flat_id, pc):样本数按 flat_id 汇总,top pc 取该 flat_id 下 - /// 样本数最多的字节码偏移(与反汇编 offset 列同单位)。函数名经当前表代际 - /// 平表解析(顶层为 0),未知 flat_id 输出 ``。 + /// 聚合键取 (flat_id, 表代际, pc):样本数按 (flat_id, 表代际) 汇总,top pc + /// 取该键下样本数最多的字节码偏移(与反汇编 offset 列同单位)。函数名经样本 + /// 记录表代际的平表解析(顶层为 0),未知 flat_id 输出 ``。 /// /// # 边界 /// - 采样关闭(`period == 0`)或无样本时直接返回,零输出零分配。 @@ -724,23 +724,24 @@ impl Vm { if self.sampling.period == 0 || self.sampling.records.is_empty() { return; } - // 聚合:(flat_id, pc) → 样本数与 opcode;flat_id → 最大 frames 深度。 - let mut pc_hist: HashMap<(u32, u32), (u64, u8)> = HashMap::new(); - let mut flat_max_frames: HashMap = HashMap::new(); - for &(flat, pc, op, frames) in &self.sampling.records { - let entry = pc_hist.entry((flat, pc)).or_insert((0, op)); + // 聚合:(flat_id, 表代际, pc) → 样本数与 opcode; + // (flat_id, 表代际) → 最大 frames 深度。 + let mut pc_hist: HashMap<(u32, u32, u32), (u64, u8)> = HashMap::new(); + let mut flat_max_frames: HashMap<(u32, u32), u32> = HashMap::new(); + for &(flat, pc, op, frames, gen) in &self.sampling.records { + let entry = pc_hist.entry((flat, gen, pc)).or_insert((0, op)); entry.0 += 1; - let top = flat_max_frames.entry(flat).or_insert(frames); + let top = flat_max_frames.entry((flat, gen)).or_insert(frames); if frames > *top { *top = frames; } } - // 按 flat_id 汇总样本数,降序排列后取 top-K。 - let mut flat_total: HashMap = HashMap::new(); - for (&(flat, _), &(count, _)) in &pc_hist { - *flat_total.entry(flat).or_insert(0) += count; + // 按 (flat_id, 表代际) 汇总样本数,降序排列后取 top-K。 + let mut flat_total: HashMap<(u32, u32), u64> = HashMap::new(); + for (&(flat, gen, _), &(count, _)) in &pc_hist { + *flat_total.entry((flat, gen)).or_insert(0) += count; } - let mut ranked: Vec<(u32, u64)> = flat_total.into_iter().collect(); + let mut ranked: Vec<((u32, u32), u64)> = flat_total.into_iter().collect(); ranked.sort_by(|a, b| b.1.cmp(&a.1).then(a.0.cmp(&b.0))); let k = self.sampling.top_k.min(ranked.len()); eprintln!( @@ -749,11 +750,12 @@ impl Vm { self.sampling.records.len(), self.profiling.instruction_count ); - for (rank, &(flat, count)) in ranked.iter().take(k).enumerate() { - // top pc:该 flat_id 下样本数最多的字节码偏移(并列取小 pc)。 + for (rank, &((flat, gen), count)) in ranked.iter().take(k).enumerate() { + // top pc:该 (flat_id, 表代际) 下样本数最多的字节码偏移(并列取哈希 + // 遍历首个,非确定,诊断用途可接受)。 let mut top_pc: Option<(u64, u32, u8)> = None; - for (&(f, pc), &(c, op)) in &pc_hist { - if f != flat { + for (&(f, g, pc), &(c, op)) in &pc_hist { + if f != flat || g != gen { continue; } match top_pc { @@ -768,11 +770,11 @@ impl Vm { .unwrap_or_else(|_| format!("op{top_op}")); let name = self .tables - .get(&self.current_gen) + .get(&gen) .and_then(|t| t.modules.get(flat as usize)) .and_then(|m| m.function_name.clone()) .unwrap_or_else(|| format!("")); - let frames = flat_max_frames.get(&flat).copied().unwrap_or(0); + let frames = flat_max_frames.get(&(flat, gen)).copied().unwrap_or(0); eprintln!( " {rank:>2}. {name:<24} (flat {flat}) {count:>8} samples top pc={top_pc} {op_name} ({top_count}) frames={frames}" ); diff --git a/crates/oxide_vm/src/vm_state.rs b/crates/oxide_vm/src/vm_state.rs index 735d5483..463db3f3 100644 --- a/crates/oxide_vm/src/vm_state.rs +++ b/crates/oxide_vm/src/vm_state.rs @@ -249,15 +249,15 @@ impl IterState { /// 指令周期采样状态:采样周期(2 的幂)与样本记录表。 /// /// 开启时 dispatch 主循环每 `period` 条指令记一条样本(flat_id、pc、opcode、 -/// frames 深度),run 末按 flat_id 聚合并输出 top-K 直方图(stderr)。 -/// 关闭(`period == 0`)时热路径仅一次可预测分支,零写零分配。 +/// frames 深度、表代际),run 末按 (flat_id, 表代际) 聚合并输出 top-K 直方图 +/// (stderr)。关闭(`period == 0`)时热路径仅一次可预测分支,零写零分配。 pub(crate) struct SampleState { /// 采样周期(2 的幂,0 = 关闭)。 pub(crate) period: u64, /// 直方图 top-K 大小(默认 10)。 pub(crate) top_k: usize, - /// 样本记录:(flat_id, pc, opcode, frames 深度),run 边界清空。 - pub(crate) records: Vec<(u32, u32, u8, u32)>, + /// 样本记录:(flat_id, pc, opcode, frames 深度, 表代际),run 边界清空。 + pub(crate) records: Vec<(u32, u32, u8, u32, u32)>, } impl SampleState {