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.

Reply via email to