Skip to content

refactor(memtrack): split monolithic eBPF C and Rust into domain files#455

Open
not-matthias wants to merge 2 commits into
mainfrom
cod-3142-improve-ebpf-multi-file-organization
Open

refactor(memtrack): split monolithic eBPF C and Rust into domain files#455
not-matthias wants to merge 2 commits into
mainfrom
cod-3142-improve-ebpf-multi-file-organization

Conversation

@not-matthias

Copy link
Copy Markdown
Member

Summary

Splits the monolithic eBPF source (memtrack.bpf.c, 392 lines) and its Rust attach code (memtrack.rs, 478 lines) into small, single-responsibility files. Pure reorganization — no behavior change.

C side

src/ebpf/c/
├── event.h                # unchanged (bindgen contract)
├── main.bpf.c             # includes + LICENSE only — no programs, no maps
├── allocator.h            # UPROBE_* macros + all uprobes + mmap/munmap/brk tracepoints
└── utils/
    ├── map_helpers.h      # BPF_HASH_MAP / BPF_ARRAY_MAP / BPF_RINGBUF macros
    ├── tracking.h         # tracked_pids, pids_ppid, tracking_enabled + is_tracked/is_enabled/track_child + sched_fork
    └── event_helpers.h    # events ringbuf, dropped_events + SUBMIT_EVENT + submit_*_event + store_param/take_param

Encapsulation improvements

  • track_child() helpersched_fork body now reads as intent only, raw bpf_map_update_elem calls hidden
  • store_mmap_args() helper — mmap enter handler no longer pokes maps directly
  • brk enter now uses store_param() instead of raw bpf_map_update_elem

Rust side

src/ebpf/memtrack/
├── mod.rs         # skel include!, MemtrackBpf struct, new(), Drop, start_polling_with_channel
├── macros.rs      # attach_uprobe_uretprobe! / attach_uprobe! / attach_tracepoint! + ensure_symbol_exists
├── maps.rs        # add_tracked_pid, enable/disable_tracking, dropped_events_count
├── allocator.rs   # all attach_* probe methods + attach_allocator_probes + per-allocator methods
└── tracking.rs    # attach_sched_fork / attach_tracepoints

#[macro_use] mod macros; ensures declarative macros are visible to sibling modules. Each submodule imports use super::MemtrackBpf; for its impl block.

Notes

  • File named main.bpf.c (not main.c) because libbpf_cargo::SkeletonBuilder requires the .bpf.c suffix
  • Skeleton struct names change from MemtrackSkel/MemtrackSkelBuilder to MainSkel/MainSkelBuilder (derived from filename). Output file memtrack.skel.rs and include! path unchanged.
  • Four load-bearing map names (tracked_pids, tracking_enabled, events, dropped_events) preserved — Rust side reads them by name from the skeleton.

Verification

  • cargo check --features ebpf — skeleton generates + compiles ✓
  • cargo build --features ebpf
  • cargo test — 2 passed, 20 ignored (sudo/GITHUB_ACTIONS gate) ✓

@codspeed-hq

codspeed-hq Bot commented Jul 14, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

✅ 17 untouched benchmarks


Comparing cod-3142-improve-ebpf-multi-file-organization (181f056) with main (5c27231)

Open in CodSpeed

@not-matthias
not-matthias force-pushed the cod-3142-improve-ebpf-multi-file-organization branch from 344d4f2 to 03ba372 Compare July 14, 2026 17:58
@greptile-apps

greptile-apps Bot commented Jul 14, 2026

Copy link
Copy Markdown

Greptile Summary

This PR splits the monolithic memtrack.bpf.c (392 lines) and memtrack.rs (478 lines) into small, single-responsibility files — pure reorganization with no behavior changes. The four load-bearing BPF map names (tracked_pids, tracking_enabled, events, dropped_events) are preserved, and new helper abstractions (track_child, store_mmap_args, store_param) improve readability without altering semantics.

  • C side: The single .bpf.c is replaced by main.bpf.c (thin entry point) + allocator.h (uprobe macros + tracepoints) + utils/ headers for map macros, tracking state, and event helpers.
  • Rust side: memtrack.rs is split into mod.rs, macros.rs, maps.rs, allocator.rs, and tracking.rs. The skeleton type rename from MemtrackSkel to MainSkel is internal-only with no external consumers.

