summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2019-06-07 03:49:40 +0000
committerMatthias Clasen <mclasen@redhat.com>2019-06-07 03:49:40 +0000
commitdcdab5b85c737cc45dfcc5d90ee200fbbdeccfe4 (patch)
tree6d0f697326dbf6c473e7c6f680576a20f958b486
parent3db1681c7670709f4257e43c204830eb5399b48d (diff)
parentef67eb0b3cc76f54c328bcf6dceafc9a4571a212 (diff)
downloadgtk+-dcdab5b85c737cc45dfcc5d90ee200fbbdeccfe4.tar.gz
Merge branch 'wip/chergert/gdkprofiler-gtk3' into 'gtk-3-24'
gdk: backport GdkProfiler See merge request GNOME/gtk!918
-rw-r--r--config.h.meson3
-rw-r--r--configure.ac24
-rw-r--r--gdk/Makefile.am2
-rw-r--r--gdk/gdk-private.c4
-rw-r--r--gdk/gdk-private.h4
-rw-r--r--gdk/gdk.c5
-rw-r--r--gdk/gdkframeclock.c112
-rw-r--r--gdk/gdkframeclockidle.c32
-rw-r--r--gdk/gdkframeclockprivate.h2
-rw-r--r--gdk/gdkprofiler.c230
-rw-r--r--gdk/gdkprofilerprivate.h46
-rw-r--r--gdk/meson.build7
-rw-r--r--gdk/wayland/gdkwindow-wayland.c4
-rw-r--r--gdk/x11/gdkdisplay-x11.c4
-rw-r--r--gtk/gtkapplication.c155
-rw-r--r--meson.build11
-rw-r--r--meson_options.txt2
17 files changed, 643 insertions, 4 deletions
diff --git a/config.h.meson b/config.h.meson
index ff17836eca..d929f00c14 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -149,6 +149,9 @@
/* Define to 1 if you have the <sys/param.h> header file. */
#mesondefine HAVE_SYS_PARAM_H
+/* Have the sysprof-capture library */
+#mesondefine HAVE_SYSPROF_CAPTURE
+
/* Define to 1 if you have the <sys/stat.h> header file. */
#mesondefine HAVE_SYS_STAT_H
diff --git a/configure.ac b/configure.ac
index afb02faea6..323ca92125 100644
--- a/configure.ac
+++ b/configure.ac
@@ -66,6 +66,7 @@ m4_define([mirclient_required_version], [0.22.0])
m4_define([mircookie_required_version], [0.17.0])
m4_define([epoxy_required_version], [1.4])
m4_define([cloudproviders_required_version], [0.2.5])
+m4_define([sysprof_required_version], [3.33.2])
GLIB_REQUIRED_VERSION=glib_required_version
PANGO_REQUIRED_VERSION=pango_required_version
ATK_REQUIRED_VERSION=atk_required_version
@@ -353,6 +354,11 @@ AC_ARG_ENABLE(cloudproviders,
[enable libcloudproviders integration])],
[cloudproviders_set=yes])
+AC_ARG_ENABLE(profiler,
+ [AS_HELP_STRING([--enable-profiler],
+ [enable profiler integration])],
+ [profiler_set=yes])
+
if test -z "$backend_set"; then
if test "$platform_win32" = yes; then
enable_win32_backend=yes
@@ -1334,11 +1340,26 @@ if test "x$cloudproviders_set" = "xyes"; then
fi
fi
+# Check for profiler support
+
+PROFILER_PACKAGES=""
+if test "x$profiler_set" = "xyes"; then
+ PROFILER_PACKAGES="sysprof-capture-3 >= sysprof_required_version"
+ if $PKG_CONFIG --exists $PROFILER_PACKAGES; then
+ AC_DEFINE(HAVE_SYSPROF_CAPTURE, [1],
+ [Define if sysprof-capture-3 is available]
+ )
+ else
+ AC_MSG_ERROR([
+*** sysprof-capture-3 not found.])
+ fi
+fi
+
CFLAGS="$saved_cflags"
LDFLAGS="$saved_ldflags"
GDK_PACKAGES="$PANGO_PACKAGES gdk-pixbuf-2.0 >= gdk_pixbuf_required_version cairo >= cairo_required_version cairo-gobject >= cairo_required_version"
-GDK_PRIVATE_PACKAGES="$GDK_GIO_PACKAGE $X_PACKAGES $WAYLAND_PACKAGES $MIR_PACKAGES $cairo_backends epoxy >= epoxy_required_version $CLOUDPROVIDER_PACKAGES fribidi >= fribidi_required_version"
+GDK_PRIVATE_PACKAGES="$GDK_GIO_PACKAGE $X_PACKAGES $WAYLAND_PACKAGES $MIR_PACKAGES $cairo_backends epoxy >= epoxy_required_version $CLOUDPROVIDER_PACKAGES $PROFILER_PACKAGES fribidi >= fribidi_required_version"
PKG_CHECK_MODULES(GDK_DEP, $GDK_PACKAGES $GDK_PRIVATE_PACKAGES)
GDK_DEP_LIBS="$GDK_EXTRA_LIBS $GDK_DEP_LIBS $MATH_LIB"
@@ -2012,3 +2033,4 @@ echo " colord support: $have_colord"
echo " Introspection: $found_introspection"
echo " Debugging: $enable_debug"
echo " Documentation: $enable_gtk_doc"
+echo " Profiler: $enable_profiler"
diff --git a/gdk/Makefile.am b/gdk/Makefile.am
index b1083fe837..6373e26a26 100644
--- a/gdk/Makefile.am
+++ b/gdk/Makefile.am
@@ -129,6 +129,7 @@ gdk_private_headers = \
gdkframeclockprivate.h \
gdkglcontextprivate.h \
gdkmonitorprivate.h \
+ gdkprofilerprivate.h \
gdkscreenprivate.h \
gdkseatprivate.h \
gdkseatdefaultprivate.h \
@@ -170,6 +171,7 @@ gdk_c_sources = \
gdkframeclockidle.c \
gdkpango.c \
gdkpixbuf-drawable.c \
+ gdkprofiler.c \
gdkproperty.c \
gdkrectangle.c \
gdkrgba.c \
diff --git a/gdk/gdk-private.c b/gdk/gdk-private.c
index cf679b0c7e..750edcd374 100644
--- a/gdk/gdk-private.c
+++ b/gdk/gdk-private.c
@@ -1,5 +1,6 @@
#include "config.h"
#include "gdk-private.h"
+#include "gdkprofilerprivate.h"
GdkPrivateVTable *
gdk__private__ (void)
@@ -19,6 +20,9 @@ gdk__private__ (void)
gdk_display_set_debug_updates,
gdk_get_desktop_startup_id,
gdk_get_desktop_autostart_id,
+ gdk_profiler_is_running,
+ gdk_profiler_start,
+ gdk_profiler_stop
};
return &table;
diff --git a/gdk/gdk-private.h b/gdk/gdk-private.h
index e38d7b1548..c71abe4634 100644
--- a/gdk/gdk-private.h
+++ b/gdk/gdk-private.h
@@ -62,6 +62,10 @@ typedef struct {
const gchar * (* gdk_get_desktop_startup_id) (void);
const gchar * (* gdk_get_desktop_autostart_id) (void);
+
+ gboolean (* gdk_profiler_is_running) (void);
+ void (* gdk_profiler_start) (int fd);
+ void (* gdk_profiler_stop) (void);
} GdkPrivateVTable;
GDK_AVAILABLE_IN_ALL
diff --git a/gdk/gdk.c b/gdk/gdk.c
index 38da23aa21..12a1d1c585 100644
--- a/gdk/gdk.c
+++ b/gdk/gdk.c
@@ -27,6 +27,7 @@
#include "gdkversionmacros.h"
#include "gdkmain.h"
+#include "gdkprofilerprivate.h"
#include "gdkinternals.h"
#include "gdkintl.h"
@@ -315,6 +316,10 @@ gdk_pre_parse (void)
_gdk_debug_flags = g_parse_debug_string (debug_string,
(GDebugKey *) gdk_debug_keys,
G_N_ELEMENTS (gdk_debug_keys));
+ if (g_getenv ("GTK_TRACE_FD"))
+ gdk_profiler_start (atoi (g_getenv ("GTK_TRACE_FD")));
+ else if (g_getenv ("GTK_TRACE"))
+ gdk_profiler_start (-1);
}
#endif /* G_ENABLE_DEBUG */
diff --git a/gdk/gdkframeclock.c b/gdk/gdkframeclock.c
index 99f93838fc..a482354d7e 100644
--- a/gdk/gdkframeclock.c
+++ b/gdk/gdkframeclock.c
@@ -26,6 +26,7 @@
#include "gdkframeclockprivate.h"
#include "gdkinternals.h"
+#include "gdkprofilerprivate.h"
/**
* SECTION:gdkframeclock
@@ -80,6 +81,10 @@ enum {
static guint signals[LAST_SIGNAL];
+#ifdef G_ENABLE_DEBUG
+static guint fps_counter;
+#endif
+
#define FRAME_HISTORY_MAX_LENGTH 16
struct _GdkFrameClockPrivate
@@ -238,6 +243,11 @@ gdk_frame_clock_init (GdkFrameClock *clock)
priv->frame_counter = -1;
priv->current = FRAME_HISTORY_MAX_LENGTH - 1;
+
+#ifdef G_ENABLE_DEBUG
+ if (fps_counter == 0)
+ fps_counter = gdk_profiler_define_counter ("fps", "Frames per Second");
+#endif
}
/**
@@ -644,3 +654,105 @@ _gdk_frame_clock_emit_resume_events (GdkFrameClock *frame_clock)
{
g_signal_emit (frame_clock, signals[RESUME_EVENTS], 0);
}
+
+#ifdef G_ENABLE_DEBUG
+static gint64
+guess_refresh_interval (GdkFrameClock *frame_clock)
+{
+ gint64 interval;
+ gint64 i;
+
+ interval = G_MAXINT64;
+
+ for (i = gdk_frame_clock_get_history_start (frame_clock);
+ i < gdk_frame_clock_get_frame_counter (frame_clock);
+ i++)
+ {
+ GdkFrameTimings *t, *before;
+ gint64 ts, before_ts;
+
+ t = gdk_frame_clock_get_timings (frame_clock, i);
+ before = gdk_frame_clock_get_timings (frame_clock, i - 1);
+ if (t == NULL || before == NULL)
+ continue;
+
+ ts = gdk_frame_timings_get_frame_time (t);
+ before_ts = gdk_frame_timings_get_frame_time (before);
+ if (ts == 0 || before_ts == 0)
+ continue;
+
+ interval = MIN (interval, ts - before_ts);
+ }
+
+ if (interval == G_MAXINT64)
+ return 0;
+
+ return interval;
+}
+
+static double
+frame_clock_get_fps (GdkFrameClock *frame_clock)
+{
+ GdkFrameTimings *start, *end;
+ gint64 start_counter, end_counter;
+ gint64 start_timestamp, end_timestamp;
+ gint64 interval;
+
+ start_counter = gdk_frame_clock_get_history_start (frame_clock);
+ end_counter = gdk_frame_clock_get_frame_counter (frame_clock);
+ start = gdk_frame_clock_get_timings (frame_clock, start_counter);
+ for (end = gdk_frame_clock_get_timings (frame_clock, end_counter);
+ end_counter > start_counter && end != NULL && !gdk_frame_timings_get_complete (end);
+ end = gdk_frame_clock_get_timings (frame_clock, end_counter))
+ end_counter--;
+ if (end_counter - start_counter < 4)
+ return 0.0;
+
+ start_timestamp = gdk_frame_timings_get_presentation_time (start);
+ end_timestamp = gdk_frame_timings_get_presentation_time (end);
+ if (start_timestamp == 0 || end_timestamp == 0)
+ {
+ start_timestamp = gdk_frame_timings_get_frame_time (start);
+ end_timestamp = gdk_frame_timings_get_frame_time (end);
+ }
+ interval = gdk_frame_timings_get_refresh_interval (end);
+ if (interval == 0)
+ {
+ interval = guess_refresh_interval (frame_clock);
+ if (interval == 0)
+ return 0.0;
+ }
+
+ return ((double) end_counter - start_counter) * G_USEC_PER_SEC / (end_timestamp - start_timestamp);
+}
+#endif
+
+void
+_gdk_frame_clock_add_timings_to_profiler (GdkFrameClock *clock,
+ GdkFrameTimings *timings)
+{
+#ifdef G_ENABLE_DEBUG
+ gdk_profiler_add_mark (timings->frame_time * 1000,
+ (timings->frame_end_time - timings->frame_time) * 1000,
+ "frame", "");
+
+ if (timings->layout_start_time != 0)
+ gdk_profiler_add_mark (timings->layout_start_time * 1000,
+ (timings->paint_start_time - timings->layout_start_time) * 1000,
+ "layout", "");
+
+ if (timings->paint_start_time != 0)
+ gdk_profiler_add_mark (timings->paint_start_time * 1000,
+ (timings->frame_end_time - timings->paint_start_time) * 1000,
+ "paint", "");
+
+ if (timings->presentation_time != 0)
+ gdk_profiler_add_mark (timings->presentation_time * 1000,
+ 0,
+ "presentation", "");
+
+ gdk_profiler_set_counter (fps_counter,
+ timings->frame_end_time * 1000,
+ frame_clock_get_fps (clock));
+#endif
+}
diff --git a/gdk/gdkframeclockidle.c b/gdk/gdkframeclockidle.c
index 2ad7da6ddd..8f17d7596f 100644
--- a/gdk/gdkframeclockidle.c
+++ b/gdk/gdkframeclockidle.c
@@ -27,6 +27,7 @@
#include "gdkinternals.h"
#include "gdkframeclockprivate.h"
#include "gdkframeclockidle.h"
+#include "gdkprofilerprivate.h"
#include "gdk.h"
#ifdef G_OS_WIN32
@@ -40,6 +41,9 @@ struct _GdkFrameClockIdlePrivate
gint64 frame_time;
gint64 min_next_frame_time;
gint64 sleep_serial;
+#ifdef G_ENABLE_DEBUG
+ gint64 freeze_time;
+#endif
guint flush_idle_id;
guint paint_idle_id;
@@ -402,7 +406,7 @@ gdk_frame_clock_paint_idle (void *data)
{
int iter;
#ifdef G_ENABLE_DEBUG
- if (GDK_DEBUG_CHECK (FRAMES))
+ if (GDK_DEBUG_CHECK (FRAMES) || gdk_profiler_is_running ())
{
if (priv->phase != GDK_FRAME_CLOCK_PHASE_LAYOUT &&
(priv->requested & GDK_FRAME_CLOCK_PHASE_LAYOUT))
@@ -431,7 +435,7 @@ gdk_frame_clock_paint_idle (void *data)
if (priv->freeze_count == 0)
{
#ifdef G_ENABLE_DEBUG
- if (GDK_DEBUG_CHECK (FRAMES))
+ if (GDK_DEBUG_CHECK (FRAMES) || gdk_profiler_is_running ())
{
if (priv->phase != GDK_FRAME_CLOCK_PHASE_PAINT &&
(priv->requested & GDK_FRAME_CLOCK_PHASE_PAINT))
@@ -457,7 +461,7 @@ gdk_frame_clock_paint_idle (void *data)
priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
#ifdef G_ENABLE_DEBUG
- if (GDK_DEBUG_CHECK (FRAMES))
+ if (GDK_DEBUG_CHECK (FRAMES) || gdk_profiler_is_running ())
timings->frame_end_time = g_get_monotonic_time ();
#endif /* G_ENABLE_DEBUG */
}
@@ -559,6 +563,14 @@ gdk_frame_clock_idle_freeze (GdkFrameClock *clock)
GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
GdkFrameClockIdlePrivate *priv = clock_idle->priv;
+#ifdef G_ENABLE_DEBUG
+ if (priv->freeze_count == 0)
+ {
+ if (gdk_profiler_is_running ())
+ priv->freeze_time = g_get_monotonic_time ();
+ }
+#endif
+
priv->freeze_count++;
maybe_stop_idle (clock_idle);
}
@@ -583,6 +595,20 @@ gdk_frame_clock_idle_thaw (GdkFrameClock *clock)
priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
priv->sleep_serial = get_sleep_serial ();
+
+#ifdef G_ENABLE_DEBUG
+ if (gdk_profiler_is_running ())
+ {
+ if (priv->freeze_time != 0)
+ {
+ gint64 thaw_time = g_get_monotonic_time ();
+ gdk_profiler_add_mark (priv->freeze_time * 1000,
+ (thaw_time - priv->freeze_time) * 1000,
+ "freeze", "");
+ priv->freeze_time = 0;
+ }
+ }
+#endif
}
}
diff --git a/gdk/gdkframeclockprivate.h b/gdk/gdkframeclockprivate.h
index 17e06dfcf7..d568887ba3 100644
--- a/gdk/gdkframeclockprivate.h
+++ b/gdk/gdkframeclockprivate.h
@@ -110,6 +110,8 @@ void _gdk_frame_clock_thaw (GdkFrameClock *clock);
void _gdk_frame_clock_begin_frame (GdkFrameClock *clock);
void _gdk_frame_clock_debug_print_timings (GdkFrameClock *clock,
GdkFrameTimings *timings);
+void _gdk_frame_clock_add_timings_to_profiler (GdkFrameClock *frame_clock,
+ GdkFrameTimings *timings);
GdkFrameTimings *_gdk_frame_timings_new (gint64 frame_counter);
gboolean _gdk_frame_timings_steal (GdkFrameTimings *timings,
diff --git a/gdk/gdkprofiler.c b/gdk/gdkprofiler.c
new file mode 100644
index 0000000000..93055ac9a8
--- /dev/null
+++ b/gdk/gdkprofiler.c
@@ -0,0 +1,230 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkprofiler.c: A simple profiler
+ *
+ * Copyright © 2018 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "gdkversionmacros.h"
+#include "gdkprofilerprivate.h"
+#include "gdkframeclockprivate.h"
+
+#ifdef HAVE_SYSPROF_CAPTURE
+
+#include <sysprof-capture.h>
+
+static SysprofCaptureWriter *writer = NULL;
+static gboolean running = FALSE;
+
+static void
+profiler_stop (void)
+{
+ if (writer)
+ sysprof_capture_writer_unref (writer);
+}
+
+void
+gdk_profiler_start (int fd)
+{
+ if (writer)
+ return;
+
+ sysprof_clock_init ();
+
+ if (fd == -1)
+ {
+ gchar *filename;
+
+ filename = g_strdup_printf ("gtk.%d.syscap", getpid ());
+ g_print ("Writing profiling data to %s\n", filename);
+ writer = sysprof_capture_writer_new (filename, 16*1024);
+ g_free (filename);
+ }
+ else if (fd > 2)
+ writer = sysprof_capture_writer_new_from_fd (fd, 16*1024);
+
+ if (writer)
+ running = TRUE;
+
+ atexit (profiler_stop);
+}
+
+void
+gdk_profiler_stop (void)
+{
+ running = FALSE;
+}
+
+gboolean
+gdk_profiler_is_running (void)
+{
+ return running;
+}
+
+void
+gdk_profiler_add_mark (gint64 start,
+ guint64 duration,
+ const char *name,
+ const char *message)
+{
+ if (!running)
+ return;
+
+ sysprof_capture_writer_add_mark (writer,
+ start,
+ -1, getpid (),
+ duration,
+ "gtk", name, message);
+}
+
+static guint
+define_counter (const char *name,
+ const char *description,
+ int type)
+{
+ SysprofCaptureCounter counter;
+
+ if (!writer)
+ return 0;
+
+ counter.id = (guint) sysprof_capture_writer_request_counter (writer, 1);
+ counter.type = type;
+ counter.value.vdbl = 0;
+ g_strlcpy (counter.category, "gtk", sizeof counter.category);
+ g_strlcpy (counter.name, name, sizeof counter.name);
+ g_strlcpy (counter.description, description, sizeof counter.name);
+
+ sysprof_capture_writer_define_counters (writer,
+ SYSPROF_CAPTURE_CURRENT_TIME,
+ -1,
+ getpid (),
+ &counter,
+ 1);
+
+ return counter.id;
+}
+
+guint
+gdk_profiler_define_counter (const char *name,
+ const char *description)
+{
+ return define_counter (name, description, SYSPROF_CAPTURE_COUNTER_DOUBLE);
+}
+
+guint
+gdk_profiler_define_int_counter (const char *name,
+ const char *description)
+{
+ return define_counter (name, description, SYSPROF_CAPTURE_COUNTER_INT64);
+}
+
+void
+gdk_profiler_set_counter (guint id,
+ gint64 time,
+ double val)
+{
+ SysprofCaptureCounterValue value;
+
+ if (!running)
+ return;
+
+ value.vdbl = val;
+ sysprof_capture_writer_set_counters (writer,
+ time,
+ -1, getpid (),
+ &id, &value, 1);
+}
+
+void
+gdk_profiler_set_int_counter (guint id,
+ gint64 time,
+ gint64 val)
+{
+ SysprofCaptureCounterValue value;
+
+ if (!running)
+ return;
+
+ value.v64 = val;
+ sysprof_capture_writer_set_counters (writer,
+ time,
+ -1, getpid (),
+ &id, &value, 1);
+}
+
+#else
+
+void
+gdk_profiler_start (int fd)
+{
+}
+
+void
+gdk_profiler_stop (void)
+{
+}
+
+gboolean
+gdk_profiler_is_running (void)
+{
+ return FALSE;
+}
+
+void
+gdk_profiler_add_mark (gint64 start,
+ guint64 duration,
+ const char *name,
+ const char *message)
+{
+}
+
+guint
+gdk_profiler_define_counter (const char *name,
+ const char *description)
+{
+ return 0;
+}
+
+void
+gdk_profiler_set_counter (guint id,
+ gint64 time,
+ double value)
+{
+}
+
+guint
+gdk_profiler_define_int_counter (const char *name,
+ const char *description)
+{
+ return 0;
+}
+
+void
+gdk_profiler_set_int_counter (guint id,
+ gint64 time,
+ gint64 value)
+{
+}
+
+#endif /* G_OS_WIN32 */
diff --git a/gdk/gdkprofilerprivate.h b/gdk/gdkprofilerprivate.h
new file mode 100644
index 0000000000..b4d81e40c4
--- /dev/null
+++ b/gdk/gdkprofilerprivate.h
@@ -0,0 +1,46 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_PROFILER_PRIVATE_H__
+#define __GDK_PROFILER_PRIVATE_H__
+
+#include "gdk/gdkframeclock.h"
+#include "gdk/gdkdisplay.h"
+
+G_BEGIN_DECLS
+
+void gdk_profiler_start (int fd);
+void gdk_profiler_stop (void);
+gboolean gdk_profiler_is_running (void);
+void gdk_profiler_add_mark (gint64 start,
+ guint64 duration,
+ const char *name,
+ const char *message);
+guint gdk_profiler_define_counter (const char *name,
+ const char *description);
+void gdk_profiler_set_counter (guint id,
+ gint64 time,
+ double value);
+guint gdk_profiler_define_int_counter (const char *name,
+ const char *description);
+void gdk_profiler_set_int_counter (guint id,
+ gint64 time,
+ gint64 value);
+
+G_END_DECLS
+
+#endif /* __GDK_PROFILER_PRIVATE_H__ */
diff --git a/gdk/meson.build b/gdk/meson.build
index 40725b25a6..49df660482 100644
--- a/gdk/meson.build
+++ b/gdk/meson.build
@@ -24,6 +24,7 @@ gdk_sources = files(
'gdkframeclockidle.c',
'gdkpango.c',
'gdkpixbuf-drawable.c',
+ 'gdkprofiler.c',
'gdkproperty.c',
'gdkrectangle.c',
'gdkrgba.c',
@@ -226,6 +227,12 @@ if win32_enabled
gdk_sources += gdk_res
endif
+if profiler_enabled
+ if profiler_dep.found()
+ gdk_deps += [profiler_dep]
+ endif
+endif
+
gdk_sources = [
# Generated
gdkconfig,
diff --git a/gdk/wayland/gdkwindow-wayland.c b/gdk/wayland/gdkwindow-wayland.c
index 3c26c2971b..1c62c8f65e 100644
--- a/gdk/wayland/gdkwindow-wayland.c
+++ b/gdk/wayland/gdkwindow-wayland.c
@@ -29,6 +29,7 @@
#include "gdkglcontext-wayland.h"
#include "gdkframeclockprivate.h"
#include "gdkprivate-wayland.h"
+#include "gdkprofilerprivate.h"
#include "gdkinternals.h"
#include "gdkdeviceprivate.h"
#include "gdkprivate-wayland.h"
@@ -560,6 +561,9 @@ frame_callback (void *data,
#ifdef G_ENABLE_DEBUG
if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0)
_gdk_frame_clock_debug_print_timings (clock, timings);
+
+ if (gdk_profiler_is_running ())
+ _gdk_frame_clock_add_timings_to_profiler (clock, timings);
#endif
}
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 5b95196a54..817944e3a5 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -39,6 +39,7 @@
#include "gdkscreen-x11.h"
#include "gdkglcontext-x11.h"
#include "gdk-private.h"
+#include "gdkprofilerprivate.h"
#include <glib.h>
#include <glib/gprintf.h>
@@ -1426,6 +1427,9 @@ _gdk_wm_protocols_filter (GdkXEvent *xev,
#ifdef G_ENABLE_DEBUG
if (GDK_DEBUG_CHECK (FRAMES))
_gdk_frame_clock_debug_print_timings (clock, timings);
+
+ if (gdk_profiler_is_running ())
+ _gdk_frame_clock_add_timings_to_profiler (clock, timings);
#endif /* G_ENABLE_DEBUG */
}
}
diff --git a/gtk/gtkapplication.c b/gtk/gtkapplication.c
index bbd36b7953..3607b69f5e 100644
--- a/gtk/gtkapplication.c
+++ b/gtk/gtkapplication.c
@@ -21,6 +21,11 @@
#include "config.h"
#include "gtkapplication.h"
+#include "gdkprivate.h"
+
+#ifdef G_OS_UNIX
+#include <gio/gunixfdlist.h>
+#endif
#include <stdlib.h>
@@ -165,6 +170,7 @@ struct _GtkApplicationPrivate
GtkActionMuxer *muxer;
GtkBuilder *menus_builder;
gchar *help_overlay_path;
+ guint profiler_id;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkApplication, gtk_application, G_TYPE_APPLICATION)
@@ -593,6 +599,153 @@ gtk_application_finalize (GObject *object)
G_OBJECT_CLASS (gtk_application_parent_class)->finalize (object);
}
+#ifdef G_OS_UNIX
+
+static const gchar org_gnome_Sysprof3_Profiler_xml[] =
+ "<node>"
+ "<interface name='org.gnome.Sysprof3.Profiler'>"
+ "<property name='Capabilities' type='a{sv}' access='read'/>"
+ "<method name='Start'>"
+ "<arg type='a{sv}' name='options' direction='in'/>"
+ "<arg type='h' name='fd' direction='in'/>"
+ "</method>"
+ "<method name='Stop'>"
+ "</method>"
+ "</interface>"
+ "</node>";
+
+static GDBusInterfaceInfo *org_gnome_Sysprof3_Profiler;
+
+static void
+sysprof_profiler_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ if (strcmp (method_name, "Start") == 0)
+ {
+ GDBusMessage *message;
+ GUnixFDList *fd_list;
+ GVariant *options;
+ int fd = -1;
+ int idx;
+
+ if (GDK_PRIVATE_CALL (gdk_profiler_is_running) ())
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Profiler already running");
+ return;
+ }
+
+ g_variant_get (parameters, "(@a{sv}h)", &options, &idx);
+
+ message = g_dbus_method_invocation_get_message (invocation);
+ fd_list = g_dbus_message_get_unix_fd_list (message);
+ if (fd_list)
+ fd = g_unix_fd_list_get (fd_list, idx, NULL);
+
+ GDK_PRIVATE_CALL (gdk_profiler_start) (fd);
+
+ g_variant_unref (options);
+ }
+ else if (strcmp (method_name, "Stop") == 0)
+ {
+ if (!GDK_PRIVATE_CALL (gdk_profiler_is_running) ())
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Profiler not running");
+ return;
+ }
+
+ GDK_PRIVATE_CALL (gdk_profiler_stop) ();
+ }
+ else
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_UNKNOWN_METHOD,
+ "Unknown method");
+ return;
+ }
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+static gboolean
+gtk_application_dbus_register (GApplication *application,
+ GDBusConnection *connection,
+ const char *obect_path,
+ GError **error)
+{
+ GtkApplicationPrivate *priv = gtk_application_get_instance_private (GTK_APPLICATION (application));
+ GDBusInterfaceVTable vtable = {
+ sysprof_profiler_method_call,
+ NULL,
+ NULL
+ };
+
+ if (org_gnome_Sysprof3_Profiler == NULL)
+ {
+ GDBusNodeInfo *info;
+
+ info = g_dbus_node_info_new_for_xml (org_gnome_Sysprof3_Profiler_xml, error);
+ if (info == NULL)
+ return FALSE;
+
+ org_gnome_Sysprof3_Profiler = g_dbus_node_info_lookup_interface (info, "org.gnome.Sysprof3.Profiler");
+ g_dbus_interface_info_ref (org_gnome_Sysprof3_Profiler);
+ g_dbus_node_info_unref (info);
+ }
+
+ priv->profiler_id = g_dbus_connection_register_object (connection,
+ "/org/gtk/Profiler",
+ org_gnome_Sysprof3_Profiler,
+ &vtable,
+ NULL,
+ NULL,
+ error);
+
+ return TRUE;
+}
+
+static void
+gtk_application_dbus_unregister (GApplication *application,
+ GDBusConnection *connection,
+ const char *obect_path)
+{
+ GtkApplicationPrivate *priv = gtk_application_get_instance_private (GTK_APPLICATION (application));
+
+ g_dbus_connection_unregister_object (connection, priv->profiler_id);
+}
+
+#else
+
+static gboolean
+gtk_application_dbus_register (GApplication *application,
+ GDBusConnection *connection,
+ const char *obect_path,
+ GError **error)
+{
+ return TRUE;
+}
+
+static void
+gtk_application_dbus_unregister (GApplication *application,
+ GDBusConnection *connection,
+ const char *obect_path)
+{
+}
+
+#endif
+
static void
gtk_application_class_init (GtkApplicationClass *class)
{
@@ -609,6 +762,8 @@ gtk_application_class_init (GtkApplicationClass *class)
application_class->after_emit = gtk_application_after_emit;
application_class->startup = gtk_application_startup;
application_class->shutdown = gtk_application_shutdown;
+ application_class->dbus_register = gtk_application_dbus_register;
+ application_class->dbus_unregister = gtk_application_dbus_unregister;
class->window_added = gtk_application_window_added;
class->window_removed = gtk_application_window_removed;
diff --git a/meson.build b/meson.build
index bc554efb3e..f2301aa082 100644
--- a/meson.build
+++ b/meson.build
@@ -798,6 +798,16 @@ if cloudproviders_enabled
endif
endif
+profiler_enabled = get_option('profiler')
+if profiler_enabled
+ profiler_dep = dependency('sysprof-capture-3', static: true, required: true)
+ if profiler_dep.found()
+ cdata.set('HAVE_SYSPROF_CAPTURE', profiler_dep.found())
+ else
+ error('Profiler support not found, but was explicitly requested.')
+ endif
+endif
+
build_gir = get_option('introspection')
subdir('gdk')
subdir('gtk')
@@ -956,6 +966,7 @@ summary = [
' Print backends: @0@'.format(' '.join(print_backends)),
' Cloud support: @0@'.format(get_option('cloudproviders')),
' Colord support: @0@'.format(get_option('colord')),
+ ' Profiler: @0@'.format(get_option('profiler')),
' Introspection: @0@'.format(get_option('introspection')),
' Documentation: @0@'.format(get_option('gtk_doc')),
' Man pages: @0@'.format(get_option('man')),
diff --git a/meson_options.txt b/meson_options.txt
index 5b30c29aa6..811a8f4069 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -15,6 +15,8 @@ option('xinerama', type: 'combo', choices : ['yes', 'no', 'auto'], value : 'auto
description : 'Enable support for the Xinerama extension')
option('cloudproviders', type: 'boolean', value: false,
description : 'Enable the cloudproviders support')
+option('profiler', type: 'boolean', value: false,
+ description : 'Enable profiler support')
# Print backends
option('print_backends', type : 'string', value : 'auto',