0b6515a1d5
This suspends and resumes all uprof timers and counters except while dealing with picking, so as to give more focused statistics. Be aware that there are still some issues with this profile option since there are a few special case counters and timers that shouldn't be suspended; noteably the frame counters are incorrect so the per frame stats can't be trusted.
200 lines
6.1 KiB
C
200 lines
6.1 KiB
C
|
|
#ifdef CLUTTER_ENABLE_PROFILE
|
|
|
|
#include "clutter-profile.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
UProfContext *_clutter_uprof_context;
|
|
#define REPORT_COLUMN0_WIDTH 40
|
|
|
|
static gboolean searched_for_gl_uprof_context = FALSE;
|
|
static UProfContext *gl_uprof_context = NULL;
|
|
|
|
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;
|
|
|
|
g_print ("\n");
|
|
|
|
/* 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.
|
|
*/
|
|
|
|
stage_paint_timer = uprof_context_get_timer_result (context, "Redrawing");
|
|
#if 0
|
|
if (!stage_paint_timer)
|
|
g_critical ("Failed to find \"Redrawing\" timer "
|
|
"(you need to update print_report code if you rename it)\n");
|
|
#endif
|
|
|
|
state.n_frames = uprof_timer_result_get_start_count (stage_paint_timer);
|
|
g_print ("Frame count = %lu\n", state.n_frames);
|
|
|
|
mainloop_timer = uprof_context_get_timer_result (context, "Mainloop");
|
|
fps = (float)state.n_frames / (uprof_timer_result_get_total_msecs (mainloop_timer)
|
|
/ 1000.0);
|
|
g_print ("Average fps = %5.2f\n", fps);
|
|
|
|
do_pick_timer = uprof_context_get_timer_result (context, "Do pick");
|
|
if (do_pick_timer)
|
|
{
|
|
int n_picks = uprof_timer_result_get_start_count (do_pick_timer);
|
|
|
|
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);
|
|
|
|
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");
|
|
root_timers = uprof_context_get_root_timer_results (context);
|
|
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)
|
|
{
|
|
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_context_unref (_clutter_uprof_context);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
#endif
|
|
|