mirror of
https://github.com/brl/mutter.git
synced 2024-12-23 19:42:05 +00:00
profile: Update to uprof-0.3 dep for --enable-profile
When building with --enable-profile we now depend on the uprof-0.3 developer release which brings a few improvements: » It lets us "fix" how we initialize uprof so that instead of using a shared object constructor/destructor (which was a hack used when first adding uprof support to Clutter) we can now initialize as part of clutter's normal initialization code. As a side note though, I found that the way Clutter initializes has some quite serious problems whenever it involves GOptionGroups. It is not able to guarantee the initialization of dependencies like uprof and Cogl. For this reason we still use the contructor/destructor approach to initialize uprof in Cogl. » uprof-0.3 provides a better API for adding custom columns when reporting timer and counter statistics which lets us remove quite a lot of manual report generation code in clutter-profile.c. » uprof-0.3 provides a shared context for tracking mainloop timer statistics. This means any mainloop based library following the same "Mainloop" timer naming convention can use the shared context and no matter who ends up owning the final mainloop the statistics will always be in the same place. This allows profiling of Clutter with an external mainloop such as with the Mutter compositor. » uprof-0.3 can export statistics over dbus and comes with an ncurses based ui to vizualize timer and counter stats live. The latest version of uprof can be cloned from: git://github.com/rib/UProf.git
This commit is contained in:
parent
a45f67bbdc
commit
fb7bf9ce02
2
README
2
README
@ -55,7 +55,7 @@ If you want support for profiling Clutter you will also need:
|
||||
|
||||
UProf is available from:
|
||||
|
||||
git://git.moblin.org/uprof.git
|
||||
git://github.com/rib/UProf.git
|
||||
|
||||
RESOURCES
|
||||
-------------------------------------------------------------------------------
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <glib.h>
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-profile.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -44,41 +45,45 @@ typedef enum {
|
||||
#ifdef __GNUC__
|
||||
|
||||
/* Try the GCC extension for valists in macros */
|
||||
#define CLUTTER_NOTE(type,x,a...) G_STMT_START { \
|
||||
if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) { \
|
||||
g_message ("[" #type "] " G_STRLOC ": " x, ##a); \
|
||||
} } G_STMT_END
|
||||
|
||||
#define CLUTTER_TIMESTAMP(type,x,a...) G_STMT_START { \
|
||||
if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) { \
|
||||
g_message ("[" #type "]" " %li:" G_STRLOC ": " \
|
||||
x, clutter_get_timestamp(), ##a); \
|
||||
} } G_STMT_END
|
||||
#define CLUTTER_NOTE(type,x,a...) G_STMT_START { \
|
||||
if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) \
|
||||
{ _clutter_profile_trace_message ("[" #type "] " \
|
||||
G_STRLOC " & " x, ##a); } \
|
||||
} G_STMT_END
|
||||
|
||||
#define CLUTTER_TIMESTAMP(type,x,a...) G_STMT_START { \
|
||||
if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) \
|
||||
{ g_message ("[" #type "]" " %li:" G_STRLOC ": " \
|
||||
x, clutter_get_timestamp(), ##a); } \
|
||||
} G_STMT_END
|
||||
#else /* !__GNUC__ */
|
||||
|
||||
/* Try the C99 version; unfortunately, this does not allow us to pass
|
||||
* empty arguments to the macro, which means we have to
|
||||
* do an intemediate printf.
|
||||
*/
|
||||
#define CLUTTER_NOTE(type,...) G_STMT_START { \
|
||||
if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) { \
|
||||
gchar * _fmt = g_strdup_printf (__VA_ARGS__); \
|
||||
g_message ("[" #type "] " G_STRLOC ": %s",_fmt); \
|
||||
g_free (_fmt); } } G_STMT_END
|
||||
#define CLUTTER_NOTE(type,...) G_STMT_START { \
|
||||
if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) \
|
||||
{ \
|
||||
gchar * _fmt = g_strdup_printf (__VA_ARGS__); \
|
||||
_clutter_profile_trace_message ("[" #type "] " \
|
||||
G_STRLOC " & %s",_fmt); \
|
||||
g_free (_fmt); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
#define CLUTTER_TIMESTAMP(type,...) G_STMT_START { \
|
||||
if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) { \
|
||||
gchar * _fmt = g_strdup_printf (__VA_ARGS__); \
|
||||
g_message ("[" #type "]" " %li:" G_STRLOC ": %s", \
|
||||
clutter_get_timestamp(), _fmt); \
|
||||
g_free (_fmt); \
|
||||
} } G_STMT_END
|
||||
#define CLUTTER_TIMESTAMP(type,...) G_STMT_START { \
|
||||
if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) \
|
||||
{ \
|
||||
gchar * _fmt = g_strdup_printf (__VA_ARGS__); \
|
||||
g_message ("[" #type "]" " %li:" G_STRLOC ": %s", \
|
||||
clutter_get_timestamp(), _fmt); \
|
||||
g_free (_fmt); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
#endif
|
||||
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#define CLUTTER_MARK() CLUTTER_NOTE(MISC, "== mark ==")
|
||||
#define CLUTTER_DBG(x) { a }
|
||||
#define CLUTTER_MARK() CLUTTER_NOTE(MISC, "== mark ==")
|
||||
#define CLUTTER_DBG(x) { a }
|
||||
|
||||
#define CLUTTER_GLERR() G_STMT_START { \
|
||||
if (clutter_debug_flags & CLUTTER_DEBUG_GL) { \
|
||||
|
@ -904,13 +904,13 @@ timed_poll (GPollFD *ufds,
|
||||
gint ret;
|
||||
CLUTTER_STATIC_TIMER (poll_timer,
|
||||
"Mainloop", /* parent */
|
||||
"poll (idle)",
|
||||
"Mainloop Idle",
|
||||
"The time spent idle in poll()",
|
||||
0 /* no application private data */);
|
||||
|
||||
CLUTTER_TIMER_START (_clutter_uprof_context, poll_timer);
|
||||
CLUTTER_TIMER_START (uprof_get_mainloop_context (), poll_timer);
|
||||
ret = prev_poll (ufds, nfsd, timeout_);
|
||||
CLUTTER_TIMER_STOP (_clutter_uprof_context, poll_timer);
|
||||
CLUTTER_TIMER_STOP (uprof_get_mainloop_context (), poll_timer);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
@ -931,7 +931,7 @@ clutter_main (void)
|
||||
0 /* no application private data */);
|
||||
|
||||
if (clutter_main_loop_level == 0)
|
||||
CLUTTER_TIMER_START (_clutter_uprof_context, mainloop_timer);
|
||||
CLUTTER_TIMER_START (uprof_get_mainloop_context (), mainloop_timer);
|
||||
|
||||
/* Make sure there is a context */
|
||||
CLUTTER_CONTEXT ();
|
||||
@ -981,7 +981,7 @@ clutter_main (void)
|
||||
CLUTTER_MARK ();
|
||||
|
||||
if (clutter_main_loop_level == 0)
|
||||
CLUTTER_TIMER_STOP (_clutter_uprof_context, mainloop_timer);
|
||||
CLUTTER_TIMER_STOP (uprof_get_mainloop_context (), mainloop_timer);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1621,12 +1621,19 @@ clutter_init_real (GError **error)
|
||||
return CLUTTER_INIT_ERROR_BACKEND;
|
||||
|
||||
#ifdef CLUTTER_ENABLE_PROFILE
|
||||
{
|
||||
UProfContext *cogl_context;
|
||||
cogl_context = uprof_find_context ("Cogl");
|
||||
if (cogl_context)
|
||||
uprof_context_link (_clutter_uprof_context, cogl_context);
|
||||
}
|
||||
/* We need to be absolutely sure that uprof has been initialized
|
||||
* before calling _clutter_uprof_init. uprof_init (NULL, NULL)
|
||||
* will be a NOP if it has been initialized but it will also
|
||||
* mean subsequent parsing of the UProf GOptionGroup will have no
|
||||
* affect.
|
||||
*
|
||||
* Sadly GOptionGroup based library initialization is extremly
|
||||
* fragile by design because GOptionGroups have no notion of
|
||||
* dependencies and our post_parse_hook may be called before
|
||||
* the cogl or uprof groups get parsed.
|
||||
*/
|
||||
uprof_init (NULL, NULL);
|
||||
_clutter_uprof_init ();
|
||||
|
||||
if (clutter_profile_flags & CLUTTER_PROFILE_PICKING_ONLY)
|
||||
_clutter_profile_suspend ();
|
||||
@ -1995,6 +2002,14 @@ clutter_init_with_args (int *argc,
|
||||
group = cogl_get_option_group ();
|
||||
g_option_context_add_group (context, group);
|
||||
|
||||
/* Note: That due to the implementation details of glib's goption
|
||||
* parsing; cogl and uprof will not actually have there arguments
|
||||
* parsed before the post_parse_hook is called! */
|
||||
#ifdef CLUTTER_ENABLE_PROFILE
|
||||
group = uprof_get_option_group ();
|
||||
g_option_context_add_group (context, group);
|
||||
#endif
|
||||
|
||||
if (entries)
|
||||
g_option_context_add_main_entries (context, entries, translation_domain);
|
||||
|
||||
@ -2027,6 +2042,9 @@ clutter_parse_args (int *argc,
|
||||
{
|
||||
GOptionContext *option_context;
|
||||
GOptionGroup *clutter_group, *cogl_group;
|
||||
#ifdef CLUTTER_ENABLE_PROFILE
|
||||
GOptionGroup *uprof_group;
|
||||
#endif
|
||||
GError *error = NULL;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
@ -2045,6 +2063,11 @@ clutter_parse_args (int *argc,
|
||||
cogl_group = cogl_get_option_group ();
|
||||
g_option_context_add_group (option_context, cogl_group);
|
||||
|
||||
#ifdef CLUTTER_ENABLE_PROFILE
|
||||
uprof_group = uprof_get_option_group ();
|
||||
g_option_context_add_group (option_context, uprof_group);
|
||||
#endif
|
||||
|
||||
if (!g_option_context_parse (option_context, argc, argv, &error))
|
||||
{
|
||||
if (error)
|
||||
|
@ -6,7 +6,8 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
UProfContext *_clutter_uprof_context;
|
||||
#define REPORT_COLUMN0_WIDTH 40
|
||||
|
||||
static UProfReport *clutter_uprof_report;
|
||||
|
||||
static gboolean searched_for_gl_uprof_context = FALSE;
|
||||
static UProfContext *gl_uprof_context = NULL;
|
||||
@ -14,164 +15,245 @@ static UProfContext *gl_uprof_context = NULL;
|
||||
typedef struct _ClutterUProfReportState
|
||||
{
|
||||
gulong n_frames;
|
||||
float fps;
|
||||
gulong n_picks;
|
||||
float msecs_picking;
|
||||
} ClutterUProfReportState;
|
||||
|
||||
static void
|
||||
print_counter (UProfCounterResult *counter,
|
||||
gpointer data)
|
||||
{
|
||||
ClutterUProfReportState *state = data;
|
||||
gulong count = uprof_counter_result_get_count (counter);
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
g_print (" %-*s %-5ld %-5ld\n", REPORT_COLUMN0_WIDTH - 2,
|
||||
uprof_counter_result_get_name (counter),
|
||||
uprof_counter_result_get_count (counter),
|
||||
uprof_counter_result_get_count (counter) / state->n_frames);
|
||||
}
|
||||
|
||||
static char *
|
||||
print_timer_fields (UProfTimerResult *timer,
|
||||
guint *fields_width,
|
||||
gpointer data)
|
||||
timer_per_frame_cb (UProfReport *report,
|
||||
UProfTimerResult *timer,
|
||||
void *user_data)
|
||||
{
|
||||
ClutterUProfReportState *state = data;
|
||||
/* Print the field titles when timer == NULL */
|
||||
if (!timer)
|
||||
return g_strdup_printf ("Per Frame");
|
||||
ClutterUProfReportState *state = user_data;
|
||||
int n_frames = state->n_frames ? state->n_frames : 1;
|
||||
|
||||
return g_strdup_printf ("%-10.2f",
|
||||
uprof_timer_result_get_total_msecs (timer) /
|
||||
(float)state->n_frames);
|
||||
(float)n_frames);
|
||||
}
|
||||
|
||||
static void
|
||||
print_report (UProfReport *report, UProfContext *context)
|
||||
static char *
|
||||
counter_per_frame_cb (UProfReport *report,
|
||||
UProfCounterResult *counter,
|
||||
void *user_data)
|
||||
{
|
||||
GList *root_timers;
|
||||
GList *l;
|
||||
UProfTimerResult *stage_paint_timer;
|
||||
UProfTimerResult *mainloop_timer;
|
||||
UProfTimerResult *do_pick_timer;
|
||||
float fps;
|
||||
ClutterUProfReportState state;
|
||||
ClutterUProfReportState *state = user_data;
|
||||
int n_frames = state->n_frames ? state->n_frames : 1;
|
||||
|
||||
/* FIXME: We need to fix the way Clutter initializes the uprof library
|
||||
* (we don't currently call uprof_init()) and add a mechanism to know
|
||||
* if uprof_init hasn't been called so we can simply bail out of report
|
||||
* generation and not print spurious warning about missing timers.
|
||||
* Probably we can just have uprof_report_print bail out if uprof wasn't
|
||||
* initialized, so we don't have to care here.
|
||||
*/
|
||||
mainloop_timer = uprof_context_get_timer_result (context, "Mainloop");
|
||||
stage_paint_timer = uprof_context_get_timer_result (context, "Redrawing");
|
||||
do_pick_timer = uprof_context_get_timer_result (context, "Do pick");
|
||||
return g_strdup_printf ("%-5ld",
|
||||
uprof_counter_result_get_count (counter) /
|
||||
n_frames);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_n_frames_cb (UProfReport *report,
|
||||
const char *statistic,
|
||||
const char *attribute,
|
||||
void *user_data)
|
||||
{
|
||||
ClutterUProfReportState *state = user_data;
|
||||
|
||||
return g_strdup_printf ("%lu", state->n_frames);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_fps_cb (UProfReport *report,
|
||||
const char *statistic,
|
||||
const char *attribute,
|
||||
void *user_data)
|
||||
{
|
||||
ClutterUProfReportState *state = user_data;
|
||||
|
||||
return g_strdup_printf ("%5.2f\n", state->fps);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_n_picks_cb (UProfReport *report,
|
||||
const char *statistic,
|
||||
const char *attribute,
|
||||
void *user_data)
|
||||
{
|
||||
ClutterUProfReportState *state = user_data;
|
||||
|
||||
return g_strdup_printf ("%lu", state->n_picks);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_picks_per_frame_cb (UProfReport *report,
|
||||
const char *statistic,
|
||||
const char *attribute,
|
||||
void *user_data)
|
||||
{
|
||||
ClutterUProfReportState *state = user_data;
|
||||
int n_frames = state->n_frames ? state->n_frames : 1;
|
||||
|
||||
return g_strdup_printf ("%3.2f",
|
||||
(float)state->n_picks / (float)n_frames);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_msecs_per_pick_cb (UProfReport *report,
|
||||
const char *statistic,
|
||||
const char *attribute,
|
||||
void *user_data)
|
||||
{
|
||||
ClutterUProfReportState *state = user_data;
|
||||
int n_picks = state->n_picks ? state->n_picks : 1;
|
||||
|
||||
return g_strdup_printf ("%3.2f", state->msecs_picking / (float)n_picks);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_clutter_uprof_report_prepare (UProfReport *report,
|
||||
void **closure_ret,
|
||||
void *user_data)
|
||||
{
|
||||
UProfContext *mainloop_context;
|
||||
UProfTimerResult *mainloop_timer;
|
||||
UProfTimerResult *stage_paint_timer;
|
||||
UProfTimerResult *do_pick_timer;
|
||||
ClutterUProfReportState *state;
|
||||
|
||||
/* NB: uprof provides a shared context for mainloop statistics which allows
|
||||
* this to work even if the application and not Clutter owns the mainloop.
|
||||
*
|
||||
* This is the case when running Mutter for example but because Mutter will
|
||||
* follow the same convention of using the shared context then we can always
|
||||
* be sure of where to look for the mainloop results. */
|
||||
mainloop_context = uprof_get_mainloop_context ();
|
||||
mainloop_timer = uprof_context_get_timer_result (mainloop_context,
|
||||
"Mainloop");
|
||||
/* just bail out if the mainloop timer wasn't hit */
|
||||
if (!mainloop_timer)
|
||||
return FALSE;
|
||||
|
||||
state = g_new0 (ClutterUProfReportState, 1);
|
||||
*closure_ret = state;
|
||||
|
||||
stage_paint_timer = uprof_context_get_timer_result (_clutter_uprof_context,
|
||||
"Redrawing");
|
||||
if (stage_paint_timer)
|
||||
{
|
||||
g_print ("\n");
|
||||
state->n_frames = uprof_timer_result_get_start_count (stage_paint_timer);
|
||||
|
||||
state.n_frames = uprof_timer_result_get_start_count (stage_paint_timer);
|
||||
g_print ("Frame count = %lu\n", state.n_frames);
|
||||
uprof_report_add_statistic (report,
|
||||
"Frames",
|
||||
"Frame count information");
|
||||
uprof_report_add_statistic_attribute (report, "Frames",
|
||||
"Count", "Count",
|
||||
"The total number of frames",
|
||||
UPROF_ATTRIBUTE_TYPE_INT,
|
||||
get_n_frames_cb,
|
||||
state);
|
||||
|
||||
fps = (float) state.n_frames
|
||||
/ (uprof_timer_result_get_total_msecs (mainloop_timer)
|
||||
/ 1000.0);
|
||||
g_print ("Average fps = %5.2f\n", fps);
|
||||
|
||||
state->fps = (float) state->n_frames
|
||||
/ (uprof_timer_result_get_total_msecs (mainloop_timer)
|
||||
/ 1000.0);
|
||||
uprof_report_add_statistic_attribute (report, "Frames",
|
||||
"Average FPS", "Average\nFPS",
|
||||
"The average frames per second",
|
||||
UPROF_ATTRIBUTE_TYPE_FLOAT,
|
||||
get_fps_cb,
|
||||
state);
|
||||
}
|
||||
|
||||
do_pick_timer = uprof_context_get_timer_result (_clutter_uprof_context,
|
||||
"Picking");
|
||||
if (do_pick_timer)
|
||||
{
|
||||
int n_picks = uprof_timer_result_get_start_count (do_pick_timer);
|
||||
state->n_picks = uprof_timer_result_get_start_count (do_pick_timer);
|
||||
state->msecs_picking =
|
||||
uprof_timer_result_get_total_msecs (do_pick_timer);
|
||||
|
||||
g_print ("\n");
|
||||
uprof_report_add_statistic (report,
|
||||
"Picks",
|
||||
"Picking information");
|
||||
uprof_report_add_statistic_attribute (report, "Picks",
|
||||
"Count", "Count",
|
||||
"The total number of picks",
|
||||
UPROF_ATTRIBUTE_TYPE_INT,
|
||||
get_n_picks_cb,
|
||||
state);
|
||||
|
||||
g_print ("Pick Stats:\n");
|
||||
g_print ("Pick count = %d\n", n_picks);
|
||||
g_print ("Average picks per frame = %3.2f\n",
|
||||
(float)n_picks / (float)state.n_frames);
|
||||
g_print ("Average Msecs per pick = %3.2f\n",
|
||||
(float)uprof_timer_result_get_total_msecs (do_pick_timer)
|
||||
/ (float)n_picks);
|
||||
uprof_report_add_statistic_attribute (report, "Picks",
|
||||
"Picks Per Frame",
|
||||
"Picks\nPer Frame",
|
||||
"The average number of picks "
|
||||
"per frame",
|
||||
UPROF_ATTRIBUTE_TYPE_FLOAT,
|
||||
get_picks_per_frame_cb,
|
||||
state);
|
||||
|
||||
uprof_report_add_statistic_attribute (report, "Picks",
|
||||
"Msecs Per Pick",
|
||||
"Msecs\nPer Pick",
|
||||
"The average number of "
|
||||
"milliseconds per pick",
|
||||
UPROF_ATTRIBUTE_TYPE_FLOAT,
|
||||
get_msecs_per_pick_cb,
|
||||
state);
|
||||
}
|
||||
|
||||
root_timers = uprof_context_get_root_timer_results (context);
|
||||
if (!root_timers)
|
||||
return;
|
||||
uprof_report_add_counters_attribute (clutter_uprof_report,
|
||||
"Per Frame",
|
||||
"Per Frame",
|
||||
"The number of counts per frame",
|
||||
UPROF_ATTRIBUTE_TYPE_INT,
|
||||
counter_per_frame_cb,
|
||||
state);
|
||||
uprof_report_add_timers_attribute (clutter_uprof_report,
|
||||
"Per Frame",
|
||||
"Per Frame",
|
||||
"The amount of timer per frame",
|
||||
UPROF_ATTRIBUTE_TYPE_FLOAT,
|
||||
timer_per_frame_cb,
|
||||
state);
|
||||
|
||||
g_print ("\n");
|
||||
|
||||
/* XXX: UProfs default reporting code now supports dynamic sizing for the Name
|
||||
* column, the only thing it's missing is support for adding custom columns but
|
||||
* when that's added we should switch away from manual report generation. */
|
||||
g_print ("Counters:\n");
|
||||
g_print (" %-*s %5s %s\n", REPORT_COLUMN0_WIDTH - 2, "Name", "Total", "Per Frame");
|
||||
g_print (" %-*s %5s %s\n", REPORT_COLUMN0_WIDTH - 2, "----", "-----", "---------");
|
||||
uprof_context_foreach_counter (context,
|
||||
UPROF_COUNTER_SORT_COUNT_INC,
|
||||
print_counter,
|
||||
&state);
|
||||
|
||||
g_print ("\n");
|
||||
g_print ("Timers:\n");
|
||||
for (l = root_timers; l != NULL; l = l->next)
|
||||
uprof_timer_result_print_and_children ((UProfTimerResult *)l->data,
|
||||
print_timer_fields,
|
||||
&state);
|
||||
|
||||
g_print ("\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* FIXME: we should be able to deal with creating the uprof context in
|
||||
* clutter_init instead. I think the only reason I did it this way originally
|
||||
* was as a quick hack.
|
||||
*/
|
||||
static void __attribute__ ((constructor))
|
||||
clutter_uprof_constructor (void)
|
||||
{
|
||||
_clutter_uprof_context = uprof_context_new ("Clutter");
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
print_timers (UProfContext *context)
|
||||
_clutter_uprof_report_done (UProfReport *report, void *closure, void *user_data)
|
||||
{
|
||||
GList *root_timers;
|
||||
GList *l;
|
||||
|
||||
root_timers = uprof_context_get_root_timer_results ();
|
||||
|
||||
root_timers =
|
||||
g_list_sort_with_data (context->root_timers,
|
||||
(GCompareDataFunc)_uprof_timer_compare_total_times,
|
||||
NULL);
|
||||
for (l = context->timers; l != NULL; l = l->next)
|
||||
{
|
||||
UProfTimerState *timer = l->data;
|
||||
timer->children =
|
||||
g_list_sort_with_data (timer->children,
|
||||
(GCompareDataFunc)
|
||||
_uprof_timer_compare_total_times,
|
||||
NULL);
|
||||
}
|
||||
g_free (closure);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __attribute__ ((destructor))
|
||||
clutter_uprof_destructor (void)
|
||||
static void
|
||||
print_exit_report (void)
|
||||
{
|
||||
if (!(clutter_profile_flags & CLUTTER_PROFILE_DISABLE_REPORT))
|
||||
{
|
||||
UProfReport *report = uprof_report_new ("Clutter report");
|
||||
uprof_report_add_context (report, _clutter_uprof_context);
|
||||
uprof_report_add_context_callback (report, print_report);
|
||||
uprof_report_print (report);
|
||||
uprof_report_unref (report);
|
||||
}
|
||||
uprof_report_print (clutter_uprof_report);
|
||||
|
||||
uprof_report_unref (clutter_uprof_report);
|
||||
|
||||
uprof_context_unref (_clutter_uprof_context);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_uprof_init (void)
|
||||
{
|
||||
UProfContext *cogl_context;
|
||||
|
||||
_clutter_uprof_context = uprof_context_new ("Clutter");
|
||||
uprof_context_link (_clutter_uprof_context, uprof_get_mainloop_context ());
|
||||
g_atexit (print_exit_report);
|
||||
|
||||
cogl_context = uprof_find_context ("Cogl");
|
||||
if (cogl_context)
|
||||
uprof_context_link (_clutter_uprof_context, cogl_context);
|
||||
|
||||
/* We make the report object up-front so we can use uprof-tool
|
||||
* to fetch reports at runtime via dbus... */
|
||||
clutter_uprof_report = uprof_report_new ("Clutter report");
|
||||
uprof_report_add_context (clutter_uprof_report, _clutter_uprof_context);
|
||||
uprof_report_set_init_fini_callbacks (clutter_uprof_report,
|
||||
_clutter_uprof_report_prepare,
|
||||
_clutter_uprof_report_done,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_profile_suspend (void)
|
||||
{
|
||||
@ -198,5 +280,18 @@ _clutter_profile_resume (void)
|
||||
uprof_context_resume (_clutter_uprof_context);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_profile_trace_message (const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, format);
|
||||
g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, format, ap);
|
||||
va_end (ap);
|
||||
|
||||
if (_clutter_uprof_context)
|
||||
uprof_context_vtrace_message (_clutter_uprof_context, format, ap);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -48,11 +48,17 @@ extern UProfContext *_clutter_uprof_context;
|
||||
#define CLUTTER_TIMER_START UPROF_TIMER_START
|
||||
#define CLUTTER_TIMER_STOP UPROF_TIMER_STOP
|
||||
|
||||
void
|
||||
_clutter_uprof_init (void);
|
||||
|
||||
void
|
||||
_clutter_profile_suspend (void);
|
||||
void
|
||||
_clutter_profile_resume (void);
|
||||
|
||||
void
|
||||
_clutter_profile_trace_message (const char *format, ...);
|
||||
|
||||
#else /* CLUTTER_ENABLE_PROFILE */
|
||||
|
||||
#define CLUTTER_STATIC_TIMER(A,B,C,D,E) extern void _clutter_dummy_decl (void)
|
||||
@ -65,6 +71,8 @@ _clutter_profile_resume (void);
|
||||
#define _clutter_profile_suspend() G_STMT_START {} G_STMT_END
|
||||
#define _clutter_profile_resume() G_STMT_START {} G_STMT_END
|
||||
|
||||
#define _clutter_profile_trace_message g_message
|
||||
|
||||
#endif /* CLUTTER_ENABLE_PROFILE */
|
||||
|
||||
extern guint clutter_profile_flags;
|
||||
|
145
clutter/cogl/cogl/cogl-debug-options.h
Normal file
145
clutter/cogl/cogl/cogl-debug-options.h
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* An object oriented GL/GLES Abstraction/Utility Layer
|
||||
*
|
||||
* Copyright (C) 2010 Intel Corporation.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
OPT (HANDLE,
|
||||
"Cogl Tracing",
|
||||
"ref-counts",
|
||||
"CoglObject references",
|
||||
"Debug ref counting issues for CoglObjects")
|
||||
OPT (SLICING,
|
||||
"Cogl Tracing",
|
||||
"slicing",
|
||||
"Trace Texture Slicing",
|
||||
"debug the creation of texture slices")
|
||||
OPT (ATLAS,
|
||||
"Cogl Tracing",
|
||||
"atlas",
|
||||
"Trace Atlas Textures",
|
||||
"Debug texture atlas management")
|
||||
OPT (BLEND_STRINGS,
|
||||
"Cogl Tracing",
|
||||
"blend-strings",
|
||||
"Trace Blend Strings",
|
||||
"Debug CoglBlendString parsing")
|
||||
OPT (JOURNAL,
|
||||
"Cogl Tracing",
|
||||
"journal",
|
||||
"Trace Journal",
|
||||
"View all the geometry passing through the journal")
|
||||
OPT (BATCHING,
|
||||
"Cogl Tracing",
|
||||
"batching",
|
||||
"Trace Batching",
|
||||
"Show how geometry is being batched in the journal")
|
||||
OPT (MATRICES,
|
||||
"Cogl Tracing",
|
||||
"matrices",
|
||||
"Trace matrices",
|
||||
"Trace all matrix manipulation")
|
||||
/* XXX we should replace the "draw" option its very hand wavy... */
|
||||
OPT (DRAW,
|
||||
"Cogl Tracing",
|
||||
"draw",
|
||||
"Trace Misc Drawing",
|
||||
"Trace some misc drawing operations")
|
||||
OPT (PANGO,
|
||||
"Cogl Tracing",
|
||||
"pango",
|
||||
"Trace Pango Renderer",
|
||||
"Trace the Cogl Pango renderer")
|
||||
OPT (TEXTURE_PIXMAP,
|
||||
"Cogl Tracing",
|
||||
"texture-pixmap",
|
||||
"Trace CoglTexturePixmap backend",
|
||||
"Trace the Cogl texture pixmap backend")
|
||||
OPT (RECTANGLES,
|
||||
"Visualize",
|
||||
"rectangles",
|
||||
"Outline rectangles",
|
||||
"Add wire outlines for all rectangular geometry")
|
||||
OPT (DISABLE_BATCHING,
|
||||
"Root Cause",
|
||||
"disable-batching",
|
||||
"Disable Journal batching",
|
||||
"Disable batching of geometry in the Cogl Journal.")
|
||||
OPT (DISABLE_VBOS,
|
||||
"Root Cause",
|
||||
"disable-vbos",
|
||||
"Disable GL Vertex Buffers",
|
||||
"Disable use of OpenGL vertex buffer objects")
|
||||
OPT (DISABLE_PBOS,
|
||||
"Root Cause",
|
||||
"disable-pbos",
|
||||
"Disable GL Pixel Buffers",
|
||||
"Disable use of OpenGL pixel buffer objects")
|
||||
OPT (DISABLE_SOFTWARE_TRANSFORM,
|
||||
"Root Cause",
|
||||
"disable-software-transform",
|
||||
"Disable software rect transform",
|
||||
"Use the GPU to transform rectangular geometry")
|
||||
OPT (DUMP_ATLAS_IMAGE,
|
||||
"Cogl Specialist",
|
||||
"dump-atlas-image",
|
||||
"Dump atlas images",
|
||||
"Dump texture atlas changes to an image file")
|
||||
OPT (DISABLE_ATLAS,
|
||||
"Root Cause",
|
||||
"disable-atlas",
|
||||
"Disable texture atlasing",
|
||||
"Disable use of texture atlasing")
|
||||
OPT (DISABLE_TEXTURING,
|
||||
"Root Cause",
|
||||
"disable-texturing",
|
||||
"Disable texturing",
|
||||
"Disable texturing any primitives")
|
||||
OPT (DISABLE_ARBFP,
|
||||
"Root Cause",
|
||||
"disable-arbfp",
|
||||
"Disable arbfp",
|
||||
"Disable use of ARB fragment programs")
|
||||
OPT (DISABLE_GLSL,
|
||||
"Root Cause",
|
||||
"disable-glsl",
|
||||
"Disable GLSL",
|
||||
"Disable use of GLSL")
|
||||
OPT (DISABLE_BLENDING,
|
||||
"Root Cause",
|
||||
"disable-blending",
|
||||
"Disable blending",
|
||||
"Disable use of blending")
|
||||
OPT (SHOW_SOURCE,
|
||||
"Cogl Tracing",
|
||||
"show-source",
|
||||
"Show source",
|
||||
"Show generated ARBfp/GLSL source code")
|
||||
OPT (OPENGL,
|
||||
"Cogl Tracing",
|
||||
"opengl",
|
||||
"Trace some OpenGL",
|
||||
"Traces some select OpenGL calls")
|
||||
OPT (OFFSCREEN,
|
||||
"Cogl Tracing",
|
||||
"offscreen",
|
||||
"Trace offscreen support",
|
||||
"Debug offscreen support")
|
||||
|
@ -103,37 +103,14 @@ _cogl_parse_debug_string (const char *value,
|
||||
else if (strcmp (value, "help") == 0)
|
||||
{
|
||||
g_printerr ("\n\n%28s\n", "Supported debug values:");
|
||||
#define OPT(NAME, HELP) \
|
||||
g_printerr ("%28s %s\n", NAME, HELP);
|
||||
OPT ("handle:", "debug ref counting issues for Cogl objects");
|
||||
OPT ("slicing:", "debug the creation of texture slices");
|
||||
OPT ("atlas:", "debug texture atlas management");
|
||||
OPT ("blend-strings:", "debug blend-string parsing");
|
||||
OPT ("journal:", "view all geometry passing through the journal");
|
||||
OPT ("batching:", "show how geometry is being batched in the journal");
|
||||
OPT ("matrices:", "trace all matrix manipulation");
|
||||
/* XXX: we should replace the "draw" option its very hand wavy... */
|
||||
OPT ("draw:", "misc tracing of some drawing operations");
|
||||
OPT ("pango:", "trace the pango renderer");
|
||||
OPT ("texture-pixmap:", "trace the Cogl texture pixmap backend");
|
||||
OPT ("rectangles:", "add wire outlines for all rectangular geometry");
|
||||
OPT ("disable-batching:", "disable the journal batching");
|
||||
OPT ("disable-vbos:", "disable use of OpenGL vertex buffer objects");
|
||||
OPT ("disable-pbos:", "disable use of OpenGL pixel buffer objects");
|
||||
OPT ("disable-software-transform",
|
||||
"use the GPU to transform rectangular geometry");
|
||||
OPT ("dump-atlas-image:", "dump atlas changes to an image file");
|
||||
OPT ("disable-atlas:", "disable texture atlasing");
|
||||
OPT ("disable-texturing:", "disable texturing primitives");
|
||||
OPT ("disable-arbfp:", "disable use of ARBfp");
|
||||
OPT ("disable-glsl:", "disable use of GLSL");
|
||||
OPT ("disable-blending:", "disable use of blending");
|
||||
OPT ("show-source:", "show generated ARBfp/GLSL");
|
||||
OPT ("opengl:", "traces some select OpenGL calls");
|
||||
OPT ("offscreen:", "debug offscreen support");
|
||||
#define OPT(MASK_NAME, GROUP, NAME, NAME_FORMATTED, DESCRIPTION) \
|
||||
g_printerr ("%28s %s\n", NAME ":", DESCRIPTION);
|
||||
#include "cogl-debug-options.h"
|
||||
g_printerr ("\n%28s\n", "Special debug values:");
|
||||
OPT ("all:", "Enables all non-behavioural debug options");
|
||||
OPT ("verbose:", "Enables all non-behavioural debug options");
|
||||
OPT (IGNORED, "ignored", "all", "ignored", \
|
||||
"Enables all non-behavioural debug options");
|
||||
OPT (IGNORED, "ignored", "verbose", "ignored", \
|
||||
"Enables all non-behavioural debug options");
|
||||
#undef OPT
|
||||
exit (1);
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
#ifndef __COGL_DEBUG_H__
|
||||
#define __COGL_DEBUG_H__
|
||||
|
||||
#include "cogl-profile.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@ -59,17 +61,17 @@ typedef enum {
|
||||
#ifdef COGL_ENABLE_DEBUG
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define COGL_NOTE(type,x,a...) G_STMT_START { \
|
||||
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_##type)) { \
|
||||
g_message ("[" #type "] " G_STRLOC ": " x, ##a); \
|
||||
#define COGL_NOTE(type,x,a...) G_STMT_START { \
|
||||
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_##type)) { \
|
||||
_cogl_profile_trace_message ("[" #type "] " G_STRLOC " & " x, ##a); \
|
||||
} } G_STMT_END
|
||||
|
||||
#else
|
||||
#define COGL_NOTE(type,...) G_STMT_START { \
|
||||
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_##type)) { \
|
||||
char *_fmt = g_strdup_printf (__VA_ARGS__); \
|
||||
g_message ("[" #type "] " G_STRLOC ": %s", _fmt); \
|
||||
g_free (_fmt); \
|
||||
#define COGL_NOTE(type,...) G_STMT_START { \
|
||||
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_##type)) { \
|
||||
char *_fmt = g_strdup_printf (__VA_ARGS__); \
|
||||
_cogl_profile_trace_message ("[" #type "] " G_STRLOC " & %s", _fmt);\
|
||||
g_free (_fmt); \
|
||||
} } G_STMT_END
|
||||
|
||||
#endif /* __GNUC__ */
|
||||
|
@ -2,16 +2,51 @@
|
||||
#ifdef COGL_ENABLE_PROFILE
|
||||
|
||||
#include "cogl-profile.h"
|
||||
#include "cogl-debug.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
UProfContext *_cogl_uprof_context;
|
||||
|
||||
static gboolean
|
||||
debug_option_getter (void *user_data)
|
||||
{
|
||||
unsigned int shift = GPOINTER_TO_UINT (user_data);
|
||||
return (cogl_debug_flags & (1 << shift)) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
debug_option_setter (gboolean value, void *user_data)
|
||||
{
|
||||
unsigned int shift = GPOINTER_TO_UINT (user_data);
|
||||
|
||||
if (value)
|
||||
cogl_debug_flags |= (1 << shift);
|
||||
else
|
||||
cogl_debug_flags &= ~(1 << shift);
|
||||
}
|
||||
|
||||
static void __attribute__ ((constructor))
|
||||
cogl_uprof_constructor (void)
|
||||
{
|
||||
_cogl_uprof_context = uprof_context_new ("Cogl");
|
||||
#define OPT(MASK_NAME, GROUP, NAME, NAME_FORMATTED, DESCRIPTION) \
|
||||
G_STMT_START { \
|
||||
int shift; \
|
||||
for (shift = 0; (COGL_DEBUG_ ## MASK_NAME >> shift) != 1; shift++) \
|
||||
; \
|
||||
uprof_context_add_boolean_option (_cogl_uprof_context, \
|
||||
GROUP, \
|
||||
NAME, \
|
||||
NAME_FORMATTED, \
|
||||
DESCRIPTION, \
|
||||
debug_option_getter, \
|
||||
debug_option_setter, \
|
||||
GUINT_TO_POINTER (shift)); \
|
||||
} G_STMT_END;
|
||||
|
||||
#include "cogl-debug-options.h"
|
||||
#undef OPT
|
||||
}
|
||||
|
||||
static void __attribute__ ((destructor))
|
||||
@ -27,4 +62,17 @@ cogl_uprof_destructor (void)
|
||||
uprof_context_unref (_cogl_uprof_context);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_profile_trace_message (const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, format);
|
||||
g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, format, ap);
|
||||
va_end (ap);
|
||||
|
||||
if (_cogl_uprof_context)
|
||||
uprof_context_vtrace_message (_cogl_uprof_context, format, ap);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -38,6 +38,9 @@ extern UProfContext *_cogl_uprof_context;
|
||||
#define COGL_TIMER_START UPROF_TIMER_START
|
||||
#define COGL_TIMER_STOP UPROF_TIMER_STOP
|
||||
|
||||
void
|
||||
_cogl_profile_trace_message (const char *format, ...);
|
||||
|
||||
#else
|
||||
|
||||
#define COGL_STATIC_TIMER(A,B,C,D,E) extern void _cogl_dummy_decl (void)
|
||||
@ -47,6 +50,7 @@ extern UProfContext *_cogl_uprof_context;
|
||||
#define COGL_TIMER_START(A,B) G_STMT_START{ (void)0; }G_STMT_END
|
||||
#define COGL_TIMER_STOP(A,B) G_STMT_START{ (void)0; }G_STMT_END
|
||||
|
||||
#define _cogl_profile_trace_message g_message
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "cogl-context.h"
|
||||
#include "cogl-handle.h"
|
||||
#include "cogl-journal-private.h"
|
||||
#include "cogl-material-private.h"
|
||||
#include "cogl-material-opengl-private.h"
|
||||
|
||||
#include <string.h>
|
||||
|
@ -942,7 +942,7 @@ AS_CASE([$enable_profile],
|
||||
[
|
||||
AS_IF([test "x$GCC" = "xyes"],
|
||||
[
|
||||
PKG_CHECK_MODULES([PROFILE_DEP], [uprof-0.2])
|
||||
PKG_CHECK_MODULES([PROFILE_DEP], [uprof-0.3])
|
||||
CLUTTER_PROFILE_CFLAGS=" -DCLUTTER_ENABLE_PROFILE -DCOGL_ENABLE_PROFILE $PROFILE_DEP_CFLAGS"
|
||||
CLUTTER_PROFILE_LDFLAGS=" $PROFILE_DEP_LIBS"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user