summaryrefslogtreecommitdiff
path: root/overlay
diff options
context:
space:
mode:
authorLionel Landwerlin <lionel.g.landwerlin@intel.com>2017-12-18 23:00:54 +0000
committerLionel Landwerlin <lionel.g.landwerlin@intel.com>2017-12-22 11:17:37 +0000
commit865a47ca2b93b208ba016f3c4fc00831ec7bfec6 (patch)
treefae09896c77b2d7c3ccd9989e23d5dc041442888 /overlay
parentbeb26d89ff5c5621c1e6b6ac2a45439507af86b7 (diff)
overlay: parse tracepoints from sysfs to figure out fields' location
With changes going to drm-tip, the tracepoints field locations are going to change. This change introduces a tracepoint parser (using a peg parser) which lets us figure out field positions on the fly. v2: Fix automake build (Lionel) v3: Make overlay build conditional on peg (Petri) Make wait_end callback more readable (Chris) Drop tracepoint_id(), instead parsing from format file (Lionel) v4: Fix existing configure.ac issue with overlay build (Petri) v5: Silence unused function (Lionel) v6: Fix missing double quote in v4 (Lionel) Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Acked-by: Chris Wilson <chris@chris-wilson.co.uk> For the build system changes: Acked-by: Petri Latvala <petri.latvala@intel.com>
Diffstat (limited to 'overlay')
-rw-r--r--overlay/Makefile.am5
-rw-r--r--overlay/gpu-perf.c164
-rw-r--r--overlay/meson.build13
-rw-r--r--overlay/tracepoint_format.leg35
4 files changed, 178 insertions, 39 deletions
diff --git a/overlay/Makefile.am b/overlay/Makefile.am
index fca04cae..0f553b7c 100644
--- a/overlay/Makefile.am
+++ b/overlay/Makefile.am
@@ -1,7 +1,12 @@
if BUILD_OVERLAY
bin_PROGRAMS = intel-gpu-overlay
+
+BUILT_SOURCES = tracepoint_format.h
endif
+tracepoint_format.h: tracepoint_format.leg
+ $(LEG) -o $@ $<
+
AM_CPPFLAGS = -I. -I$(top_srcdir)/include/drm-uapi
AM_CFLAGS = $(DRM_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS) \
$(CAIRO_CFLAGS) $(OVERLAY_CFLAGS) $(WERROR_CFLAGS) -I$(srcdir)/../lib
diff --git a/overlay/gpu-perf.c b/overlay/gpu-perf.c
index 3d4a9be9..0abd937e 100644
--- a/overlay/gpu-perf.c
+++ b/overlay/gpu-perf.c
@@ -57,39 +57,125 @@ struct sample_event {
uint64_t time;
uint64_t id;
uint32_t raw_size;
- uint32_t raw_hdr0;
- uint32_t raw_hdr1;
- uint32_t raw[0];
+ uint8_t tracepoint_data[0];
};
enum {
- DEVICE = 0,
- CTX,
- ENGINE,
- CTX_SEQNO,
- GLOBAL_SEQNO
+ TP_GEM_REQUEST_ADD,
+ TP_GEM_REQUEST_WAIT_BEGIN,
+ TP_GEM_REQUEST_WAIT_END,
+ TP_FLIP_COMPLETE,
+ TP_GEM_RING_SYNC_TO,
+ TP_GEM_RING_SWITCH_CONTEXT,
+
+ TP_NB
};
-static uint64_t tracepoint_id(const char *sys, const char *name)
+struct tracepoint {
+ const char *name;
+ int event_id;
+
+ struct {
+ char name[128];
+ int offset;
+ int size;
+ int is_signed;
+ } fields[20];
+ int n_fields;
+
+ int device_field;
+ int ctx_field;
+ int ring_field;
+ int seqno_field;
+ int global_seqno_field;
+ int plane_field;
+} tracepoints[TP_NB] = {
+ [TP_GEM_REQUEST_ADD] = { .name = "i915/i915_gem_request_add", },
+ [TP_GEM_REQUEST_WAIT_BEGIN] = { .name = "i915/i915_gem_request_wait_begin", },
+ [TP_GEM_REQUEST_WAIT_END] = { .name = "i915/i915_gem_request_wait_end", },
+ [TP_FLIP_COMPLETE] = { .name = "i915/flip_complete", },
+ [TP_GEM_RING_SYNC_TO] = { .name = "i915/gem_ring_sync_to", },
+ [TP_GEM_RING_SWITCH_CONTEXT] = { .name = "i915/gem_ring_switch_context", },
+};
+
+union parser_value {
+ char *string;
+ int integer;
+};
+
+struct parser_ctx {
+ struct tracepoint *tp;
+ FILE *fp;
+};
+
+#define YY_CTX_LOCAL
+#define YY_CTX_MEMBERS struct parser_ctx ctx;
+#define YYSTYPE union parser_value
+#define YY_LOCAL(T) static __attribute__((unused)) T
+#define YY_PARSE(T) static T
+#define YY_INPUT(yy, buf, result, max) \
+ { \
+ int c = getc(yy->ctx.fp); \
+ result = (EOF == c) ? 0 : (*(buf)= c, 1); \
+ if (EOF != c) { \
+ yyprintf((stderr, "<%c>", c)); \
+ } \
+ }
+
+#include "tracepoint_format.h"
+
+static int
+tracepoint_id(int tp_id)
{
+ struct tracepoint *tp = &tracepoints[tp_id];
+ yycontext ctx;
char buf[1024];
- int fd, n;
- snprintf(buf, sizeof(buf), "%s/tracing/events/%s/%s/id", debugfs_path, sys, name);
- fd = open(buf, 0);
- if (fd < 0)
- return 0;
- n = read(fd, buf, sizeof(buf)-1);
- close(fd);
- if (n < 0)
+ /* Already parsed? */
+ if (tp->event_id != 0)
+ return tp->event_id;
+
+ snprintf(buf, sizeof(buf), "%s/tracing/events/%s/format",
+ debugfs_path, tp->name);
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.ctx.tp = tp;
+ ctx.ctx.fp = fopen(buf, "r");
+
+ if (ctx.ctx.fp == NULL)
return 0;
- buf[n] = '\0';
- return strtoull(buf, 0, 0);
+ if (yyparse(&ctx)) {
+ for (int f = 0; f < tp->n_fields; f++) {
+ if (!strcmp(tp->fields[f].name, "device")) {
+ tp->device_field = f;
+ } else if (!strcmp(tp->fields[f].name, "ctx")) {
+ tp->ctx_field = f;
+ } else if (!strcmp(tp->fields[f].name, "ring")) {
+ tp->ring_field = f;
+ } else if (!strcmp(tp->fields[f].name, "seqno")) {
+ tp->seqno_field = f;
+ } else if (!strcmp(tp->fields[f].name, "global_seqno")) {
+ tp->global_seqno_field = f;
+ } else if (!strcmp(tp->fields[f].name, "plane")) {
+ tp->plane_field = f;
+ }
+ }
+ } else
+ tp->event_id = tp->n_fields = 0;
+
+ yyrelease(&ctx);
+ fclose(ctx.ctx.fp);
+
+ return tp->event_id;
}
-static int perf_tracepoint_open(struct gpu_perf *gp,
- const char *sys, const char *name,
+#define READ_TP_FIELD_U32(sample, tp_id, field_name) \
+ (*(const uint32_t *)((sample)->tracepoint_data + \
+ tracepoints[tp_id].fields[ \
+ tracepoints[tp_id].field_name##_field].offset))
+
+static int perf_tracepoint_open(struct gpu_perf *gp, int tp_id,
int (*func)(struct gpu_perf *, const void *))
{
struct perf_event_attr attr;
@@ -99,7 +185,7 @@ static int perf_tracepoint_open(struct gpu_perf *gp,
memset(&attr, 0, sizeof (attr));
attr.type = PERF_TYPE_TRACEPOINT;
- attr.config = tracepoint_id(sys, name);
+ attr.config = tracepoint_id(tp_id);
if (attr.config == 0)
return ENOENT;
@@ -227,7 +313,7 @@ static int request_add(struct gpu_perf *gp, const void *event)
if (comm == NULL)
return 0;
- comm->nr_requests[sample->raw[ENGINE]]++;
+ comm->nr_requests[READ_TP_FIELD_U32(sample, TP_GEM_REQUEST_ADD, ring)]++;
return 1;
}
@@ -235,7 +321,7 @@ static int flip_complete(struct gpu_perf *gp, const void *event)
{
const struct sample_event *sample = event;
- gp->flip_complete[sample->raw[0]]++;
+ gp->flip_complete[READ_TP_FIELD_U32(sample, TP_FLIP_COMPLETE, plane)]++;
return 1;
}
@@ -243,7 +329,7 @@ static int ctx_switch(struct gpu_perf *gp, const void *event)
{
const struct sample_event *sample = event;
- gp->ctx_switch[sample->raw[ENGINE]]++;
+ gp->ctx_switch[READ_TP_FIELD_U32(sample, TP_GEM_RING_SWITCH_CONTEXT, ring)]++;
return 1;
}
@@ -278,11 +364,11 @@ static int wait_begin(struct gpu_perf *gp, const void *event)
wait->comm = comm;
wait->comm->active = true;
- wait->context = sample->raw[ENGINE];
- wait->seqno = sample->raw[CTX_SEQNO];
+ wait->context = READ_TP_FIELD_U32(sample, TP_GEM_REQUEST_WAIT_BEGIN, ctx);
+ wait->seqno = READ_TP_FIELD_U32(sample, TP_GEM_REQUEST_WAIT_BEGIN, seqno);
wait->time = sample->time;
- wait->next = gp->wait[sample->raw[CTX]];
- gp->wait[sample->raw[CTX]] = wait;
+ wait->next = gp->wait[READ_TP_FIELD_U32(sample, TP_GEM_REQUEST_WAIT_BEGIN, ring)];
+ gp->wait[READ_TP_FIELD_U32(sample, TP_GEM_REQUEST_WAIT_BEGIN, ring)] = wait;
return 0;
}
@@ -291,10 +377,12 @@ static int wait_end(struct gpu_perf *gp, const void *event)
{
const struct sample_event *sample = event;
struct gpu_perf_time *wait, **prev;
+ uint32_t engine = READ_TP_FIELD_U32(sample, TP_GEM_REQUEST_WAIT_END, ring);
+ uint32_t context = READ_TP_FIELD_U32(sample, TP_GEM_REQUEST_WAIT_END, ctx);
+ uint32_t seqno = READ_TP_FIELD_U32(sample, TP_GEM_REQUEST_WAIT_END, seqno);
- for (prev = &gp->wait[sample->raw[ENGINE]]; (wait = *prev) != NULL; prev = &wait->next) {
- if (wait->context != sample->raw[CTX] ||
- wait->seqno != sample->raw[CTX_SEQNO])
+ for (prev = &gp->wait[engine]; (wait = *prev) != NULL; prev = &wait->next) {
+ if (wait->context != context || wait->seqno != seqno)
continue;
wait->comm->wait_time += sample->time - wait->time;
@@ -314,12 +402,12 @@ void gpu_perf_init(struct gpu_perf *gp, unsigned flags)
gp->nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
gp->page_size = getpagesize();
- perf_tracepoint_open(gp, "i915", "i915_gem_request_add", request_add);
- if (perf_tracepoint_open(gp, "i915", "i915_gem_request_wait_begin", wait_begin) == 0)
- perf_tracepoint_open(gp, "i915", "i915_gem_request_wait_end", wait_end);
- perf_tracepoint_open(gp, "i915", "i915_flip_complete", flip_complete);
- perf_tracepoint_open(gp, "i915", "i915_gem_ring_sync_to", ring_sync);
- perf_tracepoint_open(gp, "i915", "i915_gem_ring_switch_context", ctx_switch);
+ perf_tracepoint_open(gp, TP_GEM_REQUEST_ADD, request_add);
+ if (perf_tracepoint_open(gp, TP_GEM_REQUEST_WAIT_BEGIN, wait_begin) == 0)
+ perf_tracepoint_open(gp, TP_GEM_REQUEST_WAIT_END, wait_end);
+ perf_tracepoint_open(gp, TP_FLIP_COMPLETE, flip_complete);
+ perf_tracepoint_open(gp, TP_GEM_RING_SYNC_TO, ring_sync);
+ perf_tracepoint_open(gp, TP_GEM_RING_SWITCH_CONTEXT, ctx_switch);
if (gp->nr_events == 0) {
gp->error = "i915.ko tracepoints not available";
diff --git a/overlay/meson.build b/overlay/meson.build
index afacff5e..8b5c52b4 100644
--- a/overlay/meson.build
+++ b/overlay/meson.build
@@ -51,7 +51,18 @@ gpu_overlay_src += both_x11_src
gpu_overlay_src += 'kms/kms-overlay.c'
-if xrandr.found() and cairo.found()
+leg = find_program('leg', required : false)
+if leg.found()
+ leg_file = custom_target('tracepoint_format',
+ output: 'tracepoint_format.h',
+ input: 'tracepoint_format.leg',
+ command: [leg, '-P', '-o', '@OUTPUT@', '@INPUT@'])
+ gpu_overlay_src += leg_file
+else
+ warning('leg command not found, disabling overlay; try : apt-get install peg')
+endif
+
+if leg.found() and xrandr.found() and cairo.found()
executable('intel-gpu-overlay', gpu_overlay_src,
include_directories : inc,
c_args : gpu_overlay_cflags,
diff --git a/overlay/tracepoint_format.leg b/overlay/tracepoint_format.leg
new file mode 100644
index 00000000..7a09149d
--- /dev/null
+++ b/overlay/tracepoint_format.leg
@@ -0,0 +1,35 @@
+TracepointFmt =
+ 'name' ':' Space n:PropertyName EndLine
+ { free(v.string); }
+ 'ID:' Space v:Number EndLine
+ { yy->ctx.tp->event_id = v.integer; }
+ 'format:' EndLine
+ Field+
+ 'print fmt:' [^.]* !.
+
+Field = Space (Property ';' Space)+ EndLine
+ { yy->ctx.tp->n_fields++; }
+ | EndLine
+
+Property = 'offset' ':' v:Number
+ { yy->ctx.tp->fields[yy->ctx.tp->n_fields].offset = v.integer; }
+ | 'size' ':' v:Number
+ { yy->ctx.tp->fields[yy->ctx.tp->n_fields].size = v.integer; }
+ | 'signed' ':' v:Number
+ { yy->ctx.tp->fields[yy->ctx.tp->n_fields].is_signed = v.integer != 0; }
+ | 'field' ':' v:PropertyValue
+ { snprintf(yy->ctx.tp->fields[yy->ctx.tp->n_fields].name,
+ sizeof(yy->ctx.tp->fields[yy->ctx.tp->n_fields].name),
+ "%s", strrchr(v.string, ' ') + 1); free(v.string); }
+ | n:PropertyName ':' v:PropertyValue
+ { free(n.string); free(v.string); }
+
+PropertyName = < [A-Za-z0-9_]+ >
+ { $$.string = strdup(yytext); }
+PropertyValue = < [^;]+ >
+ { $$.string = strdup(yytext); }
+Number = < [0-9]+ >
+ { $$.integer = atoi(yytext); }
+
+EndLine = [\n]
+Space = [ \t]*