From f7eb2134ad233acabdb8ce032aac58222fc26ae0 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Fri, 21 Mar 2025 12:04:28 -0700 Subject: [PATCH] libsysprof/instruments: use provided D-Bus connection for sysprofd If we were provided a D-Bus connection to use for sysprofd then use that. Otherwise, try to fallback to doing the work in process without the help of sysprofd. --- src/libsysprof/meson.build | 2 + src/libsysprof/sysprof-linux-instrument.c | 97 ++++++++++++++++------ src/libsysprof/sysprof-sampler.c | 36 +++++--- src/libsysprof/sysprof-scheduler-details.c | 37 +++++---- 4 files changed, 119 insertions(+), 53 deletions(-) diff --git a/src/libsysprof/meson.build b/src/libsysprof/meson.build index 3a9c53b9..ca77a2c0 100644 --- a/src/libsysprof/meson.build +++ b/src/libsysprof/meson.build @@ -159,6 +159,8 @@ libsysprof_private_sources = [ 'sysprof-util.c', 'timsort/gtktimsort.c', + '../sysprofd/helpers.c', + gnome.gdbus_codegen('ipc-unwinder', sources: '../sysprofd/org.gnome.Sysprof3.Unwinder.xml', interface_prefix: 'org.gnome.Sysprof3.', diff --git a/src/libsysprof/sysprof-linux-instrument.c b/src/libsysprof/sysprof-linux-instrument.c index da21ef0c..9bdc5b76 100644 --- a/src/libsysprof/sysprof-linux-instrument.c +++ b/src/libsysprof/sysprof-linux-instrument.c @@ -29,11 +29,16 @@ #include "line-reader-private.h" +#include "../sysprofd/helpers.h" + +#define PROCESS_INFO_KEYS "pid,maps,mountinfo,cmdline,comm,cgroup" + struct _SysprofLinuxInstrument { - SysprofInstrument parent_instance; - SysprofRecording *recording; - GHashTable *seen; + SysprofInstrument parent_instance; + GDBusConnection *connection; + SysprofRecording *recording; + GHashTable *seen; }; G_DEFINE_FINAL_TYPE (SysprofLinuxInstrument, sysprof_linux_instrument, SYSPROF_TYPE_INSTRUMENT) @@ -46,6 +51,15 @@ sysprof_linux_instrument_list_required_policy (SysprofInstrument *instrument) return g_strdupv ((char **)policy); } +static void +sysprof_linux_instrument_set_connection (SysprofInstrument *instrument, + GDBusConnection *connection) +{ + SysprofLinuxInstrument *self = SYSPROF_LINUX_INSTRUMENT (instrument); + + g_set_object (&self->connection, connection); +} + static void add_mmaps (SysprofRecording *recording, GPid pid, @@ -237,11 +251,35 @@ add_process_info (SysprofLinuxInstrument *self, return dex_future_new_for_boolean (TRUE); } +static void +get_process_info_task (gpointer data) +{ + g_autoptr(DexPromise) promise = data; + g_autoptr(GVariant) info = NULL; + + if (!(info = helpers_get_process_info (PROCESS_INFO_KEYS))) + dex_promise_reject (promise, + g_error_new (G_IO_ERROR, + G_IO_ERROR_PERMISSION_DENIED, + "Failed to load process info")); + else + dex_promise_resolve_variant (promise, g_steal_pointer (&info)); +} + +static DexFuture * +get_process_info (void) +{ + DexPromise *promise = dex_promise_new (); + dex_scheduler_push (dex_thread_pool_scheduler_get_default (), + get_process_info_task, + dex_ref (promise)); + return DEX_FUTURE (g_steal_pointer (&promise)); +} + static DexFuture * sysprof_linux_instrument_prepare_fiber (gpointer user_data) { SysprofLinuxInstrument *self = user_data; - g_autoptr(GDBusConnection) bus = NULL; g_autoptr(GVariant) process_info_reply = NULL; g_autoptr(GVariant) process_info = NULL; g_autoptr(GError) error = NULL; @@ -259,28 +297,37 @@ sysprof_linux_instrument_prepare_fiber (gpointer user_data) &error)) return dex_future_new_for_error (g_steal_pointer (&error)); - /* We need access to the bus to call various sysprofd API directly */ - if (!(bus = dex_await_object (dex_bus_get (G_BUS_TYPE_SYSTEM), &error))) - return dex_future_new_for_error (g_steal_pointer (&error)); - - /* We also want to get a bunch of info on user processes so that we can add - * records about them to the recording. - */ at_time = SYSPROF_CAPTURE_CURRENT_TIME; - if (!(process_info_reply = dex_await_variant (dex_dbus_connection_call (bus, - "org.gnome.Sysprof3", - "/org/gnome/Sysprof3", - "org.gnome.Sysprof3.Service", - "GetProcessInfo", - g_variant_new ("(s)", "pid,maps,mountinfo,cmdline,comm,cgroup"), - G_VARIANT_TYPE ("(aa{sv})"), - G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION, - G_MAXINT), - &error))) - return dex_future_new_for_error (g_steal_pointer (&error)); - /* Add process records for each of the processes discovered */ - process_info = g_variant_get_child_value (process_info_reply, 0); + if (self->connection != NULL) + { + /* We also want to get a bunch of info on user processes so that we can add + * records about them to the recording. + */ + if (!(process_info_reply = dex_await_variant (dex_dbus_connection_call (self->connection, + "org.gnome.Sysprof3", + "/org/gnome/Sysprof3", + "org.gnome.Sysprof3.Service", + "GetProcessInfo", + g_variant_new ("(s)", PROCESS_INFO_KEYS), + G_VARIANT_TYPE ("(aa{sv})"), + G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION, + G_MAXINT), + &error))) + return dex_future_new_for_error (g_steal_pointer (&error)); + + /* Add process records for each of the processes discovered */ + process_info = g_variant_get_child_value (process_info_reply, 0); + } + else + { + /* Load process info using same mechanism as sysprofd */ + if (!(process_info = dex_await_variant (get_process_info (), &error))) + return dex_future_new_for_error (g_steal_pointer (&error)); + } + + g_assert (process_info != NULL); + dex_await (add_process_info (self, self->recording, process_info, at_time), NULL); return dex_future_new_for_boolean (TRUE); @@ -454,6 +501,7 @@ sysprof_linux_instrument_dispose (GObject *object) { SysprofLinuxInstrument *self = (SysprofLinuxInstrument *)object; + g_clear_object (&self->connection); g_clear_object (&self->recording); g_hash_table_remove_all (self->seen); @@ -482,6 +530,7 @@ sysprof_linux_instrument_class_init (SysprofLinuxInstrumentClass *klass) instrument_class->list_required_policy = sysprof_linux_instrument_list_required_policy; instrument_class->prepare = sysprof_linux_instrument_prepare; instrument_class->process_started = sysprof_linux_instrument_process_started; + instrument_class->set_connection = sysprof_linux_instrument_set_connection; } static void diff --git a/src/libsysprof/sysprof-sampler.c b/src/libsysprof/sysprof-sampler.c index 15b709f3..bd2fca36 100644 --- a/src/libsysprof/sysprof-sampler.c +++ b/src/libsysprof/sysprof-sampler.c @@ -29,10 +29,11 @@ struct _SysprofSampler { - SysprofInstrument parent_instance; - GPtrArray *perf_event_streams; - guint sample_lost_counter_id; - gint64 lost_count; + SysprofInstrument parent_instance; + GDBusConnection *connection; + GPtrArray *perf_event_streams; + guint sample_lost_counter_id; + gint64 lost_count; }; struct _SysprofSamplerClass @@ -312,7 +313,8 @@ sysprof_sampler_perf_event_stream_cb (const SysprofPerfEvent *event, typedef struct _Prepare { SysprofRecording *recording; - SysprofSampler *sampler; + SysprofSampler *sampler; + GDBusConnection *connection; } Prepare; static void @@ -320,6 +322,7 @@ prepare_free (Prepare *prepare) { g_clear_object (&prepare->recording); g_clear_object (&prepare->sampler); + g_clear_object (&prepare->connection); g_free (prepare); } @@ -327,7 +330,6 @@ static DexFuture * sysprof_sampler_prepare_fiber (gpointer user_data) { Prepare *prepare = user_data; - g_autoptr(GDBusConnection) connection = NULL; g_autoptr(StreamData) stream_data = NULL; g_autoptr(GPtrArray) futures = NULL; g_autoptr(GError) error = NULL; @@ -339,6 +341,7 @@ sysprof_sampler_prepare_fiber (gpointer user_data) g_assert (prepare != NULL); g_assert (SYSPROF_IS_RECORDING (prepare->recording)); g_assert (SYSPROF_IS_SAMPLER (prepare->sampler)); + g_assert (!prepare->connection || G_IS_DBUS_CONNECTION (prepare->connection)); /* First thing we need to do is to ensure the consumer has * access to kallsyms, which may be from a machine, or boot @@ -406,16 +409,13 @@ try_again: attr.sample_period = 1200000; } - if (!(connection = dex_await_object (dex_bus_get (G_BUS_TYPE_SYSTEM), &error))) - return dex_future_new_for_error (g_steal_pointer (&error)); - /* Pipeline our request for n_cpu perf_event_open calls and then * await them all to complete. */ stream_data = stream_data_new (prepare->recording); for (guint i = 0; i < n_cpu; i++) g_ptr_array_add (futures, - sysprof_perf_event_stream_new (connection, + sysprof_perf_event_stream_new (prepare->connection, &attr, i, -1, @@ -513,8 +513,9 @@ sysprof_sampler_prepare (SysprofInstrument *instrument, g_assert (SYSPROF_IS_RECORDING (recording)); prepare = g_new0 (Prepare, 1); - prepare->recording = g_object_ref (recording); - prepare->sampler = g_object_ref (self); + g_set_object (&prepare->recording, recording); + g_set_object (&prepare->sampler, self); + g_set_object (&prepare->connection, self->connection); return dex_scheduler_spawn (NULL, 0, sysprof_sampler_prepare_fiber, @@ -590,12 +591,22 @@ sysprof_sampler_record (SysprofInstrument *instrument, (GDestroyNotify)record_free); } +static void +sysprof_sampler_set_connection (SysprofInstrument *instrument, + GDBusConnection *connection) +{ + SysprofSampler *self = SYSPROF_SAMPLER (instrument); + + g_set_object (&self->connection, connection); +} + static void sysprof_sampler_finalize (GObject *object) { SysprofSampler *self = (SysprofSampler *)object; g_clear_pointer (&self->perf_event_streams, g_ptr_array_unref); + g_clear_object (&self->connection); G_OBJECT_CLASS (sysprof_sampler_parent_class)->finalize (object); } @@ -611,6 +622,7 @@ sysprof_sampler_class_init (SysprofSamplerClass *klass) instrument_class->list_required_policy = sysprof_sampler_list_required_policy; instrument_class->prepare = sysprof_sampler_prepare; instrument_class->record = sysprof_sampler_record; + instrument_class->set_connection = sysprof_sampler_set_connection; } static void diff --git a/src/libsysprof/sysprof-scheduler-details.c b/src/libsysprof/sysprof-scheduler-details.c index 67aa1a52..c05f7794 100644 --- a/src/libsysprof/sysprof-scheduler-details.c +++ b/src/libsysprof/sysprof-scheduler-details.c @@ -24,6 +24,7 @@ #include "sysprof-perf-event-stream-private.h" #include "sysprof-scheduler-details.h" #include "sysprof-recording-private.h" +#include "sysprof-util-private.h" #include "line-reader-private.h" @@ -31,6 +32,7 @@ struct _SysprofSchedulerDetails { SysprofInstrument parent_instance; + GDBusConnection *connection; SysprofRecording *recording; DexFuture *cancellable; GPtrArray *streams; @@ -193,9 +195,8 @@ static DexFuture * sysprof_scheduler_details_prepare_fiber (gpointer user_data) { SysprofSchedulerDetails *self = user_data; - g_autoptr(GDBusConnection) bus = NULL; g_autoptr(GPtrArray) futures = NULL; - g_autoptr(GVariant) format_reply = NULL; + g_autoptr(GBytes) format_bytes = NULL; g_autoptr(GError) error = NULL; g_autofree char *format = NULL; int n_cpu; @@ -203,22 +204,13 @@ sysprof_scheduler_details_prepare_fiber (gpointer user_data) g_assert (SYSPROF_IS_SCHEDULER_DETAILS (self)); g_assert (SYSPROF_IS_RECORDING (self->recording)); - if (!(bus = dex_await_object (dex_bus_get (G_BUS_TYPE_SYSTEM), &error))) + if (!(format_bytes = dex_await_boxed (sysprof_get_proc_file_bytes (self->connection, + "/sys/kernel/debug/tracing/events/sched/sched_switch/format"), + &error))) goto handle_error; - if (!(format_reply = dex_await_variant (dex_dbus_connection_call (bus, - "org.gnome.Sysprof3", - "/org/gnome/Sysprof3", - "org.gnome.Sysprof3.Service", - "GetProcFile", - g_variant_new ("(^ay)", "/sys/kernel/debug/tracing/events/sched/sched_switch/format"), - G_VARIANT_TYPE ("(ay)"), - G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION, - G_MAXINT), - &error))) - goto handle_error; - - g_variant_get (format_reply, "(^ay)", &format); + format = g_strndup (g_bytes_get_data (format_bytes, NULL), + g_bytes_get_size (format_bytes)); if (!sysprof_scheduler_details_parse_format (self, format)) { @@ -255,7 +247,7 @@ sysprof_scheduler_details_prepare_fiber (gpointer user_data) attr.size = sizeof attr; g_ptr_array_add (futures, - sysprof_perf_event_stream_new (bus, + sysprof_perf_event_stream_new (self->connection, &attr, cpu, -1, @@ -361,6 +353,15 @@ sysprof_scheduler_details_record (SysprofInstrument *instrument, g_object_unref); } +static void +sysprof_scheduler_details_set_connection (SysprofInstrument *instrument, + GDBusConnection *connection) +{ + SysprofSchedulerDetails *self = SYSPROF_SCHEDULER_DETAILS (instrument); + + g_set_object (&self->connection, connection); +} + static void sysprof_scheduler_details_dispose (GObject *object) { @@ -377,6 +378,7 @@ sysprof_scheduler_details_dispose (GObject *object) g_clear_pointer (&self->streams, g_ptr_array_unref); } + g_clear_object (&self->connection); g_clear_object (&self->recording); g_clear_pointer (&self->last_switch_times, g_free); dex_clear (&self->cancellable); @@ -394,6 +396,7 @@ sysprof_scheduler_details_class_init (SysprofSchedulerDetailsClass *klass) instrument_class->prepare = sysprof_scheduler_details_prepare; instrument_class->record = sysprof_scheduler_details_record; + instrument_class->set_connection = sysprof_scheduler_details_set_connection; } static void