mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2026-02-08 14:10:55 +00:00
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:
@ -159,6 +159,8 @@ libsysprof_private_sources = [
|
|||||||
'sysprof-util.c',
|
'sysprof-util.c',
|
||||||
'timsort/gtktimsort.c',
|
'timsort/gtktimsort.c',
|
||||||
|
|
||||||
|
'../sysprofd/helpers.c',
|
||||||
|
|
||||||
gnome.gdbus_codegen('ipc-unwinder',
|
gnome.gdbus_codegen('ipc-unwinder',
|
||||||
sources: '../sysprofd/org.gnome.Sysprof3.Unwinder.xml',
|
sources: '../sysprofd/org.gnome.Sysprof3.Unwinder.xml',
|
||||||
interface_prefix: 'org.gnome.Sysprof3.',
|
interface_prefix: 'org.gnome.Sysprof3.',
|
||||||
|
|||||||
@ -29,11 +29,16 @@
|
|||||||
|
|
||||||
#include "line-reader-private.h"
|
#include "line-reader-private.h"
|
||||||
|
|
||||||
|
#include "../sysprofd/helpers.h"
|
||||||
|
|
||||||
|
#define PROCESS_INFO_KEYS "pid,maps,mountinfo,cmdline,comm,cgroup"
|
||||||
|
|
||||||
struct _SysprofLinuxInstrument
|
struct _SysprofLinuxInstrument
|
||||||
{
|
{
|
||||||
SysprofInstrument parent_instance;
|
SysprofInstrument parent_instance;
|
||||||
SysprofRecording *recording;
|
GDBusConnection *connection;
|
||||||
GHashTable *seen;
|
SysprofRecording *recording;
|
||||||
|
GHashTable *seen;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_FINAL_TYPE (SysprofLinuxInstrument, sysprof_linux_instrument, SYSPROF_TYPE_INSTRUMENT)
|
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);
|
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
|
static void
|
||||||
add_mmaps (SysprofRecording *recording,
|
add_mmaps (SysprofRecording *recording,
|
||||||
GPid pid,
|
GPid pid,
|
||||||
@ -237,11 +251,35 @@ add_process_info (SysprofLinuxInstrument *self,
|
|||||||
return dex_future_new_for_boolean (TRUE);
|
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 *
|
static DexFuture *
|
||||||
sysprof_linux_instrument_prepare_fiber (gpointer user_data)
|
sysprof_linux_instrument_prepare_fiber (gpointer user_data)
|
||||||
{
|
{
|
||||||
SysprofLinuxInstrument *self = user_data;
|
SysprofLinuxInstrument *self = user_data;
|
||||||
g_autoptr(GDBusConnection) bus = NULL;
|
|
||||||
g_autoptr(GVariant) process_info_reply = NULL;
|
g_autoptr(GVariant) process_info_reply = NULL;
|
||||||
g_autoptr(GVariant) process_info = NULL;
|
g_autoptr(GVariant) process_info = NULL;
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
@ -259,28 +297,37 @@ sysprof_linux_instrument_prepare_fiber (gpointer user_data)
|
|||||||
&error))
|
&error))
|
||||||
return dex_future_new_for_error (g_steal_pointer (&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;
|
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 */
|
if (self->connection != NULL)
|
||||||
process_info = g_variant_get_child_value (process_info_reply, 0);
|
{
|
||||||
|
/* 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);
|
dex_await (add_process_info (self, self->recording, process_info, at_time), NULL);
|
||||||
|
|
||||||
return dex_future_new_for_boolean (TRUE);
|
return dex_future_new_for_boolean (TRUE);
|
||||||
@ -454,6 +501,7 @@ sysprof_linux_instrument_dispose (GObject *object)
|
|||||||
{
|
{
|
||||||
SysprofLinuxInstrument *self = (SysprofLinuxInstrument *)object;
|
SysprofLinuxInstrument *self = (SysprofLinuxInstrument *)object;
|
||||||
|
|
||||||
|
g_clear_object (&self->connection);
|
||||||
g_clear_object (&self->recording);
|
g_clear_object (&self->recording);
|
||||||
g_hash_table_remove_all (self->seen);
|
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->list_required_policy = sysprof_linux_instrument_list_required_policy;
|
||||||
instrument_class->prepare = sysprof_linux_instrument_prepare;
|
instrument_class->prepare = sysprof_linux_instrument_prepare;
|
||||||
instrument_class->process_started = sysprof_linux_instrument_process_started;
|
instrument_class->process_started = sysprof_linux_instrument_process_started;
|
||||||
|
instrument_class->set_connection = sysprof_linux_instrument_set_connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@ -29,10 +29,11 @@
|
|||||||
|
|
||||||
struct _SysprofSampler
|
struct _SysprofSampler
|
||||||
{
|
{
|
||||||
SysprofInstrument parent_instance;
|
SysprofInstrument parent_instance;
|
||||||
GPtrArray *perf_event_streams;
|
GDBusConnection *connection;
|
||||||
guint sample_lost_counter_id;
|
GPtrArray *perf_event_streams;
|
||||||
gint64 lost_count;
|
guint sample_lost_counter_id;
|
||||||
|
gint64 lost_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _SysprofSamplerClass
|
struct _SysprofSamplerClass
|
||||||
@ -312,7 +313,8 @@ sysprof_sampler_perf_event_stream_cb (const SysprofPerfEvent *event,
|
|||||||
typedef struct _Prepare
|
typedef struct _Prepare
|
||||||
{
|
{
|
||||||
SysprofRecording *recording;
|
SysprofRecording *recording;
|
||||||
SysprofSampler *sampler;
|
SysprofSampler *sampler;
|
||||||
|
GDBusConnection *connection;
|
||||||
} Prepare;
|
} Prepare;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -320,6 +322,7 @@ prepare_free (Prepare *prepare)
|
|||||||
{
|
{
|
||||||
g_clear_object (&prepare->recording);
|
g_clear_object (&prepare->recording);
|
||||||
g_clear_object (&prepare->sampler);
|
g_clear_object (&prepare->sampler);
|
||||||
|
g_clear_object (&prepare->connection);
|
||||||
g_free (prepare);
|
g_free (prepare);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,7 +330,6 @@ static DexFuture *
|
|||||||
sysprof_sampler_prepare_fiber (gpointer user_data)
|
sysprof_sampler_prepare_fiber (gpointer user_data)
|
||||||
{
|
{
|
||||||
Prepare *prepare = user_data;
|
Prepare *prepare = user_data;
|
||||||
g_autoptr(GDBusConnection) connection = NULL;
|
|
||||||
g_autoptr(StreamData) stream_data = NULL;
|
g_autoptr(StreamData) stream_data = NULL;
|
||||||
g_autoptr(GPtrArray) futures = NULL;
|
g_autoptr(GPtrArray) futures = NULL;
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
@ -339,6 +341,7 @@ sysprof_sampler_prepare_fiber (gpointer user_data)
|
|||||||
g_assert (prepare != NULL);
|
g_assert (prepare != NULL);
|
||||||
g_assert (SYSPROF_IS_RECORDING (prepare->recording));
|
g_assert (SYSPROF_IS_RECORDING (prepare->recording));
|
||||||
g_assert (SYSPROF_IS_SAMPLER (prepare->sampler));
|
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
|
/* First thing we need to do is to ensure the consumer has
|
||||||
* access to kallsyms, which may be from a machine, or boot
|
* access to kallsyms, which may be from a machine, or boot
|
||||||
@ -406,16 +409,13 @@ try_again:
|
|||||||
attr.sample_period = 1200000;
|
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
|
/* Pipeline our request for n_cpu perf_event_open calls and then
|
||||||
* await them all to complete.
|
* await them all to complete.
|
||||||
*/
|
*/
|
||||||
stream_data = stream_data_new (prepare->recording);
|
stream_data = stream_data_new (prepare->recording);
|
||||||
for (guint i = 0; i < n_cpu; i++)
|
for (guint i = 0; i < n_cpu; i++)
|
||||||
g_ptr_array_add (futures,
|
g_ptr_array_add (futures,
|
||||||
sysprof_perf_event_stream_new (connection,
|
sysprof_perf_event_stream_new (prepare->connection,
|
||||||
&attr,
|
&attr,
|
||||||
i,
|
i,
|
||||||
-1,
|
-1,
|
||||||
@ -513,8 +513,9 @@ sysprof_sampler_prepare (SysprofInstrument *instrument,
|
|||||||
g_assert (SYSPROF_IS_RECORDING (recording));
|
g_assert (SYSPROF_IS_RECORDING (recording));
|
||||||
|
|
||||||
prepare = g_new0 (Prepare, 1);
|
prepare = g_new0 (Prepare, 1);
|
||||||
prepare->recording = g_object_ref (recording);
|
g_set_object (&prepare->recording, recording);
|
||||||
prepare->sampler = g_object_ref (self);
|
g_set_object (&prepare->sampler, self);
|
||||||
|
g_set_object (&prepare->connection, self->connection);
|
||||||
|
|
||||||
return dex_scheduler_spawn (NULL, 0,
|
return dex_scheduler_spawn (NULL, 0,
|
||||||
sysprof_sampler_prepare_fiber,
|
sysprof_sampler_prepare_fiber,
|
||||||
@ -590,12 +591,22 @@ sysprof_sampler_record (SysprofInstrument *instrument,
|
|||||||
(GDestroyNotify)record_free);
|
(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
|
static void
|
||||||
sysprof_sampler_finalize (GObject *object)
|
sysprof_sampler_finalize (GObject *object)
|
||||||
{
|
{
|
||||||
SysprofSampler *self = (SysprofSampler *)object;
|
SysprofSampler *self = (SysprofSampler *)object;
|
||||||
|
|
||||||
g_clear_pointer (&self->perf_event_streams, g_ptr_array_unref);
|
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);
|
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->list_required_policy = sysprof_sampler_list_required_policy;
|
||||||
instrument_class->prepare = sysprof_sampler_prepare;
|
instrument_class->prepare = sysprof_sampler_prepare;
|
||||||
instrument_class->record = sysprof_sampler_record;
|
instrument_class->record = sysprof_sampler_record;
|
||||||
|
instrument_class->set_connection = sysprof_sampler_set_connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
#include "sysprof-perf-event-stream-private.h"
|
#include "sysprof-perf-event-stream-private.h"
|
||||||
#include "sysprof-scheduler-details.h"
|
#include "sysprof-scheduler-details.h"
|
||||||
#include "sysprof-recording-private.h"
|
#include "sysprof-recording-private.h"
|
||||||
|
#include "sysprof-util-private.h"
|
||||||
|
|
||||||
#include "line-reader-private.h"
|
#include "line-reader-private.h"
|
||||||
|
|
||||||
@ -31,6 +32,7 @@ struct _SysprofSchedulerDetails
|
|||||||
{
|
{
|
||||||
SysprofInstrument parent_instance;
|
SysprofInstrument parent_instance;
|
||||||
|
|
||||||
|
GDBusConnection *connection;
|
||||||
SysprofRecording *recording;
|
SysprofRecording *recording;
|
||||||
DexFuture *cancellable;
|
DexFuture *cancellable;
|
||||||
GPtrArray *streams;
|
GPtrArray *streams;
|
||||||
@ -193,9 +195,8 @@ static DexFuture *
|
|||||||
sysprof_scheduler_details_prepare_fiber (gpointer user_data)
|
sysprof_scheduler_details_prepare_fiber (gpointer user_data)
|
||||||
{
|
{
|
||||||
SysprofSchedulerDetails *self = user_data;
|
SysprofSchedulerDetails *self = user_data;
|
||||||
g_autoptr(GDBusConnection) bus = NULL;
|
|
||||||
g_autoptr(GPtrArray) futures = NULL;
|
g_autoptr(GPtrArray) futures = NULL;
|
||||||
g_autoptr(GVariant) format_reply = NULL;
|
g_autoptr(GBytes) format_bytes = NULL;
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
g_autofree char *format = NULL;
|
g_autofree char *format = NULL;
|
||||||
int n_cpu;
|
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_SCHEDULER_DETAILS (self));
|
||||||
g_assert (SYSPROF_IS_RECORDING (self->recording));
|
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;
|
goto handle_error;
|
||||||
|
|
||||||
if (!(format_reply = dex_await_variant (dex_dbus_connection_call (bus,
|
format = g_strndup (g_bytes_get_data (format_bytes, NULL),
|
||||||
"org.gnome.Sysprof3",
|
g_bytes_get_size (format_bytes));
|
||||||
"/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);
|
|
||||||
|
|
||||||
if (!sysprof_scheduler_details_parse_format (self, format))
|
if (!sysprof_scheduler_details_parse_format (self, format))
|
||||||
{
|
{
|
||||||
@ -255,7 +247,7 @@ sysprof_scheduler_details_prepare_fiber (gpointer user_data)
|
|||||||
attr.size = sizeof attr;
|
attr.size = sizeof attr;
|
||||||
|
|
||||||
g_ptr_array_add (futures,
|
g_ptr_array_add (futures,
|
||||||
sysprof_perf_event_stream_new (bus,
|
sysprof_perf_event_stream_new (self->connection,
|
||||||
&attr,
|
&attr,
|
||||||
cpu,
|
cpu,
|
||||||
-1,
|
-1,
|
||||||
@ -361,6 +353,15 @@ sysprof_scheduler_details_record (SysprofInstrument *instrument,
|
|||||||
g_object_unref);
|
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
|
static void
|
||||||
sysprof_scheduler_details_dispose (GObject *object)
|
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_pointer (&self->streams, g_ptr_array_unref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_clear_object (&self->connection);
|
||||||
g_clear_object (&self->recording);
|
g_clear_object (&self->recording);
|
||||||
g_clear_pointer (&self->last_switch_times, g_free);
|
g_clear_pointer (&self->last_switch_times, g_free);
|
||||||
dex_clear (&self->cancellable);
|
dex_clear (&self->cancellable);
|
||||||
@ -394,6 +396,7 @@ sysprof_scheduler_details_class_init (SysprofSchedulerDetailsClass *klass)
|
|||||||
|
|
||||||
instrument_class->prepare = sysprof_scheduler_details_prepare;
|
instrument_class->prepare = sysprof_scheduler_details_prepare;
|
||||||
instrument_class->record = sysprof_scheduler_details_record;
|
instrument_class->record = sysprof_scheduler_details_record;
|
||||||
|
instrument_class->set_connection = sysprof_scheduler_details_set_connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
Reference in New Issue
Block a user