[lttng-tools,v3,1/3] Enable perf PMU counters by raw ID
Commit Message
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:<name>" and "perf:thread:raw:rNNN:<name> 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 <name>
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 <jdesfossez at efficios.com>
---
doc/man/lttng-add-context.1.txt | 8 +++
src/bin/lttng/commands/add_context.c | 106 ++++++++++++++++++++++++++++++++++-
2 files changed, 113 insertions(+), 1 deletion(-)
@@ -45,6 +45,14 @@ 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<N>:<name>` or `perf:thread:raw:r<N>:<name>` format for the
+kernel and user-space respectively. `<N>` is a hexadecimal event descriptor
+which is the same format as perf-record(1): a concatenation of the `Umask
+value` and `Event number` provided by the processors manufacturer. The possible
+values for this field are processor-specific. The `<name>` 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:
@@ -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 {
@@ -688,9 +689,100 @@ end:
}
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:<mask>:<name>". */
+ 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: 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: 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:<name> or "
+ "perf:thread:raw:rNNN:<name>");
+ 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.