sysprof: add SysprofRecordingTemplate

The goal here is to have a backing object that represents what we want to
record so it becomes easier later on to save/restore state.
This commit is contained in:
Christian Hergert
2023-08-06 00:44:41 -07:00
parent 827541e88c
commit 8bf8b4455f
3 changed files with 581 additions and 0 deletions

View File

@ -41,6 +41,7 @@ sysprof_sources = [
'sysprof-processes-section.c',
'sysprof-progress-cell.c',
'sysprof-recording-pad.c',
'sysprof-recording-template.c',
'sysprof-samples-section.c',
'sysprof-scheduler.c',
'sysprof-section.c',

View File

@ -0,0 +1,539 @@
/* sysprof-recording-template.c
*
* Copyright 2023 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "config.h"
#include "sysprof-recording-template.h"
struct _SysprofRecordingTemplate
{
GObject parent_instance;
char *command_line;
char *cwd;
char *power_profile;
char **environ;
guint battery_charge : 1;
guint bundle_symbols : 1;
guint clear_environ : 1;
guint cpu_usage : 1;
guint disk_usage : 1;
guint energy_usage : 1;
guint frame_timings : 1;
guint javascript_stacks : 1;
guint memory_allocations : 1;
guint memory_usage : 1;
guint native_stacks : 1;
guint network_usage : 1;
guint session_bus : 1;
guint system_bus : 1;
guint system_log : 1;
};
enum {
PROP_0,
PROP_BATTERY_CHARGE,
PROP_BUNDLE_SYMBOLS,
PROP_CLEAR_ENVIRON,
PROP_COMMAND_LINE,
PROP_CPU_USAGE,
PROP_CWD,
PROP_DISK_USAGE,
PROP_ENERGY_USAGE,
PROP_ENVIRON,
PROP_FRAME_TIMINGS,
PROP_JAVASCRIPT_STACKS,
PROP_MEMORY_ALLOCATIONS,
PROP_MEMORY_USAGE,
PROP_NATIVE_STACKS,
PROP_NETWORK_USAGE,
PROP_POWER_PROFILE,
PROP_SESSION_BUS,
PROP_SYSTEM_BUS,
PROP_SYSTEM_LOG,
N_PROPS
};
G_DEFINE_FINAL_TYPE (SysprofRecordingTemplate, sysprof_recording_template, G_TYPE_OBJECT)
static GParamSpec *properties [N_PROPS];
static void
sysprof_recording_template_finalize (GObject *object)
{
SysprofRecordingTemplate *self = (SysprofRecordingTemplate *)object;
g_clear_pointer (&self->command_line, g_free);
g_clear_pointer (&self->cwd, g_free);
g_clear_pointer (&self->power_profile, g_free);
g_clear_pointer (&self->environ, g_free);
G_OBJECT_CLASS (sysprof_recording_template_parent_class)->finalize (object);
}
static void
sysprof_recording_template_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SysprofRecordingTemplate *self = SYSPROF_RECORDING_TEMPLATE (object);
switch (prop_id)
{
case PROP_BATTERY_CHARGE:
g_value_set_boolean (value, self->battery_charge);
break;
case PROP_BUNDLE_SYMBOLS:
g_value_set_boolean (value, self->bundle_symbols);
break;
case PROP_CLEAR_ENVIRON:
g_value_set_boolean (value, self->clear_environ);
break;
case PROP_COMMAND_LINE:
g_value_set_string (value, self->command_line);
break;
case PROP_CPU_USAGE:
g_value_set_boolean (value, self->cpu_usage);
break;
case PROP_CWD:
g_value_set_string (value, self->cwd);
break;
case PROP_DISK_USAGE:
g_value_set_boolean (value, self->disk_usage);
break;
case PROP_ENERGY_USAGE:
g_value_set_boolean (value, self->energy_usage);
break;
case PROP_ENVIRON:
g_value_set_boxed (value, self->environ);
break;
case PROP_FRAME_TIMINGS:
g_value_set_boolean (value, self->frame_timings);
break;
case PROP_JAVASCRIPT_STACKS:
g_value_set_boolean (value, self->javascript_stacks);
break;
case PROP_MEMORY_ALLOCATIONS:
g_value_set_boolean (value, self->memory_allocations);
break;
case PROP_NATIVE_STACKS:
g_value_set_boolean (value, self->native_stacks);
break;
case PROP_NETWORK_USAGE:
g_value_set_boolean (value, self->network_usage);
break;
case PROP_POWER_PROFILE:
g_value_set_string (value, self->power_profile);
break;
case PROP_SESSION_BUS:
g_value_set_boolean (value, self->session_bus);
break;
case PROP_SYSTEM_BUS:
g_value_set_boolean (value, self->system_bus);
break;
case PROP_SYSTEM_LOG:
g_value_set_boolean (value, self->system_log);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_recording_template_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SysprofRecordingTemplate *self = SYSPROF_RECORDING_TEMPLATE (object);
switch (prop_id)
{
case PROP_BATTERY_CHARGE:
self->battery_charge = g_value_get_boolean (value);
break;
case PROP_BUNDLE_SYMBOLS:
self->bundle_symbols = g_value_get_boolean (value);
break;
case PROP_CLEAR_ENVIRON:
self->clear_environ = g_value_get_boolean (value);
break;
case PROP_COMMAND_LINE:
g_set_str (&self->command_line, g_value_get_string (value));
break;
case PROP_CPU_USAGE:
self->cpu_usage = g_value_get_boolean (value);
break;
case PROP_CWD:
g_set_str (&self->cwd, g_value_get_string (value));
break;
case PROP_DISK_USAGE:
self->disk_usage = g_value_get_boolean (value);
break;
case PROP_ENERGY_USAGE:
self->energy_usage = g_value_get_boolean (value);
break;
case PROP_ENVIRON:
g_clear_pointer (&self->environ, g_strfreev);
self->environ = g_value_dup_boxed (value);
break;
case PROP_FRAME_TIMINGS:
self->frame_timings = g_value_get_boolean (value);
break;
case PROP_JAVASCRIPT_STACKS:
self->javascript_stacks = g_value_get_boolean (value);
break;
case PROP_MEMORY_ALLOCATIONS:
self->memory_allocations = g_value_get_boolean (value);
break;
case PROP_NATIVE_STACKS:
self->native_stacks = g_value_get_boolean (value);
break;
case PROP_NETWORK_USAGE:
self->network_usage = g_value_get_boolean (value);
break;
case PROP_POWER_PROFILE:
g_set_str (&self->power_profile, g_value_get_string (value));
break;
case PROP_SESSION_BUS:
self->session_bus = g_value_get_boolean (value);
break;
case PROP_SYSTEM_BUS:
self->system_bus = g_value_get_boolean (value);
break;
case PROP_SYSTEM_LOG:
self->system_log = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_recording_template_class_init (SysprofRecordingTemplateClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = sysprof_recording_template_finalize;
object_class->get_property = sysprof_recording_template_get_property;
object_class->set_property = sysprof_recording_template_set_property;
properties[PROP_BATTERY_CHARGE] =
g_param_spec_boolean ("battery-charge", NULL, NULL,
FALSE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_BUNDLE_SYMBOLS] =
g_param_spec_boolean ("bundle-symbols", NULL, NULL,
TRUE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_CLEAR_ENVIRON] =
g_param_spec_boolean ("clear-environ", NULL, NULL,
FALSE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_COMMAND_LINE] =
g_param_spec_string ("command-line", NULL, NULL,
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_CPU_USAGE] =
g_param_spec_boolean ("cpu-usage", NULL, NULL,
TRUE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_CWD] =
g_param_spec_string ("cwd", NULL, NULL,
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_DISK_USAGE] =
g_param_spec_boolean ("disk-usage", NULL, NULL,
TRUE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_ENERGY_USAGE] =
g_param_spec_boolean ("energy-usage", NULL, NULL,
FALSE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_ENVIRON] =
g_param_spec_boxed ("environ", NULL, NULL,
G_TYPE_STRV,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_FRAME_TIMINGS] =
g_param_spec_boolean ("frame-timings", NULL, NULL,
TRUE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_JAVASCRIPT_STACKS] =
g_param_spec_boolean ("javascript-stacks", NULL, NULL,
FALSE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_MEMORY_ALLOCATIONS] =
g_param_spec_boolean ("memory-allocations", NULL, NULL,
FALSE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_MEMORY_USAGE] =
g_param_spec_boolean ("memory-usage", NULL, NULL,
TRUE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_NATIVE_STACKS] =
g_param_spec_boolean ("native-stacks", NULL, NULL,
TRUE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_NETWORK_USAGE] =
g_param_spec_boolean ("network-usage", NULL, NULL,
TRUE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_POWER_PROFILE] =
g_param_spec_string ("power-profile", NULL, NULL,
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_SESSION_BUS] =
g_param_spec_boolean ("session-bus", NULL, NULL,
FALSE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_SYSTEM_BUS] =
g_param_spec_boolean ("system-bus", NULL, NULL,
FALSE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_SYSTEM_LOG] =
g_param_spec_boolean ("system-log", NULL, NULL,
TRUE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
sysprof_recording_template_init (SysprofRecordingTemplate *self)
{
self->bundle_symbols = TRUE;
self->cpu_usage = TRUE;
self->disk_usage = TRUE;
self->frame_timings = TRUE;
self->memory_usage = TRUE;
self->native_stacks = TRUE;
self->network_usage = TRUE;
self->system_log = TRUE;
}
SysprofRecordingTemplate *
sysprof_recording_template_new (void)
{
return g_object_new (SYSPROF_TYPE_RECORDING_TEMPLATE, NULL);
}
static gboolean
environ_parse (const char *pair,
char **key,
char **value)
{
const gchar *eq;
g_return_val_if_fail (pair != NULL, FALSE);
if (key != NULL)
*key = NULL;
if (value != NULL)
*value = NULL;
if ((eq = strchr (pair, '=')))
{
if (key != NULL)
*key = g_strndup (pair, eq - pair);
if (value != NULL)
*value = g_strdup (eq + 1);
return TRUE;
}
return FALSE;
}
static void
add_trace_fd (SysprofProfiler *profiler,
SysprofSpawnable *spawnable,
const char *name)
{
int trace_fd;
g_assert (SYSPROF_IS_PROFILER (profiler));
g_assert (!spawnable || SYSPROF_IS_SPAWNABLE (spawnable));
if (spawnable == NULL)
return;
trace_fd = sysprof_spawnable_add_trace_fd (spawnable, name);
sysprof_profiler_add_instrument (profiler, sysprof_tracefd_consumer_new (trace_fd));
}
SysprofProfiler *
sysprof_recording_template_apply (SysprofRecordingTemplate *self,
GError **error)
{
g_autoptr(SysprofProfiler) profiler = NULL;
g_return_val_if_fail (SYSPROF_IS_RECORDING_TEMPLATE (self), NULL);
profiler = sysprof_profiler_new ();
if (self->command_line && self->command_line[0])
{
g_autofree char *stripped = g_strstrip (g_strdup (self->command_line));
g_autoptr(SysprofSpawnable) spawnable = NULL;
g_autoptr(GError) local_error = NULL;
g_auto(GStrv) argv = NULL;
g_auto(GStrv) env = NULL;
int argc;
if (!g_shell_parse_argv (stripped, &argc, &argv, &local_error))
{
g_set_error_literal (error,
SYSPROF_RECORDING_TEMPLATE_ERROR,
SYSPROF_RECORDING_TEMPLATE_ERROR_COMMAND_LINE,
local_error->message);
return FALSE;
}
spawnable = sysprof_spawnable_new ();
sysprof_spawnable_append_args (spawnable, (const char * const *)argv);
if (self->cwd && self->cwd[0])
sysprof_spawnable_set_cwd (spawnable, self->cwd);
if (!self->clear_environ)
env = g_get_environ ();
if (self->environ)
{
for (guint i = 0; self->environ[i]; i++)
{
g_autofree char *key = NULL;
g_autofree char *value = NULL;
if (environ_parse (self->environ[i], &key, &value))
env = g_environ_setenv (env, key, value, TRUE);
}
}
if (self->memory_allocations)
sysprof_spawnable_add_ld_preload (spawnable, PACKAGE_LIBDIR"/libsysprof-memory-"API_VERSION_S".so");
sysprof_profiler_set_spawnable (profiler, spawnable);
if (self->javascript_stacks)
add_trace_fd (profiler, spawnable, "GJS_TRACE_FD");
}
if (self->power_profile && self->power_profile[0])
sysprof_profiler_add_instrument (profiler, sysprof_power_profile_new (self->power_profile));
if (self->battery_charge)
sysprof_profiler_add_instrument (profiler, sysprof_battery_charge_new ());
if (self->bundle_symbols)
sysprof_profiler_add_instrument (profiler, sysprof_symbols_bundle_new ());
if (self->disk_usage)
sysprof_profiler_add_instrument (profiler, sysprof_disk_usage_new ());
if (self->energy_usage)
sysprof_profiler_add_instrument (profiler, sysprof_energy_usage_new ());
if (self->frame_timings)
sysprof_profiler_add_instrument (profiler,
sysprof_proxied_instrument_new (G_BUS_TYPE_SESSION,
"org.gnome.Shell",
"/org/gnome/Sysprof3/Profiler"));
if (self->memory_usage)
sysprof_profiler_add_instrument (profiler, sysprof_memory_usage_new ());
if (self->native_stacks)
sysprof_profiler_add_instrument (profiler, sysprof_sampler_new ());
if (self->network_usage)
sysprof_profiler_add_instrument (profiler, sysprof_network_usage_new ());
if (self->session_bus)
sysprof_profiler_add_instrument (profiler, sysprof_dbus_monitor_new (G_BUS_TYPE_SESSION));
if (self->system_bus)
sysprof_profiler_add_instrument (profiler, sysprof_dbus_monitor_new (G_BUS_TYPE_SYSTEM));
if (self->system_log)
sysprof_profiler_add_instrument (profiler, sysprof_system_logs_new ());
return g_steal_pointer (&profiler);
}
G_DEFINE_QUARK (SysprofRecordingTemplateError, sysprof_recording_template_error)

View File

@ -0,0 +1,41 @@
/* sysprof-recording-template.h
*
* Copyright 2023 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <sysprof.h>
G_BEGIN_DECLS
#define SYSPROF_TYPE_RECORDING_TEMPLATE (sysprof_recording_template_get_type())
#define SYSPROF_RECORDING_TEMPLATE_ERROR (sysprof_recording_template_error_quark())
typedef enum
{
SYSPROF_RECORDING_TEMPLATE_ERROR_COMMAND_LINE = 1,
} SysprofRecordingTemplateError;
G_DECLARE_FINAL_TYPE (SysprofRecordingTemplate, sysprof_recording_template, SYSPROF, RECORDING_TEMPLATE, GObject)
GQuark sysprof_recording_template_error_quark (void) G_GNUC_CONST;
SysprofProfiler *sysprof_recording_template_apply (SysprofRecordingTemplate *self,
GError **error);
G_END_DECLS