feat: speedup ebpf uprobe attaching#440
Conversation
Greptile SummaryThis PR speeds up memtrack eBPF allocator attachment. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (3): Last reviewed commit: "ci(memtrack): run offset resolution benc..." | Re-trigger Greptile |
Merging this PR will not alter performance
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| 🆕 | Simulation | resolve_offsets_parallel |
N/A | 10.5 ms | N/A |
| 🆕 | Simulation | resolve_offsets_serial |
N/A | 10 ms | N/A |
Comparing cod-3070-speedup-allocator-attaching-on-nixos (9f32601) with main (eac7766)
0e8688a to
3a322ae
Compare
…f func_name Resolve every defined symbol's libbpf-compatible file offset once per library (st_value - sh_addr + sh_offset) and attach uprobes by offset, replacing the per-probe func_name lookup that reparsed the ELF each time.
Symbol resolution parses each allocator ELF independently, so fan it out across cores with rayon before the serial attach step. Cuts offset resolution for all discovered allocators from ~190ms to ~29ms locally.
Divan bench comparing serial vs parallel symbol offset resolution over the discovered allocator libraries. Runs without sudo since it only parses ELFs, no eBPF attach.
3a322ae to
9f32601
Compare
GuillaumeLagrange
left a comment
There was a problem hiding this comment.
small changes, olgtm
| paste! { | ||
| fn [<try_ $name>](&mut self, lib_path: &Path, symbol: &str) { | ||
| let result = self.$name(lib_path, symbol); | ||
| fn [<$name _by_name>](&mut self, lib_path: &Path, symbol: &str) -> Result<()> { |
There was a problem hiding this comment.
since we are resolving symbol offsets, do we still need the by_name variant?
| paste! { | ||
| fn [<try_ $name>](&mut self, lib_path: &Path, symbol: &str) { | ||
| let result = self.$name(lib_path, symbol); | ||
| fn [<$name _by_name>](&mut self, lib_path: &Path, symbol: &str) -> Result<()> { |
There was a problem hiding this comment.
same remark here
| let result = if let Some(offset) = symbols.offset(symbol) { | ||
| self.$name(lib_path, offset) | ||
| } else if symbols.is_defined_without_offset(symbol) { | ||
| self.[<$name _by_name>](lib_path, symbol) | ||
| } else { | ||
| return; | ||
| }; |
There was a problem hiding this comment.
Basically my above comment is: since we are resolving symbols ahead of time, is it possible that we failed to resolve the symbol earlier on but still manage to attach by name here?
There was a problem hiding this comment.
If that's possible, it warrants a small explanation of why it can happen
There was a problem hiding this comment.
else just remove the function
| Ok(()) | ||
| } | ||
|
|
||
| fn [<try_ $name>]( |
There was a problem hiding this comment.
in rust, try_xxx infers a Result. It seems we have them mixed up here
Seems like the attach functions should be named try_attach_xxx, and this function should be named something else, like attach_if_found or sthing
| @@ -0,0 +1,36 @@ | |||
| use memtrack::{AllocatorLib, resolve_symbol_offsets}; | |||
There was a problem hiding this comment.
shouldnt these run on vendored allocator libs as part of a testdata folder instead of relying on the host machine's allocator?
| tool: cargo-codspeed | ||
|
|
||
| - name: Install libbpf build deps | ||
| run: sudo apt-get update && sudo apt-get install -y build-essential pkgconf zlib1g-dev libbpf-dev autopoint bison flex |
There was a problem hiding this comment.
there is quite a lot of duplication to install build time dependencies of memtrack across the whole workflow, cnat we create a install-bpf-deps local action?
Dont bundle biuld-essential with it, first check if it's required here, and if it's required here, add it as either a separate step, or an additional-packages action input
No description provided.