From: Julien Desfossez Date: Tue, 5 Jul 2016 15:50:46 +0000 (-0400) Subject: Enable perf PMU counters by raw ID X-Git-Tag: v2.9.0-rc1~84 X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=commitdiff_plain;h=4fe444dafd2243de56091ab5dd7efa0050b0597f Enable perf PMU counters by raw ID Allow enabling perf PMU counters by raw ID in addition to the generic list already provided. The format for kernel tracing is "perf:cpu:raw:rNNN:" and "perf:thread:raw:rNNN: for user-space. The rNNN format is the same as perf-record(1) where NNN is a hexadecimal event descriptor in the form of umask+eventsel. The field to associate a clearer name to the counter. Example usage on Intel i7-3520M to get the unhalted reference cycles (eventsel: 0x13c) count at privilege level 0 (umask: 0x00): lttng add-context -k -t perf:cpu:raw:r0013c:x86unhalted Result in the trace: sched_switch: { cpu_id = 3 }, { perf_cpu_raw_r0013c_x86unhalted = 27632578 }, [...] Signed-off-by: Julien Desfossez Signed-off-by: Jérémie Galarneau --- diff --git a/doc/man/lttng-add-context.1.txt b/doc/man/lttng-add-context.1.txt index f995a7fbe..a1e0fe78f 100644 --- a/doc/man/lttng-add-context.1.txt +++ b/doc/man/lttng-add-context.1.txt @@ -45,6 +45,15 @@ per-thread (`perf:thread:` prefix) counters. Currently, per-CPU counters can only be used in the Linux kernel tracing domain, while per-thread counters can only be used in the user space tracing domain. +It is also possible to enable PMU counters by raw ID using the +`perf:cpu:raw:r:` or `perf:thread:raw:r:` format for +the kernel and user-space respectively. `` is a hexadecimal event +descriptor which is the same format as used by perf-record(1): a +concatenation of the `Umask value` and `Event number` provided by the +processor's manufacturer. The possible values for this field are +processor-specific. The `` field is used to associate a clearer +name to the counter. + Application-specific context fields can be added to a channel using the following syntax: diff --git a/src/bin/lttng/commands/add_context.c b/src/bin/lttng/commands/add_context.c index 2f43dc7ff..5fc65bf55 100644 --- a/src/bin/lttng/commands/add_context.c +++ b/src/bin/lttng/commands/add_context.c @@ -87,6 +87,7 @@ enum perf_type { PERF_TYPE_HARDWARE = 0, PERF_TYPE_SOFTWARE = 1, PERF_TYPE_HW_CACHE = 3, + PERF_TYPE_RAW = 4, }; enum perf_count_hard { @@ -687,10 +688,101 @@ end: return type; } +static +int find_ctx_type_perf_raw(const char *ctx, struct ctx_type *type) +{ + int ret; + int field_pos = 0; + char *tmp_list, *cur_list; + + cur_list = tmp_list = strdup(ctx); + if (!tmp_list) { + PERROR("strdup temp list"); + ret = -ENOMEM; + goto end; + } + + /* Looking for "perf:[cpu|thread]:raw::". */ + for (;;) { + char *next; + + next = strtok(cur_list, ":"); + if (!next) { + break; + } + cur_list = NULL; + switch (field_pos) { + case 0: + if (strncmp(next, "perf", 4) != 0) { + ret = -1; + goto end; + } + break; + case 1: + if (strncmp(next, "cpu", 3) == 0) { + type->opt->ctx_type = CONTEXT_PERF_CPU_COUNTER; + } else if (strncmp(next, "thread", 4) == 0) { + type->opt->ctx_type = CONTEXT_PERF_THREAD_COUNTER; + } else { + ret = -1; + goto end; + } + break; + case 2: + if (strncmp(next, "raw", 3) != 0) { + ret = -1; + goto end; + } + break; + case 3: + { + char *endptr; + + if (strlen(next) < 2 || next[0] != 'r') { + ERR("Wrong perf raw mask format: expected rNNN"); + ret = -1; + goto end; + } + errno = 0; + type->opt->u.perf.config = strtoll(next + 1, &endptr, 16); + if (errno != 0 || !endptr || *endptr) { + ERR("Wrong perf raw mask format: expected rNNN"); + ret = -1; + goto end; + } + break; + } + case 4: + /* name */ + break; + case 5: + ERR("Too many ':' in perf raw format"); + ret = -1; + goto end; + }; + field_pos++; + } + + if (field_pos < 5) { + ERR("Invalid perf counter specifier, expected a specifier of " + "the form perf:cpu:raw:rNNN: or " + "perf:thread:raw:rNNN:"); + ret = -1; + goto end; + } + + ret = 0; + goto end; + +end: + free(tmp_list); + return ret; +} + static struct ctx_type *get_context_type(const char *ctx) { - int opt_index; + int opt_index, ret; struct ctx_type *type = NULL; const char app_ctx_prefix[] = "$app."; char *provider_name = NULL, *ctx_name = NULL; @@ -713,6 +805,18 @@ struct ctx_type *get_context_type(const char *ctx) goto found; } + /* Check if ctx is a raw perf context. */ + ret = find_ctx_type_perf_raw(ctx, type); + if (ret == 0) { + type->opt->u.perf.type = PERF_TYPE_RAW; + type->opt->symbol = strdup(ctx); + if (!type->opt->symbol) { + PERROR("Copy perf field name"); + goto not_found; + } + goto found; + } + /* * No match found against static contexts; check if it is an app * context.