Confidence Score: 5/5

Pure reorganization — no logic changes, all BPF map names and program semantics are preserved.

Every behavioral path (store_param for brk, store_mmap_args for mmap, track_child for fork) is functionally identical to the deleted monolith. The skeleton type rename from MemtrackSkel to MainSkel has no external consumers. The only finding is redundant explicit includes in main.bpf.c that are already pulled in transitively — header guards prevent any compile issue.

No files require special attention; main.bpf.c has a minor redundant-include style nit.

Important Files Changed

Filename Overview
crates/memtrack/src/ebpf/c/main.bpf.c New thin entry point — only includes and LICENSE. Lines 9–12 include headers already pulled in transitively by allocator.h, leaving minor redundancy.
crates/memtrack/src/ebpf/c/allocator.h All uprobe macros (UPROBE_ARG_RET, UPROBE_RET, UPROBE_ARGS_RET) and tracepoints moved here; adds store_mmap_args() helper. Content is functionally identical to the deleted monolith.
crates/memtrack/src/ebpf/c/utils/tracking.h Extracts tracked_pids, pids_ppid, tracking_enabled maps plus is_tracked(), is_enabled(), and the new track_child() helper; sched_fork tracepoint body now calls track_child() instead of raw map updates. Functionally identical.
crates/memtrack/src/ebpf/c/utils/event_helpers.h Extracts events ring buffer, dropped_events counter, WAKEUP_DATA_SIZE, wake_flags(), store_param(), take_param(), SUBMIT_EVENT macro, and all submit_*_event helpers. No semantic changes.
crates/memtrack/src/ebpf/memtrack/mod.rs New module root: skeleton include, MemtrackBpf struct (now using MainSkel/MainSkelBuilder), new/drop/detach_probes/start_polling_with_channel. Skeleton type rename is internal-only; no external callers use MemtrackSkel directly.
crates/memtrack/src/ebpf/memtrack/macros.rs Declarative macros attach_uprobe_uretprobe!, attach_uprobe!, attach_tracepoint! moved here unchanged; #[macro_use] in mod.rs makes them visible to sibling modules.
crates/memtrack/src/ebpf/memtrack/allocator.rs All attach_* probe methods and per-allocator helpers (libc, libcpp, jemalloc, mimalloc, tcmalloc) moved here; logic is unchanged.
crates/memtrack/src/ebpf/memtrack/maps.rs add_tracked_pid, enable_tracking, disable_tracking, dropped_events_count extracted here; all map names and logic are identical to the deleted monolith.
crates/memtrack/src/ebpf/memtrack/tracking.rs Minimal file — just the attach_sched_fork tracepoint via macro and attach_tracepoints(). Clean extraction.
crates/memtrack/build.rs One-line change: SkeletonBuilder source updated from memtrack.bpf.c to main.bpf.c; output path memtrack.skel.rs is unchanged.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph "C side (BPF programs)"
        A["main.bpf.c\n(vmlinux + bpf headers + LICENSE)"]
        A --> B["allocator.h\n(UPROBE_* macros, allocator uprobes,\nmmap/munmap/brk tracepoints)"]
        B --> C["utils/event_helpers.h\n(events ringbuf, dropped_events,\nstore_param, take_param,\nSUBMIT_EVENT, submit_*_event)"]
        B --> D["utils/map_helpers.h\n(BPF_HASH_MAP, BPF_ARRAY_MAP,\nBPF_RINGBUF macros)"]
        B --> E["utils/tracking.h\n(tracked_pids, pids_ppid,\ntracking_enabled, is_tracked,\nis_enabled, track_child,\nsched_fork tracepoint)"]
        C --> D
        C --> E
        E --> D
    end

    subgraph "Rust side (libbpf-rs wrapper)"
        F["memtrack/mod.rs\n(MemtrackBpf struct, new,\ndetach_probes, start_polling)"]
        F --> G["macros.rs\n(attach_uprobe_uretprobe!\nattach_uprobe!\nattach_tracepoint!)"]
        F --> H["allocator.rs\n(attach_* probe methods,\nattach_allocators,\nper-allocator helpers)"]
        F --> I["maps.rs\n(add_tracked_pid,\nenable/disable_tracking,\ndropped_events_count)"]
        F --> J["tracking.rs\n(attach_sched_fork,\nattach_tracepoints)"]
    end

    A -.->|"SkeletonBuilder\nmain.bpf.c to memtrack.skel.rs"| F
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    subgraph "C side (BPF programs)"
        A["main.bpf.c\n(vmlinux + bpf headers + LICENSE)"]
        A --> B["allocator.h\n(UPROBE_* macros, allocator uprobes,\nmmap/munmap/brk tracepoints)"]
        B --> C["utils/event_helpers.h\n(events ringbuf, dropped_events,\nstore_param, take_param,\nSUBMIT_EVENT, submit_*_event)"]
        B --> D["utils/map_helpers.h\n(BPF_HASH_MAP, BPF_ARRAY_MAP,\nBPF_RINGBUF macros)"]
        B --> E["utils/tracking.h\n(tracked_pids, pids_ppid,\ntracking_enabled, is_tracked,\nis_enabled, track_child,\nsched_fork tracepoint)"]
        C --> D
        C --> E
        E --> D
    end

    subgraph "Rust side (libbpf-rs wrapper)"
        F["memtrack/mod.rs\n(MemtrackBpf struct, new,\ndetach_probes, start_polling)"]
        F --> G["macros.rs\n(attach_uprobe_uretprobe!\nattach_uprobe!\nattach_tracepoint!)"]
        F --> H["allocator.rs\n(attach_* probe methods,\nattach_allocators,\nper-allocator helpers)"]
        F --> I["maps.rs\n(add_tracked_pid,\nenable/disable_tracking,\ndropped_events_count)"]
        F --> J["tracking.rs\n(attach_sched_fork,\nattach_tracepoints)"]
    end

    A -.->|"SkeletonBuilder\nmain.bpf.c to memtrack.skel.rs"| F
