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.
This commit is contained in:
Christian Hergert
2025-03-21 12:04:28 -07:00
parent 94af48094d
commit f7eb2134ad
4 changed files with 119 additions and 53 deletions

View File

@ -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.',

View File

@ -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

View File

@ -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

View File

@ -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