-
Notifications
You must be signed in to change notification settings - Fork 1
Perf script parity #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ixtli
wants to merge
39
commits into
mjc:main
Choose a base branch
from
ixtli:perf-script-parity
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
4bb3249
Fix macOS package discovery and add Linux perf oracle harness
ixtli 6540a9a
Make mmap ingestion incremental via per-pid interval index
ixtli 5b1b41e
Make mmap ingestion incremental via per-pid interval index
ixtli 1cf9ded
Read thread ids with read_dir and drop procfs
ixtli fea081c
Error on unsupported profile backends and inject test platforms
ixtli 8fe1ec7
Read perf feature bitmap at the correct offset
ixtli ffc5949
Parse perf feature-section build-id records
ixtli c3254d0
Name events from HEADER_EVENT_DESC and match perf script's event-name…
ixtli 07e4747
Add aarch64 reg decoding, ebl fallback, and HEADER_ARCH parsing
ixtli 7bd582e
Default perf-script/fold to one symtab frame per callchain entry
ixtli bfc4357
Split oracle harness into record and fast compare steps
ixtli 31062c2
Update tests for the inline-off default and event-name spacing
ixtli 279650c
Seed the build-id cache in the oracle compare container
ixtli dc77743
Fold with --count-periods in the oracle compare
ixtli 89d8958
Match perf script output byte-for-byte on the fp oracle
ixtli 1c242da
Move header-arch test feature bit to the corrected bitmap offset
ixtli 58db791
Resolve the main repo from the absolute git common dir
ixtli 11453d2
Cache DWARF inline-frame indexes per object across fold rounds
ixtli 53d78c5
Thread perf arch through the fold user-unwind path
ixtli b6340da
Add aarch64 dwarf user-unwind fold tests and ebl-fallback trigger
ixtli 347bd11
Add --inline passthrough to the bench and dwarf oracle compare
ixtli 85f5cf5
Unwind aarch64 DWARF user stacks in the fold path
ixtli 5182ff2
Record dwarf parity status after aarch64 unwind merge
ixtli 16314a2
Name DWARF inline frames from linkage names like perf
ixtli 7119522
Pin current-IP-only fold tests to a synthetic x86_64 ELF
ixtli d743cae
Record green macOS suite in parity findings
ixtli 8c8416a
Expand inline frames on the sampled-IP leaf with --inline
ixtli cdd1b30
Format inline script frames with offset and (inlined) like perf
ixtli 9e32655
Resolve kernel kallsyms frames in the direct fold on the recording ma…
ixtli e5b8d6e
Match perf inline-frame symbolization on the dwarf oracle
ixtli 8262afc
Record dwarf inline parity closure in findings and beads
ixtli 251df97
Compare device with inode in file identity
ixtli 146db22
Unify symbol source across mmap record forms
ixtli 62e3d62
Emit the libdw scenario-D leaf and gate it before unwinding
ixtli c49bb8b
Test scenario-D leaf emission and the skip-gate predicate
ixtli 503e141
Test the CFI-presence memo consistency and invalidation
ixtli 25313b7
Close pyroclast-5gr and pyroclast-pkh as the leaf-only model lands
ixtli b0604fc
Emit libdw scenario-D leaves and gate unwinds that cannot advance
ixtli b940ddc
Record leaf-only model closure in parity findings
ixtli File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| # Spec: aarch64 DWARF user unwind support | ||
|
|
||
| Priority directive from the user (2026-06-11): the dwarf call-graph path is the | ||
| parity priority — fp call graphs require frame-pointer builds of the whole world. | ||
| The local oracle (Docker on Apple Silicon) records arm64 perf.data, so aarch64 | ||
| support is the critical path for oracle-driven dwarf work. Validate against | ||
| `target/oracle/dwarf.*` (re-record with `scripts/perf-oracle` after changes; the | ||
| recorded inputs are stable otherwise). | ||
|
|
||
| ## Current state | ||
|
|
||
| - `src/perfdata/unwind.rs`: `PerfX86_64Regs { ip, sp, bp, registers: [u64;16] }`, | ||
| `FramehopUnwinder { unwinder: UnwinderX86_64<ModuleBytes>, cache: CacheX86_64 }`, | ||
| `unwind_x86_64_frame_pointer_stack_like_elfutils` (x86 ebl fallback), | ||
| `PerfUserMemoryReader` (arch-neutral), module loading via | ||
| `ExplicitModuleSectionInfo` (arch-neutral). | ||
| - `src/perfdata/fold.rs` threads `&PerfX86_64Regs` through ~21 sites; entry point is | ||
| `append_perf_user_unwind_frames` → | ||
| `PerfX86_64Regs::from_perf_masked_values(event.layout.sample_regs_user, ®s.values)`. | ||
| `perf_user_reg_value(mask, values, 8)` hardcodes PERF_REG_X86_IP=8 in | ||
| `parse_sample_for_summary` too. | ||
| - x86-only logic to gate by arch: `is_syscall_return_state` (rcx==ip && r11!=0), | ||
| `libdw_arch_fallback_after_empty_object_unwind` guard `regs.bp >= regs.sp`. | ||
|
|
||
| ## Register numbering | ||
|
|
||
| - x86_64 (PERF_REG_X86_*): BP=6, SP=7, IP=8 (already implemented). | ||
| - aarch64 (PERF_REG_ARM64_*): x0..x28 = 0..28, X29/FP = 29, LR/x30 = 30, SP = 31, | ||
| PC = 32. perf records `--call-graph dwarf` on arm64 with mask covering x0-x30, | ||
| sp, pc (mask 0x1ffffffff). | ||
|
|
||
| ## Arch detection | ||
|
|
||
| perf.data does not store arch per attr; perf uses the header HEADER_ARCH feature | ||
| (string from uname, "aarch64" / "x86_64"). Header feature parsing machinery exists | ||
| (see `header_build_ids_by_filename_from_file` / `src/perfdata/build_id.rs`, | ||
| `header.rs`). Add `header_arch_from_file` reading HEADER_ARCH (feature bit 5; | ||
| perf string format: u32 len + bytes, see perf util/header.c write_arch/read). | ||
| Default to x86_64 when absent. Plumb into `FoldAccumulator`/sink construction so | ||
| `append_perf_user_unwind_frames` can decode regs per arch. | ||
|
|
||
| ## Design (project is unreleased — rename freely) | ||
|
|
||
| 1. Replace `PerfX86_64Regs` with arch-neutral `PerfUserRegs { arch: PerfArch, | ||
| ip: u64, sp: u64, fp: u64, lr: Option<u64>, values: ... }` with | ||
| `from_perf_masked_values(arch, mask, values)`; keep per-arch accessors used by | ||
| the x86 syscall-return check (rcx = values[?]; preserve current behavior via | ||
| the existing masked-value lookup). Alternatively an enum — pick whichever keeps | ||
| the 21 fold.rs sites simplest; most only use ip/sp/bp. | ||
| 2. `FramehopUnwinder` becomes an enum or holds per-arch unwinder+cache | ||
| (`framehop::aarch64::{UnwinderAarch64, CacheAarch64, UnwindRegsAarch64}`). | ||
| Module registration (`framehop::Module::new` + ExplicitModuleSectionInfo) is | ||
| shared; instantiate by arch at accumulator/PidUnwindState creation (arch comes | ||
| from the file header, one arch per perf.data). | ||
| Note framehop aarch64 `UnwindRegsAarch64::new(lr, sp, fp)`; `iter_frames` seeds | ||
| with pc. framehop strips PAC bits itself. | ||
| 3. aarch64 ebl_unwind fallback, faithful to elfutils backends/aarch64_unwind.c | ||
| (fetched 2026-06-11, evverx/elfutils mirror): | ||
| - FP_REG=29 LR_REG=30 SP_REG=31; FP_OFFSET=0 LR_OFFSET=8 SP_OFFSET=16. | ||
| - prev pc = lr; fail only if lr unreadable or lr == 0. | ||
| - newLr = mem[fp+8] else 0; newFp = mem[fp+0] else 0; newSp = fp+16. | ||
| - success iff `fp == 0 || newSp > sp` (NO bp>=sp precondition like x86; | ||
| fp==0 still yields one lr-based caller). | ||
| - Iterate like the x86 `unwind_x86_64_frame_pointer_stack_like_elfutils` loop | ||
| (callback-per-frame semantics; subsequent pc gets the `!initial && !signal` | ||
| pc-1 adjustment in the consumer like the existing code). | ||
| 4. Gate x86-only logic by arch: syscall-return truncation (no arm64 analogue), | ||
| `regs.bp >= regs.sp` fallback precondition is x86-only (aarch64 fallback has | ||
| its own conditions above). | ||
| 5. Leaf-only / scenario-D predicate (see .ace-research-perf-unwind.md §3): on | ||
| aarch64 the no-CFI fallback succeeds whenever lr != 0, so "current-IP-only" | ||
| stacks are far rarer; the cheap skip-gate condition 6 becomes | ||
| `!has_unwind_info_for_ip(ip) && lr == 0` on aarch64. | ||
|
|
||
| ## Tests | ||
|
|
||
| - Unit tests mirroring tests/perfdata_unwind.rs x86 cases for the aarch64 | ||
| fallback (synthetic stacks: fp chain at fp+0/fp+8, the fp==0-with-lr case, the | ||
| newSp <= sp failure case). | ||
| - Reg decoding tests for the arm64 mask layout (pc=32, sp=31, fp=29, lr=30). | ||
| - End-to-end: `scripts/perf-oracle` → dwarf bench comparison should go from | ||
| pyroclast_folded_lines=2 vs inferno=16 to matching (after the script-parity | ||
| naming fixes are merged; residuals analyzed against | ||
| .ace-research-perf-unwind.md). | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct the
HEADER_ARCHfeature-bit value in the spec.Line 37 says
HEADER_ARCHis feature bit 5, but the implementation uses bit 6; this mismatch will mislead future maintenance/debugging.📝 Suggested doc fix
📝 Committable suggestion
🤖 Prompt for AI Agents