overlay: Parse gem objects
authorChris Wilson <chris@chris-wilson.co.uk>
Sun, 18 Aug 2013 17:17:05 +0000 (18:17 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Sun, 18 Aug 2013 17:17:05 +0000 (18:17 +0100)
Condense the information and begin graphing it. Remaining todo for
memory is to measure bind/evict flux, and perhaps clflush.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
overlay/gem-objects.c
overlay/gem-objects.h
overlay/overlay.c

index 37d6726..ffc13f9 100644 (file)
 #include <unistd.h>
 #include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include "gem-objects.h"
 
-int gem_objects_update(char *buf, int buflen)
+/* /sys/kernel/debug/dri/0/i915_gem_objects:
+ *     46 objects, 20107264 bytes
+ *     42 [42] objects, 15863808 [15863808] bytes in gtt
+ *       0 [0] active objects, 0 [0] bytes
+ *       42 [42] inactive objects, 15863808 [15863808] bytes
+ *     0 unbound objects, 0 bytes
+ *     3 purgeable objects, 4456448 bytes
+ *     30 pinned mappable objects, 3821568 bytes
+ *     1 fault mappable objects, 3145728 bytes
+ *     2145386496 [536870912] gtt total
+ *
+ *     Xorg: 35 objects, 16347136 bytes (0 active, 12103680 inactive, 0 unbound)
+ */
+
+int gem_objects_init(struct gem_objects *obj)
 {
-       int fd, len = -1;
+       char buf[8192], *b;
+       int fd, len;
+
+       memset(obj, 0, sizeof(*obj));
 
        fd = open("/sys/kernel/debug/dri/0/i915_gem_objects", 0);
-       if (fd >= 0) {
-               len = read(fd, buf, buflen-1);
-               if (len >= 0)
-                       buf[len] = '\0';
-               close(fd);
+       if (fd < 0)
+               return errno;
+       len = read(fd, buf, sizeof(buf)-1);
+       close(fd);
+
+       if (len < 0)
+               return EIO;
+
+       b = strstr(buf, "gtt total");
+       if (b == NULL)
+               return EIO;
+
+       while (*b != '\n')
+               b--;
+
+       sscanf(b, "%ld [%ld]",
+              &obj->max_gtt, &obj->max_aperture);
+
+       return 0;
+}
+
+static void insert_sorted(struct gem_objects *obj,
+                         struct gem_objects_comm *comm)
+{
+       struct gem_objects_comm *next, **prev;
+
+       for (prev = &obj->comm; (next = *prev) != NULL; prev = &next->next)
+               if (comm->bytes > next->bytes)
+                       break;
+
+       comm->next = *prev;
+       *prev = comm;
+}
+
+int gem_objects_update(struct gem_objects *obj)
+{
+       char buf[8192], *b;
+       struct gem_objects_comm *comm;
+       struct gem_objects_comm *freed;
+       int fd, len, ret;
+
+       freed = obj->comm;
+       obj->comm = NULL;
+
+       fd = open("/sys/kernel/debug/dri/0/i915_gem_objects", 0);
+       if (fd < 0) {
+               ret = errno;
+               goto done;
+       }
+       len = read(fd, buf, sizeof(buf)-1);
+       close(fd);
+
+       if (len < 0) {
+               ret = EIO;
+               goto done;
+       }
+
+       buf[len] = '\0';
+       while (buf[--len] == '\n')
+               buf[len] = '\0';
+
+       b = buf;
+
+       sscanf(b, "%d objects, %ld bytes",
+              &obj->total_count, &obj->total_bytes);
+
+       b = strchr(b, '\n');
+       sscanf(b, "%*d [%*d] objects, %ld [%ld] bytes in gtt",
+              &obj->total_gtt, &obj->total_aperture);
+
+       ret = 0;
+       b = strchr(b, ':');
+       if (b == NULL)
+               goto done;
+
+       while (*b != '\n')
+               b--;
+
+       do {
+               comm = freed;
+               if (comm)
+                       freed = comm->next;
+               else
+                       comm = malloc(sizeof(*comm));
+               if (comm == NULL)
+                       break;
+
+               /* Xorg: 35 objects, 16347136 bytes (0 active, 12103680 inactive, 0 unbound) */
+               sscanf(++b, "%256s %u objects, %lu bytes",
+                      comm->name, &comm->count, &comm->bytes);
+
+               insert_sorted(obj, comm);
+       } while ((b = strchr(b, '\n')) != NULL);
+
+done:
+       while (freed) {
+               comm = freed;
+               freed = comm->next;
+               free(comm);
        }
 
-       return len;
+       return ret;
 }
index 898d18f..b0c4519 100644 (file)
@@ -1 +1,17 @@
-int gem_objects_update(char *buf, int buflen);
+#include <stdint.h>
+
+struct gem_objects {
+       uint64_t total_bytes;
+       uint32_t total_count;
+       uint64_t total_gtt, total_aperture;
+       uint64_t max_gtt, max_aperture;
+       struct gem_objects_comm {
+               struct gem_objects_comm *next;
+               char name[256];
+               uint64_t bytes;
+               uint32_t count;
+       } *comm;
+};
+
+int gem_objects_init(struct gem_objects *obj);
+int gem_objects_update(struct gem_objects *obj);
index b888962..56dd2e1 100644 (file)
@@ -435,33 +435,76 @@ static void show_gpu_freq(struct overlay_context *ctx, struct overlay_gpu_freq *
        ctx->last_y += 112;
 }
 
-static void show_gem_objects(struct overlay_context *ctx)
+struct overlay_gem_objects {
+       struct gem_objects gem_objects;
+       struct chart aperture;
+       struct chart gtt;
+       int error;
+};
+
+static void init_gem_objects(struct overlay_gem_objects *go,
+                        cairo_surface_t *surface)
 {
-       char gem_objects[1024], *s, *t, *end;
-       int len, y;
+       go->error = gem_objects_init(&go->gem_objects);
+       if (go->error)
+               return;
+
+       chart_init(&go->aperture, "aperture", 120);
+       chart_set_size(&go->aperture,
+                      cairo_image_surface_get_width(surface)-24,
+                      100);
+       chart_set_stroke_rgba(&go->aperture, 0.75, 0.25, 0.50, 1.);
+       chart_set_mode(&go->aperture, CHART_STROKE);
+       chart_set_range(&go->aperture, 0, go->gem_objects.max_gtt);
 
-       len = gem_objects_update(gem_objects, sizeof(gem_objects));
-       if (len <= 0)
+       chart_init(&go->gtt, "gtt", 120);
+       chart_set_size(&go->gtt,
+                      cairo_image_surface_get_width(surface)-24,
+                      100);
+       chart_set_fill_rgba(&go->gtt, 0.25, 0.75, 0.50, 1.);
+       chart_set_mode(&go->gtt, CHART_FILL);
+       chart_set_range(&go->gtt, 0, go->gem_objects.max_gtt);
+}
+
+static void show_gem_objects(struct overlay_context *ctx, struct overlay_gem_objects *go)
+{
+       struct gem_objects_comm *comm;
+       char buf[160];
+       int y;
+
+       if (go->error == 0)
+               go->error = gem_objects_update(&go->gem_objects);
+       if (go->error)
                return;
 
-       y = ctx->last_y + 18;
+       chart_add_sample(&go->gtt, go->gem_objects.total_gtt);
+       chart_add_sample(&go->aperture, go->gem_objects.total_aperture);
+
+       y = ctx->last_y + 6;
 
-       s = gem_objects;
-       end = s + len - 1;
-       while (s < end) {
-               t = strchr(s, '\n');
-               if (t == NULL)
-                       t = end;
-               *t = '\0';
+       chart_set_position(&go->gtt, 12, y);
+       chart_set_position(&go->aperture, 12, y);
 
+       chart_draw(&go->gtt, ctx->cr);
+       chart_draw(&go->aperture, ctx->cr);
+
+       sprintf(buf, "Total: %ld bytes, %d objects",
+               go->gem_objects.total_bytes, go->gem_objects.total_count);
+       cairo_set_source_rgba(ctx->cr, 1, 1, 1, 1);
+       cairo_move_to(ctx->cr, 12, y);
+       cairo_show_text(ctx->cr, buf);
+       y += 14;
+
+       for (comm = go->gem_objects.comm; comm; comm = comm->next) {
+               sprintf(buf, "    %s: %ld bytes, %d objects",
+                       comm->name, comm->bytes, comm->count);
+               cairo_set_source_rgba(ctx->cr, 1, 1, 1, 1);
                cairo_move_to(ctx->cr, 12, y);
-               cairo_show_text(ctx->cr, s);
+               cairo_show_text(ctx->cr, buf);
                y += 14;
-
-               s = t+1;
        }
 
-       ctx->last_y = y;
+       ctx->last_y += 112;
 }
 
 int main(int argc, char **argv)
@@ -470,6 +513,7 @@ int main(int argc, char **argv)
        struct overlay_gpu_top gpu_top;
        struct overlay_gpu_perf gpu_perf;
        struct overlay_gpu_freq gpu_freq;
+       struct overlay_gem_objects gem_objects;
        int i = 0;
 
        if (argc > 1) {
@@ -484,6 +528,7 @@ int main(int argc, char **argv)
        init_gpu_top(&gpu_top, surface);
        init_gpu_perf(&gpu_perf, surface);
        init_gpu_freq(&gpu_freq, surface);
+       init_gem_objects(&gem_objects, surface);
 
        while (1) {
                struct overlay_context ctx;
@@ -511,7 +556,7 @@ int main(int argc, char **argv)
                show_gpu_top(&ctx, &gpu_top);
                show_gpu_perf(&ctx, &gpu_perf);
                show_gpu_freq(&ctx, &gpu_freq);
-               show_gem_objects(&ctx);
+               show_gem_objects(&ctx, &gem_objects);
 
                cairo_destroy(ctx.cr);