2009-03-30 15:41:02 +00:00
|
|
|
|
|
|
|
#ifdef CLUTTER_ENABLE_PROFILE
|
|
|
|
|
|
|
|
#include "clutter-profile.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
UProfContext *_clutter_uprof_context;
|
|
|
|
#define REPORT_COLUMN0_WIDTH 40
|
|
|
|
|
2009-04-17 11:15:56 +00:00
|
|
|
static gboolean searched_for_gl_uprof_context = FALSE;
|
|
|
|
static UProfContext *gl_uprof_context = NULL;
|
|
|
|
|
2009-03-30 15:41:02 +00:00
|
|
|
typedef struct _ClutterUProfReportState
|
|
|
|
{
|
|
|
|
gulong n_frames;
|
|
|
|
} 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)
|
|
|
|
{
|
|
|
|
ClutterUProfReportState *state = data;
|
|
|
|
/* Print the field titles when timer == NULL */
|
|
|
|
if (!timer)
|
|
|
|
return g_strdup_printf ("Per Frame");
|
|
|
|
|
|
|
|
return g_strdup_printf ("%-10.2f",
|
|
|
|
uprof_timer_result_get_total_msecs (timer) /
|
|
|
|
(float)state->n_frames);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_report (UProfReport *report, UProfContext *context)
|
|
|
|
{
|
|
|
|
GList *root_timers;
|
|
|
|
GList *l;
|
|
|
|
UProfTimerResult *stage_paint_timer;
|
|
|
|
UProfTimerResult *mainloop_timer;
|
|
|
|
UProfTimerResult *do_pick_timer;
|
|
|
|
float fps;
|
|
|
|
ClutterUProfReportState state;
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
2010-02-26 09:44:29 +00:00
|
|
|
mainloop_timer = uprof_context_get_timer_result (context, "Mainloop");
|
2009-03-30 15:41:02 +00:00
|
|
|
stage_paint_timer = uprof_context_get_timer_result (context, "Redrawing");
|
2010-02-26 09:44:29 +00:00
|
|
|
do_pick_timer = uprof_context_get_timer_result (context, "Do pick");
|
|
|
|
|
2010-04-22 16:52:13 +00:00
|
|
|
if (stage_paint_timer)
|
|
|
|
{
|
|
|
|
g_print ("\n");
|
2009-03-30 15:41:02 +00:00
|
|
|
|
2010-04-22 16:52:13 +00:00
|
|
|
state.n_frames = uprof_timer_result_get_start_count (stage_paint_timer);
|
|
|
|
g_print ("Frame count = %lu\n", state.n_frames);
|
2009-03-30 15:41:02 +00:00
|
|
|
|
2010-04-22 16:52:13 +00:00
|
|
|
fps = (float) state.n_frames
|
|
|
|
/ (uprof_timer_result_get_total_msecs (mainloop_timer)
|
2009-03-30 15:41:02 +00:00
|
|
|
/ 1000.0);
|
2010-04-22 16:52:13 +00:00
|
|
|
g_print ("Average fps = %5.2f\n", fps);
|
|
|
|
}
|
2009-03-30 15:41:02 +00:00
|
|
|
|
|
|
|
if (do_pick_timer)
|
|
|
|
{
|
|
|
|
int n_picks = uprof_timer_result_get_start_count (do_pick_timer);
|
|
|
|
|
2010-04-22 16:52:13 +00:00
|
|
|
g_print ("\n");
|
|
|
|
|
2009-03-30 15:41:02 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-04-22 16:52:13 +00:00
|
|
|
root_timers = uprof_context_get_root_timer_results (context);
|
|
|
|
if (!root_timers)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_print ("\n");
|
|
|
|
|
2009-03-30 15:41:02 +00:00
|
|
|
/* 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");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void __attribute__ ((destructor))
|
|
|
|
clutter_uprof_destructor (void)
|
|
|
|
{
|
2010-01-06 18:15:13 +00:00
|
|
|
if (!(clutter_profile_flags & CLUTTER_PROFILE_DISABLE_REPORT))
|
2009-03-30 15:41:02 +00:00
|
|
|
{
|
|
|
|
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_context_unref (_clutter_uprof_context);
|
|
|
|
}
|
|
|
|
|
2009-04-17 11:15:56 +00:00
|
|
|
void
|
|
|
|
_clutter_profile_suspend (void)
|
|
|
|
{
|
|
|
|
if (G_UNLIKELY (!searched_for_gl_uprof_context))
|
|
|
|
{
|
|
|
|
gl_uprof_context = uprof_find_context ("OpenGL");
|
|
|
|
searched_for_gl_uprof_context = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gl_uprof_context)
|
|
|
|
uprof_context_suspend (gl_uprof_context);
|
|
|
|
|
|
|
|
/* NB: The Cogl context is linked to this so it will also be suspended... */
|
|
|
|
uprof_context_suspend (_clutter_uprof_context);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_clutter_profile_resume (void)
|
|
|
|
{
|
|
|
|
if (gl_uprof_context)
|
|
|
|
uprof_context_resume (gl_uprof_context);
|
|
|
|
|
|
|
|
/* NB: The Cogl context is linked to this so it will also be resumed... */
|
|
|
|
uprof_context_resume (_clutter_uprof_context);
|
|
|
|
}
|
|
|
|
|
2009-03-30 15:41:02 +00:00
|
|
|
#endif
|
|
|
|
|