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@xxxxxxxxx> 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@.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@.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@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/intel-gfx _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx