From 93153d19436f682b4225c7acc5d30a2292a98bf9 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Thu, 25 May 2023 16:21:40 -0700 Subject: [PATCH] libsysprof-profile: add scaffolding for base objects The goal here is to have a fairly small exposed API surface for profiling similar to libsysprof-analyze where implementation details are hidden. SysprofProfiler - Where you setup your recording SysprofInstrument - What you add to a profiler to extract data SysprofRecording - Represents an active recording w/ instruments --- src/libsysprof-profile/meson.build | 7 + .../sysprof-instrument-private.h | 39 ++++ src/libsysprof-profile/sysprof-instrument.c | 35 +++ src/libsysprof-profile/sysprof-instrument.h | 42 ++++ src/libsysprof-profile/sysprof-profiler.c | 140 ++++++++++++ src/libsysprof-profile/sysprof-profiler.h | 52 +++++ .../sysprof-recording-private.h | 29 +++ src/libsysprof-profile/sysprof-recording.c | 205 ++++++++++++++++++ src/libsysprof-profile/sysprof-recording.h | 46 ++++ 9 files changed, 595 insertions(+) create mode 100644 src/libsysprof-profile/sysprof-instrument-private.h create mode 100644 src/libsysprof-profile/sysprof-instrument.c create mode 100644 src/libsysprof-profile/sysprof-instrument.h create mode 100644 src/libsysprof-profile/sysprof-profiler.c create mode 100644 src/libsysprof-profile/sysprof-profiler.h create mode 100644 src/libsysprof-profile/sysprof-recording-private.h create mode 100644 src/libsysprof-profile/sysprof-recording.c create mode 100644 src/libsysprof-profile/sysprof-recording.h diff --git a/src/libsysprof-profile/meson.build b/src/libsysprof-profile/meson.build index 8d414a74..5ce52170 100644 --- a/src/libsysprof-profile/meson.build +++ b/src/libsysprof-profile/meson.build @@ -1,4 +1,7 @@ libsysprof_profile_public_sources = [ + 'sysprof-instrument.c', + 'sysprof-profiler.c', + 'sysprof-recording.c', ] libsysprof_profile_private_sources = [ @@ -6,6 +9,10 @@ libsysprof_profile_private_sources = [ libsysprof_profile_public_headers = [ 'sysprof-profile.h', + + 'sysprof-instrument.h', + 'sysprof-profiler.h', + 'sysprof-recording.h', ] libsysprof_profile_deps = [ diff --git a/src/libsysprof-profile/sysprof-instrument-private.h b/src/libsysprof-profile/sysprof-instrument-private.h new file mode 100644 index 00000000..3f3e37c3 --- /dev/null +++ b/src/libsysprof-profile/sysprof-instrument-private.h @@ -0,0 +1,39 @@ +/* sysprof-instrument-private.h + * + * Copyright 2023 Christian Hergert + * + * 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "sysprof-instrument.h" + +G_BEGIN_DECLS + +#define SYSPROF_INSTRUMENT_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS(obj, SYSPROF_TYPE_INSTRUMENT, SysprofInstrumentClass) + +struct _SysprofInstrument +{ + GObject parent; +}; + +struct _SysprofInstrumentClass +{ + GObjectClass parent_class; +}; + +G_END_DECLS diff --git a/src/libsysprof-profile/sysprof-instrument.c b/src/libsysprof-profile/sysprof-instrument.c new file mode 100644 index 00000000..8f9b55a2 --- /dev/null +++ b/src/libsysprof-profile/sysprof-instrument.c @@ -0,0 +1,35 @@ +/* sysprof-instrument.c + * + * Copyright 2023 Christian Hergert + * + * 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "config.h" + +#include "sysprof-instrument-private.h" + +G_DEFINE_ABSTRACT_TYPE (SysprofInstrument, sysprof_instrument, G_TYPE_OBJECT) + +static void +sysprof_instrument_class_init (SysprofInstrumentClass *klass) +{ +} + +static void +sysprof_instrument_init (SysprofInstrument *self) +{ +} diff --git a/src/libsysprof-profile/sysprof-instrument.h b/src/libsysprof-profile/sysprof-instrument.h new file mode 100644 index 00000000..7b09b779 --- /dev/null +++ b/src/libsysprof-profile/sysprof-instrument.h @@ -0,0 +1,42 @@ +/* sysprof-instrument.h + * + * Copyright 2023 Christian Hergert + * + * 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +#include + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_INSTRUMENT (sysprof_instrumentr_get_type()) +#define SYSPROF_IS_INSTRUMENT(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_INSTRUMENT) +#define SYSPROF_INSTRUMENT(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_INSTRUMENT, SysprofInstrument) +#define SYSPROF_INSTRUMENT_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_INSTRUMENT, SysprofInstrumentClass) + +typedef struct _SysprofInstrument SysprofInstrument; +typedef struct _SysprofInstrumentClass SysprofInstrumentClass; + +SYSPROF_AVAILABLE_IN_ALL +GType sysprof_instrumentr_get_type (void) G_GNUC_CONST; + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofInstrument, g_object_unref) + +G_END_DECLS diff --git a/src/libsysprof-profile/sysprof-profiler.c b/src/libsysprof-profile/sysprof-profiler.c new file mode 100644 index 00000000..5598f13b --- /dev/null +++ b/src/libsysprof-profile/sysprof-profiler.c @@ -0,0 +1,140 @@ +/* sysprof-profiler.c + * + * Copyright 2023 Christian Hergert + * + * 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "config.h" + +#include "sysprof-profiler.h" + +struct _SysprofProfiler +{ + GObject parent_instance; + GPtrArray *instruments; +}; + +enum { + PROP_0, + N_PROPS +}; + +G_DEFINE_FINAL_TYPE (SysprofProfiler, sysprof_profiler, G_TYPE_OBJECT) + +static void +sysprof_profiler_finalize (GObject *object) +{ + G_OBJECT_CLASS (sysprof_profiler_parent_class)->finalize (object); +} + +static void +sysprof_profiler_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_profiler_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_profiler_class_init (SysprofProfilerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = sysprof_profiler_finalize; + object_class->get_property = sysprof_profiler_get_property; + object_class->set_property = sysprof_profiler_set_property; +} + +static void +sysprof_profiler_init (SysprofProfiler *self) +{ + self->instruments = g_ptr_array_new_with_free_func (g_object_unref); +} + +SysprofProfiler * +sysprof_profiler_new (void) +{ + return g_object_new (SYSPROF_TYPE_PROFILER, NULL); +} + +void +sysprof_profiler_add_instrument (SysprofProfiler *self, + SysprofInstrument *instrument) +{ + g_return_if_fail (SYSPROF_IS_PROFILER (self)); + g_return_if_fail (SYSPROF_IS_INSTRUMENT (instrument)); + + g_ptr_array_add (self->instruments, g_object_ref (instrument)); +} + +void +sysprof_profiler_record_async (SysprofProfiler *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + + g_return_if_fail (SYSPROF_IS_PROFILER (self)); + g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_source_tag (task, sysprof_profiler_record_async); + + +} + +/** + * sysprof_profiler_record_finish: + * @self: a #SysprofProfiler + * @result: a #GAsyncResult + * @error: a location for a #GError + * + * Completes an asynchronous request to start recording. + * + * Returns: (transfer full): an active #SysprofRecording if successful; + * otherwise %NULL and @error is set. + */ +SysprofRecording * +sysprof_profiler_record_finish (SysprofProfiler *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (SYSPROF_IS_PROFILER (self), NULL); + g_return_val_if_fail (G_IS_TASK (result), NULL); + g_return_val_if_fail (g_task_is_valid (result, self), NULL); + + return g_task_propagate_pointer (G_TASK (result), error); +} diff --git a/src/libsysprof-profile/sysprof-profiler.h b/src/libsysprof-profile/sysprof-profiler.h new file mode 100644 index 00000000..c1ec9857 --- /dev/null +++ b/src/libsysprof-profile/sysprof-profiler.h @@ -0,0 +1,52 @@ +/* sysprof-profiler.h + * + * Copyright 2023 Christian Hergert + * + * 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +#include + +#include "sysprof-instrument.h" +#include "sysprof-recording.h" + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_PROFILER (sysprof_profiler_get_type()) + +SYSPROF_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (SysprofProfiler, sysprof_profiler, SYSPROF, PROFILER, GObject) + +SYSPROF_AVAILABLE_IN_ALL +SysprofProfiler *sysprof_profiler_new (void); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_profiler_add_instrument (SysprofProfiler *self, + SysprofInstrument *instrument); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_profiler_record_async (SysprofProfiler *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +SYSPROF_AVAILABLE_IN_ALL +SysprofRecording *sysprof_profiler_record_finish (SysprofProfiler *self, + GAsyncResult *result, + GError **error); + +G_END_DECLS diff --git a/src/libsysprof-profile/sysprof-recording-private.h b/src/libsysprof-profile/sysprof-recording-private.h new file mode 100644 index 00000000..f09ed11a --- /dev/null +++ b/src/libsysprof-profile/sysprof-recording-private.h @@ -0,0 +1,29 @@ +/* sysprof-recording-private.h + * + * Copyright 2023 Christian Hergert + * + * 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "sysprof-recording.h" + +G_BEGIN_DECLS + +SysprofRecording *_sysprof_recording_new (void); + +G_END_DECLS diff --git a/src/libsysprof-profile/sysprof-recording.c b/src/libsysprof-profile/sysprof-recording.c new file mode 100644 index 00000000..676edaa2 --- /dev/null +++ b/src/libsysprof-profile/sysprof-recording.c @@ -0,0 +1,205 @@ +/* sysprof-recording.c + * + * Copyright 2023 Christian Hergert + * + * 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "config.h" + +#include "sysprof-recording-private.h" + +typedef enum _SysprofRecordingState +{ + SYSPROF_RECORDING_STATE_INITIAL, + SYSPROF_RECORDING_STATE_PRE, + SYSPROF_RECORDING_STATE_RECORD, + SYSPROF_RECORDING_STATE_POST, + SYSPROF_RECORDING_STATE_FINISHED, + SYSPROF_RECORDING_STATE_ERROR, +} SysprofRecordingState; + +struct _SysprofRecording +{ + GObject parent_instance; + + SysprofRecordingState state : 3; + + GQueue waiters; +}; + +enum { + PROP_0, + N_PROPS +}; + +G_DEFINE_FINAL_TYPE (SysprofRecording, sysprof_recording, G_TYPE_OBJECT) + +static gboolean +sysprof_recording_state_is_terminal (SysprofRecordingState state) +{ + return state == SYSPROF_RECORDING_STATE_ERROR || + state == SYSPROF_RECORDING_STATE_FINISHED; +} + +static void +sysprof_recording_set_state (SysprofRecording *self, + SysprofRecordingState state) +{ + GQueue waiters; + GTask *task; + + g_assert (SYSPROF_IS_RECORDING (self)); + + self->state = state; + + if (!sysprof_recording_state_is_terminal (state)) + return; + + waiters = self->waiters; + self->waiters = (GQueue) {NULL, NULL, 0}; + + while ((task = g_queue_pop_head (&waiters))) + { + if (state == SYSPROF_RECORDING_STATE_ERROR) + g_task_return_new_error (task, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Recording failed"); + else + g_task_return_boolean (task, TRUE); + + g_object_unref (task); + } +} + +static void +sysprof_recording_finalize (GObject *object) +{ + G_OBJECT_CLASS (sysprof_recording_parent_class)->finalize (object); +} + +static void +sysprof_recording_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_recording_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_recording_class_init (SysprofRecordingClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = sysprof_recording_finalize; + object_class->get_property = sysprof_recording_get_property; + object_class->set_property = sysprof_recording_set_property; +} + +static void +sysprof_recording_init (SysprofRecording *self) +{ + sysprof_recording_set_state (self, SYSPROF_RECORDING_STATE_INITIAL); +} + +SysprofRecording * +_sysprof_recording_new (void) +{ + return g_object_new (SYSPROF_TYPE_RECORDING, NULL); +} + +void +sysprof_recording_stop (SysprofRecording *self) +{ + g_return_if_fail (SYSPROF_IS_RECORDING (self)); + +} + +void +sysprof_recording_wait_async (SysprofRecording *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + + g_return_if_fail (SYSPROF_IS_RECORDING (self)); + g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_source_tag (task, sysprof_recording_wait_async); + + switch (self->state) + { + case SYSPROF_RECORDING_STATE_INITIAL: + g_task_return_new_error (task, + G_IO_ERROR, + G_IO_ERROR_INVAL, + "Recording has not yet started"); + break; + + case SYSPROF_RECORDING_STATE_ERROR: + g_task_return_new_error (task, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Recording failed"); + break; + + case SYSPROF_RECORDING_STATE_FINISHED: + g_task_return_boolean (task, TRUE); + break; + + case SYSPROF_RECORDING_STATE_PRE: + case SYSPROF_RECORDING_STATE_RECORD: + case SYSPROF_RECORDING_STATE_POST: + g_queue_push_tail (&self->waiters, g_steal_pointer (&task)); + break; + + default: + g_assert_not_reached (); + } +} + +gboolean +sysprof_recording_wait_finish (SysprofRecording *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (SYSPROF_IS_RECORDING (self), FALSE); + g_return_val_if_fail (G_IS_TASK (result), FALSE); + g_return_val_if_fail (g_task_is_valid (result, self), FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} diff --git a/src/libsysprof-profile/sysprof-recording.h b/src/libsysprof-profile/sysprof-recording.h new file mode 100644 index 00000000..1758ab80 --- /dev/null +++ b/src/libsysprof-profile/sysprof-recording.h @@ -0,0 +1,46 @@ +/* sysprof-recording.h + * + * Copyright 2023 Christian Hergert + * + * 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +#include + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_RECORDING (sysprof_recording_get_type()) + +SYSPROF_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (SysprofRecording, sysprof_recording, SYSPROF, RECORDING, GObject) + +SYSPROF_AVAILABLE_IN_ALL +void sysprof_recording_wait_async (SysprofRecording *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +SYSPROF_AVAILABLE_IN_ALL +gboolean sysprof_recording_wait_finish (SysprofRecording *self, + GAsyncResult *result, + GError **error); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_recording_stop (SysprofRecording *self); + +G_END_DECLS