lkml.org 
[lkml]   [2012]   [Apr]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 2/8] perf, tool: Enable grouping logic for parsed events
    Date
    The current event grouping is basic. If you specify the '--group'
    option for record/stat/top command, all the specified events become
    members of a single group with the first event as a group leader.

    This patch adds a functionality that allows to create event groups
    based on the way they are specified on the command line. The 'group='
    syntax introduced in earlier patch is used. The current '--group/-g'
    option behaviour remains intact.

    It is possible to create a group with following:
    perf record -e group=cycles,faults ls

    creating single event group containing 'cycles' and 'faults' events,
    and with cycles event as a leader.

    All groups are created with regards to threads and cpus. Thus
    recording an event group within a 2 threads on server with
    4 CPUs will create 8 separate groups.

    Examples (first event in brackets is group leader):

    # 1 group (cpu-clock,task-clock)
    perf record --group -e cpu-clock,task-clock ls
    perf record -e group=cpu-clock,task-clock ls

    # 2 groups (cpu-clock,task-clock) (minor-faults,major-faults)
    perf record -e "group=cpu-clock,task-clock;group=minor-faults,major-faults" ls

    # 1 group (cpu-clock,task-clock,minor-faults,major-faults)
    perf record --group -e cpu-clock,task-clock \
    -e minor-faults,major-faults ls

    # 2 groups (cpu-clock,task-clock) (minor-faults,major-faults)
    perf record -v -e group=cpu-clock,task-clock \
    -e group=minor-faults,major-faults -e instructions ls

    # 1 group (cpu-clock,task-clock,minor-faults,major-faults,instructions)
    perf record --group -e cpu-clock,task-clock \
    -e minor-faults,major-faults -e instructions ls

    Updated automated test to check on group_leader settings.

    Signed-off-by: Jiri Olsa <jolsa@redhat.com>
    ---
    tools/perf/builtin-record.c | 13 +++----
    tools/perf/builtin-stat.c | 13 +++----
    tools/perf/builtin-test.c | 8 ++--
    tools/perf/builtin-top.c | 12 ++----
    tools/perf/util/evlist.c | 34 +++++++++++++------
    tools/perf/util/evlist.h | 5 ++-
    tools/perf/util/evsel.c | 46 ++++++++++++++++----------
    tools/perf/util/evsel.h | 10 ++---
    tools/perf/util/parse-events-test.c | 61 +++++++++++++++++++++++++++++++++-
    tools/perf/util/parse-events.c | 3 +-
    tools/perf/util/python.c | 7 +++-
    11 files changed, 144 insertions(+), 68 deletions(-)

    diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
    index 87fc68d..3e0ef7d 100644
    --- a/tools/perf/builtin-record.c
    +++ b/tools/perf/builtin-record.c
    @@ -177,18 +177,18 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,

    static void perf_record__open(struct perf_record *rec)
    {
    - struct perf_evsel *pos, *first;
    + struct perf_evsel *pos;
    struct perf_evlist *evlist = rec->evlist;
    struct perf_session *session = rec->session;
    struct perf_record_opts *opts = &rec->opts;

    - first = list_entry(evlist->entries.next, struct perf_evsel, node);
    -
    perf_evlist__config_attrs(evlist, opts);

    + if (opts->group)
    + perf_evlist__group(evlist);
    +
    list_for_each_entry(pos, &evlist->entries, node) {
    struct perf_event_attr *attr = &pos->attr;
    - struct xyarray *group_fd = NULL;
    /*
    * Check if parse_single_tracepoint_event has already asked for
    * PERF_SAMPLE_TIME.
    @@ -203,16 +203,13 @@ static void perf_record__open(struct perf_record *rec)
    */
    bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;

    - if (opts->group && pos != first)
    - group_fd = first->fd;
    fallback_missing_features:
    if (opts->exclude_guest_missing)
    attr->exclude_guest = attr->exclude_host = 0;
    retry_sample_id:
    attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
    try_again:
    - if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
    - opts->group, group_fd) < 0) {
    + if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
    int err = errno;

    if (err == EPERM || err == EACCES) {
    diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
    index c941bb6..9dffc8f 100644
    --- a/tools/perf/builtin-stat.c
    +++ b/tools/perf/builtin-stat.c
    @@ -282,10 +282,6 @@ static int create_perf_stat_counter(struct perf_evsel *evsel,
    struct perf_evsel *first)
    {
    struct perf_event_attr *attr = &evsel->attr;
    - struct xyarray *group_fd = NULL;
    -
    - if (group && evsel != first)
    - group_fd = first->fd;

    if (scale)
    attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
    @@ -294,15 +290,13 @@ static int create_perf_stat_counter(struct perf_evsel *evsel,
    attr->inherit = !no_inherit;

    if (system_wide)
    - return perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
    - group, group_fd);
    + return perf_evsel__open_per_cpu(evsel, evsel_list->cpus);
    if (!target_pid && !target_tid && (!group || evsel == first)) {
    attr->disabled = 1;
    attr->enable_on_exec = 1;
    }

    - return perf_evsel__open_per_thread(evsel, evsel_list->threads,
    - group, group_fd);
    + return perf_evsel__open_per_thread(evsel, evsel_list->threads);
    }

    /*
    @@ -459,6 +453,9 @@ static int run_perf_stat(int argc __used, const char **argv)
    close(child_ready_pipe[0]);
    }

    + if (group)
    + perf_evlist__group(evsel_list);
    +
    first = list_entry(evsel_list->entries.next, struct perf_evsel, node);

    list_for_each_entry(counter, &evsel_list->entries, node) {
    diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
    index 7c61eef..c19d2d7 100644
    --- a/tools/perf/builtin-test.c
    +++ b/tools/perf/builtin-test.c
    @@ -294,7 +294,7 @@ static int test__open_syscall_event(void)
    goto out_thread_map_delete;
    }

    - if (perf_evsel__open_per_thread(evsel, threads, false, NULL) < 0) {
    + if (perf_evsel__open_per_thread(evsel, threads) < 0) {
    pr_debug("failed to open counter: %s, "
    "tweak /proc/sys/kernel/perf_event_paranoid?\n",
    strerror(errno));
    @@ -369,7 +369,7 @@ static int test__open_syscall_event_on_all_cpus(void)
    goto out_thread_map_delete;
    }

    - if (perf_evsel__open(evsel, cpus, threads, false, NULL) < 0) {
    + if (perf_evsel__open(evsel, cpus, threads) < 0) {
    pr_debug("failed to open counter: %s, "
    "tweak /proc/sys/kernel/perf_event_paranoid?\n",
    strerror(errno));
    @@ -534,7 +534,7 @@ static int test__basic_mmap(void)

    perf_evlist__add(evlist, evsels[i]);

    - if (perf_evsel__open(evsels[i], cpus, threads, false, NULL) < 0) {
    + if (perf_evsel__open(evsels[i], cpus, threads) < 0) {
    pr_debug("failed to open counter: %s, "
    "tweak /proc/sys/kernel/perf_event_paranoid?\n",
    strerror(errno));
    @@ -736,7 +736,7 @@ static int test__PERF_RECORD(void)
    * Call sys_perf_event_open on all the fds on all the evsels,
    * grouping them if asked to.
    */
    - err = perf_evlist__open(evlist, opts.group);
    + err = perf_evlist__open(evlist);
    if (err < 0) {
    pr_debug("perf_evlist__open: %s\n", strerror(errno));
    goto out_delete_evlist;
    diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
    index e3c63ae..38944a2 100644
    --- a/tools/perf/builtin-top.c
    +++ b/tools/perf/builtin-top.c
    @@ -841,17 +841,14 @@ static void perf_top__mmap_read(struct perf_top *top)

    static void perf_top__start_counters(struct perf_top *top)
    {
    - struct perf_evsel *counter, *first;
    + struct perf_evsel *counter;
    struct perf_evlist *evlist = top->evlist;

    - first = list_entry(evlist->entries.next, struct perf_evsel, node);
    + if (top->group)
    + perf_evlist__group(evlist);

    list_for_each_entry(counter, &evlist->entries, node) {
    struct perf_event_attr *attr = &counter->attr;
    - struct xyarray *group_fd = NULL;
    -
    - if (top->group && counter != first)
    - group_fd = first->fd;

    attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;

    @@ -879,8 +876,7 @@ retry_sample_id:
    attr->sample_id_all = top->sample_id_all_missing ? 0 : 1;
    try_again:
    if (perf_evsel__open(counter, top->evlist->cpus,
    - top->evlist->threads, top->group,
    - group_fd) < 0) {
    + top->evlist->threads) < 0) {
    int err = errno;

    if (err == EPERM || err == EACCES) {
    diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
    index 1986d80..486f939 100644
    --- a/tools/perf/util/evlist.c
    +++ b/tools/perf/util/evlist.c
    @@ -107,6 +107,26 @@ void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
    evlist->nr_entries += nr_entries;
    }

    +void perf_evlist__group_list(struct list_head *list)
    +{
    + struct perf_evsel *evsel, *first;
    +
    + first = list_entry(list->next, struct perf_evsel, node);
    +
    + list_for_each_entry(evsel, list, node)
    + if (evsel != first)
    + evsel->leader = first;
    +}
    +
    +int perf_evlist__group(struct perf_evlist *evlist)
    +{
    + if (!evlist->nr_entries)
    + return -EINVAL;
    +
    + perf_evlist__group_list(&evlist->entries);
    + return 0;
    +}
    +
    int perf_evlist__add_default(struct perf_evlist *evlist)
    {
    struct perf_event_attr attr = {
    @@ -740,21 +760,13 @@ void perf_evlist__set_selected(struct perf_evlist *evlist,
    evlist->selected = evsel;
    }

    -int perf_evlist__open(struct perf_evlist *evlist, bool group)
    +int perf_evlist__open(struct perf_evlist *evlist)
    {
    - struct perf_evsel *evsel, *first;
    + struct perf_evsel *evsel;
    int err, ncpus, nthreads;

    - first = list_entry(evlist->entries.next, struct perf_evsel, node);
    -
    list_for_each_entry(evsel, &evlist->entries, node) {
    - struct xyarray *group_fd = NULL;
    -
    - if (group && evsel != first)
    - group_fd = first->fd;
    -
    - err = perf_evsel__open(evsel, evlist->cpus, evlist->threads,
    - group, group_fd);
    + err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
    if (err < 0)
    goto out_err;
    }
    diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
    index 21f1c9e..863789a 100644
    --- a/tools/perf/util/evlist.h
    +++ b/tools/perf/util/evlist.h
    @@ -78,7 +78,7 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);

    union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);

    -int perf_evlist__open(struct perf_evlist *evlist, bool group);
    +int perf_evlist__open(struct perf_evlist *evlist);

    void perf_evlist__config_attrs(struct perf_evlist *evlist,
    struct perf_record_opts *opts);
    @@ -122,4 +122,7 @@ void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
    struct list_head *list,
    int nr_entries);

    +void perf_evlist__group_list(struct list_head *list);
    +int perf_evlist__group(struct perf_evlist *evlist);
    +
    #endif /* __PERF_EVLIST_H */
    diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
    index 8c13dbc..445ba60 100644
    --- a/tools/perf/util/evsel.c
    +++ b/tools/perf/util/evsel.c
    @@ -16,7 +16,6 @@
    #include "thread_map.h"

    #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
    -#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))

    int __perf_evsel__sample_size(u64 sample_type)
    {
    @@ -293,9 +292,24 @@ int __perf_evsel__read(struct perf_evsel *evsel,
    return 0;
    }

    +static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread)
    +{
    + struct perf_evsel *leader = evsel->leader;
    +
    + if (!leader)
    + return -1;
    +
    + /*
    + * Leader must be already processed/open,
    + * if not it's a bug.
    + */
    + assert(leader->fd);
    +
    + return FD(leader, cpu, thread);
    +}
    +
    static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
    - struct thread_map *threads, bool group,
    - struct xyarray *group_fds)
    + struct thread_map *threads)
    {
    int cpu, thread;
    unsigned long flags = 0;
    @@ -311,13 +325,15 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
    }

    for (cpu = 0; cpu < cpus->nr; cpu++) {
    - int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1;

    for (thread = 0; thread < threads->nr; thread++) {
    + int group_fd;

    if (!evsel->cgrp)
    pid = threads->map[thread];

    + group_fd = get_group_fd(evsel, cpu, thread);
    +
    FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
    pid,
    cpus->map[cpu],
    @@ -327,8 +343,9 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
    goto out_close;
    }

    - if (group && group_fd == -1)
    - group_fd = FD(evsel, cpu, thread);
    + pr_debug("event cpu %d, thread %d, fd %d, group %d\n",
    + cpu, pid, FD(evsel, cpu, thread),
    + group_fd);
    }
    }

    @@ -372,8 +389,7 @@ static struct {
    };

    int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
    - struct thread_map *threads, bool group,
    - struct xyarray *group_fd)
    + struct thread_map *threads)
    {
    if (cpus == NULL) {
    /* Work around old compiler warnings about strict aliasing */
    @@ -383,23 +399,19 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
    if (threads == NULL)
    threads = &empty_thread_map.map;

    - return __perf_evsel__open(evsel, cpus, threads, group, group_fd);
    + return __perf_evsel__open(evsel, cpus, threads);
    }

    int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
    - struct cpu_map *cpus, bool group,
    - struct xyarray *group_fd)
    + struct cpu_map *cpus)
    {
    - return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group,
    - group_fd);
    + return __perf_evsel__open(evsel, cpus, &empty_thread_map.map);
    }

    int perf_evsel__open_per_thread(struct perf_evsel *evsel,
    - struct thread_map *threads, bool group,
    - struct xyarray *group_fd)
    + struct thread_map *threads)
    {
    - return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group,
    - group_fd);
    + return __perf_evsel__open(evsel, &empty_cpu_map.map, threads);
    }

    static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
    diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
    index 3d6b3e4..e749d5c 100644
    --- a/tools/perf/util/evsel.h
    +++ b/tools/perf/util/evsel.h
    @@ -66,6 +66,7 @@ struct perf_evsel {
    void *data;
    } handler;
    bool supported;
    + struct perf_evsel *leader;
    };

    struct cpu_map;
    @@ -91,14 +92,11 @@ void perf_evsel__free_id(struct perf_evsel *evsel);
    void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);

    int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
    - struct cpu_map *cpus, bool group,
    - struct xyarray *group_fds);
    + struct cpu_map *cpus);
    int perf_evsel__open_per_thread(struct perf_evsel *evsel,
    - struct thread_map *threads, bool group,
    - struct xyarray *group_fds);
    + struct thread_map *threads);
    int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
    - struct thread_map *threads, bool group,
    - struct xyarray *group_fds);
    + struct thread_map *threads);
    void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads);

    #define perf_evsel__match(evsel, t, c) \
    diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
    index 73ff0af..baa4caf 100644
    --- a/tools/perf/util/parse-events-test.c
    +++ b/tools/perf/util/parse-events-test.c
    @@ -388,8 +388,7 @@ static int test__checkevent_list(struct perf_evlist *evlist)

    static int test__checkevent_pmu_name(struct perf_evlist *evlist)
    {
    - struct perf_evsel *evsel = list_entry(evlist->entries.next,
    - struct perf_evsel, node);
    + struct perf_evsel *evsel;

    /* cpu/config=1,name=krava1/u */
    evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
    @@ -431,6 +430,60 @@ static int test__checkevent_pmu_branch_type(struct perf_evlist *evlist)
    return 0;
    }

    +static int test__checkevent_group(struct perf_evlist *evlist)
    +{
    + struct perf_evsel *evsel, *leader;
    +
    + TEST_ASSERT_VAL("wrong number of entries", 6 == evlist->nr_entries);
    +
    + /* cycles */
    + evsel = leader = list_entry(evlist->entries.next, struct perf_evsel, node);
    + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
    + TEST_ASSERT_VAL("wrong config",
    + PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
    + TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL);
    +
    + /* faults */
    + evsel = list_entry(evsel->node.next, struct perf_evsel, node);
    + TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
    + TEST_ASSERT_VAL("wrong config",
    + PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
    + TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
    +
    + /* r1 */
    + evsel = list_entry(evsel->node.next, struct perf_evsel, node);
    + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
    + TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
    + TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL);
    +
    + /* mem:0 */
    + evsel = list_entry(evsel->node.next, struct perf_evsel, node);
    + TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
    + TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
    + TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
    + evsel->attr.bp_type);
    + TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
    + evsel->attr.bp_len);
    + TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL);
    +
    + /* cpu/config=2,period=1000/u */
    + evsel = leader = list_entry(evsel->node.next, struct perf_evsel, node);
    + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
    + TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config);
    + TEST_ASSERT_VAL("wrong sample_period",
    + 1000 == evsel->attr.sample_period);
    + TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL);
    +
    + /* instructions:h" */
    + evsel = list_entry(evsel->node.next, struct perf_evsel, node);
    + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
    + TEST_ASSERT_VAL("wrong config",
    + PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
    + TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
    +
    + return 0;
    +}
    +
    static struct test__event_st {
    const char *name;
    __u32 type;
    @@ -544,6 +597,10 @@ static struct test__event_st {
    .name = "cpu/config=1,branch_type=hv|any_ret|1,config2=2/u",
    .check = test__checkevent_pmu_branch_type,
    },
    + [27] = {
    + .name = "group=cycles,faults;r1,mem:0:u;group=cpu/config=2,period=1000/u,instructions:h",
    + .check = test__checkevent_group,
    + },
    };

    #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
    diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
    index 53c7505..5110916 100644
    --- a/tools/perf/util/parse-events.c
    +++ b/tools/perf/util/parse-events.c
    @@ -791,8 +791,9 @@ int parse_events_add_pmu(struct list_head **list, int *idx,
    return add_event(list, idx, &attr, name);
    }

    -int parse_events__group(struct list_head *list __used)
    +int parse_events__group(struct list_head *list)
    {
    + perf_evlist__group_list(list);
    return 0;
    }

    diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
    index e03b58a..419c29e 100644
    --- a/tools/perf/util/python.c
    +++ b/tools/perf/util/python.c
    @@ -627,7 +627,7 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
    * This will group just the fds for this single evsel, to group
    * multiple events, use evlist.open().
    */
    - if (perf_evsel__open(evsel, cpus, threads, group, NULL) < 0) {
    + if (perf_evsel__open(evsel, cpus, threads) < 0) {
    PyErr_SetFromErrno(PyExc_OSError);
    return NULL;
    }
    @@ -828,7 +828,10 @@ static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, &group))
    return NULL;

    - if (perf_evlist__open(evlist, group) < 0) {
    + if (group)
    + perf_evlist__group(evlist);
    +
    + if (perf_evlist__open(evlist) < 0) {
    PyErr_SetFromErrno(PyExc_OSError);
    return NULL;
    }
    --
    1.7.7.6


    \
     
     \ /
      Last update: 2012-04-04 23:21    [W:0.052 / U:1.016 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site