javierhonduco / lightswitch

CPU profiler for Linux written in Rust
MIT License
7 stars 3 forks source link

Rework native unwind information storage and retrieval #78

Closed javierhonduco closed 1 month ago

javierhonduco commented 1 month ago

This rather large commit fundamentally modifies how unwind information is stored and retrieved. Until now we had a BPF hashmap where we stored a large C array in the values. The keys were used to index said values. We called each entry a "shard", where unwind information would be written. The way this worked was that whenever we had unwind information we wanted to store, we will append it to the current shard and/or continue appending in a new shard. We effectively treated this as a contiguous chunk of memory, that operated like a bump allocator.

As the unwind information we wanted to append might not fit in the shard, we would have to split or chunk said unwind information. In order to query it, we would search an array chunks with a linear search.

The above offers a good solution to maximising space utilisation, but it has a bunch of drawbacks, including:

Lastly, we perform a fixed number of binary search iterations to find the unwind row for a given PC. This was limiting the maximum chunk size, which we could have dealt with by inserting extra chunks and partitioning the unwind info space, which brings us to...

Unwind information divided in equal chunks or pages, which is this implementation. The unwind info is split in 16 bit pages, this has a couple of advantages:

The unwind information is not stored in a unwind info bucket. These are BPF 'maps of maps' that has a key they have the executable_id, and has a value they have a BPF array that stores the unwind information rows.

We need different buckets because the verifier requires that for each 'outer' map the 'inner' map must be configured before loading the program, so we can store up to X elements per object in each bucket.

This will allow us to remove / evict unwind information in a more granular way, doesn't require us to allocate large amount of locked memory, as we can allocate BPF arrays on the fly and store them in 'outer' maps, etc.

This commit also changes the following:

Test Plan

Many manual runs and CI

image