[sysprof] profiler: extract SpProfiler into an interface



commit 88d3ae3b742cc0952dbae94985205fb24df124cd
Author: Christian Hergert <chergert redhat com>
Date:   Thu Apr 14 02:37:28 2016 -0700

    profiler: extract SpProfiler into an interface
    
    It would be nice to be able to support a remote profiler session in the
    future, so add SpLocalProfiler implementation of SpProfiler interface.

 lib/Makefile.am         |    2 +
 lib/sp-local-profiler.c |  807 ++++++++++++++++++++++++++++++++++++++
 lib/sp-local-profiler.h |   40 ++
 lib/sp-profiler.c       | 1000 ++++++++---------------------------------------
 lib/sp-profiler.h       |  105 ++++-
 lib/sysprof.h           |    3 +-
 src/sp-window.c         |    4 +-
 tools/sysprof-cli.c     |    2 +-
 8 files changed, 1094 insertions(+), 869 deletions(-)
---
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 02956bc..1af68f8 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -56,6 +56,7 @@ headers_DATA = \
        sp-jitmap-symbol-resolver.h \
        sp-kernel-symbol.h \
        sp-kernel-symbol-resolver.h \
+       sp-local-profiler.h \
        sp-map-lookaside.h \
        sp-perf-source.h \
        sp-proc-source.h \
@@ -81,6 +82,7 @@ libsysprof_ API_VERSION@_la_SOURCES = \
        sp-kernel-symbol-resolver.c \
        sp-line-reader.c \
        sp-line-reader.h \
+       sp-local-profiler.c \
        sp-map-lookaside.c \
        sp-perf-counter.c \
        sp-perf-counter.h \
