Subject: [PATCH 0/8] perf tools: Various updates

This patch set contains various perf tools updates. Most patches deal
with event naming. If the event name is unknown it is named like the
command line string of it. This is esp. valueable for pmu events like
for AMD IBS:

$ perf report | grep '^#.*event'
# event : name = ibs_op/cnt_ctl=1/GH, type = 7, config = 0x80000, config1 = 0x0, config2 = 0x0, excl_usr = 0, excl_kern = 0, excl_host = 0, excl_guest = 0, precise_ip = 0, id = {
# event : name = ibs_fetch/config=0/, type = 6, config = 0x0, config1 = 0x0, config2 = 0x0, excl_usr = 0, excl_kern = 0, excl_host = 0, excl_guest = 1, precise_ip = 0, id = { 57,
# Samples: 20K of event 'ibs_op/cnt_ctl=1/GH'
# Samples: 4K of event 'ibs_fetch/config=0/'

Another patch stores the pmu/type mapping in the header of perf.data.
Now the pmu types are known and event can be attributed to a certain
dynamically allocated pmu:

# pmu mappings: ibs_op = 7, ibs_fetch = 6, cpu = 4, breakpoint = 5, tracepoint = 2, software = 1

This is usefull for analysing the perf.data file on a system where the
pmu mappings are no longer available, e.g. on a remote system or if
the pmu has been unregistered.

Patches base on commit 0c21f736e0a37c50f66ab248d2a52f711b28a4e4
(acme/perf/core):

perf evlist: Introduce evsel list accessors (2012-08-15 10:14:18 -0300)

-Robert

Robert Richter (8):
perf tools: Fix type for evsel->ids and add size check for ids
perf tools: Report number of pmu type of unknown events
perf tools: Rename some variables for better understanding
perf tools: Rename global variable 'events' in util/header.c
perf tools: Catch event names from command line
perf tools: Refactor print_event_desc()
perf report: Update event names from header description
perf tools: Add pmu mappings to header information

tools/perf/util/evsel.c | 3 +-
tools/perf/util/evsel.h | 2 +-
tools/perf/util/header.c | 357 ++++++++++++++++++++++++++++++----------
tools/perf/util/header.h | 3 +-
tools/perf/util/parse-events.c | 12 ++
tools/perf/util/parse-events.h | 1 +
tools/perf/util/parse-events.l | 50 +++++-
tools/perf/util/parse-events.y | 20 ++-
tools/perf/util/pmu.c | 50 ++++++-
tools/perf/util/pmu.h | 2 +
10 files changed, 396 insertions(+), 104 deletions(-)

--
1.7.8.6


Subject: [PATCH 8/8] perf tools: Add pmu mappings to header information

With dynamic pmu allocation there are also dynamically assigned pmu
ids. These ids are used in event->attr.type to describe the pmu to be
used for that event. The information is available in sysfs, e.g:

/sys/bus/event_source/devices/breakpoint/type: 5
/sys/bus/event_source/devices/cpu/type: 4
/sys/bus/event_source/devices/ibs_fetch/type: 6
/sys/bus/event_source/devices/ibs_op/type: 7
/sys/bus/event_source/devices/software/type: 1
/sys/bus/event_source/devices/tracepoint/type: 2

These mappings are needed to know which samples belong to which pmu.
If a pmu is added dynamically like for ibs_fetch or ibs_op the type
value may vary.

Now, when decoding samples from perf.data this information in sysfs
might be no longer available or may have changed. We need to store it
in perf.data. Using the header for this. Now the header information
created with perf report contains an additional section looking like
this:

# pmu mappings: ibs_op = 7, ibs_fetch = 6, cpu = 4, breakpoint = 5, tracepoint = 2, software = 1

Signed-off-by: Robert Richter <[email protected]>
---
tools/perf/util/header.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/header.h | 1 +
tools/perf/util/pmu.c | 50 ++++++++++++++++++++++++++++-
tools/perf/util/pmu.h | 2 +
4 files changed, 129 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index c0311b3..26262d5 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -20,6 +20,7 @@
#include "symbol.h"
#include "debug.h"
#include "cpumap.h"
+#include "pmu.h"

static bool no_buildid_cache = false;

@@ -1004,6 +1005,45 @@ done:
}

/*
+ * File format:
+ *
+ * struct pmu_mappings {
+ * u32 pmu_num;
+ * struct pmu_map {
+ * u32 type;
+ * char name[];
+ * }[pmu_num];
+ * };
+ */
+
+static int write_pmu_mappings(int fd, struct perf_header *h __used,
+ struct perf_evlist *evlist __used)
+{
+ struct perf_pmu *pmu = NULL;
+ off_t offset = lseek(fd, 0, SEEK_CUR);
+ __u32 pmu_num = 0;
+
+ /* write real pmu_num later */
+ do_write(fd, &pmu_num, sizeof(pmu_num));
+
+ while ((pmu = perf_pmu__scan(pmu))) {
+ if (!pmu->name)
+ continue;
+ pmu_num++;
+ do_write(fd, &pmu->type, sizeof(pmu->type));
+ do_write_string(fd, pmu->name);
+ }
+
+ if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) {
+ /* discard all */
+ lseek(fd, offset, SEEK_SET);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
* default get_cpuid(): nothing gets recorded
* actual implementation must be in arch/$(ARCH)/util/header.c
*/
@@ -1389,6 +1429,43 @@ static void print_branch_stack(struct perf_header *ph __used, int fd __used,
fprintf(fp, "# contains samples with branch stack\n");
}

+static void print_pmu_mappings(struct perf_header *ph, int fd, FILE *fp)
+{
+ const char *delimiter = "# pmu mappings: ";
+ char *name;
+ int ret;
+ u32 pmu_num;
+ u32 type;
+
+ ret = read(fd, &pmu_num, sizeof(pmu_num));
+ if (ret != sizeof(pmu_num))
+ goto error;
+
+ if (!pmu_num) {
+ fprintf(fp, "# pmu mappings: not available\n");
+ return;
+ }
+
+ while (pmu_num) {
+ if (read(fd, &type, sizeof(type)) != sizeof(type))
+ break;
+ name = do_read_string(fd, ph);
+ if (!name)
+ break;
+ pmu_num--;
+ fprintf(fp, "%s%s = %" PRIu32, delimiter, name, type);
+ free(name);
+ delimiter = ", ";
+ }
+
+ fprintf(fp, "\n");
+
+ if (!pmu_num)
+ return;
+error:
+ fprintf(fp, "# pmu mappings: unable to read\n");
+}
+
static int __event_process_build_id(struct build_id_event *bev,
char *filename,
struct perf_session *session)
@@ -1644,6 +1721,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology),
FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
FEAT_OPA(HEADER_BRANCH_STACK, branch_stack),
+ FEAT_OPA(HEADER_PMU_MAPPINGS, pmu_mappings),
};

struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 24962e7..9d5eedc 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -28,6 +28,7 @@ enum {
HEADER_CPU_TOPOLOGY,
HEADER_NUMA_TOPOLOGY,
HEADER_BRANCH_STACK,
+ HEADER_PMU_MAPPINGS,
HEADER_LAST_FEATURE,
HEADER_FEAT_BITS = 256,
};
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 67715a4..6631d82 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -10,6 +10,8 @@
#include "pmu.h"
#include "parse-events.h"

+#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
+
int perf_pmu_parse(struct list_head *list, char *name);
extern FILE *perf_pmu_in;

@@ -69,7 +71,7 @@ static int pmu_format(char *name, struct list_head *format)
return -1;

snprintf(path, PATH_MAX,
- "%s/bus/event_source/devices/%s/format", sysfs, name);
+ "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name);

if (stat(path, &st) < 0)
return 0; /* no error if format does not exist */
@@ -206,7 +208,7 @@ static int pmu_type(char *name, __u32 *type)
return -1;

snprintf(path, PATH_MAX,
- "%s/bus/event_source/devices/%s/type", sysfs, name);
+ "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name);

if (stat(path, &st) < 0)
return -1;
@@ -222,6 +224,35 @@ static int pmu_type(char *name, __u32 *type)
return ret;
}

+/* Add all pmus in sysfs to pmu list: */
+static void pmu_read_sysfs(void)
+{
+ char path[PATH_MAX];
+ const char *sysfs;
+ DIR *dir;
+ struct dirent *dent;
+
+ sysfs = sysfs_find_mountpoint();
+ if (!sysfs)
+ return;
+
+ snprintf(path, PATH_MAX,
+ "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
+
+ dir = opendir(path);
+ if (!dir)
+ return;
+
+ while ((dent = readdir(dir))) {
+ if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+ continue;
+ /* add to static LIST_HEAD(pmus): */
+ perf_pmu__find(dent->d_name);
+ }
+
+ closedir(dir);
+}
+
static struct perf_pmu *pmu_lookup(char *name)
{
struct perf_pmu *pmu;
@@ -267,6 +298,21 @@ static struct perf_pmu *pmu_find(char *name)
return NULL;
}

+struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
+{
+ /*
+ * pmu iterator: If pmu is NULL, we start at the begin,
+ * otherwise return the next pmu. Returns NULL on end.
+ */
+ if (!pmu) {
+ pmu_read_sysfs();
+ pmu = list_prepare_entry(pmu, &pmus, list);
+ }
+ list_for_each_entry_continue(pmu, &pmus, list)
+ return pmu;
+ return NULL;
+}
+
struct perf_pmu *perf_pmu__find(char *name)
{
struct perf_pmu *pmu;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 535f2c5..47f68d3 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -46,5 +46,7 @@ int perf_pmu__new_format(struct list_head *list, char *name,
int config, unsigned long *bits);
void perf_pmu__set_format(unsigned long *bits, long from, long to);

+struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
+
int perf_pmu__test(void);
#endif /* __PMU_H */
--
1.7.8.6

Subject: [PATCH 2/8] perf tools: Report number of pmu type of unknown events

If detection fails and an event name is unknown, report the type
number. Example perf header output:

# Samples: 10K of event 'unknown attr type: 7'

Signed-off-by: Robert Richter <[email protected]>
---
tools/perf/util/evsel.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 6c7dcc1..7ff3c8f 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -319,7 +319,8 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
break;

default:
- scnprintf(bf, sizeof(bf), "%s", "unknown attr type");
+ scnprintf(bf, sizeof(bf), "unknown attr type: %d",
+ evsel->attr.type);
break;
}

--
1.7.8.6

Subject: [PATCH 4/8] perf tools: Rename global variable 'events' in util/header.c

Trivial patch that renames global variable 'events' in util/header.c.

Use a more specific naming to avoid conflicts. Same for variable
'event_count'.

Signed-off-by: Robert Richter <[email protected]>
---
tools/perf/util/header.c | 40 ++++++++++++++++++++--------------------
1 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index e2e5129..1e5b6aa 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -23,8 +23,8 @@

static bool no_buildid_cache = false;

-static int event_count;
-static struct perf_trace_event_type *events;
+static int trace_event_count;
+static struct perf_trace_event_type *trace_events;

static u32 header_argc;
static const char **header_argv;
@@ -36,24 +36,24 @@ int perf_header__push_event(u64 id, const char *name)
if (strlen(name) > MAX_EVENT_NAME)
pr_warning("Event %s will be truncated\n", name);

- nevents = realloc(events, (event_count + 1) * sizeof(*events));
+ nevents = realloc(trace_events, (trace_event_count + 1) * sizeof(*trace_events));
if (nevents == NULL)
return -ENOMEM;
- events = nevents;
+ trace_events = nevents;

- memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
- events[event_count].event_id = id;
- strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
- event_count++;
+ memset(&trace_events[trace_event_count], 0, sizeof(struct perf_trace_event_type));
+ trace_events[trace_event_count].event_id = id;
+ strncpy(trace_events[trace_event_count].name, name, MAX_EVENT_NAME - 1);
+ trace_event_count++;
return 0;
}

