gdk: backport GdkProfiler

This is a backport of the GdkProfiler from master. It does not include
the pixel bandwidth numbers that come from gdkdrawcontext.c since there
does not seem to be an analog in 3.x.

Additionally, this implements the recent changes for SYsprof's D-Bus
profiler API which adds a Capabilities property and an options hash-table
to the D-Bus interface for forward portability.
This commit is contained in:
Christian Hergert 2019-06-06 16:19:36 -07:00
parent 3db1681c76
commit ef67eb0b3c
17 changed files with 643 additions and 4 deletions

View File

@ -149,6 +149,9 @@
/* Define to 1 if you have the <sys/param.h> header file. */ /* Define to 1 if you have the <sys/param.h> header file. */
#mesondefine HAVE_SYS_PARAM_H #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. */ /* Define to 1 if you have the <sys/stat.h> header file. */
#mesondefine HAVE_SYS_STAT_H #mesondefine HAVE_SYS_STAT_H

View File

@ -66,6 +66,7 @@ m4_define([mirclient_required_version], [0.22.0])
m4_define([mircookie_required_version], [0.17.0]) m4_define([mircookie_required_version], [0.17.0])
m4_define([epoxy_required_version], [1.4]) m4_define([epoxy_required_version], [1.4])
m4_define([cloudproviders_required_version], [0.2.5]) m4_define([cloudproviders_required_version], [0.2.5])
m4_define([sysprof_required_version], [3.33.2])
GLIB_REQUIRED_VERSION=glib_required_version GLIB_REQUIRED_VERSION=glib_required_version
PANGO_REQUIRED_VERSION=pango_required_version PANGO_REQUIRED_VERSION=pango_required_version
ATK_REQUIRED_VERSION=atk_required_version ATK_REQUIRED_VERSION=atk_required_version
@ -353,6 +354,11 @@ AC_ARG_ENABLE(cloudproviders,
[enable libcloudproviders integration])], [enable libcloudproviders integration])],
[cloudproviders_set=yes]) [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 -z "$backend_set"; then
if test "$platform_win32" = yes; then if test "$platform_win32" = yes; then
enable_win32_backend=yes enable_win32_backend=yes
@ -1334,11 +1340,26 @@ if test "x$cloudproviders_set" = "xyes"; then
fi fi
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" CFLAGS="$saved_cflags"
LDFLAGS="$saved_ldflags" 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_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) PKG_CHECK_MODULES(GDK_DEP, $GDK_PACKAGES $GDK_PRIVATE_PACKAGES)
GDK_DEP_LIBS="$GDK_EXTRA_LIBS $GDK_DEP_LIBS $MATH_LIB" 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 " Introspection: $found_introspection"
echo " Debugging: $enable_debug" echo " Debugging: $enable_debug"
echo " Documentation: $enable_gtk_doc" echo " Documentation: $enable_gtk_doc"
echo " Profiler: $enable_profiler"

View File

@ -129,6 +129,7 @@ gdk_private_headers = \
gdkframeclockprivate.h \ gdkframeclockprivate.h \
gdkglcontextprivate.h \ gdkglcontextprivate.h \
gdkmonitorprivate.h \ gdkmonitorprivate.h \
gdkprofilerprivate.h \
gdkscreenprivate.h \ gdkscreenprivate.h \
gdkseatprivate.h \ gdkseatprivate.h \
gdkseatdefaultprivate.h \ gdkseatdefaultprivate.h \
@ -170,6 +171,7 @@ gdk_c_sources = \
gdkframeclockidle.c \ gdkframeclockidle.c \
gdkpango.c \ gdkpango.c \
gdkpixbuf-drawable.c \ gdkpixbuf-drawable.c \
gdkprofiler.c \
gdkproperty.c \ gdkproperty.c \
gdkrectangle.c \ gdkrectangle.c \
gdkrgba.c \ gdkrgba.c \

View File

@ -1,5 +1,6 @@
#include "config.h" #include "config.h"
#include "gdk-private.h" #include "gdk-private.h"
#include "gdkprofilerprivate.h"
GdkPrivateVTable * GdkPrivateVTable *
gdk__private__ (void) gdk__private__ (void)
@ -19,6 +20,9 @@ gdk__private__ (void)
gdk_display_set_debug_updates, gdk_display_set_debug_updates,
gdk_get_desktop_startup_id, gdk_get_desktop_startup_id,
gdk_get_desktop_autostart_id, gdk_get_desktop_autostart_id,
gdk_profiler_is_running,
gdk_profiler_start,
gdk_profiler_stop
}; };
return &table; return &table;

View File