Loading

Reviews (2): Last reviewed commit: "docs(memtrack): add crate AGENTS.md guid..." | Re-trigger Greptile

Split the single-file eBPF source (memtrack.bpf.c) and its Rust attach
code (memtrack.rs) into small, single-responsibility files.

C side:
- main.bpf.c: includes + LICENSE only, no programs or maps
- utils/map_helpers.h: BPF_HASH_MAP/BPF_ARRAY_MAP/BPF_RINGBUF macros
- utils/tracking.h: tracked_pids/pids_ppid/tracking_enabled maps +
  is_tracked/is_enabled/track_child helpers + sched_fork program
- utils/event_helpers.h: events ringbuf, dropped_events, SUBMIT_EVENT,
  submit_*_event, store_param/take_param
- allocator.h: UPROBE_* macros + all allocator uprobes + mmap/munmap/brk
  tracepoints

Encapsulation improvements:
- track_child() helper extracted from sched_fork body
- store_mmap_args() helper extracted from mmap enter handler
- brk enter now uses store_param() instead of raw bpf_map_update_elem

Rust side:
- memtrack/mod.rs: skel include, MemtrackBpf struct, new(), Drop
- memtrack/macros.rs: attach_uprobe_uretprobe!/attach_uprobe!/
  attach_tracepoint! macros + ensure_symbol_exists
- memtrack/maps.rs: add_tracked_pid, enable/disable_tracking,
  dropped_events_count
- memtrack/allocator.rs: all attach_* probe methods + per-allocator
  attach methods
- memtrack/tracking.rs: attach_sched_fork / attach_tracepoints

Skeleton struct names change from MemtrackSkel to MainSkel (derived
from main.bpf.c filename). Output file memtrack.skel.rs unchanged.
@not-matthias
not-matthias force-pushed the cod-3142-improve-ebpf-multi-file-organization branch from 03ba372 to 181f056 Compare July 16, 2026 17:18
@not-matthias
not-matthias marked this pull request as ready for review July 16, 2026 17:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant