1 /* Copyright © 2013, Intel Corporation
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 #include "fips-dispatch-gl.h"
34 typedef struct counter
42 typedef struct op_metrics
44 /* This happens to also be the index into the
45 * ctx->op_metrics array currently
51 typedef struct context
55 counter_t *counter_head;
56 counter_t *counter_tail;
58 unsigned num_op_metrics;
59 op_metrics_t *op_metrics;
62 /* FIXME: Need a map from integers to context objects and track the
63 * current context with glXMakeContextCurrent, eglMakeCurrent, etc. */
65 context_t current_context;
71 metrics_op_string (metrics_op_t op)
73 if (op >= METRICS_OP_SHADER)
74 return "Shader program";
78 case METRICS_OP_ACCUM:
80 case METRICS_OP_BUFFER_DATA:
81 return "glBufferData(+)";
82 case METRICS_OP_BUFFER_SUB_DATA:
83 return "glCopyBufferSubData*";
84 case METRICS_OP_BITMAP:
86 case METRICS_OP_BLIT_FRAMEBUFFER:
87 return "glBlitFramebuffer*";
88 case METRICS_OP_CLEAR:
90 case METRICS_OP_CLEAR_BUFFER_DATA:
91 return "glCearBufferData(+)";
92 case METRICS_OP_CLEAR_TEX_IMAGE:
93 return "glClearTexImage(+)";
94 case METRICS_OP_COPY_PIXELS:
95 return "glCopyPixels";
96 case METRICS_OP_COPY_TEX_IMAGE:
97 return "glCopyTexImage(+)";
98 case METRICS_OP_DRAW_PIXELS:
99 return "glDrawPixels";
100 case METRICS_OP_GET_TEX_IMAGE:
101 return "glGetTexImage(+)";
102 case METRICS_OP_READ_PIXELS:
103 return "glReadPixels*";
104 case METRICS_OP_TEX_IMAGE:
105 return "glTexImage*(+)";
107 fprintf (stderr, "Internal error: "
108 "Unknown metrics op value: %d\n", op);
116 metrics_counter_start (void)
120 counter = xmalloc (sizeof(counter_t));
122 glGenQueries (1, &counter->id);
124 counter->op = current_context.op;
125 counter->next = NULL;
127 if (current_context.counter_tail) {
128 current_context.counter_tail->next = counter;
129 current_context.counter_tail = counter;
131 current_context.counter_tail = counter;
132 current_context.counter_head = counter;
135 glBeginQuery (GL_TIME_ELAPSED, counter->id);
139 metrics_counter_stop (void)
141 glEndQuery (GL_TIME_ELAPSED);
145 metrics_set_current_op (metrics_op_t op)
147 current_context.op = op;
151 metrics_get_current_op (void)
153 return current_context.op;
157 accumulate_program_time (metrics_op_t op, unsigned time_ns)
159 context_t *ctx = ¤t_context;
162 if (op >= ctx->num_op_metrics) {
163 ctx->op_metrics = realloc (ctx->op_metrics,
164 (op + 1) * sizeof (op_metrics_t));
165 for (i = ctx->num_op_metrics; i < op + 1; i++) {
166 ctx->op_metrics[i].op = i;
167 ctx->op_metrics[i].time_ns = 0.0;
170 ctx->num_op_metrics = op + 1;
173 ctx->op_metrics[op].time_ns += time_ns;
177 time_compare(const void *in_a, const void *in_b, void *arg)
179 int a = *(const int *)in_a;
180 int b = *(const int *)in_b;
181 struct op_metrics *metrics = arg;
183 if (metrics[a].time_ns < metrics[b].time_ns)
185 if (metrics[a].time_ns > metrics[b].time_ns)
191 print_program_metrics (void)
193 context_t *ctx = ¤t_context;
195 int *sorted; /* Sorted indices into the ctx->op_metrics */
198 /* Make a sorted list of the operations by time used, and figure
199 * out the total so we can print percentages.
201 sorted = calloc(ctx->num_op_metrics, sizeof(*sorted));
202 for (i = 0; i < ctx->num_op_metrics; i++) {
204 total += ctx->op_metrics[i].time_ns;
206 qsort_r(sorted, ctx->num_op_metrics, sizeof(*sorted),
207 time_compare, ctx->op_metrics);
209 for (i = 0; i < ctx->num_op_metrics; i++) {
210 const char *op_string;
211 op_metrics_t *metric =&ctx->op_metrics[sorted[i]];
213 /* Since we sparsely fill the array based on program
214 * id, many "programs" have no time.
216 if (metric->time_ns == 0.0)
219 op_string = metrics_op_string (metric->op);
221 printf ("%s", op_string);
222 if (metric->op >= METRICS_OP_SHADER) {
223 printf (" %d:", metric->op - METRICS_OP_SHADER);
226 for (j = strlen (op_string); j < 20; j++)
229 printf ("\t%7.2f ms (% 2.1f%%)\n",
230 metric->time_ns / 1e6,
231 metric->time_ns / total * 100);
235 /* Called at program exit */
240 printf ("fips: terminating\n");
245 metrics_end_frame (void)
247 static int initialized = 0;
248 static struct timeval tv_start, tv_now;
251 gettimeofday (&tv_start, NULL);
252 atexit (metrics_exit);
253 if (getenv ("FIPS_VERBOSE"))
259 printf ("fips: frame %d complete\n", frames);
262 gettimeofday (&tv_now, NULL);
264 /* Consume all counters that are ready. */
265 counter_t *counter = current_context.counter_head;
268 GLuint available, elapsed;
270 glGetQueryObjectuiv (counter->id, GL_QUERY_RESULT_AVAILABLE,
275 glGetQueryObjectuiv (counter->id, GL_QUERY_RESULT, &elapsed);
277 accumulate_program_time (counter->op, elapsed);
279 current_context.counter_head = counter->next;
280 if (current_context.counter_head == NULL)
281 current_context.counter_tail = NULL;
283 glDeleteQueries (1, &counter->id);
286 counter = current_context.counter_head;
289 if (frames % 60 == 0) {
292 fps = (double) frames / (tv_now.tv_sec - tv_start.tv_sec +
293 (tv_now.tv_usec - tv_start.tv_usec) / 1.0e6);
295 printf("FPS: %.3f\n", fps);
297 print_program_metrics ();