diff --git a/lib/sp-local-profiler.c b/lib/sp-local-profiler.c
new file mode 100644
index 0000000..f3ca162
--- /dev/null
+++ b/lib/sp-local-profiler.c
@@ -0,0 +1,807 @@
+/* sp-local-profiler.c
+ *
+ * Copyright (C) 2016 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/>.
+ */
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <errno.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "sp-local-profiler.h"
+
+typedef struct
+{
+  SpCaptureWriter *writer;
+
+  /* All sources added */
+  GPtrArray *sources;
+
+  /* Array of GError failures */
+  GPtrArray *failures;
+
+  /* Sources currently starting */
+  GPtrArray *starting;
+
+  /* Sources currently stopping */
+  GPtrArray *stopping;
+
+  /* Sources that have failed or finished */
+  GPtrArray *finished_or_failed;
+
+  /* Pids to notify children about before prepare */
+  GArray *pids;
+
+  /* Timer for simple time tracking */
+  GTimer *timer;
+  guint timer_notify_source;
+
+  /* Arguments and environment variables for spawning */
+  gchar **spawn_argv;
+  gchar **spawn_env;
+
+  /* State flags */
+  guint is_running : 1;
+  guint is_stopping : 1;
+  guint is_starting : 1;
+
+  /*
+   * If we should spawn argv when starting up. This allows UI to set
+   * spawn argv/env but enable disable with a toggle.
+   */
+  guint spawn : 1;
+
+  /* If we should inherit the environment when spawning */
+  guint spawn_inherit_environ : 1;
+
+  /*
+   * If we should profile the entire system. Setting this results in pids
+   * being ignored. This is primarily useful for UI to toggle on/off the
+   * feature of per-process vs whole-system.
+   */
+  guint whole_system : 1;
+} SpLocalProfilerPrivate;
+
+static void profiler_iface_init (SpProfilerInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (SpLocalProfiler, sp_local_profiler, G_TYPE_OBJECT, 0,
+                        G_ADD_PRIVATE (SpLocalProfiler)
+                        G_IMPLEMENT_INTERFACE (SP_TYPE_PROFILER, profiler_iface_init))
+
+enum {
+  PROP_0,
+  N_PROPS,
+
+  PROP_ELAPSED,
+  PROP_IS_MUTABLE,
+  PROP_IS_RUNNING,
+  PROP_SPAWN,
+  PROP_SPAWN_ARGV,
+  PROP_SPAWN_ENV,
+  PROP_SPAWN_INHERIT_ENVIRON,
+  PROP_WHOLE_SYSTEM,
+};
+
+static inline gint
+_g_ptr_array_find (GPtrArray *ar,
+                   gpointer   item)
+{
+  guint i;
+
+  for (i = 0; i < ar->len; i++)
+    {
+      if (item == g_ptr_array_index (ar, i))
+        return i;
+    }
+
+  return -1;
+}
+
+static inline gboolean
+_g_ptr_array_contains (GPtrArray *ar,
+                       gpointer   item)
+{
+  return (-1 != _g_ptr_array_find (ar, item));
+}
+
+static void
+sp_local_profiler_clear_timer (SpLocalProfiler *self)
+{
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+
+  g_assert (SP_IS_LOCAL_PROFILER (self));
+
+  g_clear_pointer (&priv->timer, g_timer_destroy);
+
+  if (priv->timer_notify_source != 0)
+    {
+      g_source_remove (priv->timer_notify_source);
+      priv->timer_notify_source = 0;
+    }
+}
+
+static void
+sp_local_profiler_real_stopped (SpProfiler *profiler)
+{
+  SpLocalProfiler *self = (SpLocalProfiler *)profiler;
+
+  g_assert (SP_IS_LOCAL_PROFILER (self));
+
+  sp_local_profiler_clear_timer (self);
+}
+
+static gboolean
+sp_local_profiler_notify_elapsed_cb (gpointer data)
+{
+  SpLocalProfiler *self = data;
+
+  g_assert (SP_IS_LOCAL_PROFILER (self));
+
+  g_object_notify (G_OBJECT (self), "elapsed");
+
+  return G_SOURCE_CONTINUE;
+}
+
+static void
+sp_local_profiler_finish_stopping (SpLocalProfiler *self)
+{
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+
+  g_assert (SP_IS_LOCAL_PROFILER (self));
+  g_assert (priv->is_starting == FALSE);
+  g_assert (priv->is_stopping == TRUE);
+  g_assert (priv->stopping->len == 0);
+
+  if (priv->failures->len > 0)
+    {
+      const GError *error = g_ptr_array_index (priv->failures, 0);
+
+      sp_profiler_emit_failed (SP_PROFILER (self), error);
+    }
+
+  priv->is_running = FALSE;
+  priv->is_stopping = FALSE;
+
+  sp_profiler_emit_stopped (SP_PROFILER (self));
+
+  g_object_notify (G_OBJECT (self), "is-mutable");
+  g_object_notify (G_OBJECT (self), "is-running");
+}
+
+static void
+sp_local_profiler_stop (SpProfiler *profiler)
+{
+  SpLocalProfiler *self = (SpLocalProfiler *)profiler;
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+  guint i;
+
+  g_return_if_fail (SP_IS_LOCAL_PROFILER (self));
+
+  if (priv->is_stopping || (!priv->is_starting && !priv->is_running))
+    return;
+
+  priv->is_stopping = TRUE;
+
+  /*
+   * First we add everything to the stopping list, so that we can
+   * be notified of when they have completed. If everything stopped
+   * synchronously, the stopping list will be empty after calling
+   * sp_source_stop() for every source. Otherwise, we need to delay
+   * stopping for a little bit.
+   */
+
+  for (i = 0; i < priv->sources->len; i++)
+    {
+      SpSource *source = g_ptr_array_index (priv->sources, i);
+
+      if (!_g_ptr_array_contains (priv->finished_or_failed, source))
+        g_ptr_array_add (priv->stopping, g_object_ref (source));
+    }
+
+  for (i = 0; i < priv->sources->len; i++)
+    {
+      SpSource *source = g_ptr_array_index (priv->sources, i);
+
+      sp_source_stop (source);
+    }
+
+  if (priv->is_stopping && priv->stopping->len == 0)
+    sp_local_profiler_finish_stopping (self);
+}
+
+
+static void
+sp_local_profiler_dispose (GObject *object)
+{
+  SpLocalProfiler *self = (SpLocalProfiler *)object;
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+
+  if (priv->is_running || priv->is_starting)
+    {
+      sp_local_profiler_stop (SP_PROFILER (self));
+      return;
+    }
+
+  sp_local_profiler_clear_timer (self);
+
+  G_OBJECT_CLASS (sp_local_profiler_parent_class)->dispose (object);
+}
+
+static void
+sp_local_profiler_finalize (GObject *object)
+{
+  SpLocalProfiler *self = (SpLocalProfiler *)object;
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+
+  g_clear_pointer (&priv->writer, sp_capture_writer_unref);
+  g_clear_pointer (&priv->sources, g_ptr_array_unref);
+  g_clear_pointer (&priv->starting, g_ptr_array_unref);
+  g_clear_pointer (&priv->stopping, g_ptr_array_unref);
+  g_clear_pointer (&priv->finished_or_failed, g_ptr_array_unref);
+  g_clear_pointer (&priv->pids, g_array_unref);
+
+  G_OBJECT_CLASS (sp_local_profiler_parent_class)->finalize (object);
+}
+
+static void
+sp_local_profiler_get_property (GObject    *object,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+  SpLocalProfiler *self = SP_LOCAL_PROFILER (object);
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+
+  switch (prop_id)
+    {
+    case PROP_ELAPSED:
+      g_value_set_double (value, priv->timer ? g_timer_elapsed (priv->timer, NULL) : 0.0);
+      break;
+
+    case PROP_IS_MUTABLE:
+      g_value_set_boolean (value, !(priv->is_starting || priv->is_starting || priv->is_running));
+      break;
+
+    case PROP_IS_RUNNING:
+      g_value_set_boolean (value, priv->is_running);
+      break;
+
+    case PROP_WHOLE_SYSTEM:
+      g_value_set_boolean (value, priv->whole_system);
+      break;
+
+    case PROP_SPAWN:
+      g_value_set_boolean (value, priv->spawn);
+      break;
+
+    case PROP_SPAWN_INHERIT_ENVIRON:
+      g_value_set_boolean (value, priv->spawn_inherit_environ);
+      break;
+
+    case PROP_SPAWN_ARGV:
+      g_value_set_boxed (value, priv->spawn_argv);
+      break;
+
+    case PROP_SPAWN_ENV:
+      g_value_set_boxed (value, priv->spawn_env);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+sp_local_profiler_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  SpLocalProfiler *self = SP_LOCAL_PROFILER (object);
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+
+  switch (prop_id)
+    {
+    case PROP_WHOLE_SYSTEM:
+      priv->whole_system = g_value_get_boolean (value);
+      break;
+
+    case PROP_SPAWN:
+      priv->spawn = g_value_get_boolean (value);
+      break;
+
+    case PROP_SPAWN_INHERIT_ENVIRON:
+      priv->spawn_inherit_environ = g_value_get_boolean (value);
+      break;
+
+    case PROP_SPAWN_ARGV:
+      g_strfreev (priv->spawn_argv);
+      priv->spawn_argv = g_value_dup_boxed (value);
+      break;
+
+    case PROP_SPAWN_ENV:
+      g_strfreev (priv->spawn_env);
+      priv->spawn_env = g_value_dup_boxed (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+sp_local_profiler_class_init (SpLocalProfilerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = sp_local_profiler_dispose;
+  object_class->finalize = sp_local_profiler_finalize;
+  object_class->get_property = sp_local_profiler_get_property;
+  object_class->set_property = sp_local_profiler_set_property;
+
+  g_object_class_override_property (object_class, PROP_ELAPSED, "elapsed");
+  g_object_class_override_property (object_class, PROP_IS_MUTABLE, "is-mutable");
+  g_object_class_override_property (object_class, PROP_IS_RUNNING, "is-running");
+  g_object_class_override_property (object_class, PROP_SPAWN, "spawn");
+  g_object_class_override_property (object_class, PROP_SPAWN_ARGV, "spawn-argv");
+  g_object_class_override_property (object_class, PROP_SPAWN_ENV, "spawn-env");
+  g_object_class_override_property (object_class, PROP_SPAWN_INHERIT_ENVIRON, "spawn-inherit-environ");
+  g_object_class_override_property (object_class, PROP_WHOLE_SYSTEM, "whole-system");
+}
+
+static void
+sp_local_profiler_init (SpLocalProfiler *self)
+{
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+
+  priv->whole_system = TRUE;
+
+  priv->failures = g_ptr_array_new_with_free_func ((GDestroyNotify)g_error_free);
+  priv->sources = g_ptr_array_new_with_free_func (g_object_unref);
+  priv->starting = g_ptr_array_new_with_free_func (g_object_unref);
+  priv->stopping = g_ptr_array_new_with_free_func (g_object_unref);
+  priv->finished_or_failed = g_ptr_array_new_with_free_func (g_object_unref);
+  priv->pids = g_array_new (FALSE, FALSE, sizeof (GPid));
+}
+
+SpProfiler *
+sp_local_profiler_new (void)
+{
+  return g_object_new (SP_TYPE_LOCAL_PROFILER, NULL);
+}
+
+static void
+sp_local_profiler_finish_startup (SpLocalProfiler *self)
+{
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+  guint i;
+
+  g_assert (SP_IS_LOCAL_PROFILER (self));
+  g_assert (priv->is_starting == TRUE);
+  g_assert (priv->starting->len == 0);
+
+  sp_local_profiler_clear_timer (self);
+
+  priv->timer = g_timer_new ();
+
+  /*
+   * Add a source to update our watchers of elapsed time.
+   * We use 1000 instead of add_seconds(1) so that we are
+   * not subject to as much drift.
+   */
+  priv->timer_notify_source =
+    g_timeout_add (1000,
+                   sp_local_profiler_notify_elapsed_cb,
+                   self);
+
+  for (i = 0; i < priv->sources->len; i++)
+    {
+      SpSource *source = g_ptr_array_index (priv->sources, i);
+
+      sp_source_start (source);
+    }
+
+  priv->is_starting = FALSE;
+
+  /*
+   * If any of the sources failed during startup, we will have a non-empty
+   * failures list.
+   */
+  if (priv->failures->len > 0)
+    {
+      const GError *error = g_ptr_array_index (priv->failures, 0);
+
+      g_object_ref (self);
+      sp_profiler_emit_failed (SP_PROFILER (self), error);
+      sp_local_profiler_stop (SP_PROFILER (self));
+      g_object_unref (self);
+      return;
+    }
+
+  priv->is_running = TRUE;
+
+  g_object_notify (G_OBJECT (self), "is-mutable");
+  g_object_notify (G_OBJECT (self), "is-running");
+
+  /*
+   * If all the sources are transient (in that they just generate information
+   * and then exit), we could be finished as soon as we complete startup.
+   *
+   * If we detect this, we stop immediately.
+   */
+  if (priv->finished_or_failed->len == priv->sources->len)
+    sp_local_profiler_stop (SP_PROFILER (self));
+}
+
+static void
+sp_local_profiler_start (SpProfiler *profiler)
+{
+  SpLocalProfiler *self = (SpLocalProfiler *)profiler;
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+  guint i;
+
+  g_return_if_fail (SP_IS_LOCAL_PROFILER (self));
+  g_return_if_fail (priv->is_running == FALSE);
+  g_return_if_fail (priv->is_stopping == FALSE);
+  g_return_if_fail (priv->is_starting == FALSE);
+
+  if (priv->writer == NULL)
+    {
+      SpCaptureWriter *writer;
+      int fd;
+
+      if ((-1 == (fd = syscall (__NR_memfd_create, "[sysprof]", 0))) ||
+          (NULL == (writer = sp_capture_writer_new_from_fd (fd, 0))))
+        {
+          const GError error = {
+            G_FILE_ERROR,
+            g_file_error_from_errno (errno),
+            (gchar *)g_strerror (errno)
+          };
+
+          if (fd != -1)
+            close (fd);
+
+          sp_profiler_emit_failed (SP_PROFILER (self), &error);
+
+          return;
+        }
+
+      sp_profiler_set_writer (SP_PROFILER (self), writer);
+      g_clear_pointer (&writer, sp_capture_writer_unref);
+    }
+
+  priv->is_running = TRUE;
+  priv->is_starting = TRUE;
+
+  if (priv->failures->len > 0)
+    g_ptr_array_remove_range (priv->failures, 0, priv->failures->len);
+
+  if (priv->spawn && priv->spawn_argv && priv->spawn_argv[0])
+    {
+      g_autoptr(GPtrArray) ar = g_ptr_array_new_with_free_func (g_free);
+      GPid pid;
+      GError *error = NULL;
+
+      if (priv->spawn_inherit_environ)
+        {
+          gchar **environ = g_get_environ ();
+
+          for (i = 0; environ[i]; i++)
+            g_ptr_array_add (ar, environ[i]);
+          g_free (environ);
+        }
+
+      if (priv->spawn_env)
+        {
+          for (i = 0; priv->spawn_env[i]; i++)
+            g_ptr_array_add (ar, g_strdup (priv->spawn_env[i]));
+        }
+
+      g_ptr_array_add (ar, NULL);
+
+      if (!g_spawn_async (g_get_home_dir (),
+                          priv->spawn_argv,
+                          (gchar **)ar->pdata,
+                          (G_SPAWN_SEARCH_PATH |
+                           G_SPAWN_STDOUT_TO_DEV_NULL |
+                           G_SPAWN_STDOUT_TO_DEV_NULL),
+                          NULL,
+                          NULL,
+                          &pid,
+                          &error))
+        g_ptr_array_add (priv->failures, error);
+      else
+        g_array_append_val (priv->pids, pid);
+    }
+
+  for (i = 0; i < priv->sources->len; i++)
+    {
+      SpSource *source = g_ptr_array_index (priv->sources, i);
+      guint j;
+
+      if (priv->whole_system == FALSE)
+        {
+          for (j = 0; j < priv->pids->len; j++)
+            {
+              GPid pid = g_array_index (priv->pids, GPid, j);
+
+              sp_source_add_pid (source, pid);
+            }
+        }
+
+      sp_source_set_writer (source, priv->writer);
+      sp_source_prepare (source);
+    }
+
+  for (i = 0; i < priv->sources->len; i++)
+    {
+      SpSource *source = g_ptr_array_index (priv->sources, i);
+
+      if (!sp_source_get_is_ready (source))
+        g_ptr_array_add (priv->starting, g_object_ref (source));
+    }
+
+  if (priv->starting->len == 0)
+    sp_local_profiler_finish_startup (self);
+}
+
+static void
+sp_local_profiler_set_writer (SpProfiler      *profiler,
+                              SpCaptureWriter *writer)
+{
+  SpLocalProfiler *self = (SpLocalProfiler *)profiler;
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+
+  g_return_if_fail (SP_IS_LOCAL_PROFILER (self));
+  g_return_if_fail (priv->is_running == FALSE);
+  g_return_if_fail (priv->is_stopping == FALSE);
+  g_return_if_fail (writer != NULL);
+
+  if (priv->writer != writer)
+    {
+      g_clear_pointer (&priv->writer, sp_capture_writer_unref);
+
+      if (writer != NULL)
+        priv->writer = sp_capture_writer_ref (writer);
+    }
+}
+
+static void
+sp_local_profiler_track_completed (SpLocalProfiler *self,
+                                   SpSource        *source)
+{
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+  gint i;
+
+  g_assert (SP_IS_LOCAL_PROFILER (self));
+  g_assert (SP_IS_SOURCE (source));
+
+  if (!_g_ptr_array_contains (priv->finished_or_failed, source))
+    g_ptr_array_add (priv->finished_or_failed, g_object_ref (source));
+
+  if (priv->is_starting)
+    {
+      i = _g_ptr_array_find (priv->starting, source);
+
+      if (i >= 0)
+        {
+          g_ptr_array_remove_index (priv->starting, i);
+          if (priv->starting->len == 0)
+            sp_local_profiler_finish_startup (self);
+        }
+    }
+
+  if (priv->is_stopping)
+    {
+      i = _g_ptr_array_find (priv->stopping, source);
+
+      if (i >= 0)
+        {
+          g_ptr_array_remove_index_fast (priv->stopping, i);
+
+          if ((priv->is_stopping == TRUE) && (priv->stopping->len == 0))
+            sp_local_profiler_finish_stopping (self);
+        }
+    }
+
+  if (!priv->is_starting)
+    {
+      if (priv->finished_or_failed->len == priv->sources->len)
+        sp_local_profiler_stop (SP_PROFILER (self));
+    }
+}
+
+static void
+sp_local_profiler_source_finished (SpLocalProfiler *self,
+                                   SpSource        *source)
+{
+  g_assert (SP_IS_LOCAL_PROFILER (self));
+  g_assert (SP_IS_SOURCE (source));
+
+  sp_local_profiler_track_completed (self, source);
+}
+
+static void
+sp_local_profiler_source_ready (SpLocalProfiler *self,
+                                SpSource        *source)
+{
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+  guint i;
+
+  g_assert (SP_IS_LOCAL_PROFILER (self));
+  g_assert (SP_IS_SOURCE (source));
+
+  for (i = 0; i < priv->starting->len; i++)
+    {
+      SpSource *ele = g_ptr_array_index (priv->starting, i);
+
+      if (ele == source)
+        {
+          g_ptr_array_remove_index_fast (priv->starting, i);
+
+          if ((priv->is_starting == TRUE) && (priv->starting->len == 0))
+            sp_local_profiler_finish_startup (self);
+
+          break;
+        }
+    }
+}
+
+static void
+sp_local_profiler_source_failed (SpLocalProfiler *self,
+                                 const GError    *reason,
+                                 SpSource        *source)
+{
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+
+  g_assert (SP_IS_LOCAL_PROFILER (self));
+  g_assert (reason != NULL);
+  g_assert (SP_IS_SOURCE (source));
+
+  sp_local_profiler_track_completed (self, source);
+
+  /* Failure emitted out of band */
+  if (!priv->is_starting && !priv->is_stopping && !priv->is_running)
+    return;
+
+  g_ptr_array_add (priv->failures, g_error_copy (reason));
+
+  /* Ignore during start/stop, we handle this in other places */
+  if (priv->is_starting || priv->is_stopping)
+    return;
+
+  if (priv->is_running)
+    sp_local_profiler_stop (SP_PROFILER (self));
+}
+
+static void
+sp_local_profiler_add_source (SpProfiler *profiler,
+                              SpSource   *source)
+{
+  SpLocalProfiler *self = (SpLocalProfiler *)profiler;
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+
+  g_return_if_fail (SP_IS_LOCAL_PROFILER (self));
+  g_return_if_fail (SP_IS_SOURCE (source));
+  g_return_if_fail (priv->is_running == FALSE);
+  g_return_if_fail (priv->is_starting == FALSE);
+  g_return_if_fail (priv->is_stopping == FALSE);
+
+  g_signal_connect_object (source,
+                           "failed",
+                           G_CALLBACK (sp_local_profiler_source_failed),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (source,
+                           "finished",
+                           G_CALLBACK (sp_local_profiler_source_finished),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (source,
+                           "ready",
+                           G_CALLBACK (sp_local_profiler_source_ready),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+
+  g_ptr_array_add (priv->sources, g_object_ref (source));
+}
+
+static void
+sp_local_profiler_add_pid (SpProfiler *profiler,
+                           GPid        pid)
+{
+  SpLocalProfiler *self = (SpLocalProfiler *)profiler;
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+
+  g_return_if_fail (SP_IS_LOCAL_PROFILER (self));
+  g_return_if_fail (pid > -1);
+  g_return_if_fail (priv->is_starting == FALSE);
+  g_return_if_fail (priv->is_stopping == FALSE);
+  g_return_if_fail (priv->is_running == FALSE);
+
+  g_array_append_val (priv->pids, pid);
+}
+
+static void
+sp_local_profiler_remove_pid (SpProfiler *profiler,
+                              GPid        pid)
+{
+  SpLocalProfiler *self = (SpLocalProfiler *)profiler;
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+  guint i;
+
+  g_return_if_fail (SP_IS_LOCAL_PROFILER (self));
+  g_return_if_fail (pid > -1);
+  g_return_if_fail (priv->is_starting == FALSE);
+  g_return_if_fail (priv->is_stopping == FALSE);
+  g_return_if_fail (priv->is_running == FALSE);
+
+  for (i = 0; i < priv->pids->len; i++)
+    {
+      GPid ele = g_array_index (priv->pids, GPid, i);
+
+      if (ele == pid)
+        {
+          g_array_remove_index_fast (priv->pids, i);
+          break;
+        }
+    }
+}
+
+static const GPid *
+sp_local_profiler_get_pids (SpProfiler *profiler,
+                            guint      *n_pids)
+{
+  SpLocalProfiler *self = (SpLocalProfiler *)profiler;
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+
+  g_return_val_if_fail (SP_IS_LOCAL_PROFILER (self), NULL);
+  g_return_val_if_fail (n_pids != NULL, NULL);
+
+  *n_pids = priv->pids->len;
+
+  return (GPid *)(gpointer)priv->pids->data;
+}
+
+static SpCaptureWriter *
+sp_local_profiler_get_writer (SpProfiler *profiler)
+{
+  SpLocalProfiler *self = (SpLocalProfiler *)profiler;
+  SpLocalProfilerPrivate *priv = sp_local_profiler_get_instance_private (self);
+
+  g_return_val_if_fail (SP_IS_LOCAL_PROFILER (self), NULL);
+
+  return priv->writer;
+}
+
+static void
+profiler_iface_init (SpProfilerInterface *iface)
+{
+  iface->add_pid = sp_local_profiler_add_pid;
+  iface->add_source = sp_local_profiler_add_source;
+  iface->get_pids = sp_local_profiler_get_pids;
+  iface->get_writer = sp_local_profiler_get_writer;
+  iface->remove_pid = sp_local_profiler_remove_pid;
+  iface->set_writer = sp_local_profiler_set_writer;
+  iface->start = sp_local_profiler_start;
+  iface->stop = sp_local_profiler_stop;
+  iface->stopped = sp_local_profiler_real_stopped;
+}
diff --git a/lib/sp-local-profiler.h b/lib/sp-local-profiler.h
new file mode 100644
index 0000000..0beae16
--- /dev/null
+++ b/lib/sp-local-profiler.h
@@ -0,0 +1,40 @@
+/* sp-local-profiler.h
+ *
+ * Copyright (C) 2016 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/>.
+ */
+
+#ifndef SP_LOCAL_PROFILER_H
+#define SP_LOCAL_PROFILER_H
+
+#include "sp-profiler.h"
+
+G_BEGIN_DECLS
+
+#define SP_TYPE_LOCAL_PROFILER (sp_local_profiler_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (SpLocalProfiler, sp_local_profiler, SP, LOCAL_PROFILER, GObject)
+
+struct _SpLocalProfilerClass
+{
+  GObjectClass parent_class;
+  gpointer     padding[8];
+};
+
+SpProfiler *sp_local_profiler_new (void);
+
+G_END_DECLS
+
+#endif /* SP_LOCAL_PROFILER_H */
diff --git a/lib/sp-profiler.c b/lib/sp-profiler.c
index 73b6388..7482f73 100644
--- a/lib/sp-profiler.c
+++ b/lib/sp-profiler.c
@@ -16,78 +16,9 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <errno.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-
 #include "sp-profiler.h"
 
-typedef struct
-{
-  SpCaptureWriter *writer;
-
-  /* All sources added */
-  GPtrArray *sources;
-
-  /* Array of GError failures */
-  GPtrArray *failures;
-
-  /* Sources currently starting */
-  GPtrArray *starting;
-
-  /* Sources currently stopping */
-  GPtrArray *stopping;
-
-  /* Sources that have failed or finished */
-  GPtrArray *finished_or_failed;
-
-  /* Pids to notify children about before prepare */
-  GArray *pids;
-
-  /* Timer for simple time tracking */
-  GTimer *timer;
-  guint timer_notify_source;
-
-  /* Arguments and environment variables for spawning */
-  gchar **spawn_argv;
-  gchar **spawn_env;
-
-  /* State flags */
-  guint is_running : 1;
-  guint is_stopping : 1;
-  guint is_starting : 1;
-
-  /*
-   * If we should spawn argv when starting up. This allows UI to set
-   * spawn argv/env but enable disable with a toggle.
-   */
-  guint spawn : 1;
-
-  /* If we should inherit the environment when spawning */
-  guint spawn_inherit_environ : 1;
-
-  /*
-   * If we should profile the entire system. Setting this results in pids
-   * being ignored. This is primarily useful for UI to toggle on/off the
-   * feature of per-process vs whole-system.
-   */
-  guint whole_system : 1;
-} SpProfilerPrivate;
-
-G_DEFINE_TYPE_WITH_PRIVATE (SpProfiler, sp_profiler, G_TYPE_OBJECT)
-
-enum {
-  PROP_0,
-  PROP_IS_MUTABLE,
-  PROP_IS_RUNNING,
-  PROP_ELAPSED,
-  PROP_SPAWN,
-  PROP_SPAWN_INHERIT_ENVIRON,
-  PROP_WHOLE_SYSTEM,
-  N_PROPS
-};
+G_DEFINE_INTERFACE (SpProfiler, sp_profiler, G_TYPE_OBJECT)
 
 enum {
   FAILED,
@@ -95,889 +26,266 @@ enum {
   N_SIGNALS
 };
 
-static GParamSpec *properties [N_PROPS];
 static guint signals [N_SIGNALS];
 
-static inline gint
-_g_ptr_array_find (GPtrArray *ar,
-                   gpointer   item)
+static void
+sp_profiler_default_init (SpProfilerInterface *iface)
 {
-  guint i;
-
-  for (i = 0; i < ar->len; i++)
-    {
-      if (item == g_ptr_array_index (ar, i))
-        return i;
-    }
-
-  return -1;
-}
+  signals [FAILED] = g_signal_new ("failed",
+                                   G_TYPE_FROM_INTERFACE (iface),
+                                   G_SIGNAL_RUN_LAST,
+                                   G_STRUCT_OFFSET (SpProfilerInterface, failed),
+                                   NULL, NULL, NULL,
+                                   G_TYPE_NONE, 1, G_TYPE_ERROR);
 
-static inline gboolean
-_g_ptr_array_contains (GPtrArray *ar,
-                       gpointer   item)
-{
-  return (-1 != _g_ptr_array_find (ar, item));
+  signals [STOPPED] = g_signal_new ("stopped",
+                                    G_TYPE_FROM_INTERFACE (iface),
+                                    G_SIGNAL_RUN_LAST,
+                                    G_STRUCT_OFFSET (SpProfilerInterface, stopped),
+                                    NULL, NULL, NULL,
+                                    G_TYPE_NONE, 0);
+
+  g_object_interface_install_property (iface,
+      g_param_spec_double ("elapsed",
+                           "Elapsed",
+                           "The amount of elapsed time profiling",
+                           0,
+                           G_MAXDOUBLE,
+                           0,
+                           (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_interface_install_property (iface,
+      g_param_spec_boolean ("is-running",
+                            "Is Running",
+                            "If the profiler is currently running.",
+                            FALSE,
+                            (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_interface_install_property (iface,
+      g_param_spec_boolean ("is-mutable",
+                            "Is Mutable",
+                            "If the profiler can still be prepared.",
+                            TRUE,
+                            (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_interface_install_property (iface,
+      g_param_spec_boolean ("spawn-inherit-environ",
+                            "Spawn Inherit Environ",
+                            "If the spawned child should inherit the parents environment",
+                            TRUE,
+                            (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_interface_install_property (iface,
+      g_param_spec_boolean ("whole-system",
+                            "Whole System",
+                            "If the whole system should be profiled",
+                            TRUE,
+                            (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_interface_install_property (iface,
+      g_param_spec_boolean ("spawn",
+                            "Spawn",
+                            "If configured child should be spawned",
+                            TRUE,
+                            (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_interface_install_property (iface,
+      g_param_spec_boxed ("spawn-argv",
+                          "Spawn Argv",
+                          "The arguments for the spawn child",
+                          G_TYPE_STRV,
+                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_interface_install_property (iface,
+      g_param_spec_boxed ("spawn-env",
+                          "Spawn Environment",
+                          "The environment for the spawn child",
+                          G_TYPE_STRV,
+                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
 }
 
 gdouble
 sp_profiler_get_elapsed (SpProfiler *self)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
+  gdouble value = 0.0;
   g_return_val_if_fail (SP_IS_PROFILER (self), 0.0);
-
-  return (priv->timer != NULL) ? g_timer_elapsed (priv->timer, NULL) : 0.0;
-}
-
-static void
-sp_profiler_clear_timer (SpProfiler *self)
-{
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
-  g_assert (SP_IS_PROFILER (self));
-
-  g_clear_pointer (&priv->timer, g_timer_destroy);
-
-  if (priv->timer_notify_source != 0)
-    {
-      g_source_remove (priv->timer_notify_source);
-      priv->timer_notify_source = 0;
-    }
-}
-
-static void
-sp_profiler_real_stopped (SpProfiler *self)
-{
-  g_assert (SP_IS_PROFILER (self));
-
-  sp_profiler_clear_timer (self);
-}
-
-static gboolean
-sp_profiler_notify_elapsed_cb (gpointer data)
-{
-  SpProfiler *self = data;
-
-  g_assert (SP_IS_PROFILER (self));
-
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ELAPSED]);
-
-  return G_SOURCE_CONTINUE;
-}
-
-static void
-sp_profiler_dispose (GObject *object)
-{
-  SpProfiler *self = (SpProfiler *)object;
-
-  if (sp_profiler_get_is_running (self))
-    {
-      sp_profiler_stop (self);
-      return;
-    }
-
-  sp_profiler_clear_timer (self);
-
-  G_OBJECT_CLASS (sp_profiler_parent_class)->dispose (object);
+  g_object_get (self, "elapsed", &value, NULL);
+  return value;
 }
 
-static void
-sp_profiler_finalize (GObject *object)
+gboolean
+sp_profiler_get_is_running (SpProfiler *self)
 {
-  SpProfiler *self = (SpProfiler *)object;
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
-  g_clear_pointer (&priv->writer, sp_capture_writer_unref);
-  g_clear_pointer (&priv->sources, g_ptr_array_unref);
-  g_clear_pointer (&priv->starting, g_ptr_array_unref);
-  g_clear_pointer (&priv->stopping, g_ptr_array_unref);
-  g_clear_pointer (&priv->finished_or_failed, g_ptr_array_unref);
-  g_clear_pointer (&priv->pids, g_array_unref);
-
-  G_OBJECT_CLASS (sp_profiler_parent_class)->finalize (object);
+  gboolean is_running = FALSE;
+  g_return_val_if_fail (SP_IS_PROFILER (self), FALSE);
+  g_object_get (self, "is-running", &is_running, NULL);
+  return is_running;
 }
 
-static void
-sp_profiler_get_property (GObject    *object,
-                          guint       prop_id,
-                          GValue     *value,
-                          GParamSpec *pspec)
+gboolean
+sp_profiler_get_is_mutable (SpProfiler *self)
 {
-  SpProfiler *self = SP_PROFILER (object);
-
-  switch (prop_id)
-    {
-    case PROP_IS_MUTABLE:
-      g_value_set_boolean (value, sp_profiler_get_is_mutable (self));
-      break;
-
-    case PROP_IS_RUNNING:
-      g_value_set_boolean (value, sp_profiler_get_is_running (self));
-      break;
-
-    case PROP_WHOLE_SYSTEM:
-      g_value_set_boolean (value, sp_profiler_get_whole_system (self));
-      break;
-
-    case PROP_SPAWN:
-      g_value_set_boolean (value, sp_profiler_get_spawn (self));
-      break;
-
-    case PROP_SPAWN_INHERIT_ENVIRON:
-      g_value_set_boolean (value, sp_profiler_get_spawn_inherit_environ (self));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
+  gboolean is_mutable = FALSE;
+  g_return_val_if_fail (SP_IS_PROFILER (self), FALSE);
+  g_object_get (self, "is-mutable", &is_mutable, NULL);
+  return is_mutable;
 }
 
-static void
-sp_profiler_set_property (GObject      *object,
-                          guint         prop_id,
-                          const GValue *value,
-                          GParamSpec   *pspec)
+gboolean
+sp_profiler_get_spawn_inherit_environ (SpProfiler *self)
 {
-  SpProfiler *self = SP_PROFILER (object);
-
-  switch (prop_id)
-    {
-    case PROP_WHOLE_SYSTEM:
-      sp_profiler_set_whole_system (self, g_value_get_boolean (value));
-      break;
-
-    case PROP_SPAWN:
-      sp_profiler_set_spawn (self, g_value_get_boolean (value));
-      break;
-
-    case PROP_SPAWN_INHERIT_ENVIRON:
-      sp_profiler_set_spawn_inherit_environ (self, g_value_get_boolean (value));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
+  gboolean spawn_inherit_environ = FALSE;
+  g_return_val_if_fail (SP_IS_PROFILER (self), FALSE);
+  g_object_get (self, "spawn-inherit-environ", &spawn_inherit_environ, NULL);
+  return spawn_inherit_environ;
 }
 
-static void
-sp_profiler_class_init (SpProfilerClass *klass)
+void
+sp_profiler_set_spawn_inherit_environ (SpProfiler *self,
+                                       gboolean    spawn_inherit_environ)
 {
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-  object_class->dispose = sp_profiler_dispose;
-  object_class->finalize = sp_profiler_finalize;
-  object_class->get_property = sp_profiler_get_property;
-  object_class->set_property = sp_profiler_set_property;
-
-  klass->stopped = sp_profiler_real_stopped;
-
-  /**
-   * SpProfiler:elapsed:
-   *
-   * This property is updated on a second basis while recording so that
-   * UIs can keep a timer of the elapsed time while recording.
-   *
-   * It contains a double with seconds as whole integers and fractions
-   * of second after the decimal point.
-   */
-  properties [PROP_ELAPSED] =
-    g_param_spec_double ("elapsed",
-                         "Elapsed Time",
-                         "The amount of time elapsed while recording",
-                         0.0,
-                         G_MAXDOUBLE,
-                         0.0,
-                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
-  /**
-   * SpProfiler:is-running:
-   *
-   * If the profiler has been started. Note that after being started, this
-   * property won't change back to %FALSE until all sources have stopped
-   * and notified of asynchronous completion.
-   */
-  properties [PROP_IS_RUNNING] =
-    g_param_spec_boolean ("is-running",
-                          "Is Running",
-                          "If the profiler has been started",
-                          FALSE,
-                          (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
-  /**
-   * SpProfiler:is-mutable:
-   *
-   * This property is useful from a UI standpoint to desensitize
-   * configuration widgets once the profiler can no longer be modified.
-   */
-  properties [PROP_IS_MUTABLE] =
-    g_param_spec_boolean ("is-mutable",
-                          "Is Mutable",
-                          "If the profiler can be modified",
-                          FALSE,
-                          (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
-  properties [PROP_SPAWN] =
-    g_param_spec_boolean ("spawn",
-                          "Spawn",
-                          "If a child should process should be spawned",
-                          FALSE,
-                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
-  properties [PROP_SPAWN_INHERIT_ENVIRON] =
-    g_param_spec_boolean ("spawn-inherit-environ",
-                          "Spawn Inherit Environ",
-                          "If a child should inherit the current environment",
-                          FALSE,
-                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
-  /**
-   * SpProfiler:whole-system:
-   *
-   * This property denotes if the whole system should be profiled instead of
-   * a single process. This is useful for UI to toggle between process
-   * selection and all processes.
-   *
-   * Setting this to %TRUE will result in the pids added to be ignored
-   * during startup.
-   */
-  properties [PROP_WHOLE_SYSTEM] =
-    g_param_spec_boolean ("whole-system",
-                          "Whole System",
-                          "If the whole system should be profiled",
-                          TRUE,
-                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_properties (object_class, N_PROPS, properties);
-
-  signals [STOPPED] = g_signal_new ("stopped",
-                                    G_TYPE_FROM_CLASS (klass),
-                                    G_SIGNAL_RUN_LAST,
-                                    G_STRUCT_OFFSET (SpProfilerClass, stopped),
-                                    NULL, NULL, NULL, G_TYPE_NONE, 0);
-
-  signals [FAILED] = g_signal_new ("failed",
-                                    G_TYPE_FROM_CLASS (klass),
-                                    G_SIGNAL_RUN_LAST,
-                                    G_STRUCT_OFFSET (SpProfilerClass, failed),
-                                    NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_ERROR);
-
+  g_return_if_fail (SP_IS_PROFILER (self));
+  g_object_set (self, "spawn-inherit-environ", !!spawn_inherit_environ, NULL);
 }
 
-static void
-sp_profiler_init (SpProfiler *self)
+gboolean
+sp_profiler_get_spawn (SpProfiler *self)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
-  priv->whole_system = TRUE;
-
-  priv->failures = g_ptr_array_new_with_free_func ((GDestroyNotify)g_error_free);
-  priv->sources = g_ptr_array_new_with_free_func (g_object_unref);
-  priv->starting = g_ptr_array_new_with_free_func (g_object_unref);
-  priv->stopping = g_ptr_array_new_with_free_func (g_object_unref);
-  priv->finished_or_failed = g_ptr_array_new_with_free_func (g_object_unref);
-  priv->pids = g_array_new (FALSE, FALSE, sizeof (GPid));
+  gboolean spawn = FALSE;
+  g_return_val_if_fail (SP_IS_PROFILER (self), FALSE);
+  g_object_get (self, "spawn", &spawn, NULL);
+  return spawn;
 }
 
-SpProfiler *
-sp_profiler_new (void)
+void
+sp_profiler_set_spawn (SpProfiler *self,
+                       gboolean    spawn)
 {
-  return g_object_new (SP_TYPE_PROFILER, NULL);
+  g_return_if_fail (SP_IS_PROFILER (self));
+  g_object_set (self, "spawn", !!spawn, NULL);
 }
 
-static void
-sp_profiler_finish_startup (SpProfiler *self)
+gboolean
+sp_profiler_get_whole_system (SpProfiler *self)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-  guint i;
-
-  g_assert (SP_IS_PROFILER (self));
-  g_assert (priv->is_starting == TRUE);
-  g_assert (priv->starting->len == 0);
-
-  sp_profiler_clear_timer (self);
-
-  priv->timer = g_timer_new ();
-
-  /*
-   * Add a source to update our watchers of elapsed time.
-   * We use 1000 instead of add_seconds(1) so that we are
-   * not subject to as much drift.
-   */
-  priv->timer_notify_source =
-    g_timeout_add (1000,
-                   sp_profiler_notify_elapsed_cb,
-                   self);
-
-  for (i = 0; i < priv->sources->len; i++)
-    {
-      SpSource *source = g_ptr_array_index (priv->sources, i);
-
-      sp_source_start (source);
-    }
-
-  priv->is_starting = FALSE;
-
-  /*
-   * If any of the sources failed during startup, we will have a non-empty
-   * failures list.
-   */
-  if (priv->failures->len > 0)
-    {
-      const GError *error = g_ptr_array_index (priv->failures, 0);
-
-      g_object_ref (self);
-      g_signal_emit (self, signals [FAILED], 0, error);
-      sp_profiler_stop (self);
-      g_object_unref (self);
-      return;
-    }
-
-  priv->is_running = TRUE;
-
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_IS_RUNNING]);
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_IS_MUTABLE]);
-
-  /*
-   * If all the sources are transient (in that they just generate information
-   * and then exit), we could be finished as soon as we complete startup.
-   *
-   * If we detect this, we stop immediately.
-   */
-  if (priv->finished_or_failed->len == priv->sources->len)
-    sp_profiler_stop (self);
+  gboolean whole_system = FALSE;
+  g_return_val_if_fail (SP_IS_PROFILER (self), FALSE);
+  g_object_get (self, "whole-system", &whole_system, NULL);
+  return whole_system;
 }
 
 void
-sp_profiler_start (SpProfiler *self)
+sp_profiler_set_whole_system (SpProfiler *self,
+                              gboolean    whole_system)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-  guint i;
-
   g_return_if_fail (SP_IS_PROFILER (self));
-  g_return_if_fail (priv->is_running == FALSE);
-  g_return_if_fail (priv->is_stopping == FALSE);
-  g_return_if_fail (priv->is_starting == FALSE);
-
-  if (priv->writer == NULL)
-    {
-      SpCaptureWriter *writer;
-      int fd;
-
-      if ((-1 == (fd = syscall (__NR_memfd_create, "[sysprof]", 0))) ||
-          (NULL == (writer = sp_capture_writer_new_from_fd (fd, 0))))
-        {
-          const GError error = {
-            G_FILE_ERROR,
-            g_file_error_from_errno (errno),
-            (gchar *)g_strerror (errno)
-          };
-
-          if (fd != -1)
-            close (fd);
-
-          g_signal_emit (self, signals [FAILED], 0, &error);
-
-          return;
-        }
-
-      sp_profiler_set_writer (self, writer);
-      g_clear_pointer (&writer, sp_capture_writer_unref);
-    }
-
-  priv->is_running = TRUE;
-  priv->is_starting = TRUE;
-
-  if (priv->failures->len > 0)
-    g_ptr_array_remove_range (priv->failures, 0, priv->failures->len);
-
-  if (priv->spawn && priv->spawn_argv && priv->spawn_argv[0])
-    {
-      g_autoptr(GPtrArray) ar = g_ptr_array_new_with_free_func (g_free);
-      GPid pid;
-      GError *error = NULL;
-
-      if (priv->spawn_inherit_environ)
-        {
-          gchar **environ = g_get_environ ();
-
-          for (i = 0; environ[i]; i++)
-            g_ptr_array_add (ar, environ[i]);
-          g_free (environ);
-        }
-
-      if (priv->spawn_env)
-        {
-          for (i = 0; priv->spawn_env[i]; i++)
-            g_ptr_array_add (ar, g_strdup (priv->spawn_env[i]));
-        }
-
-      g_ptr_array_add (ar, NULL);
-
-      if (!g_spawn_async (g_get_home_dir (),
-                          priv->spawn_argv,
-                          (gchar **)ar->pdata,
-                          (G_SPAWN_SEARCH_PATH |
-                           G_SPAWN_STDOUT_TO_DEV_NULL |
-                           G_SPAWN_STDOUT_TO_DEV_NULL),
-                          NULL,
-                          NULL,
-                          &pid,
-                          &error))
-        g_ptr_array_add (priv->failures, error);
-      else
-        g_array_append_val (priv->pids, pid);
-    }
-
-  for (i = 0; i < priv->sources->len; i++)
-    {
-      SpSource *source = g_ptr_array_index (priv->sources, i);
-      guint j;
-
-      if (priv->whole_system == FALSE)
-        {
-          for (j = 0; j < priv->pids->len; j++)
-            {
-              GPid pid = g_array_index (priv->pids, GPid, j);
-
-              sp_source_add_pid (source, pid);
-            }
-        }
-
-      sp_source_set_writer (source, priv->writer);
-      sp_source_prepare (source);
-    }
-
-  for (i = 0; i < priv->sources->len; i++)
-    {
-      SpSource *source = g_ptr_array_index (priv->sources, i);
-
-      if (!sp_source_get_is_ready (source))
-        g_ptr_array_add (priv->starting, g_object_ref (source));
-    }
-
-  if (priv->starting->len == 0)
-    sp_profiler_finish_startup (self);
+  g_object_set (self, "whole-system", !!whole_system, NULL);
 }
 
-static void
-sp_profiler_finish_stopping (SpProfiler *self)
+void
+sp_profiler_set_spawn_argv (SpProfiler          *self,
+                            const gchar * const *spawn_argv)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
-  g_assert (SP_IS_PROFILER (self));
-  g_assert (priv->is_starting == FALSE);
-  g_assert (priv->is_stopping == TRUE);
-  g_assert (priv->stopping->len == 0);
-
-  if (priv->failures->len > 0)
-    {
-      const GError *error = g_ptr_array_index (priv->failures, 0);
-
-      g_signal_emit (self, signals [FAILED], 0, error);
-    }
-
-  priv->is_running = FALSE;
-  priv->is_stopping = FALSE;
-
-  g_signal_emit (self, signals [STOPPED], 0);
-
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_IS_RUNNING]);
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_IS_MUTABLE]);
+  g_return_if_fail (SP_IS_PROFILER (self));
+  g_object_set (self, "spawn-argv", spawn_argv, NULL);
 }
 
 void
-sp_profiler_stop (SpProfiler *self)
+sp_profiler_set_spawn_env (SpProfiler          *self,
+                           const gchar * const *spawn_env)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-  guint i;
-
   g_return_if_fail (SP_IS_PROFILER (self));
-
-  if (priv->is_stopping || (!priv->is_starting && !priv->is_running))
-    return;
-
-  priv->is_stopping = TRUE;
-
-  /*
-   * First we add everything to the stopping list, so that we can
-   * be notified of when they have completed. If everything stopped
-   * synchronously, the stopping list will be empty after calling
-   * sp_source_stop() for every source. Otherwise, we need to delay
-   * stopping for a little bit.
-   */
-
-  for (i = 0; i < priv->sources->len; i++)
-    {
-      SpSource *source = g_ptr_array_index (priv->sources, i);
-
-      if (!_g_ptr_array_contains (priv->finished_or_failed, source))
-        g_ptr_array_add (priv->stopping, g_object_ref (source));
-    }
-
-  for (i = 0; i < priv->sources->len; i++)
-    {
-      SpSource *source = g_ptr_array_index (priv->sources, i);
-
-      sp_source_stop (source);
-    }
-
-  if (priv->is_stopping && priv->stopping->len == 0)
-    sp_profiler_finish_stopping (self);
+  g_object_set (self, "spawn-env", spawn_env, NULL);
 }
 
-gboolean
-sp_profiler_get_is_running (SpProfiler *self)
+void
+sp_profiler_add_source (SpProfiler *self,
+                        SpSource   *source)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
-  g_return_val_if_fail (SP_IS_PROFILER (self), FALSE);
+  g_return_if_fail (SP_IS_PROFILER (self));
+  g_return_if_fail (SP_IS_SOURCE (source));
 
-  return priv->is_running;
+  SP_PROFILER_GET_IFACE (self)->add_source (self, source);
 }
 
 void
 sp_profiler_set_writer (SpProfiler      *self,
                         SpCaptureWriter *writer)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
   g_return_if_fail (SP_IS_PROFILER (self));
-  g_return_if_fail (priv->is_running == FALSE);
-  g_return_if_fail (priv->is_stopping == FALSE);
   g_return_if_fail (writer != NULL);
 
-  if (priv->writer != writer)
-    {
-      g_clear_pointer (&priv->writer, sp_capture_writer_unref);
-
-      if (writer != NULL)
-        priv->writer = sp_capture_writer_ref (writer);
-    }
-}
-
-static void
-sp_profiler_track_completed (SpProfiler *self,
-                             SpSource   *source)
-{
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-  gint i;
-
-  g_assert (SP_IS_PROFILER (self));
-  g_assert (SP_IS_SOURCE (source));
-
-  if (!_g_ptr_array_contains (priv->finished_or_failed, source))
-    g_ptr_array_add (priv->finished_or_failed, g_object_ref (source));
-
-  if (priv->is_starting)
-    {
-      i = _g_ptr_array_find (priv->starting, source);
-
-      if (i >= 0)
-        {
-          g_ptr_array_remove_index (priv->starting, i);
-          if (priv->starting->len == 0)
-            sp_profiler_finish_startup (self);
-        }
-    }
-
-  if (priv->is_stopping)
-    {
-      i = _g_ptr_array_find (priv->stopping, source);
-
-      if (i >= 0)
-        {
-          g_ptr_array_remove_index_fast (priv->stopping, i);
-
-          if ((priv->is_stopping == TRUE) && (priv->stopping->len == 0))
-            sp_profiler_finish_stopping (self);
-        }
-    }
-
-  if (!priv->is_starting)
-    {
-      if (priv->finished_or_failed->len == priv->sources->len)
-        sp_profiler_stop (self);
-    }
-}
-
-static void
-sp_profiler_source_finished (SpProfiler *self,
-                             SpSource   *source)
-{
-  g_assert (SP_IS_PROFILER (self));
-  g_assert (SP_IS_SOURCE (source));
-
-  sp_profiler_track_completed (self, source);
+  SP_PROFILER_GET_IFACE (self)->set_writer (self, writer);
 }
 
-static void
-sp_profiler_source_ready (SpProfiler *self,
-                          SpSource   *source)
+SpCaptureWriter *
+sp_profiler_get_writer (SpProfiler *self)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-  guint i;
-
-  g_assert (SP_IS_PROFILER (self));
-  g_assert (SP_IS_SOURCE (source));
-
-  for (i = 0; i < priv->starting->len; i++)
-    {
-      SpSource *ele = g_ptr_array_index (priv->starting, i);
-
-      if (ele == source)
-        {
-          g_ptr_array_remove_index_fast (priv->starting, i);
-
-          if ((priv->is_starting == TRUE) && (priv->starting->len == 0))
-            sp_profiler_finish_startup (self);
+  g_return_val_if_fail (SP_IS_PROFILER (self), NULL);
 
-          break;
-        }
-    }
+  return SP_PROFILER_GET_IFACE (self)->get_writer (self);
 }
 
-static void
-sp_profiler_source_failed (SpProfiler   *self,
-                           const GError *reason,
-                           SpSource     *source)
+void
+sp_profiler_start (SpProfiler *self)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
-  g_assert (SP_IS_PROFILER (self));
-  g_assert (reason != NULL);
-  g_assert (SP_IS_SOURCE (source));
-
-  sp_profiler_track_completed (self, source);
-
-  /* Failure emitted out of band */
-  if (!priv->is_starting && !priv->is_stopping && !priv->is_running)
-    return;
-
-  g_ptr_array_add (priv->failures, g_error_copy (reason));
-
-  /* Ignore during start/stop, we handle this in other places */
-  if (priv->is_starting || priv->is_stopping)
-    return;
+  g_return_if_fail (SP_IS_PROFILER (self));
 
-  if (priv->is_running)
-    sp_profiler_stop (self);
+  SP_PROFILER_GET_IFACE (self)->start (self);
 }
 
 void
-sp_profiler_add_source (SpProfiler *self,
-                        SpSource   *source)
+sp_profiler_stop (SpProfiler *self)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
   g_return_if_fail (SP_IS_PROFILER (self));
-  g_return_if_fail (SP_IS_SOURCE (source));
-  g_return_if_fail (priv->is_running == FALSE);
-  g_return_if_fail (priv->is_starting == FALSE);
-  g_return_if_fail (priv->is_stopping == FALSE);
-
-  g_signal_connect_object (source,
-                           "failed",
-                           G_CALLBACK (sp_profiler_source_failed),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (source,
-                           "finished",
-                           G_CALLBACK (sp_profiler_source_finished),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (source,
-                           "ready",
-                           G_CALLBACK (sp_profiler_source_ready),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-
-  g_ptr_array_add (priv->sources, g_object_ref (source));
+
+  SP_PROFILER_GET_IFACE (self)->stop (self);
 }
 
 void
 sp_profiler_add_pid (SpProfiler *self,
                      GPid        pid)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
   g_return_if_fail (SP_IS_PROFILER (self));
   g_return_if_fail (pid > -1);
-  g_return_if_fail (priv->is_starting == FALSE);
-  g_return_if_fail (priv->is_stopping == FALSE);
-  g_return_if_fail (priv->is_running == FALSE);
 
-  g_array_append_val (priv->pids, pid);
+  SP_PROFILER_GET_IFACE (self)->add_pid (self, pid);
 }
 
 void
 sp_profiler_remove_pid (SpProfiler *self,
                         GPid        pid)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-  guint i;
-
   g_return_if_fail (SP_IS_PROFILER (self));
   g_return_if_fail (pid > -1);
-  g_return_if_fail (priv->is_starting == FALSE);
-  g_return_if_fail (priv->is_stopping == FALSE);
-  g_return_if_fail (priv->is_running == FALSE);
-
-  for (i = 0; i < priv->pids->len; i++)
-    {
-      GPid ele = g_array_index (priv->pids, GPid, i);
-
-      if (ele == pid)
-        {
-          g_array_remove_index_fast (priv->pids, i);
-          break;
-        }
-    }
-}
-
-gboolean
-sp_profiler_get_is_mutable (SpProfiler *self)
-{
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
-  g_return_val_if_fail (SP_IS_PROFILER (self), FALSE);
-
-  return !(priv->is_starting || priv->is_stopping || priv->is_running);
-}
-
-gboolean
-sp_profiler_get_whole_system (SpProfiler *self)
-{
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
-  g_return_val_if_fail (SP_IS_PROFILER (self), FALSE);
-
-  return priv->whole_system;
-}
-
-void
-sp_profiler_set_whole_system (SpProfiler *self,
-                              gboolean    whole_system)
-{
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
-  g_return_if_fail (SP_IS_PROFILER (self));
 
-  whole_system = !!whole_system;
-
-  if (whole_system != priv->whole_system)
-    {
-      priv->whole_system = whole_system;
-      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_WHOLE_SYSTEM]);
-    }
+  SP_PROFILER_GET_IFACE (self)->remove_pid (self, pid);
 }
 
 const GPid *
 sp_profiler_get_pids (SpProfiler *self,
                       guint      *n_pids)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
   g_return_val_if_fail (SP_IS_PROFILER (self), NULL);
   g_return_val_if_fail (n_pids != NULL, NULL);
 
-  *n_pids = priv->pids->len;
-
-  return (GPid *)(gpointer)priv->pids->data;
-}
-
-/**
- * sp_profiler_get_writer:
- *
- * Returns: (nullable) (transfer none): An #SpCaptureWriter or %NULL.
- */
-SpCaptureWriter *
-sp_profiler_get_writer (SpProfiler *self)
-{
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
-  g_return_val_if_fail (SP_IS_PROFILER (self), NULL);
-
-  return priv->writer;
-}
-
-gboolean
-sp_profiler_get_spawn (SpProfiler *self)
-{
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
-  g_return_val_if_fail (SP_IS_PROFILER (self), FALSE);
-
-  return priv->spawn;
-}
-
-void
-sp_profiler_set_spawn (SpProfiler *self,
-                       gboolean    spawn)
-{
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
-  g_return_if_fail (SP_IS_PROFILER (self));
-
-  spawn = !!spawn;
-
-  if (priv->spawn != spawn)
-    {
-      priv->spawn = spawn;
-      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SPAWN]);
-    }
-}
-
-gboolean
-sp_profiler_get_spawn_inherit_environ (SpProfiler *self)
-{
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
-  g_return_val_if_fail (SP_IS_PROFILER (self), FALSE);
-
-  return priv->spawn_inherit_environ;
-}
-
-void
-sp_profiler_set_spawn_inherit_environ (SpProfiler *self,
-                                       gboolean    spawn_inherit_environ)
-{
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
-  g_return_if_fail (SP_IS_PROFILER (self));
-
-  spawn_inherit_environ = !!spawn_inherit_environ;
-
-  if (priv->spawn_inherit_environ != spawn_inherit_environ)
-    {
-      priv->spawn_inherit_environ = spawn_inherit_environ;
-      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SPAWN_INHERIT_ENVIRON]);
-    }
+  return SP_PROFILER_GET_IFACE (self)->get_pids (self, n_pids);
 }
 
 void
-sp_profiler_set_spawn_argv (SpProfiler          *self,
-                            const gchar * const *spawn_argv)
+sp_profiler_emit_failed (SpProfiler   *self,
+                         const GError *error)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
   g_return_if_fail (SP_IS_PROFILER (self));
+  g_return_if_fail (error != NULL);
 
-  g_strfreev (priv->spawn_argv);
-  priv->spawn_argv = g_strdupv ((gchar **)spawn_argv);
+  g_signal_emit (self, signals [FAILED], 0, error);
 }
 
 void
-sp_profiler_set_spawn_env (SpProfiler          *self,
-                           const gchar * const *spawn_env)
+sp_profiler_emit_stopped (SpProfiler *self)
 {
-  SpProfilerPrivate *priv = sp_profiler_get_instance_private (self);
-
   g_return_if_fail (SP_IS_PROFILER (self));
 
-  g_strfreev (priv->spawn_env);
-  priv->spawn_env = g_strdupv ((gchar **)spawn_env);
+  g_signal_emit (self, signals [STOPPED], 0);
 }
diff --git a/lib/sp-profiler.h b/lib/sp-profiler.h
index 530b6b9..133b8aa 100644
--- a/lib/sp-profiler.h
+++ b/lib/sp-profiler.h
@@ -26,11 +26,11 @@ G_BEGIN_DECLS
 
 #define SP_TYPE_PROFILER (sp_profiler_get_type())
 
-G_DECLARE_DERIVABLE_TYPE (SpProfiler, sp_profiler, SP, PROFILER, GObject)
+G_DECLARE_INTERFACE (SpProfiler, sp_profiler, SP, PROFILER, GObject)
 
-struct _SpProfilerClass
+struct _SpProfilerInterface
 {
-  GObjectClass parent_class;
+  GTypeInterface parent_interface;
 
   /**
    * SpProfiler::failed:
@@ -55,11 +55,92 @@ struct _SpProfilerClass
    */
   void (*stopped) (SpProfiler *self);
 
-  gpointer padding[8];
+  /**
+   * SpProfiler::add_source:
+   *
+   * Adds a source to the profiler.
+   */
+  void (*add_source) (SpProfiler *profiler,
+                      SpSource   *source);
+
+  /**
+   * SpProfiler::set_writer:
+   *
+   * Sets the writer to use for the profiler.
+   */
+  void (*set_writer) (SpProfiler      *self,
+                      SpCaptureWriter *writer);
+
+  /**
+   * SpProfiler::get_writer:
+   *
+   * Gets the writer that is being used to capture.
+   *
+   * Returns: (nullable) (transfer none): A #SpCaptureWriter.
+   */
+  SpCaptureWriter *(*get_writer) (SpProfiler *self);
+
+  /**
+   * SpProfiler::start:
+   *
+   * Starts the profiler.
+   */
+  void (*start) (SpProfiler *self);
+
+  /**
+   * SpProfiler::stop:
+   *
+   * Stops the profiler.
+   */
+  void (*stop) (SpProfiler *self);
+
+  /**
+   * SpProfiler::add_pid:
+   *
+   * Add a pid to be profiled.
+   */
+  void (*add_pid) (SpProfiler *self,
+                   GPid        pid);
+
+  /**
+   * SpProfiler::remove_pid:
+   *
+   * Remove a pid from the profiler. This will not be called after
+   * SpProfiler::start has been called.
+   */
+  void (*remove_pid) (SpProfiler *self,
+                      GPid        pid);
+
+  /**
+   * SpProfiler::get_pids:
+   *
+   * Gets the pids that are part of this profiling session. If no pids
+   * have been specified, %NULL is returned.
+   *
+   * Returns: (nullable) (transfer none): An array of #GPid, or %NULL.
+   */
+  const GPid *(*get_pids) (SpProfiler *self,
+                           guint      *n_pids);
 };
 
-SpProfiler      *sp_profiler_new                       (void);
+void             sp_profiler_emit_failed               (SpProfiler          *self,
+                                                        const GError        *error);
+void             sp_profiler_emit_stopped              (SpProfiler          *self);
 gdouble          sp_profiler_get_elapsed               (SpProfiler          *self);
+gboolean         sp_profiler_get_is_mutable            (SpProfiler          *self);
+gboolean         sp_profiler_get_spawn_inherit_environ (SpProfiler          *self);
+void             sp_profiler_set_spawn_inherit_environ (SpProfiler          *self,
+                                                        gboolean             spawn_inherit_environ);
+gboolean         sp_profiler_get_whole_system          (SpProfiler          *self);
+void             sp_profiler_set_whole_system          (SpProfiler          *self,
+                                                        gboolean             whole_system);
+gboolean         sp_profiler_get_spawn                 (SpProfiler          *self);
+void             sp_profiler_set_spawn                 (SpProfiler          *self,
+                                                        gboolean             spawn);
+void             sp_profiler_set_spawn_argv            (SpProfiler          *self,
+                                                        const gchar * const *spawn_argv);
+void             sp_profiler_set_spawn_env             (SpProfiler          *self,
+                                                        const gchar * const *spawn_env);
 void             sp_profiler_add_source                (SpProfiler          *self,
                                                         SpSource            *source);
 void             sp_profiler_set_writer                (SpProfiler          *self,
@@ -72,22 +153,8 @@ void             sp_profiler_add_pid                   (SpProfiler          *sel
                                                         GPid                 pid);
 void             sp_profiler_remove_pid                (SpProfiler          *self,
                                                         GPid                 pid);
-gboolean         sp_profiler_get_is_mutable            (SpProfiler          *self);
-gboolean         sp_profiler_get_whole_system          (SpProfiler          *self);
-void             sp_profiler_set_whole_system          (SpProfiler          *self,
-                                                        gboolean             whole_system);
 const GPid      *sp_profiler_get_pids                  (SpProfiler          *self,
                                                         guint               *n_pids);
-gboolean         sp_profiler_get_spawn                 (SpProfiler          *self);
-void             sp_profiler_set_spawn                 (SpProfiler          *self,
-                                                        gboolean             spawn);
-void             sp_profiler_set_spawn_argv            (SpProfiler          *self,
-                                                        const gchar * const *spawn_argv);
-void             sp_profiler_set_spawn_env             (SpProfiler          *self,
-                                                        const gchar * const *spawn_env);
-gboolean         sp_profiler_get_spawn_inherit_environ (SpProfiler          *self);
-void             sp_profiler_set_spawn_inherit_environ (SpProfiler          *self,
-                                                        gboolean             spawn_inherit_environ);
 
 G_END_DECLS
 
diff --git a/lib/sysprof.h b/lib/sysprof.h
index f864b70..0ff7db7 100644
--- a/lib/sysprof.h
+++ b/lib/sysprof.h
@@ -33,8 +33,9 @@ G_BEGIN_DECLS
 # include "sp-error.h"
 # include "sp-gjs-source.h"
 # include "sp-jitmap-symbol-resolver.h"
-# include "sp-kernel-symbol.h"
 # include "sp-kernel-symbol-resolver.h"
+# include "sp-kernel-symbol.h"
+# include "sp-local-profiler.h"
 # include "sp-map-lookaside.h"
 # include "sp-perf-source.h"
 # include "sp-proc-source.h"
diff --git a/src/sp-window.c b/src/sp-window.c
index 06ffbf8..59cf431 100644
--- a/src/sp-window.c
+++ b/src/sp-window.c
@@ -263,7 +263,7 @@ sp_window_set_state (SpWindow      *self,
     {
     case SP_WINDOW_STATE_EMPTY:
     case SP_WINDOW_STATE_FAILED:
-      profiler = sp_profiler_new ();
+      profiler = sp_local_profiler_new ();
 
       gtk_button_set_label (self->record_button, _("Record"));
       gtk_widget_set_sensitive (GTK_WIDGET (self->record_button), TRUE);
@@ -667,7 +667,7 @@ sp_window_constructed (GObject *object)
 
   G_OBJECT_CLASS (sp_window_parent_class)->constructed (object);
 
-  profiler = sp_profiler_new ();
+  profiler = sp_local_profiler_new ();
   sp_window_set_profiler (self, profiler);
 
   sp_window_set_state (self, SP_WINDOW_STATE_EMPTY);
diff --git a/tools/sysprof-cli.c b/tools/sysprof-cli.c
index f94ca41..38704e2 100644
--- a/tools/sysprof-cli.c
+++ b/tools/sysprof-cli.c
@@ -128,7 +128,7 @@ main (gint   argc,
   g_source_add_unix_fd (gsource, efd, G_IO_IN);
   g_source_attach (gsource, NULL);
 
-  profiler = sp_profiler_new ();
+  profiler = sp_local_profiler_new ();
 
   g_signal_connect (profiler,
                     "failed",


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]