From patchwork Tue Dec 19 00:36:19 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lionel Landwerlin X-Patchwork-Id: 10122083 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 63039602CB for ; Tue, 19 Dec 2017 00:36:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 52C6928C02 for ; Tue, 19 Dec 2017 00:36:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4565F28C99; Tue, 19 Dec 2017 00:36:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id DB42B28C02 for ; Tue, 19 Dec 2017 00:36:29 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 2DC736E233; Tue, 19 Dec 2017 00:36:28 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by gabe.freedesktop.org (Postfix) with ESMTPS id 2CC4A6E233 for ; Tue, 19 Dec 2017 00:36:26 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 18 Dec 2017 16:36:23 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.45,423,1508828400"; d="scan'208";a="159938895" Received: from wrzedzic-mobl.ger.corp.intel.com (HELO delly.ger.corp.intel.com) ([10.252.5.43]) by orsmga004.jf.intel.com with ESMTP; 18 Dec 2017 16:36:22 -0800 From: Lionel Landwerlin To: intel-gfx@lists.freedesktop.org Date: Tue, 19 Dec 2017 00:36:19 +0000 Message-Id: <20171219003619.10517-1-lionel.g.landwerlin@intel.com> X-Mailer: git-send-email 2.15.1 Subject: [Intel-gfx] [PATCH i-g-t] overlay: parse tracepoints from sysfs to figure out fields' location X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP 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. Signed-off-by: Lionel Landwerlin --- configure.ac | 5 ++ overlay/gpu-perf.c | 164 ++++++++++++++++++++++++++++++++++-------- overlay/meson.build | 11 ++- overlay/tracepoint_format.leg | 34 +++++++++ 4 files changed, 184 insertions(+), 30 deletions(-) create mode 100644 overlay/tracepoint_format.leg diff --git a/configure.ac b/configure.ac index 8740f7a4..87ca9f91 100644 --- a/configure.ac +++ b/configure.ac @@ -151,6 +151,11 @@ else enable_overlay_xlib="no" enable_assembler="no" BUILD_SHADER_DEBUGGER="no" + + AC_CHECK_TOOL([LEG], [leg]) + if test "x$LEG" != "xleg"; then + AC_MSG_ERROR([leg command missing, try : apt-get install peg]) + fi fi AM_CONDITIONAL(BUILD_X86, [test "x$build_x86" = xyes]) 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 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]*