mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-30 15:31:34 +00:00
Merge branch 'tracing' into 'master'
Tracing See merge request GNOME/gtk!563
This commit is contained in:
commit
31cd43a245
@ -17,6 +17,9 @@ GDK_VERSION_MIN_REQUIRED
|
|||||||
GDK_VERSION_MAX_ALLOWED
|
GDK_VERSION_MAX_ALLOWED
|
||||||
GDK_DISABLE_DEPRECATION_WARNINGS
|
GDK_DISABLE_DEPRECATION_WARNINGS
|
||||||
|
|
||||||
|
<SUBSECTION Profiling>
|
||||||
|
gdk_profiler_set_mark
|
||||||
|
|
||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
GDK_TYPE_GRAB_STATUS
|
GDK_TYPE_GRAB_STATUS
|
||||||
|
|
||||||
|
@ -574,6 +574,32 @@ nevertheless.
|
|||||||
|
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
|
<refsect2 id="profiling">
|
||||||
|
<title>Profiling</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
GTK supports profiling with sysprof. It exports timing information
|
||||||
|
about frameclock phases and various characteristics of GskRenders
|
||||||
|
in a format that can be displayed by sysprof or GNOME Builder.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
A simple way to capture data is to set the <envar>GTK_TRACE</envar>
|
||||||
|
environment variable. When it is set, GTK will write profiling
|
||||||
|
data to a file called
|
||||||
|
<filename>gtk.<replaceable>PID</replaceable>.syscap</filename>.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
When launching the application from sysprof, it will set the
|
||||||
|
<envar>SYSPROF_TRACE_FD</envar> environment variable to point
|
||||||
|
GTK at a file descriptor to write profiling data to.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
When GtkApplication registers with D-Bus, it exports the
|
||||||
|
<literal>org.gnome.Sysprof2.Profiler</literal> interface
|
||||||
|
that lets sysprof request profiling data at runtime.
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
</refentry>
|
</refentry>
|
||||||
|
224
gdk/capture/sp-capture-types.h
Normal file
224
gdk/capture/sp-capture-types.h
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
/* sp-capture-types.h
|
||||||
|
*
|
||||||
|
* Copyright © 2016 Christian Hergert <chergert@redhat.com>
|
||||||
|
*
|
||||||
|
* This file 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 file 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 General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SP_CAPTURE_FORMAT_H
|
||||||
|
#define SP_CAPTURE_FORMAT_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#ifndef SP_DISABLE_GOBJECT
|
||||||
|
# include <glib-object.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "sp-clock.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define SP_CAPTURE_MAGIC (GUINT32_TO_LE(0xFDCA975E))
|
||||||
|
#define SP_CAPTURE_ALIGN (sizeof(SpCaptureAddress))
|
||||||
|
|
||||||
|
#if __WORDSIZE == 64
|
||||||
|
# define SP_CAPTURE_JITMAP_MARK G_GUINT64_CONSTANT(0xE000000000000000)
|
||||||
|
# define SP_CAPTURE_ADDRESS_FORMAT "0x%016lx"
|
||||||
|
#else
|
||||||
|
# define SP_CAPTURE_JITMAP_MARK G_GUINT64_CONSTANT(0xE0000000)
|
||||||
|
# define SP_CAPTURE_ADDRESS_FORMAT "0x%016llx"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SP_CAPTURE_CURRENT_TIME (sp_clock_get_current_time())
|
||||||
|
#define SP_CAPTURE_COUNTER_INT64 0
|
||||||
|
#define SP_CAPTURE_COUNTER_DOUBLE 1
|
||||||
|
|
||||||
|
typedef struct _SpCaptureReader SpCaptureReader;
|
||||||
|
typedef struct _SpCaptureWriter SpCaptureWriter;
|
||||||
|
typedef struct _SpCaptureCursor SpCaptureCursor;
|
||||||
|
typedef struct _SpCaptureCondition SpCaptureCondition;
|
||||||
|
|
||||||
|
typedef guint64 SpCaptureAddress;
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
gint64 v64;
|
||||||
|
gdouble vdbl;
|
||||||
|
} SpCaptureCounterValue;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SP_CAPTURE_FRAME_TIMESTAMP = 1,
|
||||||
|
SP_CAPTURE_FRAME_SAMPLE = 2,
|
||||||
|
SP_CAPTURE_FRAME_MAP = 3,
|
||||||
|
SP_CAPTURE_FRAME_PROCESS = 4,
|
||||||
|
SP_CAPTURE_FRAME_FORK = 5,
|
||||||
|
SP_CAPTURE_FRAME_EXIT = 6,
|
||||||
|
SP_CAPTURE_FRAME_JITMAP = 7,
|
||||||
|
SP_CAPTURE_FRAME_CTRDEF = 8,
|
||||||
|
SP_CAPTURE_FRAME_CTRSET = 9,
|
||||||
|
SP_CAPTURE_FRAME_MARK = 10,
|
||||||
|
} SpCaptureFrameType;
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
guint32 magic;
|
||||||
|
guint8 version;
|
||||||
|
guint32 little_endian : 1;
|
||||||
|
guint32 padding : 23;
|
||||||
|
gchar capture_time[64];
|
||||||
|
gint64 time;
|
||||||
|
gint64 end_time;
|
||||||
|
gchar suffix[168];
|
||||||
|
} SpCaptureFileHeader;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
guint16 len;
|
||||||
|
gint16 cpu;
|
||||||
|
gint32 pid;
|
||||||
|
gint64 time;
|
||||||
|
guint8 type;
|
||||||
|
guint64 padding : 56;
|
||||||
|
guint8 data[0];
|
||||||
|
} SpCaptureFrame;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpCaptureFrame frame;
|
||||||
|
guint64 start;
|
||||||
|
guint64 end;
|
||||||
|
guint64 offset;
|
||||||
|
guint64 inode;
|
||||||
|
gchar filename[0];
|
||||||
|
} SpCaptureMap;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpCaptureFrame frame;
|
||||||
|
guint32 n_jitmaps;
|
||||||
|
guint8 data[0];
|
||||||
|
} SpCaptureJitmap;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpCaptureFrame frame;
|
||||||
|
gchar cmdline[0];
|
||||||
|
} SpCaptureProcess;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpCaptureFrame frame;
|
||||||
|
guint16 n_addrs;
|
||||||
|
guint64 padding : 48;
|
||||||
|
SpCaptureAddress addrs[0];
|
||||||
|
} SpCaptureSample;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpCaptureFrame frame;
|
||||||
|
GPid child_pid;
|
||||||
|
} SpCaptureFork;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpCaptureFrame frame;
|
||||||
|
} SpCaptureExit;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpCaptureFrame frame;
|
||||||
|
} SpCaptureTimestamp;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
gchar category[32];
|
||||||
|
gchar name[32];
|
||||||
|
gchar description[52];
|
||||||
|
guint32 id : 24;
|
||||||
|
guint8 type;
|
||||||
|
SpCaptureCounterValue value;
|
||||||
|
} SpCaptureCounter;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpCaptureFrame frame;
|
||||||
|
guint16 n_counters;
|
||||||
|
guint64 padding : 48;
|
||||||
|
SpCaptureCounter counters[0];
|
||||||
|
} SpCaptureFrameCounterDefine;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* 96 bytes might seem a bit odd, but the counter frame header is 32
|
||||||
|
* bytes. So this makes a nice 2-cacheline aligned size which is
|
||||||
|
* useful when the number of counters is rather small.
|
||||||
|
*/
|
||||||
|
guint32 ids[8];
|
||||||
|
SpCaptureCounterValue values[8];
|
||||||
|
} SpCaptureCounterValues;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpCaptureFrame frame;
|
||||||
|
guint16 n_values;
|
||||||
|
guint64 padding : 48;
|
||||||
|
SpCaptureCounterValues values[0];
|
||||||
|
} SpCaptureFrameCounterSet;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpCaptureFrame frame;
|
||||||
|
gint64 duration;
|
||||||
|
gchar group[24];
|
||||||
|
gchar name[40];
|
||||||
|
gchar message[0];
|
||||||
|
} SpCaptureMark;
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
G_STATIC_ASSERT (sizeof (SpCaptureFileHeader) == 256);
|
||||||
|
G_STATIC_ASSERT (sizeof (SpCaptureFrame) == 24);
|
||||||
|
G_STATIC_ASSERT (sizeof (SpCaptureMap) == 56);
|
||||||
|
G_STATIC_ASSERT (sizeof (SpCaptureJitmap) == 28);
|
||||||
|
G_STATIC_ASSERT (sizeof (SpCaptureProcess) == 24);
|
||||||
|
G_STATIC_ASSERT (sizeof (SpCaptureSample) == 32);
|
||||||
|
G_STATIC_ASSERT (sizeof (SpCaptureFork) == 28);
|
||||||
|
G_STATIC_ASSERT (sizeof (SpCaptureExit) == 24);
|
||||||
|
G_STATIC_ASSERT (sizeof (SpCaptureTimestamp) == 24);
|
||||||
|
G_STATIC_ASSERT (sizeof (SpCaptureCounter) == 128);
|
||||||
|
G_STATIC_ASSERT (sizeof (SpCaptureCounterValues) == 96);
|
||||||
|
G_STATIC_ASSERT (sizeof (SpCaptureFrameCounterDefine) == 32);
|
||||||
|
G_STATIC_ASSERT (sizeof (SpCaptureFrameCounterSet) == 32);
|
||||||
|
G_STATIC_ASSERT (sizeof (SpCaptureMark) == 96);
|
||||||
|
|
||||||
|
static inline gint
|
||||||
|
sp_capture_address_compare (SpCaptureAddress a,
|
||||||
|
SpCaptureAddress b)
|
||||||
|
{
|
||||||
|
if (a < b)
|
||||||
|
return -1;
|
||||||
|
if (a > b)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* SP_CAPTURE_FORMAT_H */
|
||||||
|
|
1123
gdk/capture/sp-capture-writer.c
Normal file
1123
gdk/capture/sp-capture-writer.c
Normal file
File diff suppressed because it is too large
Load Diff
132
gdk/capture/sp-capture-writer.h
Normal file
132
gdk/capture/sp-capture-writer.h
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/* sp-capture-writer.h
|
||||||
|
*
|
||||||
|
* Copyright © 2016 Christian Hergert <chergert@redhat.com>
|
||||||
|
*
|
||||||
|
* This file 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 file 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 General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SP_CAPTURE_WRITER_H
|
||||||
|
#define SP_CAPTURE_WRITER_H
|
||||||
|
|
||||||
|
#include "capture/sp-capture-types.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef struct _SpCaptureWriter SpCaptureWriter;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The number of frames indexed by SpCaptureFrameType
|
||||||
|
*/
|
||||||
|
gsize frame_count[16];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Padding for future expansion.
|
||||||
|
*/
|
||||||
|
gsize padding[48];
|
||||||
|
} SpCaptureStat;
|
||||||
|
|
||||||
|
SpCaptureWriter *sp_capture_writer_new (const gchar *filename,
|
||||||
|
gsize buffer_size);
|
||||||
|
SpCaptureWriter *sp_capture_writer_new_from_fd (int fd,
|
||||||
|
gsize buffer_size);
|
||||||
|
SpCaptureWriter *sp_capture_writer_ref (SpCaptureWriter *self);
|
||||||
|
void sp_capture_writer_unref (SpCaptureWriter *self);
|
||||||
|
void sp_capture_writer_stat (SpCaptureWriter *self,
|
||||||
|
SpCaptureStat *stat);
|
||||||
|
gboolean sp_capture_writer_add_map (SpCaptureWriter *self,
|
||||||
|
gint64 time,
|
||||||
|
gint cpu,
|
||||||
|
GPid pid,
|
||||||
|
guint64 start,
|
||||||
|
guint64 end,
|
||||||
|
guint64 offset,
|
||||||
|
guint64 inode,
|
||||||
|
const gchar *filename);
|
||||||
|
gboolean sp_capture_writer_add_mark (SpCaptureWriter *self,
|
||||||
|
gint64 time,
|
||||||
|
gint cpu,
|
||||||
|
GPid pid,
|
||||||
|
guint64 duration,
|
||||||
|
const gchar *group,
|
||||||
|
const gchar *name,
|
||||||
|
const gchar *message);
|
||||||
|
guint64 sp_capture_writer_add_jitmap (SpCaptureWriter *self,
|
||||||
|
const gchar *name);
|
||||||
|
gboolean sp_capture_writer_add_process (SpCaptureWriter *self,
|
||||||
|
gint64 time,
|
||||||
|
gint cpu,
|
||||||
|
GPid pid,
|
||||||
|
const gchar *cmdline);
|
||||||
|
gboolean sp_capture_writer_add_sample (SpCaptureWriter *self,
|
||||||
|
gint64 time,
|
||||||
|
gint cpu,
|
||||||
|
GPid pid,
|
||||||
|
const SpCaptureAddress *addrs,
|
||||||
|
guint n_addrs);
|
||||||
|
gboolean sp_capture_writer_add_fork (SpCaptureWriter *self,
|
||||||
|
gint64 time,
|
||||||
|
gint cpu,
|
||||||
|
GPid pid,
|
||||||
|
GPid child_pid);
|
||||||
|
gboolean sp_capture_writer_add_exit (SpCaptureWriter *self,
|
||||||
|
gint64 time,
|
||||||
|
gint cpu,
|
||||||
|
GPid pid);
|
||||||
|
gboolean sp_capture_writer_add_timestamp (SpCaptureWriter *self,
|
||||||
|
gint64 time,
|
||||||
|
gint cpu,
|
||||||
|
GPid pid);
|
||||||
|
gboolean sp_capture_writer_define_counters (SpCaptureWriter *self,
|
||||||
|
gint64 time,
|
||||||
|
gint cpu,
|
||||||
|
GPid pid,
|
||||||
|
const SpCaptureCounter *counters,
|
||||||
|
guint n_counters);
|
||||||
|
gboolean sp_capture_writer_set_counters (SpCaptureWriter *self,
|
||||||
|
gint64 time,
|
||||||
|
gint cpu,
|
||||||
|
GPid pid,
|
||||||
|
const guint *counters_ids,
|
||||||
|
const SpCaptureCounterValue *values,
|
||||||
|
guint n_counters);
|
||||||
|
gboolean sp_capture_writer_flush (SpCaptureWriter *self);
|
||||||
|
gboolean sp_capture_writer_save_as (SpCaptureWriter *self,
|
||||||
|
const gchar *filename,
|
||||||
|
GError **error);
|
||||||
|
gint sp_capture_writer_request_counter (SpCaptureWriter *self,
|
||||||
|
guint n_counters);
|
||||||
|
SpCaptureReader *sp_capture_writer_create_reader (SpCaptureWriter *self,
|
||||||
|
GError **error);
|
||||||
|
gboolean sp_capture_writer_splice (SpCaptureWriter *self,
|
||||||
|
SpCaptureWriter *dest,
|
||||||
|
GError **error);
|
||||||
|
gboolean _sp_capture_writer_splice_from_fd (SpCaptureWriter *self,
|
||||||
|
int fd,
|
||||||
|
GError **error) G_GNUC_INTERNAL;
|
||||||
|
|
||||||
|
#ifndef SP_DISABLE_GOBJECT
|
||||||
|
# define SP_TYPE_CAPTURE_WRITER (sp_capture_writer_get_type())
|
||||||
|
GType sp_capture_writer_get_type (void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if GLIB_CHECK_VERSION(2, 44, 0)
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SpCaptureWriter, sp_capture_writer_unref)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* SP_CAPTURE_WRITER_H */
|
||||||
|
|
52
gdk/capture/sp-clock.c
Normal file
52
gdk/capture/sp-clock.c
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/* sp-clock.c
|
||||||
|
*
|
||||||
|
* Copyright © 2016 Christian Hergert <chergert@redhat.com>
|
||||||
|
*
|
||||||
|
* This file 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 file 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 General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sp-clock.h"
|
||||||
|
|
||||||
|
gint sp_clock = -1;
|
||||||
|
|
||||||
|
void
|
||||||
|
sp_clock_init (void)
|
||||||
|
{
|
||||||
|
static const gint clock_ids[] = {
|
||||||
|
CLOCK_MONOTONIC_RAW,
|
||||||
|
CLOCK_MONOTONIC_COARSE,
|
||||||
|
CLOCK_MONOTONIC,
|
||||||
|
CLOCK_REALTIME_COARSE,
|
||||||
|
CLOCK_REALTIME,
|
||||||
|
};
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
if (sp_clock != -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (clock_ids); i++)
|
||||||
|
{
|
||||||
|
struct timespec ts;
|
||||||
|
int clock_id = clock_ids [i];
|
||||||
|
|
||||||
|
if (0 == clock_gettime (clock_id, &ts))
|
||||||
|
{
|
||||||
|
sp_clock = clock_id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
55
gdk/capture/sp-clock.h
Normal file
55
gdk/capture/sp-clock.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/* sp-clock.h
|
||||||
|
*
|
||||||
|
* Copyright © 2016 Christian Hergert <chergert@redhat.com>
|
||||||
|
*
|
||||||
|
* This file 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 file 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 General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SP_CLOCK_H
|
||||||
|
#define SP_CLOCK_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef gint SpClock;
|
||||||
|
typedef gint64 SpTimeStamp;
|
||||||
|
typedef gint32 SpTimeSpan;
|
||||||
|
|
||||||
|
extern SpClock sp_clock;
|
||||||
|
|
||||||
|
static inline SpTimeStamp
|
||||||
|
sp_clock_get_current_time (void)
|
||||||
|
{
|
||||||
|
struct timespec ts;
|
||||||
|
|
||||||
|
clock_gettime (sp_clock, &ts);
|
||||||
|
|
||||||
|
return (ts.tv_sec * G_GINT64_CONSTANT (1000000000)) + ts.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline SpTimeSpan
|
||||||
|
sp_clock_get_relative_time (SpTimeStamp epoch)
|
||||||
|
{
|
||||||
|
return sp_clock_get_current_time () - epoch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sp_clock_init (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* SP_CLOCK_H */
|
||||||
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include "gdkversionmacros.h"
|
#include "gdkversionmacros.h"
|
||||||
|
|
||||||
|
#include "gdkprofilerprivate.h"
|
||||||
#include "gdkinternals.h"
|
#include "gdkinternals.h"
|
||||||
#include "gdkintl.h"
|
#include "gdkintl.h"
|
||||||
|
|
||||||
@ -211,6 +212,11 @@ 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 ("SYSPROF_TRACE_FD"))
|
||||||
|
gdk_profiler_start (atoi (g_getenv ("SYSPROF_TRACE_FD")));
|
||||||
|
else if (g_getenv ("GTK_TRACE"))
|
||||||
|
gdk_profiler_start (-1);
|
||||||
}
|
}
|
||||||
#endif /* G_ENABLE_DEBUG */
|
#endif /* G_ENABLE_DEBUG */
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
#include <gdk/gdkpaintable.h>
|
#include <gdk/gdkpaintable.h>
|
||||||
#include <gdk/gdkpango.h>
|
#include <gdk/gdkpango.h>
|
||||||
#include <gdk/gdkpixbuf.h>
|
#include <gdk/gdkpixbuf.h>
|
||||||
|
#include <gdk/gdkprofiler.h>
|
||||||
#include <gdk/gdkproperty.h>
|
#include <gdk/gdkproperty.h>
|
||||||
#include <gdk/gdkrectangle.h>
|
#include <gdk/gdkrectangle.h>
|
||||||
#include <gdk/gdkrgba.h>
|
#include <gdk/gdkrgba.h>
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "gdkinternals.h"
|
#include "gdkinternals.h"
|
||||||
#include "gdkframeclockprivate.h"
|
#include "gdkframeclockprivate.h"
|
||||||
#include "gdk.h"
|
#include "gdk.h"
|
||||||
|
#include "gdkprofilerprivate.h"
|
||||||
|
|
||||||
#ifdef G_OS_WIN32
|
#ifdef G_OS_WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@ -113,6 +114,96 @@ get_sleep_serial (void)
|
|||||||
return sleep_serial;
|
return sleep_serial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static guint fps_counter = 0;
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_timings_to_profiler (GdkFrameTimings *timings)
|
||||||
|
{
|
||||||
|
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", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gdk_frame_clock_idle_init (GdkFrameClockIdle *frame_clock_idle)
|
gdk_frame_clock_idle_init (GdkFrameClockIdle *frame_clock_idle)
|
||||||
{
|
{
|
||||||
@ -123,6 +214,11 @@ gdk_frame_clock_idle_init (GdkFrameClockIdle *frame_clock_idle)
|
|||||||
|
|
||||||
priv->frame_time = g_get_monotonic_time (); /* more sane than zero */
|
priv->frame_time = g_get_monotonic_time (); /* more sane than zero */
|
||||||
priv->freeze_count = 0;
|
priv->freeze_count = 0;
|
||||||
|
|
||||||
|
#ifdef G_ENABLE_DEBUG
|
||||||
|
if (fps_counter == 0)
|
||||||
|
fps_counter = gdk_profiler_define_counter ("fps", "Frames per Second");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -405,7 +501,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))
|
||||||
@ -435,7 +531,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))
|
||||||
@ -462,7 +558,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 */
|
||||||
}
|
}
|
||||||
@ -475,6 +571,12 @@ gdk_frame_clock_paint_idle (void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef G_ENABLE_DEBUG
|
#ifdef G_ENABLE_DEBUG
|
||||||
|
if (gdk_profiler_is_running ())
|
||||||
|
{
|
||||||
|
add_timings_to_profiler (timings);
|
||||||
|
gdk_profiler_set_counter (fps_counter, timings->frame_end_time * 1000, frame_clock_get_fps (clock));
|
||||||
|
}
|
||||||
|
|
||||||
if (GDK_DEBUG_CHECK (FRAMES))
|
if (GDK_DEBUG_CHECK (FRAMES))
|
||||||
{
|
{
|
||||||
if (timings && timings->complete)
|
if (timings && timings->complete)
|
||||||
|
259
gdk/gdkprofiler.c
Normal file
259
gdk/gdkprofiler.c
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
/* 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>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "gdkversionmacros.h"
|
||||||
|
#include "gdkprofiler.h"
|
||||||
|
#include "gdkprofilerprivate.h"
|
||||||
|
#include "gdkframeclockprivate.h"
|
||||||
|
|
||||||
|
#ifndef G_OS_WIN32
|
||||||
|
|
||||||
|
#include "capture/sp-capture-writer.h"
|
||||||
|
|
||||||
|
static SpCaptureWriter *writer = NULL;
|
||||||
|
static gboolean running = FALSE;
|
||||||
|
|
||||||
|
static void
|
||||||
|
profiler_stop (void)
|
||||||
|
{
|
||||||
|
if (writer)
|
||||||
|
sp_capture_writer_unref (writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gdk_profiler_start (int fd)
|
||||||
|
{
|
||||||
|
if (writer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sp_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 = sp_capture_writer_new (filename, 16*1024);
|
||||||
|
g_free (filename);
|
||||||
|
}
|
||||||
|
else if (fd > 2)
|
||||||
|
writer = sp_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;
|
||||||
|
|
||||||
|
sp_capture_writer_add_mark (writer,
|
||||||
|
start,
|
||||||
|
-1, getpid (),
|
||||||
|
duration,
|
||||||
|
"gtk", name, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint
|
||||||
|
define_counter (const char *name,
|
||||||
|
const char *description,
|
||||||
|
int type)
|
||||||
|
{
|
||||||
|
SpCaptureCounter counter;
|
||||||
|
|
||||||
|
if (!writer)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
counter.id = (guint) sp_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);
|
||||||
|
|
||||||
|
sp_capture_writer_define_counters (writer,
|
||||||
|
SP_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, SP_CAPTURE_COUNTER_DOUBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
guint
|
||||||
|
gdk_profiler_define_int_counter (const char *name,
|
||||||
|
const char *description)
|
||||||
|
{
|
||||||
|
return define_counter (name, description, SP_CAPTURE_COUNTER_INT64);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gdk_profiler_set_counter (guint id,
|
||||||
|
gint64 time,
|
||||||
|
double val)
|
||||||
|
{
|
||||||
|
SpCaptureCounterValue value;
|
||||||
|
|
||||||
|
if (!running)
|
||||||
|
return;
|
||||||
|
|
||||||
|
value.vdbl = val;
|
||||||
|
sp_capture_writer_set_counters (writer,
|
||||||
|
time,
|
||||||
|
-1, getpid (),
|
||||||
|
&id, &value, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gdk_profiler_set_int_counter (guint id,
|
||||||
|
gint64 time,
|
||||||
|
gint64 val)
|
||||||
|
{
|
||||||
|
SpCaptureCounterValue value;
|
||||||
|
|
||||||
|
if (!running)
|
||||||
|
return;
|
||||||
|
|
||||||
|
value.v64 = val;
|
||||||
|
sp_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 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdk_profiler_set_mark:
|
||||||
|
* @duration: the duration of the mark, or 0
|
||||||
|
* @name: the name of the mark (up to 40 characters)
|
||||||
|
* @message: (optional): the message of the mark
|
||||||
|
*
|
||||||
|
* Insert a mark into the profiling data if we
|
||||||
|
* are currently profiling.
|
||||||
|
* This information will show up in tools like sysprof
|
||||||
|
* or GNOME Builder when viewing the profiling data.
|
||||||
|
* It can be used to mark interesting regions in the
|
||||||
|
* captured data.
|
||||||
|
*
|
||||||
|
* If the duration is non-zero, the mark applies to
|
||||||
|
* the timespan from @duration microseconds in the
|
||||||
|
* past to the current time. To mark just a point in
|
||||||
|
* time, pass 0 as duration.
|
||||||
|
*
|
||||||
|
* @name should be a short string, and @message is optional.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gdk_profiler_set_mark (guint64 duration,
|
||||||
|
const char *name,
|
||||||
|
const char *message)
|
||||||
|
{
|
||||||
|
guint64 start;
|
||||||
|
|
||||||
|
start = g_get_monotonic_time () - duration;
|
||||||
|
gdk_profiler_add_mark (start, duration, name, message);
|
||||||
|
}
|
32
gdk/gdkprofiler.h
Normal file
32
gdk/gdkprofiler.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/* 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_H__
|
||||||
|
#define __GDK_PROFILER_H__
|
||||||
|
|
||||||
|
#include <gdk/gdkversionmacros.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
GDK_AVAILABLE_IN_ALL
|
||||||
|
void gdk_profiler_set_mark (guint64 duration,
|
||||||
|
const char *name,
|
||||||
|
const char *message);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GDK_PROFILER_H__ */
|
46
gdk/gdkprofilerprivate.h
Normal file
46
gdk/gdkprofilerprivate.h
Normal 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__ */
|
@ -45,8 +45,16 @@ gdk_public_sources = files([
|
|||||||
'gdkvulkancontext.c',
|
'gdkvulkancontext.c',
|
||||||
'gdksurface.c',
|
'gdksurface.c',
|
||||||
'gdksurfaceimpl.c',
|
'gdksurfaceimpl.c',
|
||||||
|
'gdkprofiler.c'
|
||||||
])
|
])
|
||||||
|
|
||||||
|
if not win32_enabled
|
||||||
|
gdk_public_sources += files([
|
||||||
|
'capture/sp-capture-writer.c',
|
||||||
|
'capture/sp-clock.c'
|
||||||
|
])
|
||||||
|
endif
|
||||||
|
|
||||||
gdk_public_headers = files([
|
gdk_public_headers = files([
|
||||||
'gdk-autocleanup.h',
|
'gdk-autocleanup.h',
|
||||||
'gdk.h',
|
'gdk.h',
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "gdk/gdkgltextureprivate.h"
|
#include "gdk/gdkgltextureprivate.h"
|
||||||
#include "gdk/gdkglcontextprivate.h"
|
#include "gdk/gdkglcontextprivate.h"
|
||||||
|
#include "gdk/gdkprofilerprivate.h"
|
||||||
|
|
||||||
#include <epoxy/gl.h>
|
#include <epoxy/gl.h>
|
||||||
#include <cairo-ft.h>
|
#include <cairo-ft.h>
|
||||||
@ -3008,7 +3009,7 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
|
|||||||
gsize buffer_size;
|
gsize buffer_size;
|
||||||
#ifdef G_ENABLE_DEBUG
|
#ifdef G_ENABLE_DEBUG
|
||||||
GskProfiler *profiler;
|
GskProfiler *profiler;
|
||||||
gint64 gpu_time, cpu_time;
|
gint64 gpu_time, cpu_time, start_time;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef G_ENABLE_DEBUG
|
#ifdef G_ENABLE_DEBUG
|
||||||
@ -3116,6 +3117,7 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
|
|||||||
#ifdef G_ENABLE_DEBUG
|
#ifdef G_ENABLE_DEBUG
|
||||||
gsk_profiler_counter_inc (profiler, self->profile_counters.frames);
|
gsk_profiler_counter_inc (profiler, self->profile_counters.frames);
|
||||||
|
|
||||||
|
start_time = gsk_profiler_timer_get_start (profiler, self->profile_timers.cpu_time);
|
||||||
cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
|
cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
|
||||||
gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
|
gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
|
||||||
|
|
||||||
@ -3123,6 +3125,10 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
|
|||||||
gsk_profiler_timer_set (profiler, self->profile_timers.gpu_time, gpu_time);
|
gsk_profiler_timer_set (profiler, self->profile_timers.gpu_time, gpu_time);
|
||||||
|
|
||||||
gsk_profiler_push_samples (profiler);
|
gsk_profiler_push_samples (profiler);
|
||||||
|
|
||||||
|
if (gdk_profiler_is_running ())
|
||||||
|
gdk_profiler_add_mark (start_time, cpu_time, "render", "");
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,6 +365,19 @@ gsk_profiler_timer_get (GskProfiler *profiler,
|
|||||||
return timer->value;
|
return timer->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gint64
|
||||||
|
gsk_profiler_timer_get_start (GskProfiler *profiler,
|
||||||
|
GQuark timer_id)
|
||||||
|
{
|
||||||
|
NamedTimer *timer;
|
||||||
|
|
||||||
|
timer = gsk_profiler_get_timer (profiler, timer_id);
|
||||||
|
if (timer == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return timer->start_time;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gsk_profiler_reset (GskProfiler *profiler)
|
gsk_profiler_reset (GskProfiler *profiler)
|
||||||
{
|
{
|
||||||
|
@ -40,6 +40,8 @@ gint64 gsk_profiler_counter_get (GskProfiler *profiler,
|
|||||||
GQuark counter_id);
|
GQuark counter_id);
|
||||||
gint64 gsk_profiler_timer_get (GskProfiler *profiler,
|
gint64 gsk_profiler_timer_get (GskProfiler *profiler,
|
||||||
GQuark timer_id);
|
GQuark timer_id);
|
||||||
|
gint64 gsk_profiler_timer_get_start (GskProfiler *profiler,
|
||||||
|
GQuark timer_id);
|
||||||
|
|
||||||
void gsk_profiler_reset (GskProfiler *profiler);
|
void gsk_profiler_reset (GskProfiler *profiler);
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "gskvulkanglyphcacheprivate.h"
|
#include "gskvulkanglyphcacheprivate.h"
|
||||||
|
|
||||||
#include "gdk/gdktextureprivate.h"
|
#include "gdk/gdktextureprivate.h"
|
||||||
|
#include "gdk/gdkprofilerprivate.h"
|
||||||
|
|
||||||
#include <graphene.h>
|
#include <graphene.h>
|
||||||
|
|
||||||
@ -38,6 +39,9 @@ typedef struct {
|
|||||||
} ProfileTimers;
|
} ProfileTimers;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static guint texture_pixels_counter;
|
||||||
|
static guint fallback_pixels_counter;
|
||||||
|
|
||||||
struct _GskVulkanRenderer
|
struct _GskVulkanRenderer
|
||||||
{
|
{
|
||||||
GskRenderer parent_instance;
|
GskRenderer parent_instance;
|
||||||
@ -170,7 +174,7 @@ gsk_vulkan_renderer_render_texture (GskRenderer *renderer,
|
|||||||
GdkTexture *texture;
|
GdkTexture *texture;
|
||||||
#ifdef G_ENABLE_DEBUG
|
#ifdef G_ENABLE_DEBUG
|
||||||
GskProfiler *profiler;
|
GskProfiler *profiler;
|
||||||
gint64 cpu_time;
|
gint64 cpu_time, start_time;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef G_ENABLE_DEBUG
|
#ifdef G_ENABLE_DEBUG
|
||||||
@ -201,10 +205,22 @@ gsk_vulkan_renderer_render_texture (GskRenderer *renderer,
|
|||||||
gsk_vulkan_render_free (render);
|
gsk_vulkan_render_free (render);
|
||||||
|
|
||||||
#ifdef G_ENABLE_DEBUG
|
#ifdef G_ENABLE_DEBUG
|
||||||
|
start_time = gsk_profiler_timer_get_start (profiler, self->profile_timers.cpu_time);
|
||||||
cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
|
cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
|
||||||
gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
|
gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
|
||||||
|
|
||||||
gsk_profiler_push_samples (profiler);
|
gsk_profiler_push_samples (profiler);
|
||||||
|
|
||||||
|
if (gdk_profiler_is_running ())
|
||||||
|
{
|
||||||
|
gdk_profiler_add_mark (start_time, cpu_time, "render", "");
|
||||||
|
gdk_profiler_set_int_counter (texture_pixels_counter,
|
||||||
|
start_time + cpu_time,
|
||||||
|
gsk_profiler_counter_get (profiler, self->profile_counters.texture_pixels));
|
||||||
|
gdk_profiler_set_int_counter (fallback_pixels_counter,
|
||||||
|
start_time + cpu_time,
|
||||||
|
gsk_profiler_counter_get (profiler, self->profile_counters.fallback_pixels));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
@ -284,6 +300,13 @@ gsk_vulkan_renderer_init (GskVulkanRenderer *self)
|
|||||||
self->profile_timers.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU time", FALSE, TRUE);
|
self->profile_timers.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU time", FALSE, TRUE);
|
||||||
if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), SYNC))
|
if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), SYNC))
|
||||||
self->profile_timers.gpu_time = gsk_profiler_add_timer (profiler, "gpu-time", "GPU time", FALSE, TRUE);
|
self->profile_timers.gpu_time = gsk_profiler_add_timer (profiler, "gpu-time", "GPU time", FALSE, TRUE);
|
||||||
|
|
||||||
|
if (texture_pixels_counter == 0)
|
||||||
|
{
|
||||||
|
texture_pixels_counter = gdk_profiler_define_int_counter ("texture-pixels", "Texture Pixels");
|
||||||
|
fallback_pixels_counter = gdk_profiler_define_int_counter ("fallback-pixels", "Fallback Pixels");
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,11 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "gtkapplication.h"
|
#include "gtkapplication.h"
|
||||||
|
#include "gdkprofilerprivate.h"
|
||||||
|
|
||||||
|
#ifdef G_OS_UNIX
|
||||||
|
#include <gio/gunixfdlist.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
@ -603,6 +608,148 @@ 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_Sysprof2_Profiler_xml[] =
|
||||||
|
"<node>"
|
||||||
|
"<interface name='org.gnome.Sysprof2.Profiler'>"
|
||||||
|
"<method name='Start'>"
|
||||||
|
"<arg type='h' name='fd' direction='in'/>"
|
||||||
|
"</method>"
|
||||||
|
"<method name='Stop'>"
|
||||||
|
"</method>"
|
||||||
|
"</interface>"
|
||||||
|
"</node>";
|
||||||
|
|
||||||
|
static GDBusInterfaceInfo *org_gnome_Sysprof2_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;
|
||||||
|
int fd = -1;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
if (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, "(h)", &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_profiler_start (fd);
|
||||||
|
}
|
||||||
|
else if (strcmp (method_name, "Stop") == 0)
|
||||||
|
{
|
||||||
|
if (!gdk_profiler_is_running ())
|
||||||
|
{
|
||||||
|
g_dbus_method_invocation_return_error (invocation,
|
||||||
|
G_DBUS_ERROR,
|
||||||
|
G_DBUS_ERROR_FAILED,
|
||||||
|
"Profiler not running");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) application;
|
||||||
|
GDBusInterfaceVTable vtable = {
|
||||||
|
sysprof_profiler_method_call,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
if (org_gnome_Sysprof2_Profiler == NULL)
|
||||||
|
{
|
||||||
|
GDBusNodeInfo *info;
|
||||||
|
|
||||||
|
info = g_dbus_node_info_new_for_xml (org_gnome_Sysprof2_Profiler_xml, error);
|
||||||
|
if (info == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
org_gnome_Sysprof2_Profiler = g_dbus_node_info_lookup_interface (info, "org.gnome.Sysprof2.Profiler");
|
||||||
|
g_dbus_interface_info_ref (org_gnome_Sysprof2_Profiler);
|
||||||
|
g_dbus_node_info_unref (info);
|
||||||
|
}
|
||||||
|
|
||||||
|
dbus->profiler_id = g_dbus_connection_register_object (connection,
|
||||||
|
"/org/gtk/Profiler",
|
||||||
|
org_gnome_Sysprof2_Profiler,
|
||||||
|
&vtable,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
error);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_application_dbus_unregister (GApplication *application,
|
||||||
|
GDBusConnection *connection,
|
||||||
|
const char *obect_path)
|
||||||
|
{
|
||||||
|
GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) application;
|
||||||
|
|
||||||
|
g_dbus_connection_unregister_object (connection, dbus->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)
|
||||||
{
|
{
|
||||||
@ -619,6 +766,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;
|
||||||
|
@ -127,6 +127,7 @@ typedef struct
|
|||||||
|
|
||||||
gchar *menubar_path;
|
gchar *menubar_path;
|
||||||
guint menubar_id;
|
guint menubar_id;
|
||||||
|
guint profiler_id;
|
||||||
|
|
||||||
/* Session management... */
|
/* Session management... */
|
||||||
GDBusProxy *sm_proxy;
|
GDBusProxy *sm_proxy;
|
||||||
|
Loading…
Reference in New Issue
Block a user