@ -62,6 +62,10 @@ typedef struct {
const gchar * (* gdk_get_desktop_startup_id) (void); const gchar * (* gdk_get_desktop_startup_id) (void);
const gchar * (* gdk_get_desktop_autostart_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; } GdkPrivateVTable;
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL

View File

@ -27,6 +27,7 @@
#include "gdkversionmacros.h" #include "gdkversionmacros.h"
#include "gdkmain.h" #include "gdkmain.h"
#include "gdkprofilerprivate.h"
#include "gdkinternals.h" #include "gdkinternals.h"
#include "gdkintl.h" #include "gdkintl.h"
@ -315,6 +316,10 @@ gdk_pre_parse (void)
_gdk_debug_flags = g_parse_debug_string (debug_string, _gdk_debug_flags = g_parse_debug_string (debug_string,
(GDebugKey *) gdk_debug_keys, (GDebugKey *) gdk_debug_keys,
G_N_ELEMENTS (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 */ #endif /* G_ENABLE_DEBUG */

View File

@ -26,6 +26,7 @@
#include "gdkframeclockprivate.h" #include "gdkframeclockprivate.h"
#include "gdkinternals.h" #include "gdkinternals.h"
#include "gdkprofilerprivate.h"
/** /**
* SECTION:gdkframeclock * SECTION:gdkframeclock
@ -80,6 +81,10 @@ enum {
static guint signals[LAST_SIGNAL]; static guint signals[LAST_SIGNAL];
#ifdef G_ENABLE_DEBUG
static guint fps_counter;
#endif
#define FRAME_HISTORY_MAX_LENGTH 16 #define FRAME_HISTORY_MAX_LENGTH 16
struct _GdkFrameClockPrivate struct _GdkFrameClockPrivate
@ -238,6 +243,11 @@ gdk_frame_clock_init (GdkFrameClock *clock)
priv->frame_counter = -1; priv->frame_counter = -1;
priv->current = FRAME_HISTORY_MAX_LENGTH - 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); 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
}

View File

@ -27,6 +27,7 @@
#include "gdkinternals.h" #include "gdkinternals.h"
#include "gdkframeclockprivate.h" #include "gdkframeclockprivate.h"
#include "gdkframeclockidle.h" #include "gdkframeclockidle.h"
#include "gdkprofilerprivate.h"
#include "gdk.h" #include "gdk.h"
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
@ -40,6 +41,9 @@ struct _GdkFrameClockIdlePrivate
gint64 frame_time; gint64 frame_time;
gint64 min_next_frame_time; gint64 min_next_frame_time;
gint64 sleep_serial; gint64 sleep_serial;
#ifdef G_ENABLE_DEBUG
gint64 freeze_time;
#endif
guint flush_idle_id; guint flush_idle_id;
guint paint_idle_id; guint paint_idle_id;
@ -402,7 +406,7 @@ gdk_frame_clock_paint_idle (void *data)
{ {
int iter; int iter;
#ifdef G_ENABLE_DEBUG #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 && if (priv->phase != GDK_FRAME_CLOCK_PHASE_LAYOUT &&
(priv->requested & 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) if (priv->freeze_count == 0)
{ {
#ifdef G_ENABLE_DEBUG #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 && if (priv->phase != GDK_FRAME_CLOCK_PHASE_PAINT &&
(priv->requested & 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; priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
#ifdef G_ENABLE_DEBUG #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 (); timings->frame_end_time = g_get_monotonic_time ();
#endif /* G_ENABLE_DEBUG */ #endif /* G_ENABLE_DEBUG */
} }
@ -559,6 +563,14 @@ gdk_frame_clock_idle_freeze (GdkFrameClock *clock)
GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock); GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
GdkFrameClockIdlePrivate *priv = clock_idle->priv; 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++; priv->freeze_count++;
maybe_stop_idle (clock_idle); maybe_stop_idle (clock_idle);
} }
@ -583,6 +595,20 @@ gdk_frame_clock_idle_thaw (GdkFrameClock *clock)
priv->phase = GDK_FRAME_CLOCK_PHASE_NONE; priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
priv->sleep_serial = get_sleep_serial (); 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
} }
} }

View File

