[Intel-gfx] [PATCH i-g-t v2] overlay: parse tracepoints from sysfs to figure out fields' location
Petri Latvala
petri.latvala at intel.com
Tue Dec 19 10:08:38 UTC 2017
On Tue, Dec 19, 2017 at 01:06:18AM +0000, Lionel Landwerlin wrote:
> 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)
>
> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin at intel.com>
Adding a new dependency that doesn't involve the tests; that would be
preferrable to be optional. I gave some snippets already on IRC, here
they are in email form.
> ---
> configure.ac | 5 ++
> overlay/Makefile.am | 5 ++
> overlay/gpu-perf.c | 164 ++++++++++++++++++++++++++++++++++--------
> overlay/meson.build | 11 ++-
> overlay/tracepoint_format.leg | 34 +++++++++
> 5 files changed, 189 insertions(+), 30 deletions(-)
> create mode 100644 overlay/tracepoint_format.leg
>
> diff --git a/configure.ac b/configure.ac
> index 8740f7a4..f87f227a 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -146,6 +146,11 @@ if test x"$build_x86" = xyes; then
> AS_IF([test x"$LEX" != "x:" -a x"$YACC" != xyacc],
> [enable_assembler=yes],
> [enable_assembler=no])
> +
> + AC_CHECK_TOOL([LEG], [leg])
> + if test "x$LEG" != "xleg"; then
> + AC_MSG_ERROR([leg command missing, try : apt-get install peg])
> + fi
> else
Squash for making peg optional:
AC_CHECK_TOOL([LEG], [leg])
if test "x$LEG" != "xleg"; then
- AC_MSG_ERROR([leg command missing, try : apt-get install peg])
+ AC_MSG_NOTICE([leg command missing, disabling overlay; try : apt-get install peg])
+ enable_overlay_xvlib="no"
+ enable_overlay_xlib="no"
fi
> enable_overlay_xvlib="no"
> enable_overlay_xlib="no"
> 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..7fa561e3 100644
> --- a/overlay/gpu-perf.c
> +++ b/overlay/gpu-perf.c
> @@ -57,25 +57,120 @@ 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 {
> + struct {
> + char name[128];
> + int offset;
> + int size;
> + int is_signed;
> + } fields[20];
> + const char *name;
> + 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_PARSE(T) static T
> +#define YY_INPUT(yy, buf, result, max) \
> + { \
> + int yyc = getc(yy->ctx.fp); \
> + result = (EOF == yyc) ? 0 : (*(buf)= yyc, 1); \
> + }
> +
> +#include "tracepoint_format.h"
> +
> +static int
> +parse_tracepoint(int tp_id)
> +{
> + struct tracepoint *tp = &tracepoints[tp_id];
> + yycontext ctx;
> + char buf[1024];
> +
> + /* Already parsed? */
> + if (tp->n_fields != 0)
> + return 0;
> +
> + 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;
> +
> + 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->n_fields = 0;
> +
> + yyrelease(&ctx);
> + fclose(ctx.ctx.fp);
> +
> + return tp->n_fields;
> +}
> +
> +static uint64_t tracepoint_id(int tp_id)
> {
> char buf[1024];
> int fd, n;
>
> - snprintf(buf, sizeof(buf), "%s/tracing/events/%s/%s/id", debugfs_path, sys, name);
> + snprintf(buf, sizeof(buf), "%s/tracing/events/%s/id", debugfs_path,
> + tracepoints[tp_id].name);
> fd = open(buf, 0);
> if (fd < 0)
> return 0;
> @@ -88,8 +183,12 @@ static uint64_t tracepoint_id(const char *sys, const char *name)
> return strtoull(buf, 0, 0);
> }
>
> -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,10 +198,13 @@ 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;
>
> + if (parse_tracepoint(tp_id) == 0)
> + return ENOENT;
> +
> attr.sample_period = 1;
> attr.sample_type = (PERF_SAMPLE_TIME | PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_TID | PERF_SAMPLE_RAW);
> attr.read_format = PERF_FORMAT_ID;
> @@ -227,7 +329,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 +337,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 +345,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 +380,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;
> }
> @@ -292,9 +394,13 @@ static int wait_end(struct gpu_perf *gp, const void *event)
> const struct sample_event *sample = event;
> struct gpu_perf_time *wait, **prev;
>
> - 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[READ_TP_FIELD_U32(sample, TP_GEM_REQUEST_WAIT_END, ring)];
> + (wait = *prev) != NULL;
> + prev = &wait->next) {
> + if (wait->context != READ_TP_FIELD_U32(sample,
> + TP_GEM_REQUEST_WAIT_END, ctx) ||
> + wait->seqno != READ_TP_FIELD_U32(sample,
> + TP_GEM_REQUEST_WAIT_END, seqno))
> continue;
>
> wait->comm->wait_time += sample->time - wait->time;
> @@ -314,12 +420,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..6a5691dc 100644
> --- a/overlay/meson.build
> +++ b/overlay/meson.build
> @@ -14,6 +14,14 @@ gpu_overlay_src = [
> 'rc6.c',
> ]
>
> +leg = find_program('leg', required : true)
> +leg_gen = generator(leg,
> + output : '@BASENAME at .h',
> + arguments : ['-o', '@OUTPUT@', '@INPUT@'])
> +leg_file = leg_gen.process('tracepoint_format.leg')
> +leg_lib = static_library('leg', leg_file)
> +leg_inc = leg_lib.private_dir_include()
> +
> xv = dependency('xv', required : false)
> x11 = dependency('x11', required : false)
> xext = dependency('xext', required : false)
> @@ -53,8 +61,9 @@ gpu_overlay_src += 'kms/kms-overlay.c'
>
> if xrandr.found() and cairo.found()
> executable('intel-gpu-overlay', gpu_overlay_src,
> - include_directories : inc,
> + include_directories : [inc, leg_inc],
> c_args : gpu_overlay_cflags,
> dependencies : gpu_overlay_deps,
> + link_with : leg_lib,
> install : true)
> endif
Making that look a bit less nonsensical and also making peg optional:
@@ -14,14 +14,6 @@ gpu_overlay_src = [
'rc6.c',
]
-leg = find_program('leg', required : true)
-leg_gen = generator(leg,
- output : '@BASENAME at .h',
- arguments : ['-o', '@OUTPUT@', '@INPUT@'])
-leg_file = leg_gen.process('tracepoint_format.leg')
-leg_lib = static_library('leg', leg_file)
-leg_inc = leg_lib.private_dir_include()
-
xv = dependency('xv', required : false)
x11 = dependency('x11', required : false)
xext = dependency('xext', required : false)
@@ -59,11 +51,19 @@ gpu_overlay_src += both_x11_src
gpu_overlay_src += 'kms/kms-overlay.c'
-if xrandr.found() and cairo.found()
- executable('intel-gpu-overlay', gpu_overlay_src,
- include_directories : [inc, leg_inc],
+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, '-o', '@OUTPUT@', '@INPUT@'])
+ gpu_overlay_src += leg_file
+
+ if xrandr.found() and cairo.found()
+ executable('intel-gpu-overlay', gpu_overlay_src,
+ include_directories : inc,
c_args : gpu_overlay_cflags,
dependencies : gpu_overlay_deps,
- link_with : leg_lib,
install : true)
+ endif
endif
--
Petri Latvala
> diff --git a/overlay/tracepoint_format.leg b/overlay/tracepoint_format.leg
> new file mode 100644
> index 00000000..ea83db91
> --- /dev/null
> +++ b/overlay/tracepoint_format.leg
> @@ -0,0 +1,34 @@
> +TracepointFormat =
> + 'name' ':' Space PropertyName EndLine
> + 'ID' ':' Space Number EndLine
> + '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]*
> --
> 2.15.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
More information about the Intel-gfx
mailing list