Changes for v4: - Separate out libdwfl_stacktrace, as requested.
* * * New data structure to coordinate caching Elf data among multiple Dwfl structs attached to different processes. Meant to reduce the overhead for profilers that use elfutils for unwinding. The caching is well-justified, as the prior approach (e.g. in eu-stacktrace, sysprof-live-unwinder) of creating a separate Dwfl per process was wildly redundant, opening ~hundreds of file descriptors just for each common library such as libc.so and leaking the data. Initial patch just introduces the struct, to be filled in by the rest of the patch series. * libdwfl_stacktrace/libdwfl_stacktrace.h (Dwflst_Process_Tracker): New struct. (dwflst_tracker_begin): New function. (dwflst_tracker_dwfl_begin): New function. (dwflst_tracker_end): New function. * libdw/libdw.map: Add new functions. * libdwfl_stacktrace/libdwfl_stacktraceP.h (struct Dwflst_Process_Tracker): New struct. * libdwfl/libdwflP.h (Dwflst_Process_Tracker): Typedef forward decl. (struct Dwfl): Add 'tracker' field. * libdwfl_stacktrace/Makefile.am (libdwfl_stacktrace_a_SOURCES): Add dwflst_process_tracker.c. * libdwfl_stacktrace/dwflst_process_tracker.c: New file. (dwflst_tracker_begin): Initialize the tracker. (dwflst_tracker_dwfl_begin): Initialize Dwfl * with specified tracker. (dwflst_tracker_end): Deallocate the tracker. --- libdw/libdw.map | 4 ++ libdwfl/libdwflP.h | 4 ++ libdwfl_stacktrace/Makefile.am | 3 +- libdwfl_stacktrace/dwflst_process_tracker.c | 66 +++++++++++++++++++++ libdwfl_stacktrace/libdwfl_stacktrace.h | 20 +++++++ libdwfl_stacktrace/libdwfl_stacktraceP.h | 6 ++ 6 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 libdwfl_stacktrace/dwflst_process_tracker.c diff --git a/libdw/libdw.map b/libdw/libdw.map index 4f3fe6ba..fb69a62a 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -396,4 +396,8 @@ ELFUTILS_0.193 { ELFUTILS_0.193_EXPERIMENTAL { global: dwflst_perf_sample_preferred_regs_mask; + dwflst_perf_sample_preferred_regs_mask; + dwflst_tracker_begin; + dwflst_tracker_dwfl_begin; + dwflst_tracker_end; }; diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h index 2b7eb8da..57305f81 100644 --- a/libdwfl/libdwflP.h +++ b/libdwfl/libdwflP.h @@ -111,9 +111,13 @@ struct Dwfl_User_Core int fd; /* close if >= 0. */ }; +/* forward decl from ../libdwfl_stacktrace/ */ +typedef struct Dwflst_Process_Tracker Dwflst_Process_Tracker; + struct Dwfl { const Dwfl_Callbacks *callbacks; + Dwflst_Process_Tracker *tracker; #ifdef ENABLE_LIBDEBUGINFOD debuginfod_client *debuginfod; #endif diff --git a/libdwfl_stacktrace/Makefile.am b/libdwfl_stacktrace/Makefile.am index 6364c292..d57431c0 100644 --- a/libdwfl_stacktrace/Makefile.am +++ b/libdwfl_stacktrace/Makefile.am @@ -40,7 +40,8 @@ noinst_LIBRARIES += libdwfl_stacktrace_pic.a pkginclude_HEADERS = libdwfl_stacktrace.h -libdwfl_stacktrace_a_SOURCES = dwflst_perf_frame.c +libdwfl_stacktrace_a_SOURCES = dwflst_process_tracker.c \ + dwflst_perf_frame.c libdwfl_stacktrace = $(libdw) libdw = ../libdw/libdw.so diff --git a/libdwfl_stacktrace/dwflst_process_tracker.c b/libdwfl_stacktrace/dwflst_process_tracker.c new file mode 100644 index 00000000..057c9f7a --- /dev/null +++ b/libdwfl_stacktrace/dwflst_process_tracker.c @@ -0,0 +1,66 @@ +/* Track multiple Dwfl structs for multiple processes. + Copyright (C) 2025, Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwfl_stacktraceP.h" + +Dwflst_Process_Tracker *dwflst_tracker_begin (const Dwfl_Callbacks *callbacks) +{ + Dwflst_Process_Tracker *tracker = calloc (1, sizeof *tracker); + if (tracker == NULL) + { + __libdwfl_seterrno (DWFL_E_NOMEM); + return tracker; + } + + tracker->callbacks = callbacks; + return tracker; +} + +Dwfl *dwflst_tracker_dwfl_begin (Dwflst_Process_Tracker *tracker) +{ + Dwfl *dwfl = INTUSE(dwfl_begin) (tracker->callbacks); + if (dwfl == NULL) + return dwfl; + + /* TODO: Could also share dwfl->debuginfod, but thread-safely? */ + dwfl->tracker = tracker; + return dwfl; +} + +void dwflst_tracker_end (Dwflst_Process_Tracker *tracker) +{ + if (tracker == NULL) + return; + + /* TODO: Call dwfl_end for each Dwfl connected to this tracker. */ + free (tracker); +} diff --git a/libdwfl_stacktrace/libdwfl_stacktrace.h b/libdwfl_stacktrace/libdwfl_stacktrace.h index 564f504a..f3a82d18 100644 --- a/libdwfl_stacktrace/libdwfl_stacktrace.h +++ b/libdwfl_stacktrace/libdwfl_stacktrace.h @@ -41,6 +41,26 @@ extern "C" { #endif +/* Keeps track of and caches Elf structs across multiple libdwfl + sessions corresponding to different processes. */ +typedef struct Dwflst_Process_Tracker Dwflst_Process_Tracker; + + +/* Initialize a new tracker for multiple libdwfl sessions. Since Elf + data will shared between the libdwfl sessions, each Dwfl must use + the same Dwfl_Callbacks CALLBACKS provided when the tracker is + created. */ +extern Dwflst_Process_Tracker *dwflst_tracker_begin (const Dwfl_Callbacks *callbacks) + __nonnull_attribute__ (1); + +/* Create a new Dwfl linked to this tracker. */ +extern Dwfl *dwflst_tracker_dwfl_begin (Dwflst_Process_Tracker *tracker) + __nonnull_attribute__ (1); + +/* End all sessions with this tracker. */ +extern void dwflst_tracker_end (Dwflst_Process_Tracker *tracker); + + /* XXX dwflst_perf_sample_getframes to be added in subsequent patch */ /* Returns the linux perf_events register mask describing a set of diff --git a/libdwfl_stacktrace/libdwfl_stacktraceP.h b/libdwfl_stacktrace/libdwfl_stacktraceP.h index fe6945fc..9313176c 100644 --- a/libdwfl_stacktrace/libdwfl_stacktraceP.h +++ b/libdwfl_stacktrace/libdwfl_stacktraceP.h @@ -33,4 +33,10 @@ #include "libdwflP.h" +struct Dwflst_Process_Tracker +{ + const Dwfl_Callbacks *callbacks; + /* ... */ +}; + #endif /* libdwfl_stacktraceP.h */ -- 2.47.0