@ -110,6 +110,8 @@ void _gdk_frame_clock_thaw (GdkFrameClock *clock);
void _gdk_frame_clock_begin_frame (GdkFrameClock *clock); void _gdk_frame_clock_begin_frame (GdkFrameClock *clock);
void _gdk_frame_clock_debug_print_timings (GdkFrameClock *clock, void _gdk_frame_clock_debug_print_timings (GdkFrameClock *clock,
GdkFrameTimings *timings); GdkFrameTimings *timings);
void _gdk_frame_clock_add_timings_to_profiler (GdkFrameClock *frame_clock,
GdkFrameTimings *timings);
GdkFrameTimings *_gdk_frame_timings_new (gint64 frame_counter); GdkFrameTimings *_gdk_frame_timings_new (gint64 frame_counter);
gboolean _gdk_frame_timings_steal (GdkFrameTimings *timings, gboolean _gdk_frame_timings_steal (GdkFrameTimings *timings,

230
gdk/gdkprofiler.c Normal file
View File

@ -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 */

46
gdk/gdkprofilerprivate.h Normal file
View File

@ -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__ */

View File

@ -24,6 +24,7 @@ gdk_sources = files(
'gdkframeclockidle.c', 'gdkframeclockidle.c',
'gdkpango.c', 'gdkpango.c',
'gdkpixbuf-drawable.c', 'gdkpixbuf-drawable.c',
'gdkprofiler.c',
'gdkproperty.c', 'gdkproperty.c',
'gdkrectangle.c', 'gdkrectangle.c',
'gdkrgba.c', 'gdkrgba.c',
@ -226,6 +227,12 @@ if win32_enabled
gdk_sources += gdk_res gdk_sources += gdk_res
endif endif
if profiler_enabled
if profiler_dep.found()
gdk_deps += [profiler_dep]
endif
endif
gdk_sources = [ gdk_sources = [
# Generated # Generated
gdkconfig, gdkconfig,

View File

@ -29,6 +29,7 @@
#include "gdkglcontext-wayland.h" #include "gdkglcontext-wayland.h"
#include "gdkframeclockprivate.h" #include "gdkframeclockprivate.h"
#include "gdkprivate-wayland.h" #include "gdkprivate-wayland.h"
#include "gdkprofilerprivate.h"
#include "gdkinternals.h" #include "gdkinternals.h"
#include "gdkdeviceprivate.h" #include "gdkdeviceprivate.h"
#include "gdkprivate-wayland.h" #include "gdkprivate-wayland.h"
@ -560,6 +561,9 @@ frame_callback (void *data,
#ifdef G_ENABLE_DEBUG #ifdef G_ENABLE_DEBUG
if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0) if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0)
_gdk_frame_clock_debug_print_timings (clock, timings); _gdk_frame_clock_debug_print_timings (clock, timings);
if (gdk_profiler_is_running ())
_gdk_frame_clock_add_timings_to_profiler (clock, timings);
#endif #endif
} }

View File

@ -39,6 +39,7 @@
#include "gdkscreen-x11.h" #include "gdkscreen-x11.h"
#include "gdkglcontext-x11.h" #include "gdkglcontext-x11.h"
#include "gdk-private.h" #include "gdk-private.h"
#include "gdkprofilerprivate.h"
#include <glib.h> #include <glib.h>
#include <glib/gprintf.h> #include <glib/gprintf.h>
@ -1426,6 +1427,9 @@ _gdk_wm_protocols_filter (GdkXEvent *xev,
#ifdef G_ENABLE_DEBUG #ifdef G_ENABLE_DEBUG
if (GDK_DEBUG_CHECK (FRAMES)) if (GDK_DEBUG_CHECK (FRAMES))
_gdk_frame_clock_debug_print_timings (clock, timings); _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 */ #endif /* G_ENABLE_DEBUG */
} }
} }

View File

@ -21,6 +21,11 @@
#include "config.h" #include "config.h"
#include "gtkapplication.h" #include "gtkapplication.h"
#include "gdkprivate.h"
#ifdef G_OS_UNIX
#include <gio/gunixfdlist.h>
#endif
#include <stdlib.h> #include <stdlib.h>
@ -165,6 +170,7 @@ struct _GtkApplicationPrivate
GtkActionMuxer *muxer; GtkActionMuxer *muxer;
GtkBuilder *menus_builder; GtkBuilder *menus_builder;
gchar *help_overlay_path; gchar *help_overlay_path;
guint profiler_id;
}; };
G_DEFINE_TYPE_WITH_PRIVATE (GtkApplication, gtk_application, G_TYPE_APPLICATION) 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); 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 static void
gtk_application_class_init (GtkApplicationClass *class) 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->after_emit = gtk_application_after_emit;
application_class->startup = gtk_application_startup; application_class->startup = gtk_application_startup;
application_class->shutdown = gtk_application_shutdown; 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_added = gtk_application_window_added;
class->window_removed = gtk_application_window_removed; class->window_removed = gtk_application_window_removed;

View File

@ -798,6 +798,16 @@ if cloudproviders_enabled
endif endif
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') build_gir = get_option('introspection')
subdir('gdk') subdir('gdk')
subdir('gtk') subdir('gtk')
@ -956,6 +966,7 @@ summary = [
' Print backends: @0@'.format(' '.join(print_backends)), ' Print backends: @0@'.format(' '.join(print_backends)),
' Cloud support: @0@'.format(get_option('cloudproviders')), ' Cloud support: @0@'.format(get_option('cloudproviders')),
' Colord support: @0@'.format(get_option('colord')), ' Colord support: @0@'.format(get_option('colord')),
' Profiler: @0@'.format(get_option('profiler')),
' Introspection: @0@'.format(get_option('introspection')), ' Introspection: @0@'.format(get_option('introspection')),
' Documentation: @0@'.format(get_option('gtk_doc')), ' Documentation: @0@'.format(get_option('gtk_doc')),
' Man pages: @0@'.format(get_option('man')), ' Man pages: @0@'.format(get_option('man')),

View File

@ -15,6 +15,8 @@ option('xinerama', type: 'combo', choices : ['yes', 'no', 'auto'], value : 'auto
description : 'Enable support for the Xinerama extension') description : 'Enable support for the Xinerama extension')
option('cloudproviders', type: 'boolean', value: false, option('cloudproviders', type: 'boolean', value: false,
description : 'Enable the cloudproviders support') description : 'Enable the cloudproviders support')
option('profiler', type: 'boolean', value: false,
description : 'Enable profiler support')
# Print backends # Print backends
option('print_backends', type : 'string', value : 'auto', option('print_backends', type : 'string', value : 'auto',