From patchwork Thu Jun 23 02:11:56 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wang Nan X-Patchwork-Id: 70707 Delivered-To: patch@linaro.org Received: by 10.140.28.4 with SMTP id 4csp200077qgy; Wed, 22 Jun 2016 19:12:53 -0700 (PDT) X-Received: by 10.98.193.1 with SMTP id i1mr16495456pfg.78.1466647973375; Wed, 22 Jun 2016 19:12:53 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id zb10si3459572pab.236.2016.06.22.19.12.53; Wed, 22 Jun 2016 19:12:53 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751872AbcFWCMv (ORCPT + 30 others); Wed, 22 Jun 2016 22:12:51 -0400 Received: from szxga01-in.huawei.com ([58.251.152.64]:30087 "EHLO szxga01-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751166AbcFWCMu (ORCPT ); Wed, 22 Jun 2016 22:12:50 -0400 Received: from 172.24.1.36 (EHLO szxeml426-hub.china.huawei.com) ([172.24.1.36]) by szxrg01-dlp.huawei.com (MOS 4.3.7-GA FastPath queued) with ESMTP id DMQ01087; Thu, 23 Jun 2016 10:12:37 +0800 (CST) Received: from linux-4hy3.site (10.107.193.248) by szxeml426-hub.china.huawei.com (10.82.67.181) with Microsoft SMTP Server id 14.3.235.1; Thu, 23 Jun 2016 10:12:30 +0800 From: Wang Nan To: CC: , , Wang Nan , He Kuang , Jiri Olsa , Masami Hiramatsu , Namhyung Kim , Zefan Li Subject: [PATCH v9.1] perf evlist: Introduce aux evlist Date: Thu, 23 Jun 2016 02:11:56 +0000 Message-ID: <1466647916-94670-1-git-send-email-wangnan0@huawei.com> X-Mailer: git-send-email 1.8.3.4 In-Reply-To: <1466586531-89751-2-git-send-email-wangnan0@huawei.com> References: <1466586531-89751-2-git-send-email-wangnan0@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.107.193.248] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A090204.576B4597.004B, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2013-06-18 04:22:30, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: de11e5c98897071c28d9e8658981695d Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org An auxiliary evlist is created by perf_evlist__new_aux() using an existing evlist as its parent. An auxiliary evlist can have its own 'struct perf_mmap', but can't have any other data. User should use its parent instead when accessing other data. Auxiliary evlists are containers of 'struct perf_mmap'. It is introduced to allow its parent evlist to map different events into separated mmaps. Following commits create an auxiliary evlist for overwritable events, because overwritable events need a read only and backwards ring buffer, which is different from normal events. To achieve this goal, this patch carefully changes 'evlist' to 'evlist->parent' in all functions in the path of 'perf_evlist__mmap_ex', except 'evlist->mmap' related operations, to make sure all evlist modifications (like pollfd and event id hash tables) goes to original evlist. A 'evlist->parent' pointer is added to 'struct perf_evlist' and points to the evlist itself for normal evlists. Children of one evlist are linked into it so one can find all children from its parent. To avoid potential complexity, forbid creating aux evlist from another aux evlist. Improve perf_evlist__munmap_filtered(), so when recording, if an event is terminated, unmap mmaps, from parent and children. Signed-off-by: Wang Nan Cc: He Kuang Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com --- Minor code change: in perf_evlist__new_aux, set evlist->parent to parent, not parent->parent. Because we have already forbid creating an aux evlist from another aux evlist, we don't need to use parent->parent trick to avoid grandchildren. Thanks Nilay and Arnaldo. --- tools/perf/util/evlist.c | 49 +++++++++++++++++++++++++++++++++++++----------- tools/perf/util/evlist.h | 12 ++++++++++++ 2 files changed, 50 insertions(+), 11 deletions(-) -- 1.8.3.4 diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 1b918aa..5b924ae8 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -41,10 +41,12 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i) INIT_HLIST_HEAD(&evlist->heads[i]); INIT_LIST_HEAD(&evlist->entries); + INIT_LIST_HEAD(&evlist->children); perf_evlist__set_maps(evlist, cpus, threads); fdarray__init(&evlist->pollfd, 64); evlist->workload.pid = -1; evlist->backward = false; + evlist->parent = evlist; } struct perf_evlist *perf_evlist__new(void) @@ -487,13 +489,17 @@ static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd, void *arg __maybe_unused) { struct perf_evlist *evlist = container_of(fda, struct perf_evlist, pollfd); + struct perf_evlist *child; perf_evlist__mmap_put(evlist, fda->priv[fd].idx); + list_for_each_entry(child, &evlist->children, list) + perf_evlist__mmap_put(child, fda->priv[fd].idx); + } int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask) { - return fdarray__filter(&evlist->pollfd, revents_and_mask, + return fdarray__filter(&evlist->parent->pollfd, revents_and_mask, perf_evlist__munmap_filtered, NULL); } @@ -1012,7 +1018,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, struct perf_evsel *evsel; int revent; - evlist__for_each(evlist, evsel) { + evlist__for_each(evlist->parent, evsel) { int fd; if (evsel->overwrite != (evlist->overwrite && evlist->backward)) @@ -1044,16 +1050,16 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, * Therefore don't add it for polling. */ if (!evsel->system_wide && - __perf_evlist__add_pollfd(evlist, fd, idx, revent) < 0) { + __perf_evlist__add_pollfd(evlist->parent, fd, idx, revent) < 0) { perf_evlist__mmap_put(evlist, idx); return -1; } if (evsel->attr.read_format & PERF_FORMAT_ID) { - if (perf_evlist__id_add_fd(evlist, evsel, cpu, thread, + if (perf_evlist__id_add_fd(evlist->parent, evsel, cpu, thread, fd) < 0) return -1; - perf_evlist__set_sid_idx(evlist, evsel, idx, cpu, + perf_evlist__set_sid_idx(evlist->parent, evsel, idx, cpu, thread); } } @@ -1094,13 +1100,13 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, struct mmap_params *mp) { int thread; - int nr_threads = thread_map__nr(evlist->threads); + int nr_threads = thread_map__nr(evlist->parent->threads); pr_debug2("perf event ring buffer mmapped per thread\n"); for (thread = 0; thread < nr_threads; thread++) { int output = -1; - auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, thread, + auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist->parent, thread, false); if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread, @@ -1239,8 +1245,8 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, bool auxtrace_overwrite) { struct perf_evsel *evsel; - const struct cpu_map *cpus = evlist->cpus; - const struct thread_map *threads = evlist->threads; + const struct cpu_map *cpus = evlist->parent->cpus; + const struct thread_map *threads = evlist->parent->threads; struct mmap_params mp = { .prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), }; @@ -1248,7 +1254,7 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) return -ENOMEM; - if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0) + if (evlist->parent->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist->parent) < 0) return -ENOMEM; evlist->overwrite = overwrite; @@ -1259,7 +1265,7 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, auxtrace_mmap_params__init(&mp.auxtrace_mp, evlist->mmap_len, auxtrace_pages, auxtrace_overwrite); - evlist__for_each(evlist, evsel) { + evlist__for_each(evlist->parent, evsel) { if ((evsel->attr.read_format & PERF_FORMAT_ID) && evsel->sample_id == NULL && perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0) @@ -1916,3 +1922,24 @@ perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, return NULL; } + +struct perf_evlist *perf_evlist__new_aux(struct perf_evlist *parent) +{ + struct perf_evlist *evlist; + + if (perf_evlist__is_aux(parent)) { + pr_err("Internal error: create aux evlist from another aux evlist\n"); + return NULL; + } + + evlist = zalloc(sizeof(*evlist)); + if (!evlist) + return NULL; + + perf_evlist__init(evlist, parent->cpus, parent->threads); + evlist->parent = parent; + INIT_LIST_HEAD(&evlist->list); + list_add(&evlist->list, &parent->children); + + return evlist; +} diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 68cb136..5b50692 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -37,6 +37,10 @@ struct perf_mmap { struct perf_evlist { struct list_head entries; + union { + struct list_head children; + struct list_head list; + }; struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; int nr_entries; int nr_groups; @@ -60,8 +64,14 @@ struct perf_evlist { struct perf_evsel *selected; struct events_stats stats; struct perf_env *env; + struct perf_evlist *parent; }; +static inline bool perf_evlist__is_aux(struct perf_evlist *evlist) +{ + return evlist->parent != evlist; +} + struct perf_evsel_str_handler { const char *name; void *handler; @@ -70,6 +80,8 @@ struct perf_evsel_str_handler { struct perf_evlist *perf_evlist__new(void); struct perf_evlist *perf_evlist__new_default(void); struct perf_evlist *perf_evlist__new_dummy(void); +struct perf_evlist *perf_evlist__new_aux(struct perf_evlist *); + void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, struct thread_map *threads); void perf_evlist__exit(struct perf_evlist *evlist);