Release Clutter 1.11.4 (snapshot)
[profile/ivi/clutter.git] / clutter / clutter-profile.c
1 #ifdef CLUTTER_ENABLE_PROFILE
2
3 #include <stdlib.h>
4
5 /* XXX - we need this for g_atexit() */
6 #define G_DISABLE_DEPRECATION_WARNINGS
7 #include "clutter-profile.h"
8
9 UProfContext *_clutter_uprof_context;
10
11 static UProfReport *clutter_uprof_report;
12
13 static gboolean searched_for_gl_uprof_context = FALSE;
14 static UProfContext *gl_uprof_context = NULL;
15
16 typedef struct _ClutterUProfReportState
17 {
18   gulong n_frames;
19   float fps;
20   gulong n_picks;
21   float msecs_picking;
22 } ClutterUProfReportState;
23
24 static char *
25 timer_per_frame_cb (UProfReport *report,
26                     UProfTimerResult *timer,
27                     void *user_data)
28 {
29   ClutterUProfReportState *state = user_data;
30   int n_frames = state->n_frames ? state->n_frames : 1;
31
32   return g_strdup_printf ("%-10.2f",
33                           uprof_timer_result_get_total_msecs (timer) /
34                           (float)n_frames);
35 }
36
37 static char *
38 counter_per_frame_cb (UProfReport *report,
39                       UProfCounterResult *counter,
40                       void *user_data)
41 {
42   ClutterUProfReportState *state = user_data;
43   int n_frames = state->n_frames ? state->n_frames : 1;
44
45   return g_strdup_printf ("%-5ld",
46                           uprof_counter_result_get_count (counter) /
47                           n_frames);
48 }
49
50 static char *
51 get_n_frames_cb (UProfReport *report,
52                  const char *statistic,
53                  const char *attribute,
54                  void *user_data)
55 {
56   ClutterUProfReportState *state = user_data;
57
58   return g_strdup_printf ("%lu", state->n_frames);
59 }
60
61 static char *
62 get_fps_cb (UProfReport *report,
63             const char *statistic,
64             const char *attribute,
65             void *user_data)
66 {
67   ClutterUProfReportState *state = user_data;
68
69   return g_strdup_printf ("%5.2f\n", state->fps);
70 }
71
72 static char *
73 get_n_picks_cb (UProfReport *report,
74                 const char *statistic,
75                 const char *attribute,
76                 void *user_data)
77 {
78   ClutterUProfReportState *state = user_data;
79
80   return g_strdup_printf ("%lu", state->n_picks);
81 }
82
83 static char *
84 get_picks_per_frame_cb (UProfReport *report,
85                         const char *statistic,
86                         const char *attribute,
87                         void *user_data)
88 {
89   ClutterUProfReportState *state = user_data;
90   int n_frames = state->n_frames ? state->n_frames : 1;
91
92   return g_strdup_printf ("%3.2f",
93                           (float)state->n_picks / (float)n_frames);
94 }
95
96 static char *
97 get_msecs_per_pick_cb (UProfReport *report,
98                        const char *statistic,
99                        const char *attribute,
100                        void *user_data)
101 {
102   ClutterUProfReportState *state = user_data;
103   int n_picks = state->n_picks ? state->n_picks : 1;
104
105   return g_strdup_printf ("%3.2f", state->msecs_picking / (float)n_picks);
106 }
107
108 static gboolean
109 _clutter_uprof_report_prepare (UProfReport *report,
110                                void **closure_ret,
111                                void *user_data)
112 {
113   UProfContext            *mainloop_context;
114   UProfTimerResult        *mainloop_timer;
115   UProfTimerResult        *stage_paint_timer;
116   UProfTimerResult        *do_pick_timer;
117   ClutterUProfReportState *state;
118
119   /* NB: uprof provides a shared context for mainloop statistics which allows
120    * this to work even if the application and not Clutter owns the mainloop.
121    *
122    * This is the case when running Mutter for example but because Mutter will
123    * follow the same convention of using the shared context then we can always
124    * be sure of where to look for the mainloop results. */
125   mainloop_context = uprof_get_mainloop_context ();
126   mainloop_timer = uprof_context_get_timer_result (mainloop_context,
127                                                    "Mainloop");
128   /* just bail out if the mainloop timer wasn't hit */
129   if (!mainloop_timer)
130     return FALSE;
131
132   state = g_new0 (ClutterUProfReportState, 1);
133   *closure_ret = state;
134
135   stage_paint_timer = uprof_context_get_timer_result (_clutter_uprof_context,
136                                                       "Redrawing");
137   if (stage_paint_timer)
138     {
139       state->n_frames = uprof_timer_result_get_start_count (stage_paint_timer);
140
141       uprof_report_add_statistic (report,
142                                   "Frames",
143                                   "Frame count information");
144       uprof_report_add_statistic_attribute (report, "Frames",
145                                             "Count", "Count",
146                                             "The total number of frames",
147                                             UPROF_ATTRIBUTE_TYPE_INT,
148                                             get_n_frames_cb,
149                                             state);
150
151
152       state->fps = (float) state->n_frames
153         / (uprof_timer_result_get_total_msecs (mainloop_timer)
154            / 1000.0);
155       uprof_report_add_statistic_attribute (report, "Frames",
156                                             "Average FPS", "Average\nFPS",
157                                             "The average frames per second",
158                                             UPROF_ATTRIBUTE_TYPE_FLOAT,
159                                             get_fps_cb,
160                                             state);
161     }
162
163   do_pick_timer = uprof_context_get_timer_result (_clutter_uprof_context,
164                                                   "Picking");
165   if (do_pick_timer)
166     {
167       state->n_picks = uprof_timer_result_get_start_count (do_pick_timer);
168       state->msecs_picking =
169         uprof_timer_result_get_total_msecs (do_pick_timer);
170
171       uprof_report_add_statistic (report,
172                                   "Picks",
173                                   "Picking information");
174       uprof_report_add_statistic_attribute (report, "Picks",
175                                             "Count", "Count",
176                                             "The total number of picks",
177                                             UPROF_ATTRIBUTE_TYPE_INT,
178                                             get_n_picks_cb,
179                                             state);
180
181       uprof_report_add_statistic_attribute (report, "Picks",
182                                             "Picks Per Frame",
183                                             "Picks\nPer Frame",
184                                             "The average number of picks "
185                                             "per frame",
186                                             UPROF_ATTRIBUTE_TYPE_FLOAT,
187                                             get_picks_per_frame_cb,
188                                             state);
189
190       uprof_report_add_statistic_attribute (report, "Picks",
191                                             "Msecs Per Pick",
192                                             "Msecs\nPer Pick",
193                                             "The average number of "
194                                             "milliseconds per pick",
195                                             UPROF_ATTRIBUTE_TYPE_FLOAT,
196                                             get_msecs_per_pick_cb,
197                                             state);
198     }
199
200   uprof_report_add_counters_attribute (clutter_uprof_report,
201                                        "Per Frame",
202                                        "Per Frame",
203                                        "The number of counts per frame",
204                                        UPROF_ATTRIBUTE_TYPE_INT,
205                                        counter_per_frame_cb,
206                                        state);
207   uprof_report_add_timers_attribute (clutter_uprof_report,
208                                      "Per Frame\nmsecs",
209                                      "Per Frame",
210                                      "The time spent in the timer per frame",
211                                      UPROF_ATTRIBUTE_TYPE_FLOAT,
212                                      timer_per_frame_cb,
213                                      state);
214
215   return TRUE;
216 }
217
218 static void
219 _clutter_uprof_report_done (UProfReport *report, void *closure, void *user_data)
220 {
221   g_free (closure);
222 }
223
224 static void
225 print_exit_report (void)
226 {
227   if (!(clutter_profile_flags & CLUTTER_PROFILE_DISABLE_REPORT))
228     uprof_report_print (clutter_uprof_report);
229
230   uprof_report_unref (clutter_uprof_report);
231
232   uprof_context_unref (_clutter_uprof_context);
233 }
234
235 void
236 _clutter_uprof_init (void)
237 {
238   UProfContext *cogl_context;
239
240   _clutter_uprof_context = uprof_context_new ("Clutter");
241   uprof_context_link (_clutter_uprof_context, uprof_get_mainloop_context ());
242   g_atexit (print_exit_report);
243
244   cogl_context = uprof_find_context ("Cogl");
245   if (cogl_context)
246     uprof_context_link (_clutter_uprof_context, cogl_context);
247
248   /* We make the report object up-front so we can use uprof-tool
249    * to fetch reports at runtime via dbus... */
250   clutter_uprof_report = uprof_report_new ("Clutter report");
251   uprof_report_add_context (clutter_uprof_report, _clutter_uprof_context);
252   uprof_report_set_init_fini_callbacks (clutter_uprof_report,
253                                         _clutter_uprof_report_prepare,
254                                         _clutter_uprof_report_done,
255                                         NULL);
256 }
257
258 void
259 _clutter_profile_suspend (void)
260 {
261   if (G_UNLIKELY (!searched_for_gl_uprof_context))
262     {
263       gl_uprof_context = uprof_find_context ("OpenGL");
264       searched_for_gl_uprof_context = TRUE;
265     }
266
267   if (gl_uprof_context)
268     uprof_context_suspend (gl_uprof_context);
269
270   /* NB: The Cogl context is linked to this so it will also be suspended... */
271   uprof_context_suspend (_clutter_uprof_context);
272 }
273
274 void
275 _clutter_profile_resume (void)
276 {
277   if (gl_uprof_context)
278     uprof_context_resume (gl_uprof_context);
279
280   /* NB: The Cogl context is linked to this so it will also be resumed... */
281   uprof_context_resume (_clutter_uprof_context);
282 }
283 #endif