[PATCH RFC v2 4/4] perf/tool: IRQ-bound performance events

From: Alexander Gordeev
Date: Sat Jan 04 2014 - 13:22:44 EST


Signed-off-by: Alexander Gordeev <agordeev@xxxxxxxxxx>
---
tools/perf/builtin-stat.c | 9 +++++++++
tools/perf/util/evlist.c | 38 ++++++++++++++++++++++++++++++++++++++
tools/perf/util/evlist.h | 3 +++
tools/perf/util/evsel.c | 8 ++++++++
tools/perf/util/evsel.h | 3 +++
tools/perf/util/parse-events.c | 24 ++++++++++++++++++++++++
tools/perf/util/parse-events.h | 1 +
7 files changed, 86 insertions(+), 0 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index b27b264..48c9d90 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -292,6 +292,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
PERF_FORMAT_TOTAL_TIME_RUNNING;

attr->inherit = !no_inherit;
+ attr->hardirq = 1;

if (target__has_cpu(&target))
return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
@@ -590,6 +591,12 @@ static int __run_perf_stat(int argc, const char **argv)
return -1;
}

+ if (perf_evlist__apply_hardirq(evsel_list)) {
+ error("failed to set hardirq with %d (%s)\n", errno,
+ strerror(errno));
+ return -1;
+ }
+
/*
* Enable counters and exec the command:
*/
@@ -1613,6 +1620,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
parse_events_option),
OPT_CALLBACK(0, "filter", &evsel_list, "filter",
"event filter", parse_filter),
+ OPT_CALLBACK('h', "hardirq", &evsel_list, "hardirq",
+ "stat events on existing hardware IRQ", parse_hardirq),
OPT_BOOLEAN('i', "no-inherit", &no_inherit,
"child tasks do not inherit counters"),
OPT_STRING('p', "pid", &target.pid, "pid",
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 0810f5c..5104232 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -861,6 +861,27 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist)
return err;
}

+int perf_evlist__apply_hardirq(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel;
+ int err = 0;
+ const int ncpus = cpu_map__nr(evlist->cpus),
+ nthreads = thread_map__nr(evlist->threads);
+
+ list_for_each_entry(evsel, &evlist->entries, node) {
+ if (evsel->hardirq == NULL)
+ continue;
+
+ err = perf_evsel__set_hardirq(evsel, ncpus, nthreads, evsel->hardirq);
+ if (err)
+ break;
+
+ evsel->attr.hardirq = 1;
+ }
+
+ return err;
+}
+
int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
{
struct perf_evsel *evsel;
@@ -877,6 +898,23 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
return err;
}

+int perf_evlist__set_hardirq(struct perf_evlist *evlist,
+ const struct perf_hardirq_event_disp *hardirq)
+{
+ struct perf_evsel *evsel;
+ int err = 0;
+ const int ncpus = cpu_map__nr(evlist->cpus),
+ nthreads = thread_map__nr(evlist->threads);
+
+ list_for_each_entry(evsel, &evlist->entries, node) {
+ err = perf_evsel__set_hardirq(evsel, ncpus, nthreads, hardirq);
+ if (err)
+ break;
+ }
+
+ return err;
+}
+
bool perf_evlist__valid_sample_type(struct perf_evlist *evlist)
{
struct perf_evsel *pos;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 518e521..12dc36d 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -71,6 +71,8 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist,
const char *sys, const char *name, void *handler);

int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter);
+int perf_evlist__set_hardirq(struct perf_evlist *evlist,
+ const struct perf_hardirq_event_disp *hardirq);

struct perf_evsel *
perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id);
@@ -136,6 +138,7 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,

int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target);
int perf_evlist__apply_filters(struct perf_evlist *evlist);
+int perf_evlist__apply_hardirq(struct perf_evlist *evlist);

void __perf_evlist__set_leader(struct list_head *list);
void perf_evlist__set_leader(struct perf_evlist *evlist);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index ade8d9c..23d52a3 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -704,6 +704,14 @@ int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
(void *)filter);
}

+int perf_evsel__set_hardirq(struct perf_evsel *evsel, int ncpus, int nthreads,
+ const struct perf_hardirq_event_disp *disp)
+{
+ return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
+ PERF_EVENT_IOC_SET_HARDIRQ,
+ (void *)disp);
+}
+
int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
{
return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index f1b3256..f07221b 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -59,6 +59,7 @@ struct perf_evsel {
struct list_head node;
struct perf_event_attr attr;
char *filter;
+ struct perf_hardirq_event_disp *hardirq;
struct xyarray *fd;
struct xyarray *sample_id;
u64 *id;
@@ -169,6 +170,8 @@ void perf_evsel__set_sample_id(struct perf_evsel *evsel,

int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
const char *filter);
+int perf_evsel__set_hardirq(struct perf_evsel *evsel, int ncpus, int nthreads,
+ const struct perf_hardirq_event_disp *hardirq);
int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads);

int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 0153435..7a5114d 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -987,6 +987,30 @@ int parse_filter(const struct option *opt, const char *str,
return 0;
}

+int parse_hardirq(const struct option *opt, const char *str,
+ int unset __maybe_unused)
+{
+ struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
+ struct perf_evsel *evsel;
+ struct perf_hardirq_event_disp *event_disp;
+
+ event_disp = malloc(offsetof(typeof(*event_disp), disp) +
+ sizeof(event_disp->disp[0]));
+ if (!event_disp) {
+ fprintf(stderr, "not enough memory to hold hardirq disp\n");
+ return -1;
+ }
+
+ event_disp->nr_disp = 1;
+ event_disp->disp[0].irq_nr = atoi(str);
+ event_disp->disp[0].actions = -1;
+
+ list_for_each_entry(evsel, &evlist->entries, node)
+ evsel->hardirq = event_disp;
+
+ return 0;
+}
+
static const char * const event_type_descriptors[] = {
"Hardware event",
"Software event",
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index f1cb4c4..a6927d6 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -33,6 +33,7 @@ extern int parse_events_option(const struct option *opt, const char *str,
extern int parse_events(struct perf_evlist *evlist, const char *str);
extern int parse_events_terms(struct list_head *terms, const char *str);
extern int parse_filter(const struct option *opt, const char *str, int unset);
+extern int parse_hardirq(const struct option *opt, const char *str, int unset);

#define EVENTS_HELP_MAX (128*1024)

--
1.7.7.6

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/