On Tue, Dec 10, 2024, at 4:42 PM, Serhei Makarov wrote:
> This email sketches an 'unwinder cache' interface for libdwfl, derived
> from recent eu-stacktrace code [1] and based on Christian Hergert's
> adaptation of eu-stacktrace as sysprof-live-unwinder [2]. The intent is
> to remove the need for a lot of boilerplate code that would be
> identical among profiling tools that use libdwfl to unwind perf_events
> stack samples. But since this becomes a library design, it's in need of
> feedback and bikeshedding.
In advance of finishing up the Dwfl_Process_Tracker patchset
(initial version currently under review),
wanted to post an update summarizing the current api design.
api summary
===
(1) Create a Dwfl_Process_Tracker that caches data from multiple
Dwfls related to a system-wide profiling session:
typedef struct Dwfl_Process_Tracker Dwfl_Process_Tracker;
Dwfl_Process_Tracker *dwfl_process_tracker_begin (const Dwfl_Callbacks
*callbacks);
Dwfl *dwfl_begin_with_tracker (Dwfl_Process_Tracker *tracker);
void dwfl_process_tracker_end (Dwfl_Process_Tracker *tracker);
(2) Given a pid, check if a Dwfl has already been created for it and return
that;
if it hasn't been created, invoke the callback (which is expected to use
dwfl_begin_with_tracker to create an appropriate Dwfl).
Dwfl *dwfl_process_tracker_find_pid (Dwfl_Process_Tracker *tracker,
pid_t pid, Dwfl *(*callback) (Dwfl_Process_Tracker *tracker, pid_t pid,
void *arg), void *arg);
(3) This is a variant of the dwfl_linux_proc_find_elf callback which first
checks the Dwfl_Process_Tracker associated with the Dwfl,
and reuses any previously-loaded Elf data;
otherwise, it creates a new Elf using dwfl_linux_proc_find_elf.
int dwfl_process_tracker_find_elf (Dwfl_Module *mod, void **userdata,
const char *module_name, Dwarf_Addr base, char **file_name, Elf **)
-> same arguments as dwfl_linux_proc_find_elf
(4) Obtain a perf_events regs_mask suitable for unwinding
on the specified architecture.
Then, use the elfutils unwinder to unwind the stack sample
data returned from perf_events:
uint64_t dwfl_perf_sample_preferred_regs_mask (GElf_Half machine);
int dwfl_perf_sample_getframes (Dwfl *dwfl, Elf *elf, pid_t pid, pid_t tid,
const Dwarf_Word *regs, uint32_t n_regs,
uint64_t perf_regs_mask, uint32_t abi,
int (*callback) (Dwfl_Frame *state, void *arg), void *arg);
NOTE -- based on patch-review feedback, I'm considering to
add another api function that must be called on an unattached
Dwfl prior to using dwfl_perf_sample_getframes:
int dwfl_sample_attach (Dwfl *dwfl);
Otherwise, the flow with dwfl_perf_sample_getframes() is too confusing;
currently it calls dwfl_attach_state on an unattached Dwfl (with its own
callbacks arg, hidden to the library user), but it can also be called
on a Dwfl that was attached by a previous call to dwfl_perf_sample_getframes().
This 'just works' when used in the profiler code,
but is too fiddly to explain what is and isn't permissible to do.