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 header file. */ #mesondefine HAVE_SYS_PARAM_H +/* Have the sysprof-capture library */ +#mesondefine HAVE_SYSPROF_CAPTURE + /* Define to 1 if you have the 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 . + */ + +#include "config.h" + +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "gdkversionmacros.h" +#include "gdkprofilerprivate.h" +#include "gdkframeclockprivate.h" + +#ifdef HAVE_SYSPROF_CAPTURE + +#include + +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 . + */ + +#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 #include @@ -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 +#endif #include @@ -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[] = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + +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',