char *perf_header__find_event(u64 id)
{
int i;
- for (i = 0 ; i < event_count; i++) {
- if (events[i].event_id == id)
- return events[i].name;
+ for (i = 0 ; i < trace_event_count; i++) {
+ if (trace_events[i].event_id == id)
+ return trace_events[i].name;
}
return NULL;
}
@@ -1726,9 +1726,9 @@ out_err_write:
}

header->event_offset = lseek(fd, 0, SEEK_CUR);
- header->event_size = event_count * sizeof(struct perf_trace_event_type);
- if (events) {
- err = do_write(fd, events, header->event_size);
+ header->event_size = trace_event_count * sizeof(struct perf_trace_event_type);
+ if (trace_events) {
+ err = do_write(fd, trace_events, header->event_size);
if (err < 0) {
pr_debug("failed to write perf header events\n");
return err;
@@ -2211,13 +2211,13 @@ int perf_session__read_header(struct perf_session *session, int fd)

if (f_header.event_types.size) {
lseek(fd, f_header.event_types.offset, SEEK_SET);
- events = malloc(f_header.event_types.size);
- if (events == NULL)
+ trace_events = malloc(f_header.event_types.size);
+ if (trace_events == NULL)
return -ENOMEM;
- if (perf_header__getbuffer64(header, fd, events,
+ if (perf_header__getbuffer64(header, fd, trace_events,
f_header.event_types.size))
goto out_errno;
- event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
+ trace_event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
}

perf_header__process_sections(header, fd, &session->pevent,
@@ -2362,8 +2362,8 @@ int perf_event__synthesize_event_types(struct perf_tool *tool,
struct perf_trace_event_type *type;
int i, err = 0;

- for (i = 0; i < event_count; i++) {
- type = &events[i];
+ for (i = 0; i < trace_event_count; i++) {
+ type = &trace_events[i];

err = perf_event__synthesize_event_type(tool, type->event_id,
type->name, process,
--
1.7.8.6

Subject: [PATCH 5/8] perf tools: Catch event names from command line

Use command line string provided by the -e option to name events. This
way we get unique events names that also support pmu event syntax
(<pmu_name>/<config>/<modifier>). No need to reconstruct the name
anymore from its attributes. We use the event_desc of the header to
store the name in the perf.data header. Thus it is also available for
perf report.

Implemented by putting the parser in different states to parse events
or configs.

Signed-off-by: Robert Richter <[email protected]>
---
tools/perf/util/parse-events.c | 12 +++++++++
tools/perf/util/parse-events.h | 1 +
tools/perf/util/parse-events.l | 50 ++++++++++++++++++++++++++++++++--------
tools/perf/util/parse-events.y | 20 ++++++++++++++-
4 files changed, 71 insertions(+), 12 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 925784a..b246303 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -751,6 +751,18 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add)
return 0;
}

+int parse_events_name(struct list_head *list, char *name)
+{
+ struct perf_evsel *evsel;
+
+ list_for_each_entry(evsel, list, node) {
+ if (!evsel->name)
+ evsel->name = strdup(name);
+ }
+
+ return 0;
+}
+
static int parse_events__scanner(const char *str, void *data, int start_token)
{
YY_BUFFER_STATE buffer;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 0b9782d..c356e44 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -81,6 +81,7 @@ int parse_events__term_clone(struct parse_events__term **new,
void parse_events__free_terms(struct list_head *terms);
int parse_events__modifier_event(struct list_head *list, char *str, bool add);
int parse_events__modifier_group(struct list_head *list, char *event_mod);
+int parse_events_name(struct list_head *list, char *name);
int parse_events_add_tracepoint(struct list_head **list, int *idx,
char *sys, char *event);
int parse_events_add_numeric(struct list_head **list, int *idx,
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 2c0d006..f5e28dc 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -70,6 +70,12 @@ static int term(yyscan_t scanner, int type)
%}

%x mem
+%s config
+%x event
+
+group [^,{}/]*[{][^}]*[}][^,{}/]*
+event_pmu [^,{}/]+[/][^/]*[/][^,{}/]*
+event [^,{}/]+

num_dec [0-9]+
num_hex 0x[a-fA-F0-9]+
@@ -84,7 +90,13 @@ modifier_bp [rwx]{1,3}
{
int start_token;

- start_token = (int) parse_events_get_extra(yyscanner);
+ start_token = parse_events_get_extra(yyscanner);
+
+ if (start_token == PE_START_TERMS)
+ BEGIN(config);
+ else if (start_token == PE_START_EVENTS)
+ BEGIN(event);
+
if (start_token) {
parse_events_set_extra(NULL, yyscanner);
return start_token;
@@ -92,6 +104,26 @@ modifier_bp [rwx]{1,3}
}
%}

+<event>{
+
+{group} {
+ BEGIN(INITIAL); yyless(0);
+ }
+
+{event_pmu} |
+{event} {
+ str(yyscanner, PE_EVENT_NAME);
+ BEGIN(INITIAL); yyless(0);
+ return PE_EVENT_NAME;
+ }
+
+. |
+<<EOF>> {
+ BEGIN(INITIAL); yyless(0);
+ }
+
+}
+
cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
@@ -127,18 +159,16 @@ speculative-read|speculative-load |
refs|Reference|ops|access |
misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); }

- /*
- * These are event config hardcoded term names to be specified
- * within xxx/.../ syntax. So far we dont clash with other names,
- * so we can put them here directly. In case the we have a conflict
- * in future, this needs to go into '//' condition block.
- */
+<config>{
config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
+, { return ','; }
+"/" { BEGIN(INITIAL); return '/'; }
+}

mem: { BEGIN(mem); return PE_PREFIX_MEM; }
r{num_raw_hex} { return raw(yyscanner); }
@@ -147,11 +177,11 @@ r{num_raw_hex} { return raw(yyscanner); }

{modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); }
{name} { return str(yyscanner, PE_NAME); }
-"/" { return '/'; }
+"/" { BEGIN(config); return '/'; }
- { return '-'; }
-, { return ','; }
+, { BEGIN(event); return ','; }
: { return ':'; }
-"{" { return '{'; }
+"{" { BEGIN(event); return '{'; }
"}" { return '}'; }
= { return '='; }
\n { }
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 66850f8..42d9a17 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -27,6 +27,7 @@ do { \

%token PE_START_EVENTS PE_START_TERMS
%token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM
+%token PE_EVENT_NAME
%token PE_NAME
%token PE_MODIFIER_EVENT PE_MODIFIER_BP
%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
@@ -42,6 +43,7 @@ do { \
%type <str> PE_NAME_CACHE_OP_RESULT
%type <str> PE_MODIFIER_EVENT
%type <str> PE_MODIFIER_BP
+%type <str> PE_EVENT_NAME
%type <num> value_sym
%type <head> event_config
%type <term> event_term
@@ -53,6 +55,8 @@ do { \
%type <head> event_legacy_numeric
%type <head> event_legacy_raw
%type <head> event_def
+%type <head> event_mod
+%type <head> event_name
%type <head> event
%type <head> events
%type <head> group_def
@@ -143,8 +147,10 @@ events ',' event
|
event

-event:
-event_def PE_MODIFIER_EVENT
+event: event_mod
+
+event_mod:
+event_name PE_MODIFIER_EVENT
{
struct list_head *list = $1;

@@ -157,6 +163,16 @@ event_def PE_MODIFIER_EVENT
$$ = list;
}
|
+event_name
+
+event_name:
+PE_EVENT_NAME event_def
+{
+ ABORT_ON(parse_events_name($2, $1));
+ free($1);
+ $$ = $2;
+}
+|
event_def

event_def: event_pmu |
--
1.7.8.6

Subject: [PATCH 6/8] perf tools: Refactor print_event_desc()

For later use we need a function read_event_desc() for processing the
event_desc feature. Split it from print_event_desc().

Signed-off-by: Robert Richter <[email protected]>
---
tools/perf/util/header.c | 134 ++++++++++++++++++++++++++++++++--------------
1 files changed, 93 insertions(+), 41 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 1e5b6aa..7454cf4 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1148,12 +1148,29 @@ static void print_cpu_topology(struct perf_header *ph, int fd, FILE *fp)
}
}

-static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
+static void free_event_desc(struct perf_evsel *events)
{
- struct perf_event_attr attr;
- uint64_t id;
+ struct perf_evsel *evsel;
+
+ if (!events)
+ return;
+
+ for (evsel = events; evsel->attr.size; evsel++) {
+ if (evsel->name)
+ free(evsel->name);
+ if (evsel->id)
+ free(evsel->id);
+ }
+
+ free(events);
+}
+
+static struct perf_evsel *
+read_event_desc(struct perf_header *ph, int fd)
+{
+ struct perf_evsel *evsel, *events = NULL;
+ u64 *id;
void *buf = NULL;
- char *str;
u32 nre, sz, nr, i, j;
ssize_t ret;
size_t msz;
@@ -1173,18 +1190,22 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
if (ph->needs_swap)
sz = bswap_32(sz);

- memset(&attr, 0, sizeof(attr));
-
/* buffer to hold on file attr struct */
buf = malloc(sz);
if (!buf)
goto error;

- msz = sizeof(attr);
+ /* the last event terminates with evsel->attr.size == 0: */
+ events = calloc(nre + 1, sizeof(*events));
+ if (!events)
+ goto error;
+
+ msz = sizeof(evsel->attr);
if (sz < msz)
msz = sz;

- for (i = 0 ; i < nre; i++) {
+ for (i = 0, evsel = events; i < nre; evsel++, i++) {
+ evsel->idx = i;

/*
* must read entire on-file attr struct to
@@ -1197,7 +1218,7 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
if (ph->needs_swap)
perf_event__attr_swap(buf);

- memcpy(&attr, buf, msz);
+ memcpy(&evsel->attr, buf, msz);

ret = read(fd, &nr, sizeof(nr));
if (ret != (ssize_t)sizeof(nr))
@@ -1206,51 +1227,82 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
if (ph->needs_swap)
nr = bswap_32(nr);

- str = do_read_string(fd, ph);
- fprintf(fp, "# event : name = %s, ", str);
- free(str);
+ evsel->name = do_read_string(fd, ph);
+
+ if (!nr)
+ continue;
+
+ id = calloc(nr, sizeof(*id));
+ if (!id)
+ goto error;
+ evsel->ids = nr;
+ evsel->id = id;
+
+ for (j = 0 ; j < nr; j++) {
+ ret = read(fd, id, sizeof(*id));
+ if (ret != (ssize_t)sizeof(*id))
+ goto error;
+ if (ph->needs_swap)
+ *id = bswap_64(*id);
+ id++;
+ }
+ }
+out:
+ if (buf)
+ free(buf);
+ return events;
+error:
+ if (events)
+ free_event_desc(events);
+ events = NULL;
+ goto out;
+}
+
+static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
+{
+ struct perf_evsel *evsel, *events = read_event_desc(ph, fd);
+ u32 j;
+ u64 *id;
+
+ if (!events) {
+ fprintf(fp, "# event desc: not available or unable to read\n");
+ return;
+ }
+
+ for (evsel = events; evsel->attr.size; evsel++) {
+ fprintf(fp, "# event : name = %s, ", evsel->name);

fprintf(fp, "type = %d, config = 0x%"PRIx64
", config1 = 0x%"PRIx64", config2 = 0x%"PRIx64,
- attr.type,
- (u64)attr.config,
- (u64)attr.config1,
- (u64)attr.config2);
+ evsel->attr.type,
+ (u64)evsel->attr.config,
+ (u64)evsel->attr.config1,
+ (u64)evsel->attr.config2);

fprintf(fp, ", excl_usr = %d, excl_kern = %d",
- attr.exclude_user,
- attr.exclude_kernel);
+ evsel->attr.exclude_user,
+ evsel->attr.exclude_kernel);

fprintf(fp, ", excl_host = %d, excl_guest = %d",
- attr.exclude_host,
- attr.exclude_guest);
+ evsel->attr.exclude_host,
+ evsel->attr.exclude_guest);

- fprintf(fp, ", precise_ip = %d", attr.precise_ip);
+ fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip);

- if (nr)
+ if (evsel->ids) {
fprintf(fp, ", id = {");
-
- for (j = 0 ; j < nr; j++) {
- ret = read(fd, &id, sizeof(id));
- if (ret != (ssize_t)sizeof(id))
- goto error;
-
- if (ph->needs_swap)
- id = bswap_64(id);
-
- if (j)
- fputc(',', fp);
-
- fprintf(fp, " %"PRIu64, id);
- }
- if (nr && j == nr)
+ for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) {
+ if (j)
+ fputc(',', fp);
+ fprintf(fp, " %"PRIu64, *id);
+ }
fprintf(fp, " }");
+ }
+
fputc('\n', fp);
}
- free(buf);
- return;
-error:
- fprintf(fp, "# event desc: not available or unable to read\n");
+
+ free_event_desc(events);
}

static void print_total_mem(struct perf_header *h __used, int fd, FILE *fp)
--
1.7.8.6

Subject: [PATCH 7/8] perf report: Update event names from header description

Name events based on the event description in the perf.data header.

Example output:

$ perf report | grep '^#.*event'
# event : name = ibs_op/cnt_ctl=1/GH, type = 7, config = 0x80000, config1 = 0x0, config2 = 0x0, excl_usr = 0, excl_kern = 0, excl_host = 0, excl_guest = 0, precise_ip = 0, id = { 49, 50, 51, 52, 53, 54, 55, 56 }
# event : name = ibs_fetch/config=0/, type = 6, config = 0x0, config1 = 0x0, config2 = 0x0, excl_usr = 0, excl_kern = 0, excl_host = 0, excl_guest = 1, precise_ip = 0, id = { 57, 58, 59, 60, 61, 62, 63, 64 }
# Samples: 20K of event 'ibs_op/cnt_ctl=1/GH'
# Samples: 4K of event 'ibs_fetch/config=0/'

Note the new pmu event syntax of the names.

Signed-off-by: Robert Richter <[email protected]>
---
tools/perf/util/header.c | 52 +++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 51 insertions(+), 1 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 7454cf4..c0311b3 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1556,6 +1556,56 @@ static int process_build_id(struct perf_file_section *section,
return 0;
}

+static struct perf_evsel *
+perf_evlist_find_by_index(struct perf_evlist *evlist, int idx)
+{
+ struct perf_evsel *evsel;
+
+ list_for_each_entry(evsel, &evlist->entries, node) {
+ if (evsel->idx == idx)
+ return evsel;
+ }
+
+ return NULL;
+}
+
+static void
+perf_evlist__set_event_name(struct perf_evlist *evlist, struct perf_evsel *event)
+{
+ struct perf_evsel *evsel;
+
+ if (!event->name)
+ return;
+
+ evsel = perf_evlist_find_by_index(evlist, event->idx);
+ if (!evsel)
+ return;
+
+ if (evsel->name)
+ return;
+
+ evsel->name = strdup(event->name);
+}
+
+static int
+process_event_desc(struct perf_file_section *section __unused,
+ struct perf_header *header, int feat __unused, int fd,
+ void *data __used)
+{
+ struct perf_session *session = container_of(header, struct perf_session, header);
+ struct perf_evsel *evsel, *events = read_event_desc(header, fd);
+
+ if (!events)
+ return 0;
+
+ for (evsel = events; evsel->attr.size; evsel++)
+ perf_evlist__set_event_name(session->evlist, evsel);
+
+ free_event_desc(events);
+
+ return 0;
+}
+
struct feature_ops {
int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1589,7 +1639,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPA(HEADER_CPUDESC, cpudesc),
FEAT_OPA(HEADER_CPUID, cpuid),
FEAT_OPA(HEADER_TOTAL_MEM, total_mem),
- FEAT_OPA(HEADER_EVENT_DESC, event_desc),
+ FEAT_OPP(HEADER_EVENT_DESC, event_desc),
FEAT_OPA(HEADER_CMDLINE, cmdline),
FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology),
FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
--
1.7.8.6

Subject: [PATCH 1/8] perf tools: Fix type for evsel->ids and add size check for ids

Use same type for ids everywhere.

In case of writing to perf.data the size is u32. In pipe mode it is
limited to header.size (less than u16). Adding a size check here.

Size overflow due to casting shouldn't actually happen in practice,
but during development this may cause type missmatch warninngs/errors,
unifying types avoids this.

Signed-off-by: Robert Richter <[email protected]>
---
tools/perf/util/evsel.h | 2 +-
tools/perf/util/header.c | 11 +++++++----
tools/perf/util/header.h | 2 +-
3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 65f39fd..94f6ba1 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -53,7 +53,7 @@ struct perf_evsel {
u64 *id;
struct perf_counts *counts;
int idx;
- int ids;
+ u32 ids;
struct hists hists;
char *name;
struct event_format *tp_format;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 77832b8..471b0c4 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2240,7 +2240,7 @@ out_delete_evlist:
}

int perf_event__synthesize_attr(struct perf_tool *tool,
- struct perf_event_attr *attr, u16 ids, u64 *id,
+ struct perf_event_attr *attr, u32 ids, u64 *id,
perf_event__handler_t process)
{
union perf_event *ev;
@@ -2261,9 +2261,12 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
memcpy(ev->attr.id, id, ids * sizeof(u64));

ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
- ev->attr.header.size = size;
+ ev->attr.header.size = (u16)size;

- err = process(tool, ev, NULL, NULL);
+ if (ev->attr.header.size == size)
+ err = process(tool, ev, NULL, NULL);
+ else
+ err = -E2BIG;

free(ev);

@@ -2292,7 +2295,7 @@ int perf_event__synthesize_attrs(struct perf_tool *tool,
int perf_event__process_attr(union perf_event *event,
struct perf_evlist **pevlist)
{
- unsigned int i, ids, n_ids;
+ u32 i, ids, n_ids;
struct perf_evsel *evsel;
struct perf_evlist *evlist = *pevlist;

diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 2d42b3e..24962e7 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -99,7 +99,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);

int perf_event__synthesize_attr(struct perf_tool *tool,
- struct perf_event_attr *attr, u16 ids, u64 *id,
+ struct perf_event_attr *attr, u32 ids, u64 *id,
perf_event__handler_t process);
int perf_event__synthesize_attrs(struct perf_tool *tool,
struct perf_session *session,
--
1.7.8.6

Subject: [PATCH 3/8] perf tools: Rename some variables for better understanding

Trivial patch to improve understanding of code.

Varible attr is usually used for struct perf_event_attr. Using it in a
different context is irritating. Thus, renaming it.

Signed-off-by: Robert Richter <[email protected]>
---
tools/perf/util/header.c | 42 +++++++++++++++++++++---------------------
1 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 471b0c4..e2e5129 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -608,11 +608,11 @@ static int write_nrcpus(int fd, struct perf_header *h __used,
static int write_event_desc(int fd, struct perf_header *h __used,
struct perf_evlist *evlist)
{
- struct perf_evsel *attr;
+ struct perf_evsel *evsel;
u32 nre = 0, nri, sz;
int ret;

- list_for_each_entry(attr, &evlist->entries, node)
+ list_for_each_entry(evsel, &evlist->entries, node)
nre++;

/*
@@ -625,14 +625,14 @@ static int write_event_desc(int fd, struct perf_header *h __used,
/*
* size of perf_event_attr struct
*/
- sz = (u32)sizeof(attr->attr);
+ sz = (u32)sizeof(evsel->attr);
ret = do_write(fd, &sz, sizeof(sz));
if (ret < 0)
return ret;

- list_for_each_entry(attr, &evlist->entries, node) {
+ list_for_each_entry(evsel, &evlist->entries, node) {

- ret = do_write(fd, &attr->attr, sz);
+ ret = do_write(fd, &evsel->attr, sz);
if (ret < 0)
return ret;
/*
@@ -642,7 +642,7 @@ static int write_event_desc(int fd, struct perf_header *h __used,
* copy into an nri to be independent of the
* type of ids,
*/
- nri = attr->ids;
+ nri = evsel->ids;
ret = do_write(fd, &nri, sizeof(nri));
if (ret < 0)
return ret;
@@ -650,13 +650,13 @@ static int write_event_desc(int fd, struct perf_header *h __used,
/*
* write event string as passed on cmdline
*/
- ret = do_write_string(fd, perf_evsel__name(attr));
+ ret = do_write_string(fd, perf_evsel__name(evsel));
if (ret < 0)
return ret;
/*
* write unique ids for this event
*/
- ret = do_write(fd, attr->id, attr->ids * sizeof(u64));
+ ret = do_write(fd, evsel->id, evsel->ids * sizeof(u64));
if (ret < 0)
return ret;
}
@@ -1683,7 +1683,7 @@ int perf_session__write_header(struct perf_session *session,
struct perf_file_header f_header;
struct perf_file_attr f_attr;
struct perf_header *header = &session->header;
- struct perf_evsel *attr, *pair = NULL;
+ struct perf_evsel *evsel, *pair = NULL;
int err;

lseek(fd, sizeof(f_header), SEEK_SET);
@@ -1691,9 +1691,9 @@ int perf_session__write_header(struct perf_session *session,
if (session->evlist != evlist)
pair = perf_evlist__first(session->evlist);

- list_for_each_entry(attr, &evlist->entries, node) {
- attr->id_offset = lseek(fd, 0, SEEK_CUR);
- err = do_write(fd, attr->id, attr->ids * sizeof(u64));
+ list_for_each_entry(evsel, &evlist->entries, node) {
+ evsel->id_offset = lseek(fd, 0, SEEK_CUR);
+ err = do_write(fd, evsel->id, evsel->ids * sizeof(u64));
if (err < 0) {
out_err_write:
pr_debug("failed to write perf header\n");
@@ -1703,19 +1703,19 @@ out_err_write:
err = do_write(fd, pair->id, pair->ids * sizeof(u64));
if (err < 0)
goto out_err_write;
- attr->ids += pair->ids;
+ evsel->ids += pair->ids;
pair = perf_evsel__next(pair);
}
}

header->attr_offset = lseek(fd, 0, SEEK_CUR);

- list_for_each_entry(attr, &evlist->entries, node) {
+ list_for_each_entry(evsel, &evlist->entries, node) {
f_attr = (struct perf_file_attr){
- .attr = attr->attr,
+ .attr = evsel->attr,
.ids = {
- .offset = attr->id_offset,
- .size = attr->ids * sizeof(u64),
+ .offset = evsel->id_offset,
+ .size = evsel->ids * sizeof(u64),
}
};
err = do_write(fd, &f_attr, sizeof(f_attr));
@@ -2277,12 +2277,12 @@ int perf_event__synthesize_attrs(struct perf_tool *tool,
struct perf_session *session,
perf_event__handler_t process)
{
- struct perf_evsel *attr;
+ struct perf_evsel *evsel;
int err = 0;

- list_for_each_entry(attr, &session->evlist->entries, node) {
- err = perf_event__synthesize_attr(tool, &attr->attr, attr->ids,
- attr->id, process);
+ list_for_each_entry(evsel, &session->evlist->entries, node) {
+ err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids,
+ evsel->id, process);
if (err) {
pr_debug("failed to create perf header attribute\n");
return err;
--
1.7.8.6

2012-08-17 15:35:01

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 3/8] perf tools: Rename some variables for better understanding

Em Thu, Aug 16, 2012 at 09:10:19PM +0200, Robert Richter escreveu:
> Trivial patch to improve understanding of code.
>
> Varible attr is usually used for struct perf_event_attr. Using it in a
> different context is irritating. Thus, renaming it.

Right, this is historical stuff, originally it was a perf_event_attr, so
'attr', when I converted it to evsel I kept 'attr' to reduce the patch
size.

Anyway, applying, thanks,

- Arnaldo

> Signed-off-by: Robert Richter <[email protected]>
> ---
> tools/perf/util/header.c | 42 +++++++++++++++++++++---------------------
> 1 files changed, 21 insertions(+), 21 deletions(-)
>
> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> index 471b0c4..e2e5129 100644
> --- a/tools/perf/util/header.c
> +++ b/tools/perf/util/header.c
> @@ -608,11 +608,11 @@ static int write_nrcpus(int fd, struct perf_header *h __used,
> static int write_event_desc(int fd, struct perf_header *h __used,
> struct perf_evlist *evlist)
> {
> - struct perf_evsel *attr;
> + struct perf_evsel *evsel;
> u32 nre = 0, nri, sz;
> int ret;
>
> - list_for_each_entry(attr, &evlist->entries, node)
> + list_for_each_entry(evsel, &evlist->entries, node)
> nre++;
>
> /*
> @@ -625,14 +625,14 @@ static int write_event_desc(int fd, struct perf_header *h __used,
> /*
> * size of perf_event_attr struct
> */
> - sz = (u32)sizeof(attr->attr);
> + sz = (u32)sizeof(evsel->attr);
> ret = do_write(fd, &sz, sizeof(sz));
> if (ret < 0)
> return ret;
>
> - list_for_each_entry(attr, &evlist->entries, node) {
> + list_for_each_entry(evsel, &evlist->entries, node) {
>
> - ret = do_write(fd, &attr->attr, sz);
> + ret = do_write(fd, &evsel->attr, sz);
> if (ret < 0)
> return ret;
> /*
> @@ -642,7 +642,7 @@ static int write_event_desc(int fd, struct perf_header *h __used,
> * copy into an nri to be independent of the
> * type of ids,
> */
> - nri = attr->ids;
> + nri = evsel->ids;
> ret = do_write(fd, &nri, sizeof(nri));
> if (ret < 0)
> return ret;
> @@ -650,13 +650,13 @@ static int write_event_desc(int fd, struct perf_header *h __used,
> /*
> * write event string as passed on cmdline
> */
> - ret = do_write_string(fd, perf_evsel__name(attr));
> + ret = do_write_string(fd, perf_evsel__name(evsel));
> if (ret < 0)
> return ret;
> /*
> * write unique ids for this event
> */
> - ret = do_write(fd, attr->id, attr->ids * sizeof(u64));
> + ret = do_write(fd, evsel->id, evsel->ids * sizeof(u64));
> if (ret < 0)
> return ret;
> }
> @@ -1683,7 +1683,7 @@ int perf_session__write_header(struct perf_session *session,
> struct perf_file_header f_header;
> struct perf_file_attr f_attr;
> struct perf_header *header = &session->header;
> - struct perf_evsel *attr, *pair = NULL;
> + struct perf_evsel *evsel, *pair = NULL;
> int err;
>
> lseek(fd, sizeof(f_header), SEEK_SET);
> @@ -1691,9 +1691,9 @@ int perf_session__write_header(struct perf_session *session,
> if (session->evlist != evlist)
> pair = perf_evlist__first(session->evlist);
>
> - list_for_each_entry(attr, &evlist->entries, node) {
> - attr->id_offset = lseek(fd, 0, SEEK_CUR);
> - err = do_write(fd, attr->id, attr->ids * sizeof(u64));
> + list_for_each_entry(evsel, &evlist->entries, node) {
> + evsel->id_offset = lseek(fd, 0, SEEK_CUR);
> + err = do_write(fd, evsel->id, evsel->ids * sizeof(u64));
> if (err < 0) {
> out_err_write:
> pr_debug("failed to write perf header\n");
> @@ -1703,19 +1703,19 @@ out_err_write:
> err = do_write(fd, pair->id, pair->ids * sizeof(u64));
> if (err < 0)
> goto out_err_write;
> - attr->ids += pair->ids;
> + evsel->ids += pair->ids;
> pair = perf_evsel__next(pair);
> }
> }
>
> header->attr_offset = lseek(fd, 0, SEEK_CUR);
>
> - list_for_each_entry(attr, &evlist->entries, node) {
> + list_for_each_entry(evsel, &evlist->entries, node) {
> f_attr = (struct perf_file_attr){
> - .attr = attr->attr,
> + .attr = evsel->attr,
> .ids = {
> - .offset = attr->id_offset,
> - .size = attr->ids * sizeof(u64),
> + .offset = evsel->id_offset,
> + .size = evsel->ids * sizeof(u64),
> }
> };
> err = do_write(fd, &f_attr, sizeof(f_attr));
> @@ -2277,12 +2277,12 @@ int perf_event__synthesize_attrs(struct perf_tool *tool,
> struct perf_session *session,
> perf_event__handler_t process)
> {
> - struct perf_evsel *attr;
> + struct perf_evsel *evsel;
> int err = 0;
>
> - list_for_each_entry(attr, &session->evlist->entries, node) {
> - err = perf_event__synthesize_attr(tool, &attr->attr, attr->ids,
> - attr->id, process);
> + list_for_each_entry(evsel, &session->evlist->entries, node) {
> + err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids,
> + evsel->id, process);
> if (err) {
> pr_debug("failed to create perf header attribute\n");
> return err;
> --
> 1.7.8.6
>

2012-08-17 16:18:54

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 0/8] perf tools: Various updates

Em Thu, Aug 16, 2012 at 09:10:16PM +0200, Robert Richter escreveu:
> This patch set contains various perf tools updates. Most patches deal
> with event naming. If the event name is unknown it is named like the
> command line string of it. This is esp. valueable for pmu events like
> for AMD IBS:
>
> $ perf report | grep '^#.*event'
> # event : name = ibs_op/cnt_ctl=1/GH, type = 7, config = 0x80000, config1 = 0x0, config2 = 0x0, excl_usr = 0, excl_kern = 0, excl_host = 0, excl_guest = 0, precise_ip = 0, id = {
> # event : name = ibs_fetch/config=0/, type = 6, config = 0x0, config1 = 0x0, config2 = 0x0, excl_usr = 0, excl_kern = 0, excl_host = 0, excl_guest = 1, precise_ip = 0, id = { 57,
> # Samples: 20K of event 'ibs_op/cnt_ctl=1/GH'
> # Samples: 4K of event 'ibs_fetch/config=0/'

There is a command for that pipe sequence:

[root@sandy ~]# perf record -e cache-misses:u,cycles:k,instructions usleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.020 MB perf.data (~861 samples) ]
[root@sandy ~]# perf evlist
cache-misses:u
cycles:k
instructions
[root@sandy ~]# perf evlist -v
cache-misses:u: sample_freq=4000, config: 3, size: 96, sample_type: 327, read_format: 7, disabled: 1, inherit: 1, exclude_kernel: 1, exclude_hv: 1, mmap: 1, comm: 1, freq: 1, enable_on_exec: 1, sample_id_all: 1
cycles:k: sample_freq=4000, size: 96, sample_type: 327, read_format: 7, disabled: 1, inherit: 1, exclude_user: 1, exclude_hv: 1, freq: 1, enable_on_exec: 1, sample_id_all: 1
instructions: sample_freq=4000, config: 1, size: 96, sample_type: 327, read_format: 7, disabled: 1, inherit: 1, freq: 1, enable_on_exec: 1, sample_id_all: 1, exclude_guest: 1
[root@sandy ~]#

- Arnaldo

2012-08-20 17:42:57

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH 5/8] perf tools: Catch event names from command line

On Thu, Aug 16, 2012 at 09:10:21PM +0200, Robert Richter wrote:
> Use command line string provided by the -e option to name events. This
> way we get unique events names that also support pmu event syntax
> (<pmu_name>/<config>/<modifier>). No need to reconstruct the name
> anymore from its attributes. We use the event_desc of the header to
> store the name in the perf.data header. Thus it is also available for
> perf report.
>
> Implemented by putting the parser in different states to parse events
> or configs.

I like the idea of multiple states in parser,
but parse tests fails:

[jolsa@krava perf]$ ./perf test -vvv parse
5: parse events tests:
--- start ---
running test 0 'syscalls:sys_enter_open'
running test 1 'syscalls:*'
running test 2 'r1a'
running test 3 '1:1'
running test 4 'instructions'
running test 5 'cycles/period=100000,config2/'
running test 6 'faults'
running test 7 'L1-dcache-load-miss'
running test 8 'mem:0'
running test 9 'mem:0:x'
running test 10 'mem:0:r'
running test 11 'mem:0:w'
running test 12 'syscalls:sys_enter_open:k'
running test 13 'syscalls:*:u'
running test 14 'r1a:kp'
running test 15 '1:1:hp'
running test 16 'instructions:h'
running test 17 'faults:u'
running test 18 'L1-dcache-load-miss:kp'
running test 19 'mem:0:u'
FAILED util/parse-events-test.c:309 wrong name
---- end ----
parse events tests: FAILED!


jirka

Subject: [tip:perf/core] perf tools: Fix type for evsel-> ids and add size check for ids

Commit-ID: f4d834367cda98eee3769638da6ad687607c74e6
Gitweb: http://git.kernel.org/tip/f4d834367cda98eee3769638da6ad687607c74e6
Author: Robert Richter <[email protected]>
AuthorDate: Thu, 16 Aug 2012 21:10:17 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Fri, 17 Aug 2012 12:38:07 -0300

perf tools: Fix type for evsel->ids and add size check for ids

Use same type for ids everywhere.

In case of writing to perf.data the size is u32. In pipe mode it is
limited to header.size (less than u16). Adding a size check here.

Size overflow due to casting shouldn't actually happen in practice, but
during development this may cause type missmatch warninngs/errors,
unifying types avoids this.

Signed-off-by: Robert Richter <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/evsel.h | 2 +-
tools/perf/util/header.c | 11 +++++++----
tools/perf/util/header.h | 2 +-
3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 65f39fd..94f6ba1 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -53,7 +53,7 @@ struct perf_evsel {
u64 *id;
struct perf_counts *counts;
int idx;
- int ids;
+ u32 ids;
struct hists hists;
char *name;
struct event_format *tp_format;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 77832b8..471b0c4 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2240,7 +2240,7 @@ out_delete_evlist:
}

int perf_event__synthesize_attr(struct perf_tool *tool,
- struct perf_event_attr *attr, u16 ids, u64 *id,
+ struct perf_event_attr *attr, u32 ids, u64 *id,
perf_event__handler_t process)
{
union perf_event *ev;
@@ -2261,9 +2261,12 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
memcpy(ev->attr.id, id, ids * sizeof(u64));

ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
- ev->attr.header.size = size;
+ ev->attr.header.size = (u16)size;

- err = process(tool, ev, NULL, NULL);
+ if (ev->attr.header.size == size)
+ err = process(tool, ev, NULL, NULL);
+ else
+ err = -E2BIG;

free(ev);

@@ -2292,7 +2295,7 @@ int perf_event__synthesize_attrs(struct perf_tool *tool,
int perf_event__process_attr(union perf_event *event,
struct perf_evlist **pevlist)
{
- unsigned int i, ids, n_ids;
+ u32 i, ids, n_ids;
struct perf_evsel *evsel;
struct perf_evlist *evlist = *pevlist;

diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 2d42b3e..24962e7 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -99,7 +99,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);

int perf_event__synthesize_attr(struct perf_tool *tool,
- struct perf_event_attr *attr, u16 ids, u64 *id,
+ struct perf_event_attr *attr, u32 ids, u64 *id,
perf_event__handler_t process);
int perf_event__synthesize_attrs(struct perf_tool *tool,
struct perf_session *session,

Subject: [tip:perf/core] perf tools: Report number of pmu type of unknown events

Commit-ID: ca1b145761e9355f90bfae1f42c9d9194702066b
Gitweb: http://git.kernel.org/tip/ca1b145761e9355f90bfae1f42c9d9194702066b
Author: Robert Richter <[email protected]>
AuthorDate: Thu, 16 Aug 2012 21:10:18 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Fri, 17 Aug 2012 13:11:29 -0300

perf tools: Report number of pmu type of unknown events

If detection fails and an event name is unknown, report the type number.
Example perf header output:

# Samples: 10K of event 'unknown attr type: 7'

Signed-off-by: Robert Richter <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/evsel.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 6c7dcc1..7ff3c8f 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -319,7 +319,8 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
break;

default:
- scnprintf(bf, sizeof(bf), "%s", "unknown attr type");
+ scnprintf(bf, sizeof(bf), "unknown attr type: %d",
+ evsel->attr.type);
break;
}

Subject: [tip:perf/core] perf tools: Rename some variables for better understanding

Commit-ID: 6606f8733d7b635e09e2dc3a391a5e1f0feb218f
Gitweb: http://git.kernel.org/tip/6606f8733d7b635e09e2dc3a391a5e1f0feb218f
Author: Robert Richter <[email protected]>
AuthorDate: Thu, 16 Aug 2012 21:10:19 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Fri, 17 Aug 2012 13:11:58 -0300

perf tools: Rename some variables for better understanding

Trivial patch to improve understanding of code.

Varible attr is usually used for struct perf_event_attr. Using it in a
different context is irritating. Thus, renaming it.

Signed-off-by: Robert Richter <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/header.c | 42 +++++++++++++++++++++---------------------
1 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 471b0c4..e2e5129 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -608,11 +608,11 @@ static int write_nrcpus(int fd, struct perf_header *h __used,
static int write_event_desc(int fd, struct perf_header *h __used,
struct perf_evlist *evlist)
{
- struct perf_evsel *attr;
+ struct perf_evsel *evsel;
u32 nre = 0, nri, sz;
int ret;

- list_for_each_entry(attr, &evlist->entries, node)
+ list_for_each_entry(evsel, &evlist->entries, node)
nre++;

/*
@@ -625,14 +625,14 @@ static int write_event_desc(int fd, struct perf_header *h __used,
/*
* size of perf_event_attr struct
*/
- sz = (u32)sizeof(attr->attr);
+ sz = (u32)sizeof(evsel->attr);
ret = do_write(fd, &sz, sizeof(sz));
if (ret < 0)
return ret;

- list_for_each_entry(attr, &evlist->entries, node) {
+ list_for_each_entry(evsel, &evlist->entries, node) {

- ret = do_write(fd, &attr->attr, sz);
+ ret = do_write(fd, &evsel->attr, sz);
if (ret < 0)
return ret;
/*
@@ -642,7 +642,7 @@ static int write_event_desc(int fd, struct perf_header *h __used,
* copy into an nri to be independent of the
* type of ids,
*/
- nri = attr->ids;
+ nri = evsel->ids;
ret = do_write(fd, &nri, sizeof(nri));
if (ret < 0)
return ret;
@@ -650,13 +650,13 @@ static int write_event_desc(int fd, struct perf_header *h __used,
/*
* write event string as passed on cmdline
*/
- ret = do_write_string(fd, perf_evsel__name(attr));
+ ret = do_write_string(fd, perf_evsel__name(evsel));
if (ret < 0)
return ret;
/*
* write unique ids for this event
*/
- ret = do_write(fd, attr->id, attr->ids * sizeof(u64));
+ ret = do_write(fd, evsel->id, evsel->ids * sizeof(u64));
if (ret < 0)
return ret;
}
@@ -1683,7 +1683,7 @@ int perf_session__write_header(struct perf_session *session,
struct perf_file_header f_header;
struct perf_file_attr f_attr;
struct perf_header *header = &session->header;
- struct perf_evsel *attr, *pair = NULL;
+ struct perf_evsel *evsel, *pair = NULL;
int err;

lseek(fd, sizeof(f_header), SEEK_SET);
@@ -1691,9 +1691,9 @@ int perf_session__write_header(struct perf_session *session,
if (session->evlist != evlist)
pair = perf_evlist__first(session->evlist);

- list_for_each_entry(attr, &evlist->entries, node) {
- attr->id_offset = lseek(fd, 0, SEEK_CUR);
- err = do_write(fd, attr->id, attr->ids * sizeof(u64));
+ list_for_each_entry(evsel, &evlist->entries, node) {
+ evsel->id_offset = lseek(fd, 0, SEEK_CUR);
+ err = do_write(fd, evsel->id, evsel->ids * sizeof(u64));
if (err < 0) {
out_err_write:
pr_debug("failed to write perf header\n");
@@ -1703,19 +1703,19 @@ out_err_write:
err = do_write(fd, pair->id, pair->ids * sizeof(u64));
if (err < 0)
goto out_err_write;
- attr->ids += pair->ids;
+ evsel->ids += pair->ids;
pair = perf_evsel__next(pair);
}
}

header->attr_offset = lseek(fd, 0, SEEK_CUR);

- list_for_each_entry(attr, &evlist->entries, node) {
+ list_for_each_entry(evsel, &evlist->entries, node) {
f_attr = (struct perf_file_attr){
- .attr = attr->attr,
+ .attr = evsel->attr,
.ids = {
- .offset = attr->id_offset,
- .size = attr->ids * sizeof(u64),
+ .offset = evsel->id_offset,
+ .size = evsel->ids * sizeof(u64),
}
};
err = do_write(fd, &f_attr, sizeof(f_attr));
@@ -2277,12 +2277,12 @@ int perf_event__synthesize_attrs(struct perf_tool *tool,
struct perf_session *session,
perf_event__handler_t process)
{
- struct perf_evsel *attr;
+ struct perf_evsel *evsel;
int err = 0;

- list_for_each_entry(attr, &session->evlist->entries, node) {
- err = perf_event__synthesize_attr(tool, &attr->attr, attr->ids,
- attr->id, process);
+ list_for_each_entry(evsel, &session->evlist->entries, node) {
+ err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids,
+ evsel->id, process);
if (err) {
pr_debug("failed to create perf header attribute\n");
return err;

Subject: [tip:perf/core] perf tools: Rename global variable 'events' in util/header.c

Commit-ID: db146f06ac0bbea63271b6c78f4341ee46843e10
Gitweb: http://git.kernel.org/tip/db146f06ac0bbea63271b6c78f4341ee46843e10
Author: Robert Richter <[email protected]>
AuthorDate: Thu, 16 Aug 2012 21:10:20 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Fri, 17 Aug 2012 13:13:08 -0300

perf tools: Rename global variable 'events' in util/header.c

Trivial patch that renames global variable 'events' in util/header.c.

Use a more specific naming to avoid conflicts. Same for variable
'event_count'.

Signed-off-by: Robert Richter <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/header.c | 40 ++++++++++++++++++++--------------------
1 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index e2e5129..1e5b6aa 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -23,8 +23,8 @@

static bool no_buildid_cache = false;

-static int event_count;
-static struct perf_trace_event_type *events;
+static int trace_event_count;
+static struct perf_trace_event_type *trace_events;

static u32 header_argc;
static const char **header_argv;
@@ -36,24 +36,24 @@ int perf_header__push_event(u64 id, const char *name)
if (strlen(name) > MAX_EVENT_NAME)
pr_warning("Event %s will be truncated\n", name);

- nevents = realloc(events, (event_count + 1) * sizeof(*events));
+ nevents = realloc(trace_events, (trace_event_count + 1) * sizeof(*trace_events));
if (nevents == NULL)
return -ENOMEM;
- events = nevents;
+ trace_events = nevents;

- memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
- events[event_count].event_id = id;
- strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
- event_count++;
+ memset(&trace_events[trace_event_count], 0, sizeof(struct perf_trace_event_type));
+ trace_events[trace_event_count].event_id = id;
+ strncpy(trace_events[trace_event_count].name, name, MAX_EVENT_NAME - 1);
+ trace_event_count++;
return 0;
}

char *perf_header__find_event(u64 id)
{
int i;
- for (i = 0 ; i < event_count; i++) {
- if (events[i].event_id == id)
- return events[i].name;
+ for (i = 0 ; i < trace_event_count; i++) {
+ if (trace_events[i].event_id == id)
+ return trace_events[i].name;
}
return NULL;
}
@@ -1726,9 +1726,9 @@ out_err_write:
}

header->event_offset = lseek(fd, 0, SEEK_CUR);
- header->event_size = event_count * sizeof(struct perf_trace_event_type);
- if (events) {
- err = do_write(fd, events, header->event_size);
+ header->event_size = trace_event_count * sizeof(struct perf_trace_event_type);
+ if (trace_events) {
+ err = do_write(fd, trace_events, header->event_size);
if (err < 0) {
pr_debug("failed to write perf header events\n");
return err;
@@ -2211,13 +2211,13 @@ int perf_session__read_header(struct perf_session *session, int fd)

if (f_header.event_types.size) {
lseek(fd, f_header.event_types.offset, SEEK_SET);
- events = malloc(f_header.event_types.size);
- if (events == NULL)
+ trace_events = malloc(f_header.event_types.size);
+ if (trace_events == NULL)
return -ENOMEM;
- if (perf_header__getbuffer64(header, fd, events,
+ if (perf_header__getbuffer64(header, fd, trace_events,
f_header.event_types.size))
goto out_errno;
- event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
+ trace_event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
}

perf_header__process_sections(header, fd, &session->pevent,
@@ -2362,8 +2362,8 @@ int perf_event__synthesize_event_types(struct perf_tool *tool,
struct perf_trace_event_type *type;
int i, err = 0;

- for (i = 0; i < event_count; i++) {
- type = &events[i];
+ for (i = 0; i < trace_event_count; i++) {
+ type = &trace_events[i];

err = perf_event__synthesize_event_type(tool, type->event_id,
type->name, process,

Subject: Re: [PATCH 5/8] perf tools: Catch event names from command line

On 20.08.12 19:42:47, Jiri Olsa wrote:
> I like the idea of multiple states in parser,
> but parse tests fails:
>
> [jolsa@krava perf]$ ./perf test -vvv parse
> 5: parse events tests:
> --- start ---
> running test 0 'syscalls:sys_enter_open'
> running test 1 'syscalls:*'
> running test 2 'r1a'
> running test 3 '1:1'
> running test 4 'instructions'
> running test 5 'cycles/period=100000,config2/'
> running test 6 'faults'
> running test 7 'L1-dcache-load-miss'
> running test 8 'mem:0'
> running test 9 'mem:0:x'
> running test 10 'mem:0:r'
> running test 11 'mem:0:w'
> running test 12 'syscalls:sys_enter_open:k'
> running test 13 'syscalls:*:u'
> running test 14 'r1a:kp'
> running test 15 '1:1:hp'
> running test 16 'instructions:h'
> running test 17 'faults:u'
> running test 18 'L1-dcache-load-miss:kp'
> running test 19 'mem:0:u'
> FAILED util/parse-events-test.c:309 wrong name
> ---- end ----
> parse events tests: FAILED!

Right, I need to updated the test cases. Have patches ready for this.

-Robert

--
Advanced Micro Devices, Inc.
Operating System Research Center

Subject: [PATCH 2/2] perf test: Do not abort tests on error

Run through all tests regardless of failures. On errors, return the
first error code detected.

Signed-off-by: Robert Richter <[email protected]>
---
tools/perf/util/parse-events-test.c | 24 ++++++++++++++----------
1 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
index 74be1bf..bc8b651 100644
--- a/tools/perf/util/parse-events-test.c
+++ b/tools/perf/util/parse-events-test.c
@@ -949,19 +949,19 @@ static int test_event(struct test__event_st *e)

static int test_events(struct test__event_st *events, unsigned cnt)
{
- int ret = 0;
+ int ret1, ret2 = 0;
unsigned i;

for (i = 0; i < cnt; i++) {
struct test__event_st *e = &events[i];

pr_debug("running test %d '%s'\n", i, e->name);
- ret = test_event(e);
- if (ret)
- break;
+ ret1 = test_event(e);
+ if (ret1)
+ ret2 = ret1;
}

- return ret;
+ return ret2;
}

static int test_term(struct test__term *t)
@@ -1022,13 +1022,13 @@ static int test_pmu(void)

int parse_events__test(void)
{
- int ret;
+ int ret1, ret2 = 0;

#define TEST_EVENTS(tests) \
do { \
- ret = test_events(tests, ARRAY_SIZE(tests)); \
- if (ret) \
- return ret; \
+ ret1 = test_events(tests, ARRAY_SIZE(tests)); \
+ if (!ret2) \
+ ret2 = ret1; \
} while (0)

TEST_EVENTS(test__events);
@@ -1036,5 +1036,9 @@ do { \
if (test_pmu())
TEST_EVENTS(test__events_pmu);

- return test_terms(test__terms, ARRAY_SIZE(test__terms));
+ ret1 = test_terms(test__terms, ARRAY_SIZE(test__terms));
+ if (!ret2)
+ ret2 = ret1;
+
+ return ret2;
}
--
1.7.8.6

Subject: [PATCH 1/2] perf test: Update event names in test cases

Event names are now generated from the command line specification.
Update event names in test cases accordingly.

Signed-off-by: Robert Richter <[email protected]>
---
tools/perf/util/parse-events-test.c | 13 +++++++------
1 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
index bf055ce..74be1bf 100644
--- a/tools/perf/util/parse-events-test.c
+++ b/tools/perf/util/parse-events-test.c
@@ -301,12 +301,13 @@ static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
{
struct perf_evsel *evsel = perf_evlist__first(evlist);

+
TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong name",
- !strcmp(perf_evsel__name(evsel), "mem:0x0:rw:u"));
+ !strcmp(perf_evsel__name(evsel), "mem:0:u"));

return test__checkevent_breakpoint(evlist);
}
@@ -320,7 +321,7 @@ static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong name",
- !strcmp(perf_evsel__name(evsel), "mem:0x0:x:k"));
+ !strcmp(perf_evsel__name(evsel), "mem:0:x:k"));

return test__checkevent_breakpoint_x(evlist);
}
@@ -334,7 +335,7 @@ static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong name",
- !strcmp(perf_evsel__name(evsel), "mem:0x0:r:hp"));
+ !strcmp(perf_evsel__name(evsel), "mem:0:r:hp"));

return test__checkevent_breakpoint_r(evlist);
}
@@ -348,7 +349,7 @@ static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong name",
- !strcmp(perf_evsel__name(evsel), "mem:0x0:w:up"));
+ !strcmp(perf_evsel__name(evsel), "mem:0:w:up"));

return test__checkevent_breakpoint_w(evlist);
}
@@ -362,7 +363,7 @@ static int test__checkevent_breakpoint_rw_modifier(struct perf_evlist *evlist)
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong name",
- !strcmp(perf_evsel__name(evsel), "mem:0x0:rw:kp"));
+ !strcmp(perf_evsel__name(evsel), "mem:0:rw:kp"));

return test__checkevent_breakpoint_rw(evlist);
}
@@ -437,7 +438,7 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist)
TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config);
TEST_ASSERT_VAL("wrong name",
- !strcmp(perf_evsel__name(evsel), "raw 0x2:u"));
+ !strcmp(perf_evsel__name(evsel), "cpu/config=2/u"));

return 0;
}
--
1.7.8.6

Subject: [tip:perf/core] perf test: Do not abort tests on error

Commit-ID: 9bfbbc6d1e6b4d055860231e232b807911bf8325
Gitweb: http://git.kernel.org/tip/9bfbbc6d1e6b4d055860231e232b807911bf8325
Author: Robert Richter <[email protected]>
AuthorDate: Tue, 21 Aug 2012 20:03:15 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 22 Aug 2012 13:34:23 -0300

perf test: Do not abort tests on error

Run through all tests regardless of failures. On errors, return the
first error code detected.

Signed-off-by: Robert Richter <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/parse-events-test.c | 24 ++++++++++++++----------
1 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
index bf055ce..392308c 100644
--- a/tools/perf/util/parse-events-test.c
+++ b/tools/perf/util/parse-events-test.c
@@ -948,19 +948,19 @@ static int test_event(struct test__event_st *e)

static int test_events(struct test__event_st *events, unsigned cnt)
{
- int ret = 0;
+ int ret1, ret2 = 0;
unsigned i;

for (i = 0; i < cnt; i++) {
struct test__event_st *e = &events[i];

pr_debug("running test %d '%s'\n", i, e->name);
- ret = test_event(e);
- if (ret)
- break;
+ ret1 = test_event(e);
+ if (ret1)
+ ret2 = ret1;
}

- return ret;
+ return ret2;
}

static int test_term(struct test__term *t)
@@ -1021,13 +1021,13 @@ static int test_pmu(void)

int parse_events__test(void)
{
- int ret;
+ int ret1, ret2 = 0;

#define TEST_EVENTS(tests) \
do { \
- ret = test_events(tests, ARRAY_SIZE(tests)); \
- if (ret) \
- return ret; \
+ ret1 = test_events(tests, ARRAY_SIZE(tests)); \
+ if (!ret2) \
+ ret2 = ret1; \
} while (0)

TEST_EVENTS(test__events);
@@ -1035,5 +1035,9 @@ do { \
if (test_pmu())
TEST_EVENTS(test__events_pmu);

- return test_terms(test__terms, ARRAY_SIZE(test__terms));
+ ret1 = test_terms(test__terms, ARRAY_SIZE(test__terms));
+ if (!ret2)
+ ret2 = ret1;
+
+ return ret2;
}

Subject: [tip:perf/core] perf tools: Catch event names from command line

Commit-ID: ac2ba9f36bb400755e411309f3e76dbf308a10e7
Gitweb: http://git.kernel.org/tip/ac2ba9f36bb400755e411309f3e76dbf308a10e7
Author: Robert Richter <[email protected]>
AuthorDate: Thu, 16 Aug 2012 21:10:21 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 22 Aug 2012 13:40:49 -0300

perf tools: Catch event names from command line

Use command line string provided by the -e option to name events. This
way we get unique events names that also support pmu event syntax
(<pmu_name>/<config>/<modifier>). No need to reconstruct the name
anymore from its attributes. We use the event_desc of the header to
store the name in the perf.data header. Thus it is also available for
perf report.

Implemented by putting the parser in different states to parse events or
configs.

And since event names are now generated from the command line
specification. Update event names in test cases accordingly.

Signed-off-by: Robert Richter <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
[ committer note: Folded patch fixing 'perf test' failure reported by Jiri Olsa ]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/parse-events-test.c | 13 +++++----
tools/perf/util/parse-events.c | 12 ++++++++
tools/perf/util/parse-events.h | 1 +
tools/perf/util/parse-events.l | 50 ++++++++++++++++++++++++++++-------
tools/perf/util/parse-events.y | 20 ++++++++++++-
5 files changed, 78 insertions(+), 18 deletions(-)

diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
index 392308c..bc8b651 100644
--- a/tools/perf/util/parse-events-test.c
+++ b/tools/perf/util/parse-events-test.c
@@ -301,12 +301,13 @@ static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
{
struct perf_evsel *evsel = perf_evlist__first(evlist);

+
TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong name",
- !strcmp(perf_evsel__name(evsel), "mem:0x0:rw:u"));
+ !strcmp(perf_evsel__name(evsel), "mem:0:u"));

return test__checkevent_breakpoint(evlist);
}
@@ -320,7 +321,7 @@ static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong name",
- !strcmp(perf_evsel__name(evsel), "mem:0x0:x:k"));
+ !strcmp(perf_evsel__name(evsel), "mem:0:x:k"));

return test__checkevent_breakpoint_x(evlist);
}
@@ -334,7 +335,7 @@ static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong name",
- !strcmp(perf_evsel__name(evsel), "mem:0x0:r:hp"));
+ !strcmp(perf_evsel__name(evsel), "mem:0:r:hp"));

return test__checkevent_breakpoint_r(evlist);
}
@@ -348,7 +349,7 @@ static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong name",
- !strcmp(perf_evsel__name(evsel), "mem:0x0:w:up"));
+ !strcmp(perf_evsel__name(evsel), "mem:0:w:up"));

return test__checkevent_breakpoint_w(evlist);
}
@@ -362,7 +363,7 @@ static int test__checkevent_breakpoint_rw_modifier(struct perf_evlist *evlist)
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong name",
- !strcmp(perf_evsel__name(evsel), "mem:0x0:rw:kp"));
+ !strcmp(perf_evsel__name(evsel), "mem:0:rw:kp"));

return test__checkevent_breakpoint_rw(evlist);
}
@@ -437,7 +438,7 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist)
TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config);
TEST_ASSERT_VAL("wrong name",
- !strcmp(perf_evsel__name(evsel), "raw 0x2:u"));
+ !strcmp(perf_evsel__name(evsel), "cpu/config=2/u"));

return 0;
}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 925784a..b246303 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -751,6 +751,18 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add)
return 0;
}

+int parse_events_name(struct list_head *list, char *name)
+{
+ struct perf_evsel *evsel;
+
+ list_for_each_entry(evsel, list, node) {
+ if (!evsel->name)
+ evsel->name = strdup(name);
+ }
+
+ return 0;
+}
+
static int parse_events__scanner(const char *str, void *data, int start_token)
{
YY_BUFFER_STATE buffer;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 0b9782d..c356e44 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -81,6 +81,7 @@ int parse_events__term_clone(struct parse_events__term **new,
void parse_events__free_terms(struct list_head *terms);
int parse_events__modifier_event(struct list_head *list, char *str, bool add);
int parse_events__modifier_group(struct list_head *list, char *event_mod);
+int parse_events_name(struct list_head *list, char *name);
int parse_events_add_tracepoint(struct list_head **list, int *idx,
char *sys, char *event);
int parse_events_add_numeric(struct list_head **list, int *idx,
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 2c0d006..f5e28dc 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -70,6 +70,12 @@ static int term(yyscan_t scanner, int type)
%}

%x mem
+%s config
+%x event
+
+group [^,{}/]*[{][^}]*[}][^,{}/]*
+event_pmu [^,{}/]+[/][^/]*[/][^,{}/]*
+event [^,{}/]+

num_dec [0-9]+
num_hex 0x[a-fA-F0-9]+
@@ -84,7 +90,13 @@ modifier_bp [rwx]{1,3}
{
int start_token;

- start_token = (int) parse_events_get_extra(yyscanner);
+ start_token = parse_events_get_extra(yyscanner);
+
+ if (start_token == PE_START_TERMS)
+ BEGIN(config);
+ else if (start_token == PE_START_EVENTS)
+ BEGIN(event);
+
if (start_token) {
parse_events_set_extra(NULL, yyscanner);
return start_token;
@@ -92,6 +104,26 @@ modifier_bp [rwx]{1,3}
}
%}

+<event>{
+
+{group} {
+ BEGIN(INITIAL); yyless(0);
+ }
+
+{event_pmu} |
+{event} {
+ str(yyscanner, PE_EVENT_NAME);
+ BEGIN(INITIAL); yyless(0);
+ return PE_EVENT_NAME;
+ }
+
+. |
+<<EOF>> {
+ BEGIN(INITIAL); yyless(0);
+ }
+
+}
+
cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
@@ -127,18 +159,16 @@ speculative-read|speculative-load |
refs|Reference|ops|access |
misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); }

- /*
- * These are event config hardcoded term names to be specified
- * within xxx/.../ syntax. So far we dont clash with other names,
- * so we can put them here directly. In case the we have a conflict
- * in future, this needs to go into '//' condition block.
- */
+<config>{
config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
+, { return ','; }
+"/" { BEGIN(INITIAL); return '/'; }
+}

mem: { BEGIN(mem); return PE_PREFIX_MEM; }
r{num_raw_hex} { return raw(yyscanner); }
@@ -147,11 +177,11 @@ r{num_raw_hex} { return raw(yyscanner); }

{modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); }
{name} { return str(yyscanner, PE_NAME); }
-"/" { return '/'; }
+"/" { BEGIN(config); return '/'; }
- { return '-'; }
-, { return ','; }
+, { BEGIN(event); return ','; }
: { return ':'; }
-"{" { return '{'; }
+"{" { BEGIN(event); return '{'; }
"}" { return '}'; }
= { return '='; }
\n { }
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 66850f8..42d9a17 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -27,6 +27,7 @@ do { \

%token PE_START_EVENTS PE_START_TERMS
%token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM
+%token PE_EVENT_NAME
%token PE_NAME
%token PE_MODIFIER_EVENT PE_MODIFIER_BP
%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
@@ -42,6 +43,7 @@ do { \
%type <str> PE_NAME_CACHE_OP_RESULT
%type <str> PE_MODIFIER_EVENT
%type <str> PE_MODIFIER_BP
+%type <str> PE_EVENT_NAME
%type <num> value_sym
%type <head> event_config
%type <term> event_term
@@ -53,6 +55,8 @@ do { \
%type <head> event_legacy_numeric
%type <head> event_legacy_raw
%type <head> event_def
+%type <head> event_mod
+%type <head> event_name
%type <head> event
%type <head> events
%type <head> group_def
@@ -143,8 +147,10 @@ events ',' event
|
event

-event:
-event_def PE_MODIFIER_EVENT
+event: event_mod
+
+event_mod:
+event_name PE_MODIFIER_EVENT
{
struct list_head *list = $1;

@@ -157,6 +163,16 @@ event_def PE_MODIFIER_EVENT
$$ = list;
}
|
+event_name
+
+event_name:
+PE_EVENT_NAME event_def
+{
+ ABORT_ON(parse_events_name($2, $1));
+ free($1);
+ $$ = $2;
+}
+|
event_def

event_def: event_pmu |

Subject: [tip:perf/core] perf tools: Refactor print_event_desc()

Commit-ID: 4e1b9c679fcb208275b55eb8fc46c2d58ef6a2ee
Gitweb: http://git.kernel.org/tip/4e1b9c679fcb208275b55eb8fc46c2d58ef6a2ee
Author: Robert Richter <[email protected]>
AuthorDate: Thu, 16 Aug 2012 21:10:22 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 22 Aug 2012 13:45:59 -0300

perf tools: Refactor print_event_desc()

For later use we need a function read_event_desc() for processing the
event_desc feature. Split it from print_event_desc().

Signed-off-by: Robert Richter <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/header.c | 134 ++++++++++++++++++++++++++++++++--------------
1 files changed, 93 insertions(+), 41 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 1e5b6aa..7454cf4 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1148,12 +1148,29 @@ static void print_cpu_topology(struct perf_header *ph, int fd, FILE *fp)
}
}

-static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
+static void free_event_desc(struct perf_evsel *events)
{
- struct perf_event_attr attr;
- uint64_t id;
+ struct perf_evsel *evsel;
+
+ if (!events)
+ return;
+
+ for (evsel = events; evsel->attr.size; evsel++) {
+ if (evsel->name)
+ free(evsel->name);
+ if (evsel->id)
+ free(evsel->id);
+ }
+
+ free(events);
+}
+
+static struct perf_evsel *
+read_event_desc(struct perf_header *ph, int fd)
+{
+ struct perf_evsel *evsel, *events = NULL;
+ u64 *id;
void *buf = NULL;
- char *str;
u32 nre, sz, nr, i, j;
ssize_t ret;
size_t msz;
@@ -1173,18 +1190,22 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
if (ph->needs_swap)
sz = bswap_32(sz);

- memset(&attr, 0, sizeof(attr));
-
/* buffer to hold on file attr struct */
buf = malloc(sz);
if (!buf)
goto error;

- msz = sizeof(attr);
+ /* the last event terminates with evsel->attr.size == 0: */
+ events = calloc(nre + 1, sizeof(*events));
+ if (!events)
+ goto error;
+
+ msz = sizeof(evsel->attr);
if (sz < msz)
msz = sz;

- for (i = 0 ; i < nre; i++) {
+ for (i = 0, evsel = events; i < nre; evsel++, i++) {
+ evsel->idx = i;

/*
* must read entire on-file attr struct to
@@ -1197,7 +1218,7 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
if (ph->needs_swap)
perf_event__attr_swap(buf);

- memcpy(&attr, buf, msz);
+ memcpy(&evsel->attr, buf, msz);

ret = read(fd, &nr, sizeof(nr));
if (ret != (ssize_t)sizeof(nr))
@@ -1206,51 +1227,82 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
if (ph->needs_swap)
nr = bswap_32(nr);

- str = do_read_string(fd, ph);
- fprintf(fp, "# event : name = %s, ", str);
- free(str);
+ evsel->name = do_read_string(fd, ph);
+
+ if (!nr)
+ continue;
+
+ id = calloc(nr, sizeof(*id));
+ if (!id)
+ goto error;
+ evsel->ids = nr;
+ evsel->id = id;
+
+ for (j = 0 ; j < nr; j++) {
+ ret = read(fd, id, sizeof(*id));
+ if (ret != (ssize_t)sizeof(*id))
+ goto error;
+ if (ph->needs_swap)
+ *id = bswap_64(*id);
+ id++;
+ }
+ }
+out:
+ if (buf)
+ free(buf);
+ return events;
+error:
+ if (events)
+ free_event_desc(events);
+ events = NULL;
+ goto out;
+}
+
+static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
+{
+ struct perf_evsel *evsel, *events = read_event_desc(ph, fd);
+ u32 j;
+ u64 *id;
+
+ if (!events) {
+ fprintf(fp, "# event desc: not available or unable to read\n");
+ return;
+ }
+
+ for (evsel = events; evsel->attr.size; evsel++) {
+ fprintf(fp, "# event : name = %s, ", evsel->name);

fprintf(fp, "type = %d, config = 0x%"PRIx64
", config1 = 0x%"PRIx64", config2 = 0x%"PRIx64,
- attr.type,
- (u64)attr.config,
- (u64)attr.config1,
- (u64)attr.config2);
+ evsel->attr.type,
+ (u64)evsel->attr.config,
+ (u64)evsel->attr.config1,
+ (u64)evsel->attr.config2);

fprintf(fp, ", excl_usr = %d, excl_kern = %d",
- attr.exclude_user,
- attr.exclude_kernel);
+ evsel->attr.exclude_user,
+ evsel->attr.exclude_kernel);

fprintf(fp, ", excl_host = %d, excl_guest = %d",
- attr.exclude_host,
- attr.exclude_guest);
+ evsel->attr.exclude_host,
+ evsel->attr.exclude_guest);

- fprintf(fp, ", precise_ip = %d", attr.precise_ip);
+ fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip);

- if (nr)
+ if (evsel->ids) {
fprintf(fp, ", id = {");
-
- for (j = 0 ; j < nr; j++) {
- ret = read(fd, &id, sizeof(id));
- if (ret != (ssize_t)sizeof(id))
- goto error;
-
- if (ph->needs_swap)
- id = bswap_64(id);
-
- if (j)
- fputc(',', fp);
-
- fprintf(fp, " %"PRIu64, id);
- }
- if (nr && j == nr)
+ for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) {
+ if (j)
+ fputc(',', fp);
+ fprintf(fp, " %"PRIu64, *id);
+ }
fprintf(fp, " }");
+ }
+
fputc('\n', fp);
}
- free(buf);
- return;
-error:
- fprintf(fp, "# event desc: not available or unable to read\n");
+
+ free_event_desc(events);
}

static void print_total_mem(struct perf_header *h __used, int fd, FILE *fp)

Subject: [tip:perf/core] perf report: Update event names from header description

Commit-ID: 7c2f7afd36cc111dd08eb8eb8ef74fb6564fd131
Gitweb: http://git.kernel.org/tip/7c2f7afd36cc111dd08eb8eb8ef74fb6564fd131
Author: Robert Richter <[email protected]>
AuthorDate: Thu, 16 Aug 2012 21:10:23 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 22 Aug 2012 13:47:17 -0300

perf report: Update event names from header description

Name events based on the event description in the perf.data header.

Example output:

$ perf report | grep '^#.*event'
# event : name = ibs_op/cnt_ctl=1/GH, type = 7, config = 0x80000, config1 = 0x0, config2 = 0x0, excl_usr = 0, excl_kern = 0, excl_host = 0, excl_guest = 0, precise_ip = 0, id = { 49, 50, 51, 52, 53, 54, 55, 56 }
# event : name = ibs_fetch/config=0/, type = 6, config = 0x0, config1 = 0x0, config2 = 0x0, excl_usr = 0, excl_kern = 0, excl_host = 0, excl_guest = 1, precise_ip = 0, id = { 57, 58, 59, 60, 61, 62, 63, 64 }
# Samples: 20K of event 'ibs_op/cnt_ctl=1/GH'
# Samples: 4K of event 'ibs_fetch/config=0/'

Note the new pmu event syntax of the names.

Signed-off-by: Robert Richter <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/header.c | 52 +++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 51 insertions(+), 1 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 7454cf4..69374de 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1556,6 +1556,56 @@ static int process_build_id(struct perf_file_section *section,
return 0;
}

+static struct perf_evsel *
+perf_evlist__find_by_index(struct perf_evlist *evlist, int idx)
+{
+ struct perf_evsel *evsel;
+
+ list_for_each_entry(evsel, &evlist->entries, node) {
+ if (evsel->idx == idx)
+ return evsel;
+ }
+
+ return NULL;
+}
+
+static void
+perf_evlist__set_event_name(struct perf_evlist *evlist, struct perf_evsel *event)
+{
+ struct perf_evsel *evsel;
+
+ if (!event->name)
+ return;
+
+ evsel = perf_evlist__find_by_index(evlist, event->idx);
+ if (!evsel)
+ return;
+
+ if (evsel->name)
+ return;
+
+ evsel->name = strdup(event->name);
+}
+
+static int
+process_event_desc(struct perf_file_section *section __unused,
+ struct perf_header *header, int feat __unused, int fd,
+ void *data __used)
+{
+ struct perf_session *session = container_of(header, struct perf_session, header);
+ struct perf_evsel *evsel, *events = read_event_desc(header, fd);
+
+ if (!events)
+ return 0;
+
+ for (evsel = events; evsel->attr.size; evsel++)
+ perf_evlist__set_event_name(session->evlist, evsel);
+
+ free_event_desc(events);
+
+ return 0;
+}
+
struct feature_ops {
int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1589,7 +1639,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPA(HEADER_CPUDESC, cpudesc),
FEAT_OPA(HEADER_CPUID, cpuid),
FEAT_OPA(HEADER_TOTAL_MEM, total_mem),
- FEAT_OPA(HEADER_EVENT_DESC, event_desc),
+ FEAT_OPP(HEADER_EVENT_DESC, event_desc),
FEAT_OPA(HEADER_CMDLINE, cmdline),
FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology),
FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),

Subject: [tip:perf/core] perf tools: Add pmu mappings to header information

Commit-ID: 50a9667c9383982d7ec4e6bbc707f67be0e163d2
Gitweb: http://git.kernel.org/tip/50a9667c9383982d7ec4e6bbc707f67be0e163d2
Author: Robert Richter <[email protected]>
AuthorDate: Thu, 16 Aug 2012 21:10:24 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 22 Aug 2012 15:22:55 -0300

perf tools: Add pmu mappings to header information

With dynamic pmu allocation there are also dynamically assigned pmu ids.
These ids are used in event->attr.type to describe the pmu to be used
for that event. The information is available in sysfs, e.g:

/sys/bus/event_source/devices/breakpoint/type: 5
/sys/bus/event_source/devices/cpu/type: 4
/sys/bus/event_source/devices/ibs_fetch/type: 6
/sys/bus/event_source/devices/ibs_op/type: 7
/sys/bus/event_source/devices/software/type: 1
/sys/bus/event_source/devices/tracepoint/type: 2

These mappings are needed to know which samples belong to which pmu. If
a pmu is added dynamically like for ibs_fetch or ibs_op the type value
may vary.

Now, when decoding samples from perf.data this information in sysfs
might be no longer available or may have changed. We need to store it in
perf.data. Using the header for this. Now the header information created
with perf report contains an additional section looking like this:

# pmu mappings: ibs_op = 7, ibs_fetch = 6, cpu = 4, breakpoint = 5, tracepoint = 2, software = 1

Signed-off-by: Robert Richter <[email protected]>
Acked-by: Peter Zijlstra <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/header.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/header.h | 1 +
tools/perf/util/pmu.c | 50 ++++++++++++++++++++++++++++-
tools/perf/util/pmu.h | 2 +
4 files changed, 129 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 69374de..63aad31 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -20,6 +20,7 @@
#include "symbol.h"
#include "debug.h"
#include "cpumap.h"
+#include "pmu.h"

static bool no_buildid_cache = false;

@@ -1004,6 +1005,45 @@ done:
}

/*
+ * File format:
+ *
+ * struct pmu_mappings {
+ * u32 pmu_num;
+ * struct pmu_map {
+ * u32 type;
+ * char name[];
+ * }[pmu_num];
+ * };
+ */
+
+static int write_pmu_mappings(int fd, struct perf_header *h __used,
+ struct perf_evlist *evlist __used)
+{
+ struct perf_pmu *pmu = NULL;
+ off_t offset = lseek(fd, 0, SEEK_CUR);
+ __u32 pmu_num = 0;
+
+ /* write real pmu_num later */
+ do_write(fd, &pmu_num, sizeof(pmu_num));
+
+ while ((pmu = perf_pmu__scan(pmu))) {
+ if (!pmu->name)
+ continue;
+ pmu_num++;
+ do_write(fd, &pmu->type, sizeof(pmu->type));
+ do_write_string(fd, pmu->name);
+ }
+
+ if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) {
+ /* discard all */
+ lseek(fd, offset, SEEK_SET);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
* default get_cpuid(): nothing gets recorded
* actual implementation must be in arch/$(ARCH)/util/header.c
*/
@@ -1389,6 +1429,43 @@ static void print_branch_stack(struct perf_header *ph __used, int fd __used,
fprintf(fp, "# contains samples with branch stack\n");
}

+static void print_pmu_mappings(struct perf_header *ph, int fd, FILE *fp)
+{
+ const char *delimiter = "# pmu mappings: ";
+ char *name;
+ int ret;
+ u32 pmu_num;
+ u32 type;
+
+ ret = read(fd, &pmu_num, sizeof(pmu_num));
+ if (ret != sizeof(pmu_num))
+ goto error;
+
+ if (!pmu_num) {
+ fprintf(fp, "# pmu mappings: not available\n");
+ return;
+ }
+
+ while (pmu_num) {
+ if (read(fd, &type, sizeof(type)) != sizeof(type))
+ break;
+ name = do_read_string(fd, ph);
+ if (!name)
+ break;
+ pmu_num--;
+ fprintf(fp, "%s%s = %" PRIu32, delimiter, name, type);
+ free(name);
+ delimiter = ", ";
+ }
+
+ fprintf(fp, "\n");
+
+ if (!pmu_num)
+ return;
+error:
+ fprintf(fp, "# pmu mappings: unable to read\n");
+}
+
static int __event_process_build_id(struct build_id_event *bev,
char *filename,
struct perf_session *session)
@@ -1644,6 +1721,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology),
FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
FEAT_OPA(HEADER_BRANCH_STACK, branch_stack),
+ FEAT_OPA(HEADER_PMU_MAPPINGS, pmu_mappings),
};

struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 24962e7..9d5eedc 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -28,6 +28,7 @@ enum {
HEADER_CPU_TOPOLOGY,
HEADER_NUMA_TOPOLOGY,
HEADER_BRANCH_STACK,
+ HEADER_PMU_MAPPINGS,
HEADER_LAST_FEATURE,
HEADER_FEAT_BITS = 256,
};
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 67715a4..6631d82 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -10,6 +10,8 @@
#include "pmu.h"
#include "parse-events.h"

+#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
+
int perf_pmu_parse(struct list_head *list, char *name);
extern FILE *perf_pmu_in;

@@ -69,7 +71,7 @@ static int pmu_format(char *name, struct list_head *format)
return -1;

snprintf(path, PATH_MAX,
- "%s/bus/event_source/devices/%s/format", sysfs, name);
+ "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name);

if (stat(path, &st) < 0)
return 0; /* no error if format does not exist */
@@ -206,7 +208,7 @@ static int pmu_type(char *name, __u32 *type)
return -1;

snprintf(path, PATH_MAX,
- "%s/bus/event_source/devices/%s/type", sysfs, name);
+ "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name);

if (stat(path, &st) < 0)
return -1;
@@ -222,6 +224,35 @@ static int pmu_type(char *name, __u32 *type)
return ret;
}

+/* Add all pmus in sysfs to pmu list: */
+static void pmu_read_sysfs(void)
+{
+ char path[PATH_MAX];
+ const char *sysfs;
+ DIR *dir;
+ struct dirent *dent;
+
+ sysfs = sysfs_find_mountpoint();
+ if (!sysfs)
+ return;
+
+ snprintf(path, PATH_MAX,
+ "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
+
+ dir = opendir(path);
+ if (!dir)
+ return;
+
+ while ((dent = readdir(dir))) {
+ if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+ continue;
+ /* add to static LIST_HEAD(pmus): */
+ perf_pmu__find(dent->d_name);
+ }
+
+ closedir(dir);
+}
+
static struct perf_pmu *pmu_lookup(char *name)
{
struct perf_pmu *pmu;
@@ -267,6 +298,21 @@ static struct perf_pmu *pmu_find(char *name)
return NULL;
}

+struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
+{
+ /*
+ * pmu iterator: If pmu is NULL, we start at the begin,
+ * otherwise return the next pmu. Returns NULL on end.
+ */
+ if (!pmu) {
+ pmu_read_sysfs();
+ pmu = list_prepare_entry(pmu, &pmus, list);
+ }
+ list_for_each_entry_continue(pmu, &pmus, list)
+ return pmu;
+ return NULL;
+}
+
struct perf_pmu *perf_pmu__find(char *name)
{
struct perf_pmu *pmu;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 535f2c5..47f68d3 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -46,5 +46,7 @@ int perf_pmu__new_format(struct list_head *list, char *name,
int config, unsigned long *bits);
void perf_pmu__set_format(unsigned long *bits, long from, long to);

+struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
+
int perf_pmu__test(void);
#endif /* __PMU_H */