X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=metrics.c;h=09083e639ab966d6e80c36845c8da3c76f447059;hb=da0ee5e7efab316635f59d212028844f848fa6ce;hp=39ed5bacf2f9733010b5564893e76b9f7b0be1a1;hpb=02c39fbdaa29d62a8e7b8d223f62ccd08d4782ee;p=fips diff --git a/metrics.c b/metrics.c index 39ed5ba..09083e6 100644 --- a/metrics.c +++ b/metrics.c @@ -19,6 +19,8 @@ * THE SOFTWARE. */ +#define _GNU_SOURCE + #include #include @@ -27,29 +29,34 @@ #include "fips-dispatch-gl.h" #include "metrics.h" +#include "xmalloc.h" typedef struct counter { unsigned id; - unsigned program; + + metrics_op_t op; struct counter *next; } counter_t; -typedef struct program_metrics +typedef struct op_metrics { - unsigned id; - double ticks; -} program_metrics_t; + /* This happens to also be the index into the + * ctx->op_metrics array currently + */ + metrics_op_t op; + double time_ns; +} op_metrics_t; typedef struct context { - unsigned int program; + metrics_op_t op; counter_t *counter_head; counter_t *counter_tail; - unsigned num_program_metrics; - program_metrics_t *program_metrics; + unsigned num_op_metrics; + op_metrics_t *op_metrics; } context_t; /* FIXME: Need a map from integers to context objects and track the @@ -60,20 +67,61 @@ context_t current_context; int frames; int verbose; -unsigned -metrics_counter_new (void) +static const char * +metrics_op_string (metrics_op_t op) { - counter_t *counter; - - counter = malloc (sizeof(counter_t)); - if (counter == NULL) { - fprintf (stderr, "Out of memory\n"); + if (op >= METRICS_OP_SHADER) + return "Shader program"; + + switch (op) + { + case METRICS_OP_ACCUM: + return "glAccum*(+)"; + case METRICS_OP_BUFFER_DATA: + return "glBufferData(+)"; + case METRICS_OP_BUFFER_SUB_DATA: + return "glCopyBufferSubData*"; + case METRICS_OP_BITMAP: + return "glBitmap*"; + case METRICS_OP_BLIT_FRAMEBUFFER: + return "glBlitFramebuffer*"; + case METRICS_OP_CLEAR: + return "glClear(+)"; + case METRICS_OP_CLEAR_BUFFER_DATA: + return "glCearBufferData(+)"; + case METRICS_OP_CLEAR_TEX_IMAGE: + return "glClearTexImage(+)"; + case METRICS_OP_COPY_PIXELS: + return "glCopyPixels"; + case METRICS_OP_COPY_TEX_IMAGE: + return "glCopyTexImage(+)"; + case METRICS_OP_DRAW_PIXELS: + return "glDrawPixels"; + case METRICS_OP_GET_TEX_IMAGE: + return "glGetTexImage(+)"; + case METRICS_OP_READ_PIXELS: + return "glReadPixels*"; + case METRICS_OP_TEX_IMAGE: + return "glTexImage*(+)"; + default: + fprintf (stderr, "Internal error: " + "Unknown metrics op value: %d\n", op); exit (1); } + return ""; +} + +void +metrics_counter_start (void) +{ + counter_t *counter; + + counter = xmalloc (sizeof(counter_t)); + glGenQueries (1, &counter->id); - counter->program = current_context.program; + counter->op = current_context.op; counter->next = NULL; if (current_context.counter_tail) { @@ -84,59 +132,103 @@ metrics_counter_new (void) current_context.counter_head = counter; } - return counter->id; + glBeginQuery (GL_TIME_ELAPSED, counter->id); } void -metrics_counter_start (unsigned counter) +metrics_counter_stop (void) { - glBeginQuery (GL_TIME_ELAPSED, counter); + glEndQuery (GL_TIME_ELAPSED); } void -metrics_counter_stop (void) +metrics_set_current_op (metrics_op_t op) { - glEndQuery (GL_TIME_ELAPSED); + current_context.op = op; } -void -metrics_set_current_program (unsigned program) +metrics_op_t +metrics_get_current_op (void) { - current_context.program = program; + return current_context.op; } static void -accumulate_program_ticks (unsigned program_id, unsigned ticks) +accumulate_program_time (metrics_op_t op, unsigned time_ns) { context_t *ctx = ¤t_context; unsigned i; - if (program_id >= ctx->num_program_metrics) { - ctx->program_metrics = realloc (ctx->program_metrics, - (program_id + 1) * sizeof (program_metrics_t)); - for (i = ctx->num_program_metrics; i < program_id + 1; i++) { - ctx->program_metrics[i].id = i; - ctx->program_metrics[i].ticks = 0.0; + if (op >= ctx->num_op_metrics) { + ctx->op_metrics = realloc (ctx->op_metrics, + (op + 1) * sizeof (op_metrics_t)); + for (i = ctx->num_op_metrics; i < op + 1; i++) { + ctx->op_metrics[i].op = i; + ctx->op_metrics[i].time_ns = 0.0; } - ctx->num_program_metrics = program_id + 1; + ctx->num_op_metrics = op + 1; } - ctx->program_metrics[program_id].ticks += ticks; + ctx->op_metrics[op].time_ns += time_ns; +} + +static int +time_compare(const void *in_a, const void *in_b, void *arg) +{ + int a = *(const int *)in_a; + int b = *(const int *)in_b; + struct op_metrics *metrics = arg; + + if (metrics[a].time_ns < metrics[b].time_ns) + return -1; + if (metrics[a].time_ns > metrics[b].time_ns) + return 1; + return 0; } -/* FIXME: Should sort the metrics, print out percentages, etc. */ static void print_program_metrics (void) { context_t *ctx = ¤t_context; - unsigned i; + unsigned i, j; + int *sorted; /* Sorted indices into the ctx->op_metrics */ + double total = 0; + + /* Make a sorted list of the operations by time used, and figure + * out the total so we can print percentages. + */ + sorted = calloc(ctx->num_op_metrics, sizeof(*sorted)); + for (i = 0; i < ctx->num_op_metrics; i++) { + sorted[i] = i; + total += ctx->op_metrics[i].time_ns; + } + qsort_r(sorted, ctx->num_op_metrics, sizeof(*sorted), + time_compare, ctx->op_metrics); + + for (i = 0; i < ctx->num_op_metrics; i++) { + const char *op_string; + op_metrics_t *metric =&ctx->op_metrics[sorted[i]]; - for (i = 0; i < ctx->num_program_metrics; i++) { - if (ctx->program_metrics[i].ticks == 0.0) + /* Since we sparsely fill the array based on program + * id, many "programs" have no time. + */ + if (metric->time_ns == 0.0) continue; - printf ("Program %d:\t%7.2f mega-ticks\n", - i, ctx->program_metrics[i].ticks / 1e6); + + op_string = metrics_op_string (metric->op); + + printf ("%s", op_string); + if (metric->op >= METRICS_OP_SHADER) { + printf (" %d:", metric->op - METRICS_OP_SHADER); + } else { + printf (":"); + for (j = strlen (op_string); j < 20; j++) + printf (" "); + } + printf ("\t%7.2f ms (% 2.1f%%)\n", + metric->time_ns / 1e6, + metric->time_ns / total * 100); } } @@ -182,7 +274,7 @@ metrics_end_frame (void) glGetQueryObjectuiv (counter->id, GL_QUERY_RESULT, &elapsed); - accumulate_program_ticks (counter->program, elapsed); + accumulate_program_time (counter->op, elapsed); current_context.counter_head = counter->next; if (current_context.counter_head == NULL)