]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdwfl_stacktrace [5/12]: introduce Dwflst_Process_Tracker
authorSerhei Makarov <serhei@serhei.io>
Mon, 20 Jan 2025 21:38:42 +0000 (16:38 -0500)
committerSerhei Makarov <serhei@serhei.io>
Fri, 25 Apr 2025 14:09:58 +0000 (10:09 -0400)
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
libdwfl/libdwflP.h
libdwfl_stacktrace/Makefile.am
libdwfl_stacktrace/dwflst_process_tracker.c [new file with mode: 0644]
libdwfl_stacktrace/libdwfl_stacktrace.h
libdwfl_stacktrace/libdwfl_stacktraceP.h

index 4f3fe6baba12076944bf0dabce27da6fe76e3798..fb69a62a1af47a6ab5aae161790c618d3ec6101b 100644 (file)
@@ -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;
 };
index 150d26f953800481efe3cd92287b24d053be78c1..8e6157ea82f50b1908fe2f3cbe84347edf02653c 100644 (file)
@@ -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
index 6364c2926c6a5fe4d40444bdabc71fb86397bcb3..d57431c056d63d14953d3b7c577fb8fb033b2f37 100644 (file)
@@ -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 (file)
index 0000000..057c9f7
--- /dev/null
@@ -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);
+}
index 564f504a6af9b1a33573f0f41037f42cc36646d0..f3a82d18a14481600719da920c03e9ca6332e4a1 100644 (file)
 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
index fe6945fcaffa933a8dd6c6d6b7a7e38d64de7c88..9313176cdd90f21726bc3de9c01661559947888f 100644 (file)
 
 #include "libdwflP.h"
 
+struct Dwflst_Process_Tracker
+{
+  const Dwfl_Callbacks *callbacks;
+  /* ... */
+};
+
 #endif  /* libdwfl_stacktraceP.h */