From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.1 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0AE4FC43381 for ; Thu, 21 Mar 2019 18:55:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id BB6872192B for ; Thu, 21 Mar 2019 18:55:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1553194524; bh=nnx5+Cw23LzdLpoZRxFgAffO1bXHgdibV7uMtzIZ3Fg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-ID:From; b=ux3PN+7LniXrHfTXTFVgjtqZ71KXVLVo2UrUeDHl+fVbVJYRB1SFBTaEJ9cVhMq7n iZZszJjC9aWGS9pNoKVEg7RoA5HFAsirltUgM2N8RhX4ggn8tvQq0z18VT9NxD2t4S CQc9737sychvbcJ48kGs3m1RSyyhLHMgV3o8VL9E= Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729249AbfCUSzX (ORCPT ); Thu, 21 Mar 2019 14:55:23 -0400 Received: from mail.kernel.org ([198.145.29.99]:47000 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729236AbfCUSzU (ORCPT ); Thu, 21 Mar 2019 14:55:20 -0400 Received: from quaco.ghostprotocols.net (unknown [190.15.121.82]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id BB20E205F4; Thu, 21 Mar 2019 18:55:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1553194518; bh=nnx5+Cw23LzdLpoZRxFgAffO1bXHgdibV7uMtzIZ3Fg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pGuembi04NAMzI4u82OGPPrpkUdZGJj87n/fd0aXhrfJDO74M5o6PrCwsk6MZJQ8K 0Y5Ht50YIM6T13kstOGDctSNKjkiVBlOnk/AGAMvvQYMRs+AkLUg4UkDmIoVXYQ6uv FYKX7pNaNWi7UHMAHveBipGpDGSMYzhXRGaAObdE= From: Arnaldo Carvalho de Melo To: Ingo Molnar Cc: Jiri Olsa , Namhyung Kim , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Song Liu , Arnaldo Carvalho de Melo , Alexei Starovoitov , Daniel Borkmann , Peter Zijlstra , Stanislav Fomichev Subject: [PATCH 41/44] perf evlist: Introduce side band thread Date: Thu, 21 Mar 2019 15:51:39 -0300 Message-Id: <20190321185142.11441-42-acme@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190321185142.11441-1-acme@kernel.org> References: <20190321185142.11441-1-acme@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Song Liu This patch introduces side band thread that captures extended information for events like PERF_RECORD_BPF_EVENT. This new thread uses its own evlist that uses ring buffer with very low watermark for lower latency. To use side band thread, we need to: 1. add side band event(s) by calling perf_evlist__add_sb_event(); 2. calls perf_evlist__start_sb_thread(); 3. at the end of perf run, perf_evlist__stop_sb_thread(). In the next patch, we use this thread to handle PERF_RECORD_BPF_EVENT. Committer notes: Add fix by Jiri Olsa for when te sb_tread can't get started and then at the end the stop_sb_thread() segfaults when joining the (non-existing) thread. That can happen when running 'perf top' or 'perf record' as a normal user, for instance. Further checks need to be done on top of this to more graciously handle these possible failure scenarios. Signed-off-by: Song Liu Reviewed-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Alexei Starovoitov Cc: Daniel Borkmann Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stanislav Fomichev Link: http://lkml.kernel.org/r/20190312053051.2690567-15-songliubraving@fb.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 9 +++ tools/perf/builtin-top.c | 9 +++ tools/perf/util/evlist.c | 119 ++++++++++++++++++++++++++++++++++++ tools/perf/util/evlist.h | 12 ++++ tools/perf/util/evsel.h | 6 ++ 5 files changed, 155 insertions(+) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index e79faccd7842..6f645fd72fed 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1137,6 +1137,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) struct perf_data *data = &rec->data; struct perf_session *session; bool disabled = false, draining = false; + struct perf_evlist *sb_evlist = NULL; int fd; atexit(record__sig_exit); @@ -1237,6 +1238,11 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) goto out_child; } + if (perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target)) { + pr_debug("Couldn't start the BPF side band thread:\nBPF programs starting from now on won't be annotatable\n"); + opts->no_bpf_event = true; + } + err = record__synthesize(rec, false); if (err < 0) goto out_child; @@ -1487,6 +1493,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) out_delete_session: perf_session__delete(session); + + if (!opts->no_bpf_event) + perf_evlist__stop_sb_thread(sb_evlist); return status; } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c2ea22c4ea67..3ce8a8db6c1d 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1501,6 +1501,7 @@ int cmd_top(int argc, const char **argv) "number of thread to run event synthesize"), OPT_END() }; + struct perf_evlist *sb_evlist = NULL; const char * const top_usage[] = { "perf top []", NULL @@ -1636,8 +1637,16 @@ int cmd_top(int argc, const char **argv) goto out_delete_evlist; } + if (perf_evlist__start_sb_thread(sb_evlist, target)) { + pr_debug("Couldn't start the BPF side band thread:\nBPF programs starting from now on won't be annotatable\n"); + opts->no_bpf_event = true; + } + status = __cmd_top(&top); + if (!opts->no_bpf_event) + perf_evlist__stop_sb_thread(sb_evlist); + out_delete_evlist: perf_evlist__delete(top.evlist); perf_session__delete(top.session); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index ed20f4379956..ec78e93085de 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -19,6 +19,7 @@ #include "debug.h" #include "units.h" #include "asm/bug.h" +#include "bpf-event.h" #include #include @@ -1856,3 +1857,121 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list, } return leader; } + +int perf_evlist__add_sb_event(struct perf_evlist **evlist, + struct perf_event_attr *attr, + perf_evsel__sb_cb_t cb, + void *data) +{ + struct perf_evsel *evsel; + bool new_evlist = (*evlist) == NULL; + + if (*evlist == NULL) + *evlist = perf_evlist__new(); + if (*evlist == NULL) + return -1; + + if (!attr->sample_id_all) { + pr_warning("enabling sample_id_all for all side band events\n"); + attr->sample_id_all = 1; + } + + evsel = perf_evsel__new_idx(attr, (*evlist)->nr_entries); + if (!evsel) + goto out_err; + + evsel->side_band.cb = cb; + evsel->side_band.data = data; + perf_evlist__add(*evlist, evsel); + return 0; + +out_err: + if (new_evlist) { + perf_evlist__delete(*evlist); + *evlist = NULL; + } + return -1; +} + +static void *perf_evlist__poll_thread(void *arg) +{ + struct perf_evlist *evlist = arg; + bool draining = false; + int i; + + while (draining || !(evlist->thread.done)) { + if (draining) + draining = false; + else if (evlist->thread.done) + draining = true; + + if (!draining) + perf_evlist__poll(evlist, 1000); + + for (i = 0; i < evlist->nr_mmaps; i++) { + struct perf_mmap *map = &evlist->mmap[i]; + union perf_event *event; + + if (perf_mmap__read_init(map)) + continue; + while ((event = perf_mmap__read_event(map)) != NULL) { + struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event); + + if (evsel && evsel->side_band.cb) + evsel->side_band.cb(event, evsel->side_band.data); + else + pr_warning("cannot locate proper evsel for the side band event\n"); + + perf_mmap__consume(map); + } + perf_mmap__read_done(map); + } + } + return NULL; +} + +int perf_evlist__start_sb_thread(struct perf_evlist *evlist, + struct target *target) +{ + struct perf_evsel *counter; + + if (!evlist) + return 0; + + if (perf_evlist__create_maps(evlist, target)) + goto out_delete_evlist; + + evlist__for_each_entry(evlist, counter) { + if (perf_evsel__open(counter, evlist->cpus, + evlist->threads) < 0) + goto out_delete_evlist; + } + + if (perf_evlist__mmap(evlist, UINT_MAX)) + goto out_delete_evlist; + + evlist__for_each_entry(evlist, counter) { + if (perf_evsel__enable(counter)) + goto out_delete_evlist; + } + + evlist->thread.done = 0; + if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist)) + goto out_delete_evlist; + + return 0; + +out_delete_evlist: + perf_evlist__delete(evlist); + evlist = NULL; + return -1; +} + +void perf_evlist__stop_sb_thread(struct perf_evlist *evlist) +{ + if (!evlist) + return; + evlist->thread.done = 1; + pthread_join(evlist->thread.th, NULL); + perf_evlist__delete(evlist); +} diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 744906dd4887..dcb68f34d2cd 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -54,6 +54,10 @@ struct perf_evlist { struct perf_sample *sample); u64 first_sample_time; u64 last_sample_time; + struct { + pthread_t th; + volatile int done; + } thread; }; struct perf_evsel_str_handler { @@ -87,6 +91,14 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, int perf_evlist__add_dummy(struct perf_evlist *evlist); +int perf_evlist__add_sb_event(struct perf_evlist **evlist, + struct perf_event_attr *attr, + perf_evsel__sb_cb_t cb, + void *data); +int perf_evlist__start_sb_thread(struct perf_evlist *evlist, + struct target *target); +void perf_evlist__stop_sb_thread(struct perf_evlist *evlist); + int perf_evlist__add_newtp(struct perf_evlist *evlist, const char *sys, const char *name, void *handler); diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index cc578e02e08f..0f2c6c93d721 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -73,6 +73,8 @@ struct perf_evsel_config_term { struct perf_stat_evsel; +typedef int (perf_evsel__sb_cb_t)(union perf_event *event, void *data); + /** struct perf_evsel - event selector * * @evlist - evlist this evsel is in, if it is in one. @@ -151,6 +153,10 @@ struct perf_evsel { bool collect_stat; bool weak_group; const char *pmu_name; + struct { + perf_evsel__sb_cb_t *cb; + void *data; + } side_band; }; union u64_swap { -- 2.20.1