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.