From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753211AbcEMNFa (ORCPT ); Fri, 13 May 2016 09:05:30 -0400 Received: from mail.kernel.org ([198.145.29.136]:34565 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752918AbcEMNF3 (ORCPT ); Fri, 13 May 2016 09:05:29 -0400 Date: Fri, 13 May 2016 10:05:16 -0300 From: Arnaldo Carvalho de Melo To: Wang Nan Cc: arnaldo.melo@gmail.com, linux-kernel@vger.kernel.org, He Kuang , Arnaldo Carvalho de Melo , Jiri Olsa , Masami Hiramatsu , Namhyung Kim , Zefan Li , pi3orama@163.com Subject: Re: [PATCH 02/17] perf tools: Add evlist channel helpers Message-ID: <20160513130516.GH11346@kernel.org> References: <1463126174-119290-1-git-send-email-wangnan0@huawei.com> <1463126174-119290-3-git-send-email-wangnan0@huawei.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1463126174-119290-3-git-send-email-wangnan0@huawei.com> X-Url: http://acmel.wordpress.com User-Agent: Mutt/1.6.0 (2016-04-01) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Em Fri, May 13, 2016 at 07:55:59AM +0000, Wang Nan escreveu: > In this commit sereval helpers are introduced to support the principle several > of channel. Channels hold different groups of evsels which configured > differently. It will be used for overwritable evsels, which allows perf why not use multiple evlists? An "evlist" is a "list of evsels", why do we need yet another way of grouping evlists? - Arnaldo > record some events continuously while capture snapshot for other events > when something happen. Tracking events (mmap, mmap2, fork, exit ...) > are another possible events worth to be put into a separated channel. > > Channels are represented by an array with channel flags. Each channel > contains evlist->nr_mmaps mmaps. Channels are configured before > perf_evlist__mmap_ex(). During that function nr_mmaps mmaps for each > channel are allocated together as a big array. > perf_evlist__channel_idx() converts index in the big array and the > channel number. For API functions which accept idx, _ex() versions are > introduced to accept selecting an mmap from a channel. > > Signed-off-by: Wang Nan > Signed-off-by: He Kuang > Cc: Arnaldo Carvalho de Melo > Cc: Jiri Olsa > Cc: Masami Hiramatsu > Cc: Namhyung Kim > Cc: Zefan Li > Cc: pi3orama@163.com > --- > tools/perf/builtin-record.c | 6 ++ > tools/perf/util/evlist.c | 130 ++++++++++++++++++++++++++++++++++++++++++-- > tools/perf/util/evlist.h | 58 ++++++++++++++++++++ > 3 files changed, 188 insertions(+), 6 deletions(-) > > diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c > index f3679c4..6e44834 100644 > --- a/tools/perf/builtin-record.c > +++ b/tools/perf/builtin-record.c > @@ -316,6 +316,12 @@ try_again: > goto out; > } > > + perf_evlist__channel_reset(evlist); > + rc = perf_evlist__channel_add(evlist, 0, true); > + if (rc < 0) > + goto out; > + rc = 0; > + > if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false, > opts->auxtrace_mmap_pages, > opts->auxtrace_snapshot_mode) < 0) { > diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c > index 5e86972..6c11b9e 100644 > --- a/tools/perf/util/evlist.c > +++ b/tools/perf/util/evlist.c > @@ -679,6 +679,33 @@ static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, > return NULL; > } > > +int perf_evlist__channel_idx(struct perf_evlist *evlist, > + int *p_channel, int *p_idx) > +{ > + int channel = *p_channel; > + int _idx = *p_idx; > + > + if (_idx < 0) > + return -EINVAL; > + /* > + * Negative channel means caller explicitly use real index. > + */ > + if (channel < 0) { > + channel = perf_evlist__idx_channel(evlist, _idx); > + _idx = _idx % evlist->nr_mmaps; > + } > + if (channel < 0) > + return channel; > + if (channel >= PERF_EVLIST__NR_CHANNELS) > + return -E2BIG; > + if (_idx >= evlist->nr_mmaps) > + return -E2BIG; > + > + *p_channel = channel; > + *p_idx = evlist->nr_mmaps * channel + _idx; > + return 0; > +} > + > /* When check_messup is true, 'end' must points to a good entry */ > static union perf_event * > perf_mmap__read(struct perf_mmap *md, bool check_messup, u64 start, > @@ -756,11 +783,19 @@ __perf_evlist__mmap_read(struct perf_mmap *md, bool overwrite, u64 head, > return perf_mmap__read(md, overwrite, old, head, prev); > } > > -union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) > +union perf_event *perf_evlist__mmap_read_ex(struct perf_evlist *evlist, > + int channel, int idx) > { > struct perf_mmap *md = &evlist->mmap[idx]; > - u64 head; > - u64 old = md->prev; > + u64 head, old; > + int err = perf_evlist__channel_idx(evlist, &channel, &idx); > + > + if (err || !perf_evlist__channel_is_enabled(evlist, channel)) { > + pr_err("ERROR: invalid mmap index: channel %d, idx: %d\n", > + channel, idx); > + return NULL; > + } > + old = md->prev; > > /* > * Check if event was unmapped due to a POLLHUP/POLLERR. > @@ -824,6 +859,11 @@ void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx) > md->prev = head; > } > > +union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) > +{ > + return perf_evlist__mmap_read_ex(evlist, -1, idx); > +} > + > static bool perf_mmap__empty(struct perf_mmap *md) > { > return perf_mmap__read_head(md) == md->prev && !md->auxtrace_mmap.base; > @@ -842,10 +882,18 @@ static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx) > __perf_evlist__munmap(evlist, idx); > } > > -void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx) > +void perf_evlist__mmap_consume_ex(struct perf_evlist *evlist, > + int channel, int idx) > { > + int err = perf_evlist__channel_idx(evlist, &channel, &idx); > struct perf_mmap *md = &evlist->mmap[idx]; > > + if (err || !perf_evlist__channel_is_enabled(evlist, channel)) { > + pr_err("ERROR: invalid mmap index: channel %d, idx: %d\n", > + channel, idx); > + return; > + } > + > if (!evlist->overwrite) { > u64 old = md->prev; > > @@ -856,6 +904,11 @@ void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx) > perf_evlist__mmap_put(evlist, idx); > } > > +void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx) > +{ > + perf_evlist__mmap_consume_ex(evlist, -1, idx); > +} > + > int __weak auxtrace_mmap__mmap(struct auxtrace_mmap *mm __maybe_unused, > struct auxtrace_mmap_params *mp __maybe_unused, > void *userpg __maybe_unused, > @@ -901,7 +954,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist) > if (evlist->mmap == NULL) > return; > > - for (i = 0; i < evlist->nr_mmaps; i++) > + for (i = 0; i < perf_evlist__mmap_nr(evlist); i++) > __perf_evlist__munmap(evlist, i); > > zfree(&evlist->mmap); > @@ -909,10 +962,17 @@ void perf_evlist__munmap(struct perf_evlist *evlist) > > static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) > { > + int total_mmaps; > + > evlist->nr_mmaps = cpu_map__nr(evlist->cpus); > if (cpu_map__empty(evlist->cpus)) > evlist->nr_mmaps = thread_map__nr(evlist->threads); > - evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); > + > + total_mmaps = perf_evlist__mmap_nr(evlist); > + if (!total_mmaps) > + return -EINVAL; > + > + evlist->mmap = zalloc(total_mmaps * sizeof(struct perf_mmap)); > return evlist->mmap != NULL ? 0 : -ENOMEM; > } > > @@ -1221,6 +1281,12 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, > int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, > bool overwrite) > { > + int err; > + > + perf_evlist__channel_reset(evlist); > + err = perf_evlist__channel_add(evlist, 0, true); > + if (err < 0) > + return err; > return perf_evlist__mmap_ex(evlist, pages, overwrite, 0, false); > } > > @@ -1862,3 +1928,55 @@ perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, > > return NULL; > } > + > +int perf_evlist__channel_nr(struct perf_evlist *evlist) > +{ > + int i; > + > + for (i = PERF_EVLIST__NR_CHANNELS - 1; i >= 0; i--) { > + unsigned long flags = evlist->channel_flags[i]; > + > + if (flags & PERF_EVLIST__CHANNEL_ENABLED) > + return i + 1; > + } > + return 0; > +} > + > +int perf_evlist__mmap_nr(struct perf_evlist *evlist) > +{ > + return evlist->nr_mmaps * perf_evlist__channel_nr(evlist); > +} > + > +void perf_evlist__channel_reset(struct perf_evlist *evlist) > +{ > + int i; > + > + BUG_ON(evlist->mmap); > + > + for (i = 0; i < PERF_EVLIST__NR_CHANNELS; i++) > + evlist->channel_flags[i] = 0; > +} > + > +int perf_evlist__channel_add(struct perf_evlist *evlist, > + unsigned long flag, > + bool is_default) > +{ > + int n = perf_evlist__channel_nr(evlist); > + unsigned long *flags = evlist->channel_flags; > + > + BUG_ON(evlist->mmap); > + > + if (n >= PERF_EVLIST__NR_CHANNELS) { > + pr_debug("ERROR: too many channels. Increase PERF_EVLIST__NR_CHANNELS\n"); > + return -ENOSPC; > + } > + > + if (is_default) { > + memmove(&flags[1], &flags[0], > + sizeof(evlist->channel_flags) - > + sizeof(evlist->channel_flags[0])); > + n = 0; > + } > + flags[n] = flag | PERF_EVLIST__CHANNEL_ENABLED; > + return n; > +} > diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h > index 85d1b59..4cb5d3a 100644 > --- a/tools/perf/util/evlist.h > +++ b/tools/perf/util/evlist.h > @@ -20,6 +20,11 @@ struct record_opts; > #define PERF_EVLIST__HLIST_BITS 8 > #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) > > +#define PERF_EVLIST__NR_CHANNELS 1 > +enum perf_evlist_mmap_flag { > + PERF_EVLIST__CHANNEL_ENABLED = 1, > +}; > + > /** > * struct perf_mmap - perf's ring buffer mmap details > * > @@ -52,6 +57,7 @@ struct perf_evlist { > pid_t pid; > } workload; > struct fdarray pollfd; > + unsigned long channel_flags[PERF_EVLIST__NR_CHANNELS]; > struct perf_mmap *mmap; > struct thread_map *threads; > struct cpu_map *cpus; > @@ -127,13 +133,65 @@ struct perf_evsel *perf_evlist__id2evsel_strict(struct perf_evlist *evlist, > > struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); > > +union perf_event *perf_evlist__mmap_read_ex(struct perf_evlist *evlist, > + int channel, int idx); > union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx); > > union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist, > int idx); > void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx); > > +void perf_evlist__mmap_consume_ex(struct perf_evlist *evlist, > + int channel, int idx); > void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); > +int perf_evlist__mmap_nr(struct perf_evlist *evlist); > + > +int perf_evlist__channel_nr(struct perf_evlist *evlist); > +void perf_evlist__channel_reset(struct perf_evlist *evlist); > +int perf_evlist__channel_add(struct perf_evlist *evlist, > + unsigned long flag, > + bool is_default); > + > +static inline bool > +__perf_evlist__channel_check(struct perf_evlist *evlist, int channel, > + enum perf_evlist_mmap_flag bits) > +{ > + if (channel >= PERF_EVLIST__NR_CHANNELS) > + return false; > + > + return (evlist->channel_flags[channel] & bits) ? true : false; > +} > +#define perf_evlist__channel_check(e, c, b) \ > + __perf_evlist__channel_check(e, c, PERF_EVLIST__CHANNEL_##b) > + > +static inline bool > +perf_evlist__channel_is_enabled(struct perf_evlist *evlist, int channel) > +{ > + return perf_evlist__channel_check(evlist, channel, ENABLED); > +} > + > +static inline int > +perf_evlist__idx_channel(struct perf_evlist *evlist, int idx) > +{ > + int channel = idx / evlist->nr_mmaps; > + > + if (channel >= PERF_EVLIST__NR_CHANNELS) > + return -E2BIG; > + return channel; > +} > + > +int perf_evlist__channel_idx(struct perf_evlist *evlist, > + int *p_channel, int *p_idx); > + > +static inline struct perf_mmap * > +perf_evlist__get_mmap(struct perf_evlist *evlist, > + int channel, int idx) > +{ > + if (perf_evlist__channel_idx(evlist, &channel, &idx)) > + return NULL; > + > + return &evlist->mmap[idx]; > +} > > int perf_evlist__open(struct perf_evlist *evlist); > void perf_evlist__close(struct perf_evlist *evlist); > -- > 1.8.3.4