From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7C8F6C433EF for ; Mon, 17 Jan 2022 18:34:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242616AbiAQSeq (ORCPT ); Mon, 17 Jan 2022 13:34:46 -0500 Received: from mga12.intel.com ([192.55.52.136]:48606 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242193AbiAQSen (ORCPT ); Mon, 17 Jan 2022 13:34:43 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444483; x=1673980483; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=AAQ1YHDRhw2jiixtPVTsB9v7oMgUunFg3Ew8CBPPBW0=; b=SmWHNwjAJchCLp5do3sDAcx/FV/nuxlua3TSQSOByNyTt25V6Beft1+2 znW77fA8GRAKyp72CiEhSDTaAux9IvXqOLBuR3u+iH0MYd8fCi4tHfZcj WlOofnvO+6ydGc1xnSw7TQevoXBVq0CdmBd2wbIVLGcQXhUXaOHXX9VcG daISxk5fVUk9BFvDLgyBM6OwXgkbpnQfb8fGmUktv7PwcwYmDYIcjqW8p 3GiWGX763DOkCSIoWks0e1htD0P7vHLjwxVO1wiAJT4VGGmTqsLFO2K1o ORqdqpY9CNaTMhZGzibTYruG/MKGFEh95ti5/oJYODky3rq5e7ZlNhBoM A==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224655967" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224655967" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:34:43 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434180" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:34:40 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 01/16] perf record: Introduce thread affinity and mmap masks Date: Mon, 17 Jan 2022 21:34:21 +0300 Message-Id: <9042bf7daf988e17e17e6acbf5d29590bde869cd.1642440724.git.alexey.v.bayduraev@linux.intel.com> X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Introduce affinity and mmap thread masks. Thread affinity mask defines CPUs that a thread is allowed to run on. Thread maps mask defines mmap data buffers the thread serves to stream profiling data from. Acked-by: Andi Kleen Acked-by: Namhyung Kim Reviewed-by: Riccardo Mancini Tested-by: Riccardo Mancini Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/perf/builtin-record.c | 123 ++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index bb716c953d02..41998f2140cd 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -87,6 +87,11 @@ struct switch_output { int cur_file; }; =20 +struct thread_mask { + struct mmap_cpu_mask maps; + struct mmap_cpu_mask affinity; +}; + struct record { struct perf_tool tool; struct record_opts opts; @@ -112,6 +117,8 @@ struct record { struct mmap_cpu_mask affinity_mask; unsigned long output_max_size; /* =3D 0: unlimited */ struct perf_debuginfod debuginfod; + int nr_threads; + struct thread_mask *thread_masks; }; =20 static volatile int done; @@ -2204,6 +2211,47 @@ static int record__parse_affinity(const struct optio= n *opt, const char *str, int return 0; } =20 +static int record__mmap_cpu_mask_alloc(struct mmap_cpu_mask *mask, int nr_= bits) +{ + mask->nbits =3D nr_bits; + mask->bits =3D bitmap_zalloc(mask->nbits); + if (!mask->bits) + return -ENOMEM; + + return 0; +} + +static void record__mmap_cpu_mask_free(struct mmap_cpu_mask *mask) +{ + bitmap_free(mask->bits); + mask->nbits =3D 0; +} + +static int record__thread_mask_alloc(struct thread_mask *mask, int nr_bits) +{ + int ret; + + ret =3D record__mmap_cpu_mask_alloc(&mask->maps, nr_bits); + if (ret) { + mask->affinity.bits =3D NULL; + return ret; + } + + ret =3D record__mmap_cpu_mask_alloc(&mask->affinity, nr_bits); + if (ret) { + record__mmap_cpu_mask_free(&mask->maps); + mask->maps.bits =3D NULL; + } + + return ret; +} + +static void record__thread_mask_free(struct thread_mask *mask) +{ + record__mmap_cpu_mask_free(&mask->maps); + record__mmap_cpu_mask_free(&mask->affinity); +} + static int parse_output_max_size(const struct option *opt, const char *str, int unset) { @@ -2683,6 +2731,73 @@ static struct option __record_options[] =3D { =20 struct option *record_options =3D __record_options; =20 +static void record__mmap_cpu_mask_init(struct mmap_cpu_mask *mask, struct = perf_cpu_map *cpus) +{ + int c; + + for (c =3D 0; c < cpus->nr; c++) + set_bit(cpus->map[c].cpu, mask->bits); +} + +static void record__free_thread_masks(struct record *rec, int nr_threads) +{ + int t; + + if (rec->thread_masks) + for (t =3D 0; t < nr_threads; t++) + record__thread_mask_free(&rec->thread_masks[t]); + + zfree(&rec->thread_masks); +} + +static int record__alloc_thread_masks(struct record *rec, int nr_threads, = int nr_bits) +{ + int t, ret; + + rec->thread_masks =3D zalloc(nr_threads * sizeof(*(rec->thread_masks))); + if (!rec->thread_masks) { + pr_err("Failed to allocate thread masks\n"); + return -ENOMEM; + } + + for (t =3D 0; t < nr_threads; t++) { + ret =3D record__thread_mask_alloc(&rec->thread_masks[t], nr_bits); + if (ret) { + pr_err("Failed to allocate thread masks[%d]\n", t); + goto out_free; + } + } + + return 0; + +out_free: + record__free_thread_masks(rec, nr_threads); + + return ret; +} + +static int record__init_thread_default_masks(struct record *rec, struct pe= rf_cpu_map *cpus) +{ + int ret; + + ret =3D record__alloc_thread_masks(rec, 1, cpu__max_cpu().cpu); + if (ret) + return ret; + + record__mmap_cpu_mask_init(&rec->thread_masks->maps, cpus); + + rec->nr_threads =3D 1; + + return 0; +} + +static int record__init_thread_masks(struct record *rec) +{ + struct perf_cpu_map *cpus =3D rec->evlist->core.cpus; + + return record__init_thread_default_masks(rec, cpus); +} + int cmd_record(int argc, const char **argv) { int err; @@ -2948,6 +3063,12 @@ int cmd_record(int argc, const char **argv) goto out; } =20 + err =3D record__init_thread_masks(rec); + if (err) { + pr_err("Failed to initialize parallel data streaming masks\n"); + goto out; + } + if (rec->opts.nr_cblocks > nr_cblocks_max) rec->opts.nr_cblocks =3D nr_cblocks_max; pr_debug("nr_cblocks: %d\n", rec->opts.nr_cblocks); @@ -2966,6 +3087,8 @@ int cmd_record(int argc, const char **argv) symbol__exit(); auxtrace_record__free(rec->itr); out_opts: + record__free_thread_masks(rec, rec->nr_threads); + rec->nr_threads =3D 0; evlist__close_control(rec->opts.ctl_fd, rec->opts.ctl_fd_ack, &rec->opts.= ctl_fd_close); return err; } --=20 2.19.0 From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 908F3C433EF for ; Mon, 17 Jan 2022 18:36:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232673AbiAQSga (ORCPT ); Mon, 17 Jan 2022 13:36:30 -0500 Received: from mga12.intel.com ([192.55.52.136]:48606 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242628AbiAQSer (ORCPT ); Mon, 17 Jan 2022 13:34:47 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444486; x=1673980486; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mYkC69QeVaw1eSEJY4L24VYYn4aS7wkr+OUnrytuVIU=; b=DjtOYLva9X6VyJYYucFBN4oUD1nvVf9Y9JZmbkH5a80TVoI3mDyGrilM GCkkFZeCFMfeiJtSYV2i6mxaTF1veZC2wNq6Z5Uol1td9cl1Nfw76L8rK IOHDHdU1us3LZxRk27YCBgx2qG6FNytfS1/QzVuDFTh9lEny1tnx2Obf+ MJHuHyq7PKkK5UiB1PNRtTvl64MPu0cG8o/AQ6ID2pMe4KxAmVTq38SN0 PfihSe5BZ3S/qbbue2nnR4PsiRMX3GaNDQvi5arVyQaNbiTXtUcUOyIja 4YyPOg48auHxca8P7OttG3I0f+cTzr4tfCKPdrZJzEXjxkhOKjRL2Wf30 g==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224655971" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224655971" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:34:46 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434184" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:34:43 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 02/16] tools lib: Introduce fdarray duplicate function Date: Mon, 17 Jan 2022 21:34:22 +0300 Message-Id: <2891f1def287d5863cc82683a4d5879195c8d90c.1642440724.git.alexey.v.bayduraev@linux.intel.com> X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Introduce a function to duplicate an existing file descriptor in the fdarray structure. The function returns the position of the duplicated file descriptor. Acked-by: Namhyung Kim Reviewed-by: Riccardo Mancini Tested-by: Riccardo Mancini Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/lib/api/fd/array.c | 17 +++++++++++++++++ tools/lib/api/fd/array.h | 1 + 2 files changed, 18 insertions(+) diff --git a/tools/lib/api/fd/array.c b/tools/lib/api/fd/array.c index 5e6cb9debe37..f0f195207fca 100644 --- a/tools/lib/api/fd/array.c +++ b/tools/lib/api/fd/array.c @@ -88,6 +88,23 @@ int fdarray__add(struct fdarray *fda, int fd, short reve= nts, enum fdarray_flags return pos; } =20 +int fdarray__dup_entry_from(struct fdarray *fda, int pos, struct fdarray *= from) +{ + struct pollfd *entry; + int npos; + + if (pos >=3D from->nr) + return -EINVAL; + + entry =3D &from->entries[pos]; + + npos =3D fdarray__add(fda, entry->fd, entry->events, from->priv[pos].flag= s); + if (npos >=3D 0) + fda->priv[npos] =3D from->priv[pos]; + + return npos; +} + int fdarray__filter(struct fdarray *fda, short revents, void (*entry_destructor)(struct fdarray *fda, int fd, void *arg), void *arg) diff --git a/tools/lib/api/fd/array.h b/tools/lib/api/fd/array.h index 7fcf21a33c0c..60ad197c8ee9 100644 --- a/tools/lib/api/fd/array.h +++ b/tools/lib/api/fd/array.h @@ -42,6 +42,7 @@ struct fdarray *fdarray__new(int nr_alloc, int nr_autogro= w); void fdarray__delete(struct fdarray *fda); =20 int fdarray__add(struct fdarray *fda, int fd, short revents, enum fdarray_= flags flags); +int fdarray__dup_entry_from(struct fdarray *fda, int pos, struct fdarray *= from); int fdarray__poll(struct fdarray *fda, int timeout); int fdarray__filter(struct fdarray *fda, short revents, void (*entry_destructor)(struct fdarray *fda, int fd, void *arg), --=20 2.19.0 From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 64509C433EF for ; Mon, 17 Jan 2022 18:34:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242193AbiAQSew (ORCPT ); Mon, 17 Jan 2022 13:34:52 -0500 Received: from mga12.intel.com ([192.55.52.136]:48606 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242623AbiAQSeu (ORCPT ); Mon, 17 Jan 2022 13:34:50 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444490; x=1673980490; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=nt4t4Xuqp1GYKchGNKkhe1lICgaJ+eeqMu+6O4L6II4=; b=Qyu6/q0tT8qF3zZpZNIIcrDQ9IJbB9fQQtrge+aijSjbWhqx4Cee/edx INbUmG88gKTDVricSS4TbBal73k22hTSzVuAtaZh51HR21E4gGNMvLyLD QSIBHi4Q7+cADyXT59vK3/6n6aMWkoY/m4iSPl2VmaE2T0FPGnNvfz9gM NPCtco4uGv1dKMpiFoEki5f6RKDcADIbyUQPu6HmKP1ZR+Iv2htlezFIq sEQp2+XCEYshVpMCYaJpUzNoO7dFsW1namh865isnTZPWurR+9XtuKcjw zaBWRnxycYJshPFlRYhWqInpVUoIbfuqyd1mRUmo+xALwKWYOoNdowJFM w==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224655981" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224655981" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:34:50 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434191" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:34:47 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 03/16] perf record: Introduce thread specific data array Date: Mon, 17 Jan 2022 21:34:23 +0300 Message-Id: X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Introduce thread specific data object and array of such objects to store and manage thread local data. Implement functions to allocate, initialize, finalize and release thread specific data. Thread local maps and overwrite_maps arrays keep pointers to mmap buffer objects to serve according to maps thread mask. Thread local pollfd array keeps event fds connected to mmaps buffers according to maps thread mask. Thread control commands are delivered via thread local comm pipes and ctlfd_pos fd. External control commands (--control option) are delivered via evlist ctlfd_pos fd and handled by the main tool thread. Acked-by: Namhyung Kim Reviewed-by: Riccardo Mancini Tested-by: Riccardo Mancini Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/perf/builtin-record.c | 247 +++++++++++++++++++++++++++++++++++- 1 file changed, 244 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 41998f2140cd..0d4a34c66274 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -58,6 +58,9 @@ #include #include #include +#ifndef HAVE_GETTID +#include +#endif #include #include #ifdef HAVE_EVENTFD_SUPPORT @@ -92,6 +95,21 @@ struct thread_mask { struct mmap_cpu_mask affinity; }; =20 +struct record_thread { + pid_t tid; + struct thread_mask *mask; + struct { + int msg[2]; + int ack[2]; + } pipes; + struct fdarray pollfd; + int ctlfd_pos; + int nr_mmaps; + struct mmap **maps; + struct mmap **overwrite_maps; + struct record *rec; +}; + struct record { struct perf_tool tool; struct record_opts opts; @@ -119,6 +137,7 @@ struct record { struct perf_debuginfod debuginfod; int nr_threads; struct thread_mask *thread_masks; + struct record_thread *thread_data; }; =20 static volatile int done; @@ -131,6 +150,13 @@ static const char *affinity_tags[PERF_AFFINITY_MAX] = =3D { "SYS", "NODE", "CPU" }; =20 +#ifndef HAVE_GETTID +static inline pid_t gettid(void) +{ + return (pid_t)syscall(__NR_gettid); +} +#endif + static bool switch_output_signal(struct record *rec) { return rec->switch_output.signal && @@ -848,9 +874,218 @@ static int record__kcore_copy(struct machine *machine= , struct perf_data *data) return kcore_copy(from_dir, kcore_dir); } =20 +static void record__thread_data_init_pipes(struct record_thread *thread_da= ta) +{ + thread_data->pipes.msg[0] =3D -1; + thread_data->pipes.msg[1] =3D -1; + thread_data->pipes.ack[0] =3D -1; + thread_data->pipes.ack[1] =3D -1; +} + +static int record__thread_data_open_pipes(struct record_thread *thread_dat= a) +{ + if (pipe(thread_data->pipes.msg)) + return -EINVAL; + + if (pipe(thread_data->pipes.ack)) { + close(thread_data->pipes.msg[0]); + thread_data->pipes.msg[0] =3D -1; + close(thread_data->pipes.msg[1]); + thread_data->pipes.msg[1] =3D -1; + return -EINVAL; + } + + pr_debug2("thread_data[%p]: msg=3D[%d,%d], ack=3D[%d,%d]\n", thread_data, + thread_data->pipes.msg[0], thread_data->pipes.msg[1], + thread_data->pipes.ack[0], thread_data->pipes.ack[1]); + + return 0; +} + +static void record__thread_data_close_pipes(struct record_thread *thread_d= ata) +{ + if (thread_data->pipes.msg[0] !=3D -1) { + close(thread_data->pipes.msg[0]); + thread_data->pipes.msg[0] =3D -1; + } + if (thread_data->pipes.msg[1] !=3D -1) { + close(thread_data->pipes.msg[1]); + thread_data->pipes.msg[1] =3D -1; + } + if (thread_data->pipes.ack[0] !=3D -1) { + close(thread_data->pipes.ack[0]); + thread_data->pipes.ack[0] =3D -1; + } + if (thread_data->pipes.ack[1] !=3D -1) { + close(thread_data->pipes.ack[1]); + thread_data->pipes.ack[1] =3D -1; + } +} + +static int record__thread_data_init_maps(struct record_thread *thread_data= , struct evlist *evlist) +{ + int m, tm, nr_mmaps =3D evlist->core.nr_mmaps; + struct mmap *mmap =3D evlist->mmap; + struct mmap *overwrite_mmap =3D evlist->overwrite_mmap; + struct perf_cpu_map *cpus =3D evlist->core.cpus; + + thread_data->nr_mmaps =3D bitmap_weight(thread_data->mask->maps.bits, + thread_data->mask->maps.nbits); + if (mmap) { + thread_data->maps =3D zalloc(thread_data->nr_mmaps * sizeof(struct mmap = *)); + if (!thread_data->maps) + return -ENOMEM; + } + if (overwrite_mmap) { + thread_data->overwrite_maps =3D zalloc(thread_data->nr_mmaps * sizeof(st= ruct mmap *)); + if (!thread_data->overwrite_maps) { + zfree(&thread_data->maps); + return -ENOMEM; + } + } + pr_debug2("thread_data[%p]: nr_mmaps=3D%d, maps=3D%p, ow_maps=3D%p\n", th= read_data, + thread_data->nr_mmaps, thread_data->maps, thread_data->overwrite_maps); + + for (m =3D 0, tm =3D 0; m < nr_mmaps && tm < thread_data->nr_mmaps; m++) { + if (test_bit(cpus->map[m].cpu, thread_data->mask->maps.bits)) { + if (thread_data->maps) { + thread_data->maps[tm] =3D &mmap[m]; + pr_debug2("thread_data[%p]: cpu%d: maps[%d] -> mmap[%d]\n", + thread_data, cpus->map[m].cpu, tm, m); + } + if (thread_data->overwrite_maps) { + thread_data->overwrite_maps[tm] =3D &overwrite_mmap[m]; + pr_debug2("thread_data[%p]: cpu%d: ow_maps[%d] -> ow_mmap[%d]\n", + thread_data, cpus->map[m].cpu, tm, m); + } + tm++; + } + } + + return 0; +} + +static int record__thread_data_init_pollfd(struct record_thread *thread_da= ta, struct evlist *evlist) +{ + int f, tm, pos; + struct mmap *map, *overwrite_map; + + fdarray__init(&thread_data->pollfd, 64); + + for (tm =3D 0; tm < thread_data->nr_mmaps; tm++) { + map =3D thread_data->maps ? thread_data->maps[tm] : NULL; + overwrite_map =3D thread_data->overwrite_maps ? + thread_data->overwrite_maps[tm] : NULL; + + for (f =3D 0; f < evlist->core.pollfd.nr; f++) { + void *ptr =3D evlist->core.pollfd.priv[f].ptr; + + if ((map && ptr =3D=3D map) || (overwrite_map && ptr =3D=3D overwrite_m= ap)) { + pos =3D fdarray__dup_entry_from(&thread_data->pollfd, f, + &evlist->core.pollfd); + if (pos < 0) + return pos; + pr_debug2("thread_data[%p]: pollfd[%d] <- event_fd=3D%d\n", + thread_data, pos, evlist->core.pollfd.entries[f].fd); + } + } + } + + return 0; +} + +static void record__free_thread_data(struct record *rec) +{ + int t; + struct record_thread *thread_data =3D rec->thread_data; + + if (thread_data =3D=3D NULL) + return; + + for (t =3D 0; t < rec->nr_threads; t++) { + record__thread_data_close_pipes(&thread_data[t]); + zfree(&thread_data[t].maps); + zfree(&thread_data[t].overwrite_maps); + fdarray__exit(&thread_data[t].pollfd); + } + + zfree(&rec->thread_data); +} + +static int record__alloc_thread_data(struct record *rec, struct evlist *ev= list) +{ + int t, ret; + struct record_thread *thread_data; + + rec->thread_data =3D zalloc(rec->nr_threads * sizeof(*(rec->thread_data))= ); + if (!rec->thread_data) { + pr_err("Failed to allocate thread data\n"); + return -ENOMEM; + } + thread_data =3D rec->thread_data; + + for (t =3D 0; t < rec->nr_threads; t++) + record__thread_data_init_pipes(&thread_data[t]); + + for (t =3D 0; t < rec->nr_threads; t++) { + thread_data[t].rec =3D rec; + thread_data[t].mask =3D &rec->thread_masks[t]; + ret =3D record__thread_data_init_maps(&thread_data[t], evlist); + if (ret) { + pr_err("Failed to initialize thread[%d] maps\n", t); + goto out_free; + } + ret =3D record__thread_data_init_pollfd(&thread_data[t], evlist); + if (ret) { + pr_err("Failed to initialize thread[%d] pollfd\n", t); + goto out_free; + } + if (t) { + thread_data[t].tid =3D -1; + ret =3D record__thread_data_open_pipes(&thread_data[t]); + if (ret) { + pr_err("Failed to open thread[%d] communication pipes\n", t); + goto out_free; + } + ret =3D fdarray__add(&thread_data[t].pollfd, thread_data[t].pipes.msg[0= ], + POLLIN | POLLERR | POLLHUP, fdarray_flag__nonfilterable); + if (ret < 0) { + pr_err("Failed to add descriptor to thread[%d] pollfd\n", t); + goto out_free; + } + thread_data[t].ctlfd_pos =3D ret; + pr_debug2("thread_data[%p]: pollfd[%d] <- ctl_fd=3D%d\n", + thread_data, thread_data[t].ctlfd_pos, + thread_data[t].pipes.msg[0]); + } else { + thread_data[t].tid =3D gettid(); + if (evlist->ctl_fd.pos =3D=3D -1) + continue; + ret =3D fdarray__dup_entry_from(&thread_data[t].pollfd, evlist->ctl_fd.= pos, + &evlist->core.pollfd); + if (ret < 0) { + pr_err("Failed to duplicate descriptor in main thread pollfd\n"); + goto out_free; + } + thread_data[t].ctlfd_pos =3D ret; + pr_debug2("thread_data[%p]: pollfd[%d] <- ctl_fd=3D%d\n", + thread_data, thread_data[t].ctlfd_pos, + evlist->core.pollfd.entries[evlist->ctl_fd.pos].fd); + } + } + + return 0; + +out_free: + record__free_thread_data(rec); + + return ret; +} + static int record__mmap_evlist(struct record *rec, struct evlist *evlist) { + int ret; struct record_opts *opts =3D &rec->opts; bool auxtrace_overwrite =3D opts->auxtrace_snapshot_mode || opts->auxtrace_sample_mode; @@ -881,6 +1116,14 @@ static int record__mmap_evlist(struct record *rec, return -EINVAL; } } + + if (evlist__initialize_ctlfd(evlist, opts->ctl_fd, opts->ctl_fd_ack)) + return -1; + + ret =3D record__alloc_thread_data(rec, evlist); + if (ret) + return ret; + return 0; } =20 @@ -1862,9 +2105,6 @@ static int __cmd_record(struct record *rec, int argc,= const char **argv) evlist__start_workload(rec->evlist); } =20 - if (evlist__initialize_ctlfd(rec->evlist, opts->ctl_fd, opts->ctl_fd_ack)) - goto out_child; - if (opts->initial_delay) { pr_info(EVLIST_DISABLED_MSG); if (opts->initial_delay > 0) { @@ -2022,6 +2262,7 @@ static int __cmd_record(struct record *rec, int argc,= const char **argv) out_child: evlist__finalize_ctlfd(rec->evlist); record__mmap_read_all(rec, true); + record__free_thread_data(rec); record__aio_mmap_read_sync(rec); =20 if (rec->session->bytes_transferred && rec->session->bytes_compressed) { --=20 2.19.0 From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9A630C433EF for ; Mon, 17 Jan 2022 18:34:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242712AbiAQSe5 (ORCPT ); Mon, 17 Jan 2022 13:34:57 -0500 Received: from mga12.intel.com ([192.55.52.136]:48606 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242674AbiAQSex (ORCPT ); Mon, 17 Jan 2022 13:34:53 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444493; x=1673980493; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=erpC/Dx6pqbW4EyR2ekvXQCrbWogcl+3QBNVqLLTqXQ=; b=iK+uDiYlfeODitGLbJsa3MrwaBn1K5g+WeBm6057MTgeyuUydBgMkcGP 01Ok40i+GU3/PhfRN5nxVPSRkJxzwLGuLyEnFOUmC3AXU+jF0hM7fOrHl Fhy48pTWWUQ/PzS3oqsRnNa9Nb/lB9GJh2K91zoBXBrc9E4I2XPw1JviS oz0gt9SaxhscgYLVJSTz9Viqq/5Y79z47NOIFtkbXtl+kaLM5sQ16HlhJ 2wuvNOnGqbNCbNEZ5Ql+DQWYNfDDhRIilT8F+IUMcASSQacKVwcr7u5Mo /OpJL8lzlo4dFSrZYd9uHxGbQM7YyUJ1KQGOtz0F5K7zDfZtnOODTSBTG w==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224655987" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224655987" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:34:53 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434211" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:34:50 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 04/16] perf record: Introduce function to propagate control commands Date: Mon, 17 Jan 2022 21:34:24 +0300 Message-Id: <7df52c9816b13c74897b9e518128b29a391462fe.1642440724.git.alexey.v.bayduraev@linux.intel.com> X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Introduce evlist__ctlfd_update() function to propagate external control commands to global evlist object. Acked-by: Andi Kleen Acked-by: Namhyung Kim Reviewed-by: Riccardo Mancini Tested-by: Riccardo Mancini Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/perf/util/evlist.c | 16 ++++++++++++++++ tools/perf/util/evlist.h | 1 + 2 files changed, 17 insertions(+) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 6e88d404b5b3..48a865221636 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -2131,6 +2131,22 @@ int evlist__ctlfd_process(struct evlist *evlist, enu= m evlist_ctl_cmd *cmd) return err; } =20 +int evlist__ctlfd_update(struct evlist *evlist, struct pollfd *update) +{ + int ctlfd_pos =3D evlist->ctl_fd.pos; + struct pollfd *entries =3D evlist->core.pollfd.entries; + + if (!evlist__ctlfd_initialized(evlist)) + return 0; + + if (entries[ctlfd_pos].fd !=3D update->fd || + entries[ctlfd_pos].events !=3D update->events) + return -1; + + entries[ctlfd_pos].revents =3D update->revents; + return 0; +} + struct evsel *evlist__find_evsel(struct evlist *evlist, int idx) { struct evsel *evsel; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 64cba56fbc74..a21daaa5fc1b 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -410,6 +410,7 @@ void evlist__close_control(int ctl_fd, int ctl_fd_ack, = bool *ctl_fd_close); int evlist__initialize_ctlfd(struct evlist *evlist, int ctl_fd, int ctl_fd= _ack); int evlist__finalize_ctlfd(struct evlist *evlist); bool evlist__ctlfd_initialized(struct evlist *evlist); +int evlist__ctlfd_update(struct evlist *evlist, struct pollfd *update); int evlist__ctlfd_process(struct evlist *evlist, enum evlist_ctl_cmd *cmd); int evlist__ctlfd_ack(struct evlist *evlist); =20 --=20 2.19.0 From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A0EBAC433F5 for ; Mon, 17 Jan 2022 18:35:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242705AbiAQSe7 (ORCPT ); Mon, 17 Jan 2022 13:34:59 -0500 Received: from mga12.intel.com ([192.55.52.136]:48606 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242708AbiAQSe5 (ORCPT ); Mon, 17 Jan 2022 13:34:57 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444497; x=1673980497; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=jZd+8dmje7szDGLDnWKkGcY40ZV41aftv5QtfGDWTao=; b=lOGAGPIUd9p3JTtEQjviAWeSfGaJIMCFKSAKlPLy1SvgVuC2jR4CO/gP 0hQB4uWEeSmf2xp2J/qHhseNZ1lsl/eWFlRUzNpir7Meby1j9xmJHzMkW 9tWVaTbfn69m0Ej+HTRJCvHaUgJjuAzdBH3r/MrwKMQnS2z1s9cAq/vlY WvU+enSp3MjYMFRWFyIo1S9WEKYc9xIOn26jmw7BlKRBDX2IsfLfbfEjo 2CVrN9jD8+brfCCtrNrgLAMvMqycmpmk3EtjpJFpC/rnnNx6AT1PCNNPc cJBwZCiBS3VTQnC9r3fcEd1Of7rXwr/USz/J9L4HwwE9X+oz58dWfJF62 g==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224655992" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224655992" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:34:57 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434221" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:34:53 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 05/16] perf record: Introduce thread local variable Date: Mon, 17 Jan 2022 21:34:25 +0300 Message-Id: <0d127555219991c1dcd6c6bb76b24fa6b78d2932.1642440724.git.alexey.v.bayduraev@linux.intel.com> X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Introduce thread local variable and use it for threaded trace streaming. Use thread affinity mask instead of record affinity mask in affinity modes. Use evlist__ctlfd_update() to propagate control commands from thread object to global evlist object to enable evlist__ctlfd_* functionality. Move waking and sample statistic to struct record_thread and introduce record__waking function to calculate the total number of wakes. Acked-by: Andi Kleen Acked-by: Namhyung Kim Reviewed-by: Riccardo Mancini Tested-by: Riccardo Mancini Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/perf/builtin-record.c | 140 ++++++++++++++++++++++++------------ 1 file changed, 94 insertions(+), 46 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0d4a34c66274..163d261dd293 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -108,8 +108,12 @@ struct record_thread { struct mmap **maps; struct mmap **overwrite_maps; struct record *rec; + unsigned long long samples; + unsigned long waking; }; =20 +static __thread struct record_thread *thread; + struct record { struct perf_tool tool; struct record_opts opts; @@ -132,7 +136,6 @@ struct record { bool timestamp_boundary; struct switch_output switch_output; unsigned long long samples; - struct mmap_cpu_mask affinity_mask; unsigned long output_max_size; /* =3D 0: unlimited */ struct perf_debuginfod debuginfod; int nr_threads; @@ -575,7 +578,7 @@ static int record__pushfn(struct mmap *map, void *to, v= oid *bf, size_t size) bf =3D map->data; } =20 - rec->samples++; + thread->samples++; return record__write(rec, map, bf, size); } =20 @@ -1315,15 +1318,17 @@ static struct perf_event_header finished_round_even= t =3D { static void record__adjust_affinity(struct record *rec, struct mmap *map) { if (rec->opts.affinity !=3D PERF_AFFINITY_SYS && - !bitmap_equal(rec->affinity_mask.bits, map->affinity_mask.bits, - rec->affinity_mask.nbits)) { - bitmap_zero(rec->affinity_mask.bits, rec->affinity_mask.nbits); - bitmap_or(rec->affinity_mask.bits, rec->affinity_mask.bits, - map->affinity_mask.bits, rec->affinity_mask.nbits); - sched_setaffinity(0, MMAP_CPU_MASK_BYTES(&rec->affinity_mask), - (cpu_set_t *)rec->affinity_mask.bits); - if (verbose =3D=3D 2) - mmap_cpu_mask__scnprintf(&rec->affinity_mask, "thread"); + !bitmap_equal(thread->mask->affinity.bits, map->affinity_mask.bits, + thread->mask->affinity.nbits)) { + bitmap_zero(thread->mask->affinity.bits, thread->mask->affinity.nbits); + bitmap_or(thread->mask->affinity.bits, thread->mask->affinity.bits, + map->affinity_mask.bits, thread->mask->affinity.nbits); + sched_setaffinity(0, MMAP_CPU_MASK_BYTES(&thread->mask->affinity), + (cpu_set_t *)thread->mask->affinity.bits); + if (verbose =3D=3D 2) { + pr_debug("threads[%d]: running on cpu%d: ", thread->tid, sched_getcpu()= ); + mmap_cpu_mask__scnprintf(&thread->mask->affinity, "affinity"); + } } } =20 @@ -1364,14 +1369,17 @@ static int record__mmap_read_evlist(struct record *= rec, struct evlist *evlist, u64 bytes_written =3D rec->bytes_written; int i; int rc =3D 0; - struct mmap *maps; + int nr_mmaps; + struct mmap **maps; int trace_fd =3D rec->data.file.fd; off_t off =3D 0; =20 if (!evlist) return 0; =20 - maps =3D overwrite ? evlist->overwrite_mmap : evlist->mmap; + nr_mmaps =3D thread->nr_mmaps; + maps =3D overwrite ? thread->overwrite_maps : thread->maps; + if (!maps) return 0; =20 @@ -1381,9 +1389,9 @@ static int record__mmap_read_evlist(struct record *re= c, struct evlist *evlist, if (record__aio_enabled(rec)) off =3D record__aio_get_pos(trace_fd); =20 - for (i =3D 0; i < evlist->core.nr_mmaps; i++) { + for (i =3D 0; i < nr_mmaps; i++) { u64 flush =3D 0; - struct mmap *map =3D &maps[i]; + struct mmap *map =3D maps[i]; =20 if (map->core.base) { record__adjust_affinity(rec, map); @@ -1446,6 +1454,15 @@ static int record__mmap_read_all(struct record *rec,= bool synch) return record__mmap_read_evlist(rec, rec->evlist, true, synch); } =20 +static void record__thread_munmap_filtered(struct fdarray *fda, int fd, + void *arg __maybe_unused) +{ + struct perf_mmap *map =3D fda->priv[fd].ptr; + + if (map) + perf_mmap__put(map); +} + static void record__init_features(struct record *rec) { struct perf_session *session =3D rec->session; @@ -1869,11 +1886,44 @@ static void record__uniquify_name(struct record *re= c) } } =20 +static int record__start_threads(struct record *rec) +{ + struct record_thread *thread_data =3D rec->thread_data; + + thread =3D &thread_data[0]; + + pr_debug("threads[%d]: started on cpu%d\n", thread->tid, sched_getcpu()); + + return 0; +} + +static int record__stop_threads(struct record *rec) +{ + int t; + struct record_thread *thread_data =3D rec->thread_data; + + for (t =3D 0; t < rec->nr_threads; t++) + rec->samples +=3D thread_data[t].samples; + + return 0; +} + +static unsigned long record__waking(struct record *rec) +{ + int t; + unsigned long waking =3D 0; + struct record_thread *thread_data =3D rec->thread_data; + + for (t =3D 0; t < rec->nr_threads; t++) + waking +=3D thread_data[t].waking; + + return waking; +} + static int __cmd_record(struct record *rec, int argc, const char **argv) { int err; int status =3D 0; - unsigned long waking =3D 0; const bool forks =3D argc > 0; struct perf_tool *tool =3D &rec->tool; struct record_opts *opts =3D &rec->opts; @@ -1977,7 +2027,7 @@ static int __cmd_record(struct record *rec, int argc,= const char **argv) =20 if (record__open(rec) !=3D 0) { err =3D -1; - goto out_child; + goto out_free_threads; } session->header.env.comp_mmap_len =3D session->evlist->core.mmap_len; =20 @@ -1985,7 +2035,7 @@ static int __cmd_record(struct record *rec, int argc,= const char **argv) err =3D record__kcore_copy(&session->machines.host, data); if (err) { pr_err("ERROR: Failed to copy kcore\n"); - goto out_child; + goto out_free_threads; } } =20 @@ -1996,7 +2046,7 @@ static int __cmd_record(struct record *rec, int argc,= const char **argv) bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf)); pr_err("ERROR: Apply config to BPF failed: %s\n", errbuf); - goto out_child; + goto out_free_threads; } =20 /* @@ -2014,11 +2064,11 @@ static int __cmd_record(struct record *rec, int arg= c, const char **argv) if (data->is_pipe) { err =3D perf_header__write_pipe(fd); if (err < 0) - goto out_child; + goto out_free_threads; } else { err =3D perf_session__write_header(session, rec->evlist, fd, false); if (err < 0) - goto out_child; + goto out_free_threads; } =20 err =3D -1; @@ -2026,16 +2076,16 @@ static int __cmd_record(struct record *rec, int arg= c, const char **argv) && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) { pr_err("Couldn't generate buildids. " "Use --no-buildid to profile anyway.\n"); - goto out_child; + goto out_free_threads; } =20 err =3D record__setup_sb_evlist(rec); if (err) - goto out_child; + goto out_free_threads; =20 err =3D record__synthesize(rec, false); if (err < 0) - goto out_child; + goto out_free_threads; =20 if (rec->realtime_prio) { struct sched_param param; @@ -2044,10 +2094,13 @@ static int __cmd_record(struct record *rec, int arg= c, const char **argv) if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { pr_err("Could not set realtime priority.\n"); err =3D -1; - goto out_child; + goto out_free_threads; } } =20 + if (record__start_threads(rec)) + goto out_free_threads; + /* * When perf is starting the traced process, all the events * (apart from group members) have enable_on_exec=3D1 set, @@ -2118,7 +2171,7 @@ static int __cmd_record(struct record *rec, int argc,= const char **argv) trigger_ready(&switch_output_trigger); perf_hooks__invoke_record_start(); for (;;) { - unsigned long long hits =3D rec->samples; + unsigned long long hits =3D thread->samples; =20 /* * rec->evlist->bkw_mmap_state is possible to be @@ -2172,8 +2225,8 @@ static int __cmd_record(struct record *rec, int argc,= const char **argv) =20 if (!quiet) fprintf(stderr, "[ perf record: dump data: Woken up %ld times ]\n", - waking); - waking =3D 0; + record__waking(rec)); + thread->waking =3D 0; fd =3D record__switch_output(rec, false); if (fd < 0) { pr_err("Failed to switch to new file\n"); @@ -2187,20 +2240,24 @@ static int __cmd_record(struct record *rec, int arg= c, const char **argv) alarm(rec->switch_output.time); } =20 - if (hits =3D=3D rec->samples) { + if (hits =3D=3D thread->samples) { if (done || draining) break; - err =3D evlist__poll(rec->evlist, -1); + err =3D fdarray__poll(&thread->pollfd, -1); /* * Propagate error, only if there's any. Ignore positive * number of returned events and interrupt error. */ if (err > 0 || (err < 0 && errno =3D=3D EINTR)) err =3D 0; - waking++; + thread->waking++; =20 - if (evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) =3D=3D 0) + if (fdarray__filter(&thread->pollfd, POLLERR | POLLHUP, + record__thread_munmap_filtered, NULL) =3D=3D 0) draining =3D true; + + evlist__ctlfd_update(rec->evlist, + &thread->pollfd.entries[thread->ctlfd_pos]); } =20 if (evlist__ctlfd_process(rec->evlist, &cmd) > 0) { @@ -2254,15 +2311,18 @@ static int __cmd_record(struct record *rec, int arg= c, const char **argv) } =20 if (!quiet) - fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", w= aking); + fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", + record__waking(rec)); =20 if (target__none(&rec->opts.target)) record__synthesize_workload(rec, true); =20 out_child: - evlist__finalize_ctlfd(rec->evlist); + record__stop_threads(rec); record__mmap_read_all(rec, true); +out_free_threads: record__free_thread_data(rec); + evlist__finalize_ctlfd(rec->evlist); record__aio_mmap_read_sync(rec); =20 if (rec->session->bytes_transferred && rec->session->bytes_compressed) { @@ -3164,17 +3224,6 @@ int cmd_record(int argc, const char **argv) =20 symbol__init(NULL); =20 - if (rec->opts.affinity !=3D PERF_AFFINITY_SYS) { - rec->affinity_mask.nbits =3D cpu__max_cpu().cpu; - rec->affinity_mask.bits =3D bitmap_zalloc(rec->affinity_mask.nbits); - if (!rec->affinity_mask.bits) { - pr_err("Failed to allocate thread mask for %zd cpus\n", rec->affinity_m= ask.nbits); - err =3D -ENOMEM; - goto out_opts; - } - pr_debug2("thread mask[%zd]: empty\n", rec->affinity_mask.nbits); - } - err =3D record__auxtrace_init(rec); if (err) goto out; @@ -3323,7 +3372,6 @@ int cmd_record(int argc, const char **argv) =20 err =3D __cmd_record(&record, argc, argv); out: - bitmap_free(rec->affinity_mask.bits); evlist__delete(rec->evlist); symbol__exit(); auxtrace_record__free(rec->itr); --=20 2.19.0 From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9E13DC433EF for ; Mon, 17 Jan 2022 18:35:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242753AbiAQSfH (ORCPT ); Mon, 17 Jan 2022 13:35:07 -0500 Received: from mga12.intel.com ([192.55.52.136]:48606 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242714AbiAQSfB (ORCPT ); Mon, 17 Jan 2022 13:35:01 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444501; x=1673980501; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=0aHYD73piCArIhy7L3X52iWfwqLV+CmuHF+Tctl2QoI=; b=QUaQ9daO8cJsEgvUfNHYCVRrB/9zwgNLD8B16sgkkYsPf2psVTPBhl4n 1H0rdojQk6q4GAAVXneBYfZWyELqal4ZgvwoyBBGxKBtEXksHhq1QF6Ys QpsKq3GNyH1PIAJiNGHUTkPd0pbSWcjBqWLjAc61J0VYdB2oTxK+N6xWq S9Ry+UVjS3ZUGT29QGu5bBZ6Am59a2LM5pEohkBWKCg/lO/T3nuePnddC E7u522wRsmX2ZJKPdHifEAaaP9jR51f7rxa0/UNHUXvBVL+Cwajm6C6LI qp+TCH3bFPTzqF1S4lF3t+U9b73uveL5t+OqcdmJdFwxSbahnymGDKJQe w==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224656000" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224656000" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:35:00 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434227" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:34:57 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 06/16] perf record: Stop threads in the end of trace streaming Date: Mon, 17 Jan 2022 21:34:26 +0300 Message-Id: <55ef8cc5ec3a96360660d9dc1763573225325f8c.1642440724.git.alexey.v.bayduraev@linux.intel.com> X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Signal thread to terminate by closing write fd of msg pipe. Receive THREAD_MSG__READY message as the confirmation of the thread's termination. Stop threads created for parallel trace streaming prior their stats processing. Acked-by: Andi Kleen Acked-by: Namhyung Kim Reviewed-by: Riccardo Mancini Tested-by: Riccardo Mancini Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/perf/builtin-record.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 163d261dd293..0e65b80927b7 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -114,6 +114,16 @@ struct record_thread { =20 static __thread struct record_thread *thread; =20 +enum thread_msg { + THREAD_MSG__UNDEFINED =3D 0, + THREAD_MSG__READY, + THREAD_MSG__MAX, +}; + +static const char *thread_msg_tags[THREAD_MSG__MAX] =3D { + "UNDEFINED", "READY" +}; + struct record { struct perf_tool tool; struct record_opts opts; @@ -1886,6 +1896,24 @@ static void record__uniquify_name(struct record *rec) } } =20 +static int record__terminate_thread(struct record_thread *thread_data) +{ + int err; + enum thread_msg ack =3D THREAD_MSG__UNDEFINED; + pid_t tid =3D thread_data->tid; + + close(thread_data->pipes.msg[1]); + thread_data->pipes.msg[1] =3D -1; + err =3D read(thread_data->pipes.ack[0], &ack, sizeof(ack)); + if (err > 0) + pr_debug2("threads[%d]: sent %s\n", tid, thread_msg_tags[ack]); + else + pr_warning("threads[%d]: failed to receive termination notification from= %d\n", + thread->tid, tid); + + return 0; +} + static int record__start_threads(struct record *rec) { struct record_thread *thread_data =3D rec->thread_data; @@ -1902,6 +1930,9 @@ static int record__stop_threads(struct record *rec) int t; struct record_thread *thread_data =3D rec->thread_data; =20 + for (t =3D 1; t < rec->nr_threads; t++) + record__terminate_thread(&thread_data[t]); + for (t =3D 0; t < rec->nr_threads; t++) rec->samples +=3D thread_data[t].samples; =20 --=20 2.19.0 From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3C799C433EF for ; Mon, 17 Jan 2022 18:35:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242769AbiAQSfM (ORCPT ); Mon, 17 Jan 2022 13:35:12 -0500 Received: from mga12.intel.com ([192.55.52.136]:48625 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242751AbiAQSfD (ORCPT ); Mon, 17 Jan 2022 13:35:03 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444503; x=1673980503; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=vsyZWwGBsGFhD3Lx8Tnil6HXjJubaiVUXye0tTrVZ7E=; b=K3fCp9eH8qIirRK1OSAyF5KUNTtOZy49pNLwWE7WVc5Qn8Vx4eQxnENg o31Y5384tjO7oHvgLAoh7C23S00ahbMduRQoCQsM/T7jfKI4Yyegb9dbG kK89EOToZ7nMBwzsqTrG4g8lVlSDT+MA57U0J7IfRqq1EU5xhoo36MHlA euvXe+S2hD6HGBHWv3pEm7wv46Z10yGwKUdFFQptd/O7Fv/WiB5YVnXP+ KnzEIO3+9HBtRDYLqs12R7PLcUCA9kku04/nCaVKZZBXPwxb1avUYnfWh kt6fhqBrxJ8eke/SqFoyJ8JenpcNn/3VicbooRZm1d1n1vmZr89+w+oTC A==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224656003" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224656003" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:35:03 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434242" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:35:00 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 07/16] perf record: Start threads in the beginning of trace streaming Date: Mon, 17 Jan 2022 21:34:27 +0300 Message-Id: <95784dd9f7c81ee408eab27b50b4c09ad4cf7be6.1642440724.git.alexey.v.bayduraev@linux.intel.com> X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Start thread in detached state because its management is implemented via messaging to avoid any scaling issues. Block signals prior thread start so only main tool thread would be notified on external async signals during data collection. Thread affinity mask is used to assign eligible CPUs for the thread to run. Wait and sync on thread start using thread ack pipe. Acked-by: Namhyung Kim Reviewed-by: Riccardo Mancini Tested-by: Riccardo Mancini Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/perf/builtin-record.c | 121 +++++++++++++++++++++++++++++++++++- tools/perf/util/record.h | 1 + 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0e65b80927b7..517520ae1520 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -170,6 +170,11 @@ static inline pid_t gettid(void) } #endif =20 +static int record__threads_enabled(struct record *rec) +{ + return rec->opts.threads_spec; +} + static bool switch_output_signal(struct record *rec) { return rec->switch_output.signal && @@ -1473,6 +1478,68 @@ static void record__thread_munmap_filtered(struct fd= array *fda, int fd, perf_mmap__put(map); } =20 +static void *record__thread(void *arg) +{ + enum thread_msg msg =3D THREAD_MSG__READY; + bool terminate =3D false; + struct fdarray *pollfd; + int err, ctlfd_pos; + + thread =3D arg; + thread->tid =3D gettid(); + + err =3D write(thread->pipes.ack[1], &msg, sizeof(msg)); + if (err =3D=3D -1) + pr_warning("threads[%d]: failed to notify on start: %s\n", + thread->tid, strerror(errno)); + + pr_debug("threads[%d]: started on cpu%d\n", thread->tid, sched_getcpu()); + + pollfd =3D &thread->pollfd; + ctlfd_pos =3D thread->ctlfd_pos; + + for (;;) { + unsigned long long hits =3D thread->samples; + + if (record__mmap_read_all(thread->rec, false) < 0 || terminate) + break; + + if (hits =3D=3D thread->samples) { + + err =3D fdarray__poll(pollfd, -1); + /* + * Propagate error, only if there's any. Ignore positive + * number of returned events and interrupt error. + */ + if (err > 0 || (err < 0 && errno =3D=3D EINTR)) + err =3D 0; + thread->waking++; + + if (fdarray__filter(pollfd, POLLERR | POLLHUP, + record__thread_munmap_filtered, NULL) =3D=3D 0) + break; + } + + if (pollfd->entries[ctlfd_pos].revents & POLLHUP) { + terminate =3D true; + close(thread->pipes.msg[0]); + thread->pipes.msg[0] =3D -1; + pollfd->entries[ctlfd_pos].fd =3D -1; + pollfd->entries[ctlfd_pos].events =3D 0; + } + + pollfd->entries[ctlfd_pos].revents =3D 0; + } + record__mmap_read_all(thread->rec, true); + + err =3D write(thread->pipes.ack[1], &msg, sizeof(msg)); + if (err =3D=3D -1) + pr_warning("threads[%d]: failed to notify on termination: %s\n", + thread->tid, strerror(errno)); + + return NULL; +} + static void record__init_features(struct record *rec) { struct perf_session *session =3D rec->session; @@ -1916,13 +1983,65 @@ static int record__terminate_thread(struct record_t= hread *thread_data) =20 static int record__start_threads(struct record *rec) { + int t, tt, err, ret =3D 0, nr_threads =3D rec->nr_threads; struct record_thread *thread_data =3D rec->thread_data; + sigset_t full, mask; + pthread_t handle; + pthread_attr_t attrs; =20 thread =3D &thread_data[0]; =20 + if (!record__threads_enabled(rec)) + return 0; + + sigfillset(&full); + if (sigprocmask(SIG_SETMASK, &full, &mask)) { + pr_err("Failed to block signals on threads start: %s\n", strerror(errno)= ); + return -1; + } + + pthread_attr_init(&attrs); + pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED); + + for (t =3D 1; t < nr_threads; t++) { + enum thread_msg msg =3D THREAD_MSG__UNDEFINED; + +#ifdef HAVE_PTHREAD_ATTR_SETAFFINITY_NP + pthread_attr_setaffinity_np(&attrs, + MMAP_CPU_MASK_BYTES(&(thread_data[t].mask->affinity)), + (cpu_set_t *)(thread_data[t].mask->affinity.bits)); +#endif + if (pthread_create(&handle, &attrs, record__thread, &thread_data[t])) { + for (tt =3D 1; tt < t; tt++) + record__terminate_thread(&thread_data[t]); + pr_err("Failed to start threads: %s\n", strerror(errno)); + ret =3D -1; + goto out_err; + } + + err =3D read(thread_data[t].pipes.ack[0], &msg, sizeof(msg)); + if (err > 0) + pr_debug2("threads[%d]: sent %s\n", rec->thread_data[t].tid, + thread_msg_tags[msg]); + else + pr_warning("threads[%d]: failed to receive start notification from %d\n= ", + thread->tid, rec->thread_data[t].tid); + } + + sched_setaffinity(0, MMAP_CPU_MASK_BYTES(&thread->mask->affinity), + (cpu_set_t *)thread->mask->affinity.bits); + pr_debug("threads[%d]: started on cpu%d\n", thread->tid, sched_getcpu()); =20 - return 0; +out_err: + pthread_attr_destroy(&attrs); + + if (sigprocmask(SIG_SETMASK, &mask, NULL)) { + pr_err("Failed to unblock signals on threads start: %s\n", strerror(errn= o)); + ret =3D -1; + } + + return ret; } =20 static int record__stop_threads(struct record *rec) diff --git a/tools/perf/util/record.h b/tools/perf/util/record.h index ef6c2715fdd9..ad08c092f3dd 100644 --- a/tools/perf/util/record.h +++ b/tools/perf/util/record.h @@ -78,6 +78,7 @@ struct record_opts { int ctl_fd_ack; bool ctl_fd_close; int synth; + int threads_spec; }; =20 extern const char * const *record_usage; --=20 2.19.0 From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D87B0C433F5 for ; Mon, 17 Jan 2022 18:35:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242808AbiAQSfO (ORCPT ); Mon, 17 Jan 2022 13:35:14 -0500 Received: from mga12.intel.com ([192.55.52.136]:48629 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242747AbiAQSfH (ORCPT ); Mon, 17 Jan 2022 13:35:07 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444507; x=1673980507; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=AL4EKZNnBI2MBBIv8OMH0sp//vTHeZd9Kg5ZpCYp7Zw=; b=E0/ZKe0BTDH5zk248GcauGY0E/KMPOib2pVJ1QNcicMJtJGaBcUZklLI z+uuXnhWlpioW46NImeuED7tRgwraYqwsEZ4PGaD/mcuNEbAYSOo7VwLF sgy81oINupQ+P/mf+Af7zdoVQrlUH4SC2ezhPXSQw/Zre+6DwQ1LlRnyH TVsW5yUc9v5HzUu2y9Q2BU9kZpTlXfGf2YV3JkM+DzIQYDKWYjQPJ5xz9 X+QBiqNh/uN8GLy9NBSsv1tNQVh6lI3zOmYqF164KRk5ogJaHmkVT4X0W yNnycN+G7O5Q7XRDwom5OT2dtJpQ5UOTYGK9J5PA8DCcTtH5cuPc8SZaX A==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224656016" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224656016" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:35:07 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434267" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:35:03 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 08/16] perf record: Introduce data file at mmap buffer object Date: Mon, 17 Jan 2022 21:34:28 +0300 Message-Id: <177077f7734b63e5c999ccd75ac6dc3c694f0d0d.1642440724.git.alexey.v.bayduraev@linux.intel.com> X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Introduce data file objects into mmap object so it could be used to process and store data stream from the corresponding kernel data buffer. Initialize data files located at mmap buffer objects so trace data can be written into several data file located at data directory. Acked-by: Andi Kleen Acked-by: Namhyung Kim Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/perf/builtin-record.c | 37 ++++++++++++++++++++++++++++++++----- tools/perf/util/mmap.h | 1 + 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 517520ae1520..8766a3dc9440 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -205,12 +205,16 @@ static int record__write(struct record *rec, struct m= map *map __maybe_unused, { struct perf_data_file *file =3D &rec->session->data->file; =20 + if (map && map->file) + file =3D map->file; + if (perf_data_file__write(file, bf, size) < 0) { pr_err("failed to write perf data, error: %m\n"); return -1; } =20 - rec->bytes_written +=3D size; + if (!(map && map->file)) + rec->bytes_written +=3D size; =20 if (record__output_max_size_exceeded(rec) && !done) { fprintf(stderr, "[ perf record: perf size limit reached (%" PRIu64 " KB)= ," @@ -1103,7 +1107,7 @@ static int record__alloc_thread_data(struct record *r= ec, struct evlist *evlist) static int record__mmap_evlist(struct record *rec, struct evlist *evlist) { - int ret; + int i, ret; struct record_opts *opts =3D &rec->opts; bool auxtrace_overwrite =3D opts->auxtrace_snapshot_mode || opts->auxtrace_sample_mode; @@ -1142,6 +1146,18 @@ static int record__mmap_evlist(struct record *rec, if (ret) return ret; =20 + if (record__threads_enabled(rec)) { + ret =3D perf_data__create_dir(&rec->data, evlist->core.nr_mmaps); + if (ret) + return ret; + for (i =3D 0; i < evlist->core.nr_mmaps; i++) { + if (evlist->mmap) + evlist->mmap[i].file =3D &rec->data.dir.files[i]; + if (evlist->overwrite_mmap) + evlist->overwrite_mmap[i].file =3D &rec->data.dir.files[i]; + } + } + return 0; } =20 @@ -1448,8 +1464,12 @@ static int record__mmap_read_evlist(struct record *r= ec, struct evlist *evlist, /* * Mark the round finished in case we wrote * at least one event. + * + * No need for round events in directory mode, + * because per-cpu maps and files have data + * sorted by kernel. */ - if (bytes_written !=3D rec->bytes_written) + if (!record__threads_enabled(rec) && bytes_written !=3D rec->bytes_writte= n) rc =3D record__write(rec, NULL, &finished_round_event, sizeof(finished_r= ound_event)); =20 if (overwrite) @@ -1566,7 +1586,9 @@ static void record__init_features(struct record *rec) if (!rec->opts.use_clockid) perf_header__clear_feat(&session->header, HEADER_CLOCK_DATA); =20 - perf_header__clear_feat(&session->header, HEADER_DIR_FORMAT); + if (!record__threads_enabled(rec)) + perf_header__clear_feat(&session->header, HEADER_DIR_FORMAT); + if (!record__comp_enabled(rec)) perf_header__clear_feat(&session->header, HEADER_COMPRESSED); =20 @@ -1576,6 +1598,7 @@ static void record__init_features(struct record *rec) static void record__finish_output(struct record *rec) { + int i; struct perf_data *data =3D &rec->data; int fd =3D perf_data__fd(data); =20 @@ -1584,6 +1607,10 @@ record__finish_output(struct record *rec) =20 rec->session->header.data_size +=3D rec->bytes_written; data->file.size =3D lseek(perf_data__fd(data), 0, SEEK_CUR); + if (record__threads_enabled(rec)) { + for (i =3D 0; i < data->dir.nr; i++) + data->dir.files[i].size =3D lseek(data->dir.files[i].fd, 0, SEEK_CUR); + } =20 if (!rec->no_buildid) { process_buildids(rec); @@ -3330,7 +3357,7 @@ int cmd_record(int argc, const char **argv) goto out_opts; } =20 - if (rec->opts.kcore) + if (rec->opts.kcore || record__threads_enabled(rec)) rec->data.is_dir =3D true; =20 if (rec->opts.comp_level !=3D 0) { diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h index 83f6bd4d4082..62f38d7977bb 100644 --- a/tools/perf/util/mmap.h +++ b/tools/perf/util/mmap.h @@ -45,6 +45,7 @@ struct mmap { struct mmap_cpu_mask affinity_mask; void *data; int comp_level; + struct perf_data_file *file; }; =20 struct mmap_params { --=20 2.19.0 From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 22AAFC433EF for ; Mon, 17 Jan 2022 18:35:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242906AbiAQSfc (ORCPT ); Mon, 17 Jan 2022 13:35:32 -0500 Received: from mga12.intel.com ([192.55.52.136]:48629 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242770AbiAQSfL (ORCPT ); Mon, 17 Jan 2022 13:35:11 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444511; x=1673980511; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=jXewn2D3TS6sPyNfV5Vn+j8dLBIuSljGeQz6Yl1GSqM=; b=iSPywyDb9MpC6zfuyRf3V9Ni0wjYcKOR23ejKrcS4PifocV4YAt5Z0vM q1Q/BcIuAPDNnIzNAgVACcj9Gatnal6HS9DjPsi3W9TLEzOwjQ2/q89Ji BwpwQrtqv4ZciWXV9cVbxAVGx7RvSFRaE4cLVNS3/NGJO7fU7lhVj1XpP zvtNRRR89mHXvrFXq873kbBx5T3pNl8rCmSEx/hFDsYK+GJFhn3mxYuzy CZgznMFoC71iK2+mSqANyIRMuQ5BbJy789yWb5pcPvLmprFQRhmDNlJfn 8IRpLjcupUtwkyQoIv4gifC7pfZNGXFkNiV7K6oBdSYl4wIQabbWHUKBf g==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224656021" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224656021" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:35:10 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434276" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:35:07 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 09/16] perf record: Introduce bytes written stats Date: Mon, 17 Jan 2022 21:34:29 +0300 Message-Id: <3e2c69186641446f8ab003ec209bccc762b3394d.1642440724.git.alexey.v.bayduraev@linux.intel.com> X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Introduce a function to calculate the total amount of data written and use it to support the --max-size option. Acked-by: Namhyung Kim Reviewed-by: Riccardo Mancini Tested-by: Riccardo Mancini Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/perf/builtin-record.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 8766a3dc9440..50981bbc98bb 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -110,6 +110,7 @@ struct record_thread { struct record *rec; unsigned long long samples; unsigned long waking; + u64 bytes_written; }; =20 static __thread struct record_thread *thread; @@ -194,10 +195,22 @@ static bool switch_output_time(struct record *rec) trigger_is_ready(&switch_output_trigger); } =20 +static u64 record__bytes_written(struct record *rec) +{ + int t; + u64 bytes_written =3D rec->bytes_written; + struct record_thread *thread_data =3D rec->thread_data; + + for (t =3D 0; t < rec->nr_threads; t++) + bytes_written +=3D thread_data[t].bytes_written; + + return bytes_written; +} + static bool record__output_max_size_exceeded(struct record *rec) { return rec->output_max_size && - (rec->bytes_written >=3D rec->output_max_size); + (record__bytes_written(rec) >=3D rec->output_max_size); } =20 static int record__write(struct record *rec, struct mmap *map __maybe_unus= ed, @@ -213,13 +226,15 @@ static int record__write(struct record *rec, struct m= map *map __maybe_unused, return -1; } =20 - if (!(map && map->file)) + if (map && map->file) + thread->bytes_written +=3D size; + else rec->bytes_written +=3D size; =20 if (record__output_max_size_exceeded(rec) && !done) { fprintf(stderr, "[ perf record: perf size limit reached (%" PRIu64 " KB)= ," " stopping session ]\n", - rec->bytes_written >> 10); + record__bytes_written(rec) >> 10); done =3D 1; } =20 --=20 2.19.0 From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0379FC433F5 for ; Mon, 17 Jan 2022 18:35:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242818AbiAQSfn (ORCPT ); Mon, 17 Jan 2022 13:35:43 -0500 Received: from mga12.intel.com ([192.55.52.136]:48633 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242803AbiAQSfO (ORCPT ); Mon, 17 Jan 2022 13:35:14 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444514; x=1673980514; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mTvjI7jqZE7zzXv2aMcu/5dmwpgIxeFqPYg6k1BSd9M=; b=JPPDRTEqRZ23e32e1CtYE5pnUl2alUSHOxP2W5xkxZKKwsq4/C00GOov lJJQr4LV4qVCErTqLtbo8AtLlOzXwAD/Ajs39x599pIjjBudX3bPbqwj1 IL7dtLL02VM/J1ugpwIo4+ixbEUJ/7XysimW7DAPXIKkJ3LizU7eQDh42 oAg7TUkDYhGMRfAxrhoBGMW5aHXS1CKcNSXe1haSH8b0RuCpN0ohsieLu Dn5AqMll9+LJXTrfr/emq82JA2+7A81H10pCNzVZi3CB1F2oUpf4+pUeC P1oFh72USttbKHILm2dNo9zB1upg+Ax9p79J0fLHtJ+SqwOk0kXscWFMh A==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224656027" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224656027" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:35:13 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434288" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:35:10 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 10/16] perf record: Introduce compressor at mmap buffer object Date: Mon, 17 Jan 2022 21:34:30 +0300 Message-Id: <80edc286cf6543139a7d5a91217605123aa0b50d.1642440724.git.alexey.v.bayduraev@linux.intel.com> X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Introduce compressor object into mmap object so it could be used to pack the data stream from the corresponding kernel data buffer. Initialize and make use of the introduced per mmap compressor. Acked-by: Andi Kleen Acked-by: Namhyung Kim Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/perf/builtin-record.c | 18 +++++++++++------- tools/perf/util/mmap.c | 10 ++++++++++ tools/perf/util/mmap.h | 2 ++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 50981bbc98bb..7d0338b5a0e3 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -246,8 +246,8 @@ static int record__write(struct record *rec, struct mma= p *map __maybe_unused, =20 static int record__aio_enabled(struct record *rec); static int record__comp_enabled(struct record *rec); -static size_t zstd_compress(struct perf_session *session, void *dst, size_= t dst_size, - void *src, size_t src_size); +static size_t zstd_compress(struct perf_session *session, struct mmap *map, + void *dst, size_t dst_size, void *src, size_t src_size); =20 #ifdef HAVE_AIO_SUPPORT static int record__aio_write(struct aiocb *cblock, int trace_fd, @@ -381,7 +381,7 @@ static int record__aio_pushfn(struct mmap *map, void *t= o, void *buf, size_t size */ =20 if (record__comp_enabled(aio->rec)) { - size =3D zstd_compress(aio->rec->session, aio->data + aio->size, + size =3D zstd_compress(aio->rec->session, NULL, aio->data + aio->size, mmap__mmap_len(map) - aio->size, buf, size); } else { @@ -608,7 +608,7 @@ static int record__pushfn(struct mmap *map, void *to, v= oid *bf, size_t size) struct record *rec =3D to; =20 if (record__comp_enabled(rec)) { - size =3D zstd_compress(rec->session, map->data, mmap__mmap_len(map), bf,= size); + size =3D zstd_compress(rec->session, map, map->data, mmap__mmap_len(map)= , bf, size); bf =3D map->data; } =20 @@ -1394,13 +1394,17 @@ static size_t process_comp_header(void *record, siz= e_t increment) return size; } =20 -static size_t zstd_compress(struct perf_session *session, void *dst, size_= t dst_size, - void *src, size_t src_size) +static size_t zstd_compress(struct perf_session *session, struct mmap *map, + void *dst, size_t dst_size, void *src, size_t src_size) { size_t compressed; size_t max_record_size =3D PERF_SAMPLE_MAX_SIZE - sizeof(struct perf_reco= rd_compressed) - 1; + struct zstd_data *zstd_data =3D &session->zstd_data; =20 - compressed =3D zstd_compress_stream_to_records(&session->zstd_data, dst, = dst_size, src, src_size, + if (map && map->file) + zstd_data =3D &map->zstd_data; + + compressed =3D zstd_compress_stream_to_records(zstd_data, dst, dst_size, = src, src_size, max_record_size, process_comp_header); =20 session->bytes_transferred +=3D src_size; diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c index 12261ed8c15b..8bf97d9b8424 100644 --- a/tools/perf/util/mmap.c +++ b/tools/perf/util/mmap.c @@ -230,6 +230,10 @@ void mmap__munmap(struct mmap *map) { bitmap_free(map->affinity_mask.bits); =20 +#ifndef PYTHON_PERF + zstd_fini(&map->zstd_data); +#endif + perf_mmap__aio_munmap(map); if (map->data !=3D NULL) { munmap(map->data, mmap__mmap_len(map)); @@ -292,6 +296,12 @@ int mmap__mmap(struct mmap *map, struct mmap_params *m= p, int fd, struct perf_cpu map->core.flush =3D mp->flush; =20 map->comp_level =3D mp->comp_level; +#ifndef PYTHON_PERF + if (zstd_init(&map->zstd_data, map->comp_level)) { + pr_debug2("failed to init mmap commpressor, error %d\n", errno); + return -1; + } +#endif =20 if (map->comp_level && !perf_mmap__aio_enabled(map)) { map->data =3D mmap(NULL, mmap__mmap_len(map), PROT_READ|PROT_WRITE, diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h index 62f38d7977bb..cd8b0777473b 100644 --- a/tools/perf/util/mmap.h +++ b/tools/perf/util/mmap.h @@ -15,6 +15,7 @@ #endif #include "auxtrace.h" #include "event.h" +#include "util/compress.h" =20 struct aiocb; =20 @@ -46,6 +47,7 @@ struct mmap { void *data; int comp_level; struct perf_data_file *file; + struct zstd_data zstd_data; }; =20 struct mmap_params { --=20 2.19.0 From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 67EE6C433F5 for ; Mon, 17 Jan 2022 18:35:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242854AbiAQSfu (ORCPT ); Mon, 17 Jan 2022 13:35:50 -0500 Received: from mga12.intel.com ([192.55.52.136]:48634 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242843AbiAQSfR (ORCPT ); Mon, 17 Jan 2022 13:35:17 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444517; x=1673980517; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=IgZjj9XbMC7hMTZDfcpEgux3Es+6Lrg4o7zKivFg6PY=; b=PcMiqLVoSu9VN8i4/914pwfQLxc4vLjAbErNIXxOeES0uVXFlXflLI4o CKmVqINWUGP+m5beHJ2g1tjhPrAwOYYeBJrCiX/v3mfayqLAQpcB2fGPi UNB74SvgiiPFCu+CYkN6uRd+08C3pLAgwFzleVug00BixaYkqtJgcpJzV CNACnkTyK27ur/2tQlq+nr+1tb07/Y5ZU5NAhQt4Oqd++xU3JWpMfI9CD pcMeU+yBgU2693xz5z2NnlolDXH8weL1BnKQgyLI5kWrpRJoQzBlZO/XR 097wJRitotblLkiedWdBJJzBUHeTAiozfVtjyGomzam1XtaNI+ZPm5hF+ A==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224656030" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224656030" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:35:16 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434292" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:35:13 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 11/16] perf record: Introduce data transferred and compressed stats Date: Mon, 17 Jan 2022 21:34:31 +0300 Message-Id: X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Introduce bytes_transferred and bytes_compressed stats so they would capture statistics for the related data buffer transfers. Acked-by: Andi Kleen Acked-by: Namhyung Kim Reviewed-by: Riccardo Mancini Tested-by: Riccardo Mancini Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/perf/builtin-record.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 7d0338b5a0e3..0f8488d12f44 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -111,6 +111,8 @@ struct record_thread { unsigned long long samples; unsigned long waking; u64 bytes_written; + u64 bytes_transferred; + u64 bytes_compressed; }; =20 static __thread struct record_thread *thread; @@ -1407,8 +1409,13 @@ static size_t zstd_compress(struct perf_session *ses= sion, struct mmap *map, compressed =3D zstd_compress_stream_to_records(zstd_data, dst, dst_size, = src, src_size, max_record_size, process_comp_header); =20 - session->bytes_transferred +=3D src_size; - session->bytes_compressed +=3D compressed; + if (map && map->file) { + thread->bytes_transferred +=3D src_size; + thread->bytes_compressed +=3D compressed; + } else { + session->bytes_transferred +=3D src_size; + session->bytes_compressed +=3D compressed; + } =20 return compressed; } @@ -2098,8 +2105,20 @@ static int record__stop_threads(struct record *rec) for (t =3D 1; t < rec->nr_threads; t++) record__terminate_thread(&thread_data[t]); =20 - for (t =3D 0; t < rec->nr_threads; t++) + for (t =3D 0; t < rec->nr_threads; t++) { rec->samples +=3D thread_data[t].samples; + if (!record__threads_enabled(rec)) + continue; + rec->session->bytes_transferred +=3D thread_data[t].bytes_transferred; + rec->session->bytes_compressed +=3D thread_data[t].bytes_compressed; + pr_debug("threads[%d]: samples=3D%lld, wakes=3D%ld, ", thread_data[t].ti= d, + thread_data[t].samples, thread_data[t].waking); + if (thread_data[t].bytes_transferred && thread_data[t].bytes_compressed) + pr_debug("trasferred=3D%ld, compressed=3D%ld\n", + thread_data[t].bytes_transferred, thread_data[t].bytes_compressed); + else + pr_debug("written=3D%ld\n", thread_data[t].bytes_written); + } =20 return 0; } --=20 2.19.0 From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 841A6C433EF for ; Mon, 17 Jan 2022 18:35:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242814AbiAQSfz (ORCPT ); Mon, 17 Jan 2022 13:35:55 -0500 Received: from mga12.intel.com ([192.55.52.136]:48629 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242885AbiAQSfY (ORCPT ); Mon, 17 Jan 2022 13:35:24 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444524; x=1673980524; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=nrckZ+4w+t9xcn0jGApSjWwJZOqejG13YfVPSf21LRY=; b=XfybOAGdF0G0N54HWJB0DgyhtQKxIiuw2mRE2aCD8Hjmpgn48F9Igb2G eswKUe3VoZ2GPGCPFXJZD58Xl1yPhFiAJurhWQFJJqRkKkRCFttphxGg4 4/xmY3Ez+9e5ZQC2E9/HO0PYkcXjYuB/HpDOsTifIvbjSPHDYokYlwry8 t+piYhHcKB3dEJ48sr0AEDFNhkIQCtQMqJJSKRaHkR4kT4uTSDQbH9mzx thQen5QCRuSmD7GZ5eJc1u+LcZTr0BoM0N8dlj9/xKze0DxwAnUMrPxMk 14XQlBnnoGjRr/yS87xgmM7qm3HH7STmWg+z35yz+WEcA2OawYEeX5i0b A==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224656040" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224656040" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:35:20 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434298" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:35:17 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 12/16] perf record: Introduce --threads command line option Date: Mon, 17 Jan 2022 21:34:32 +0300 Message-Id: <01aeae43b047f428596c4ef9f9342ab94865cedd.1642440724.git.alexey.v.bayduraev@linux.intel.com> X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Provide --threads option in perf record command line interface. The option creates a data streaming thread for each CPU in the system. Document --threads option in Documentation/perf-record.txt. Reviewed-by: Riccardo Mancini Tested-by: Riccardo Mancini Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/perf/Documentation/perf-record.txt | 4 ++ tools/perf/builtin-record.c | 48 +++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Document= ation/perf-record.txt index 9ccc75935bc5..b9c6b112bf46 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -713,6 +713,10 @@ measurements: wait -n ${perf_pid} exit $? =20 +--threads:: +Write collected trace data into several data files using parallel threads. +The option creates a data streaming thread for each CPU in the system. + include::intel-hybrid.txt[] =20 --debuginfod[=3DURLs]:: diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0f8488d12f44..ba1622a192a9 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -127,6 +127,11 @@ static const char *thread_msg_tags[THREAD_MSG__MAX] = =3D { "UNDEFINED", "READY" }; =20 +enum thread_spec { + THREAD_SPEC__UNDEFINED =3D 0, + THREAD_SPEC__CPU, +}; + struct record { struct perf_tool tool; struct record_opts opts; @@ -2768,6 +2773,16 @@ static void record__thread_mask_free(struct thread_m= ask *mask) record__mmap_cpu_mask_free(&mask->affinity); } =20 +static int record__parse_threads(const struct option *opt, const char *str= , int unset) +{ + struct record_opts *opts =3D opt->value; + + if (unset || !str || !strlen(str)) + opts->threads_spec =3D THREAD_SPEC__CPU; + + return 0; +} + static int parse_output_max_size(const struct option *opt, const char *str, int unset) { @@ -3242,6 +3257,9 @@ static struct option __record_options[] =3D { &record.debuginfod.set, "debuginfod urls", "Enable debuginfod data retrieval from DEBUGINFOD_URLS or specified u= rls", "system"), + OPT_CALLBACK_OPTARG(0, "threads", &record.opts, NULL, "spec", + "write collected trace data into several data files using parallel = threads", + record__parse_threads), OPT_END() }; =20 @@ -3292,6 +3310,31 @@ static int record__alloc_thread_masks(struct record = *rec, int nr_threads, int nr return ret; } =20 +static int record__init_thread_cpu_masks(struct record *rec, struct perf_c= pu_map *cpus) +{ + int t, ret, nr_cpus =3D perf_cpu_map__nr(cpus); + + ret =3D record__alloc_thread_masks(rec, nr_cpus, cpu__max_cpu().cpu); + if (ret) + return ret; + + rec->nr_threads =3D nr_cpus; + pr_debug("nr_threads: %d\n", rec->nr_threads); + + for (t =3D 0; t < rec->nr_threads; t++) { + set_bit(cpus->map[t].cpu, rec->thread_masks[t].maps.bits); + set_bit(cpus->map[t].cpu, rec->thread_masks[t].affinity.bits); + if (verbose) { + pr_debug("thread_masks[%d]: ", t); + mmap_cpu_mask__scnprintf(&rec->thread_masks[t].maps, "maps"); + pr_debug("thread_masks[%d]: ", t); + mmap_cpu_mask__scnprintf(&rec->thread_masks[t].affinity, "affinity"); + } + } + + return 0; +} + static int record__init_thread_default_masks(struct record *rec, struct pe= rf_cpu_map *cpus) { int ret; @@ -3311,7 +3354,10 @@ static int record__init_thread_masks(struct record *= rec) { struct perf_cpu_map *cpus =3D rec->evlist->core.cpus; =20 - return record__init_thread_default_masks(rec, cpus); + if (!record__threads_enabled(rec)) + return record__init_thread_default_masks(rec, cpus); + + return record__init_thread_cpu_masks(rec, cpus); } =20 int cmd_record(int argc, const char **argv) --=20 2.19.0 From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 70133C433F5 for ; Mon, 17 Jan 2022 18:36:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242823AbiAQSf6 (ORCPT ); Mon, 17 Jan 2022 13:35:58 -0500 Received: from mga12.intel.com ([192.55.52.136]:48633 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242784AbiAQSfg (ORCPT ); Mon, 17 Jan 2022 13:35:36 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444535; x=1673980535; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=r20iCj4310PzijzGGoig5msS5MWyzTL+7iY5DnpEZuM=; b=fFIg+Dtsxl/fB7Yym+QDSx7sXg5eMJeG//XEB+3Mifo9Hvz5/zgEqXKq or0hm5Nsa8ySk89pAo8ZPjZdPlo0Lj0sTWu3VM33uHrRV2kmQOimKQwct sVTIK0Kn1x3PzgXA5SffO0X1bGHJ1DciPNezwMhnNFCYvu4I0J24QhRD1 9b+mq4Y4XRk/K1PkaRYCqdpk4DwLOl1nn/xb8dbMQsyUnZ0wtzj+SNJXx AS/oXSop+A22qf2XsSFu/EF/5HXK2mwYB/jHq/u//8w0kXsCsUgkUZtIc AiMBKJR2eLOPcxJ0qRSIX71qr5L7hFryfWlLxWdk6+fJjqergY5cVjVU+ Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224656057" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224656057" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:35:23 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434307" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:35:20 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 13/16] perf record: Extend --threads command line option Date: Mon, 17 Jan 2022 21:34:33 +0300 Message-Id: <079e2619be70c465317cf7c9fdaf5fa069728c32.1642440724.git.alexey.v.bayduraev@linux.intel.com> X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Extend --threads option in perf record command line interface. The option can have a value in the form of masks that specify CPUs to be monitored with data streaming threads and its layout in system topology. The masks can be filtered using CPU mask provided via -C option. The specification value can be user defined list of masks. Masks separated by colon define CPUs to be monitored by one thread and affinity mask of that thread is separated by slash. For example: /:/ specifies parallel threads layout that consists of two threads with corresponding assigned CPUs to be monitored. The specification value can be a string e.g. "cpu", "core" or "package" meaning creation of data streaming thread for every CPU or core or package to monitor distinct CPUs or CPUs grouped by core or package. The option provided with no or empty value defaults to per-cpu parallel threads layout creating data streaming thread for every CPU being monitored. Document --threads option syntax and parallel data streaming modes in Documentation/perf-record.txt. Suggested-by: Jiri Olsa Suggested-by: Namhyung Kim Acked-by: Andi Kleen Acked-by: Namhyung Kim Reviewed-by: Riccardo Mancini Tested-by: Riccardo Mancini Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/perf/Documentation/perf-record.txt | 34 ++- tools/perf/builtin-record.c | 318 ++++++++++++++++++++++- tools/perf/util/record.h | 1 + 3 files changed, 349 insertions(+), 4 deletions(-) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Document= ation/perf-record.txt index b9c6b112bf46..465be4e62a17 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -713,9 +713,39 @@ measurements: wait -n ${perf_pid} exit $? =20 ---threads:: +--threads=3D:: Write collected trace data into several data files using parallel threads. -The option creates a data streaming thread for each CPU in the system. + value can be user defined list of masks. Masks separated by colon +define CPUs to be monitored by a thread and affinity mask of that thread +is separated by slash: + + /:/:... + +CPUs or affinity masks must not overlap with other corresponding masks. +Invalid CPUs are ignored, but masks containing only invalid CPUs are not +allowed. + +For example user specification like the following: + + 0,2-4/2-4:1,5-7/5-7 + +specifies parallel threads layout that consists of two threads, +the first thread monitors CPUs 0 and 2-4 with the affinity mask 2-4, +the second monitors CPUs 1 and 5-7 with the affinity mask 5-7. + + value can also be a string meaning predefined parallel threads +layout: + + cpu - create new data streaming thread for every monitored cpu + core - create new thread to monitor CPUs grouped by a core + package - create new thread to monitor CPUs grouped by a package + numa - create new threed to monitor CPUs grouped by a NUMA domain + +Predefined layouts can be used on systems with large number of CPUs in +order not to spawn multiple per-cpu streaming threads but still avoid LOST +events in data directory files. Option specified with no or empty value +defaults to CPU layout. Masks defined or provided by the option value are +filtered through the mask provided by -C option. =20 include::intel-hybrid.txt[] =20 diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ba1622a192a9..e60bf0e3bc25 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -51,6 +51,7 @@ #include "util/evlist-hybrid.h" #include "asm/bug.h" #include "perf.h" +#include "cputopo.h" =20 #include #include @@ -130,6 +131,15 @@ static const char *thread_msg_tags[THREAD_MSG__MAX] = =3D { enum thread_spec { THREAD_SPEC__UNDEFINED =3D 0, THREAD_SPEC__CPU, + THREAD_SPEC__CORE, + THREAD_SPEC__PACKAGE, + THREAD_SPEC__NUMA, + THREAD_SPEC__USER, + THREAD_SPEC__MAX, +}; + +static const char *thread_spec_tags[THREAD_SPEC__MAX] =3D { + "undefined", "cpu", "core", "package", "numa", "user" }; =20 struct record { @@ -2775,10 +2785,31 @@ static void record__thread_mask_free(struct thread_= mask *mask) =20 static int record__parse_threads(const struct option *opt, const char *str= , int unset) { + int s; struct record_opts *opts =3D opt->value; =20 - if (unset || !str || !strlen(str)) + if (unset || !str || !strlen(str)) { opts->threads_spec =3D THREAD_SPEC__CPU; + } else { + for (s =3D 1; s < THREAD_SPEC__MAX; s++) { + if (s =3D=3D THREAD_SPEC__USER) { + opts->threads_user_spec =3D strdup(str); + if (!opts->threads_user_spec) + return -ENOMEM; + opts->threads_spec =3D THREAD_SPEC__USER; + break; + } + if (!strncasecmp(str, thread_spec_tags[s], strlen(thread_spec_tags[s]))= ) { + opts->threads_spec =3D s; + break; + } + } + } + + if (opts->threads_spec =3D=3D THREAD_SPEC__USER) + pr_debug("threads_spec: %s\n", opts->threads_user_spec); + else + pr_debug("threads_spec: %s\n", thread_spec_tags[opts->threads_spec]); =20 return 0; } @@ -3273,6 +3304,21 @@ static void record__mmap_cpu_mask_init(struct mmap_c= pu_mask *mask, struct perf_c set_bit(cpus->map[c].cpu, mask->bits); } =20 +static int record__mmap_cpu_mask_init_spec(struct mmap_cpu_mask *mask, con= st char *mask_spec) +{ + struct perf_cpu_map *cpus; + + cpus =3D perf_cpu_map__new(mask_spec); + if (!cpus) + return -ENOMEM; + + bitmap_zero(mask->bits, mask->nbits); + record__mmap_cpu_mask_init(mask, cpus); + perf_cpu_map__put(cpus); + + return 0; +} + static void record__free_thread_masks(struct record *rec, int nr_threads) { int t; @@ -3335,6 +3381,253 @@ static int record__init_thread_cpu_masks(struct rec= ord *rec, struct perf_cpu_map return 0; } =20 +static int record__init_thread_masks_spec(struct record *rec, struct perf_= cpu_map *cpus, + const char **maps_spec, const char **affinity_spec, + u32 nr_spec) +{ + u32 s; + int ret =3D 0, t =3D 0; + struct mmap_cpu_mask cpus_mask; + struct thread_mask thread_mask, full_mask, *thread_masks; + + ret =3D record__mmap_cpu_mask_alloc(&cpus_mask, cpu__max_cpu().cpu); + if (ret) { + pr_err("Failed to allocate CPUs mask\n"); + return ret; + } + record__mmap_cpu_mask_init(&cpus_mask, cpus); + + ret =3D record__thread_mask_alloc(&full_mask, cpu__max_cpu().cpu); + if (ret) { + pr_err("Failed to allocate full mask\n"); + goto out_free_cpu_mask; + } + + ret =3D record__thread_mask_alloc(&thread_mask, cpu__max_cpu().cpu); + if (ret) { + pr_err("Failed to allocate thread mask\n"); + goto out_free_full_and_cpu_masks; + } + + for (s =3D 0; s < nr_spec; s++) { + ret =3D record__mmap_cpu_mask_init_spec(&thread_mask.maps, maps_spec[s]); + if (ret) { + pr_err("Failed to initialize maps thread mask\n"); + goto out_free; + } + ret =3D record__mmap_cpu_mask_init_spec(&thread_mask.affinity, affinity_= spec[s]); + if (ret) { + pr_err("Failed to initialize affinity thread mask\n"); + goto out_free; + } + + /* ignore invalid CPUs but do not allow empty masks */ + if (!bitmap_and(thread_mask.maps.bits, thread_mask.maps.bits, + cpus_mask.bits, thread_mask.maps.nbits)) { + pr_err("Empty maps mask: %s\n", maps_spec[s]); + ret =3D -EINVAL; + goto out_free; + } + if (!bitmap_and(thread_mask.affinity.bits, thread_mask.affinity.bits, + cpus_mask.bits, thread_mask.affinity.nbits)) { + pr_err("Empty affinity mask: %s\n", affinity_spec[s]); + ret =3D -EINVAL; + goto out_free; + } + + /* do not allow intersection with other masks (full_mask) */ + if (bitmap_intersects(thread_mask.maps.bits, full_mask.maps.bits, + thread_mask.maps.nbits)) { + pr_err("Intersecting maps mask: %s\n", maps_spec[s]); + ret =3D -EINVAL; + goto out_free; + } + if (bitmap_intersects(thread_mask.affinity.bits, full_mask.affinity.bits, + thread_mask.affinity.nbits)) { + pr_err("Intersecting affinity mask: %s\n", affinity_spec[s]); + ret =3D -EINVAL; + goto out_free; + } + + bitmap_or(full_mask.maps.bits, full_mask.maps.bits, + thread_mask.maps.bits, full_mask.maps.nbits); + bitmap_or(full_mask.affinity.bits, full_mask.affinity.bits, + thread_mask.affinity.bits, full_mask.maps.nbits); + + thread_masks =3D realloc(rec->thread_masks, (t + 1) * sizeof(struct thre= ad_mask)); + if (!thread_masks) { + pr_err("Failed to reallocate thread masks\n"); + ret =3D -ENOMEM; + goto out_free; + } + rec->thread_masks =3D thread_masks; + rec->thread_masks[t] =3D thread_mask; + if (verbose) { + pr_debug("thread_masks[%d]: ", t); + mmap_cpu_mask__scnprintf(&rec->thread_masks[t].maps, "maps"); + pr_debug("thread_masks[%d]: ", t); + mmap_cpu_mask__scnprintf(&rec->thread_masks[t].affinity, "affinity"); + } + t++; + ret =3D record__thread_mask_alloc(&thread_mask, cpu__max_cpu().cpu); + if (ret) { + pr_err("Failed to allocate thread mask\n"); + goto out_free_full_and_cpu_masks; + } + } + rec->nr_threads =3D t; + pr_debug("nr_threads: %d\n", rec->nr_threads); + if (!rec->nr_threads) + ret =3D -EINVAL; + +out_free: + record__thread_mask_free(&thread_mask); +out_free_full_and_cpu_masks: + record__thread_mask_free(&full_mask); +out_free_cpu_mask: + record__mmap_cpu_mask_free(&cpus_mask); + + return ret; +} + +static int record__init_thread_core_masks(struct record *rec, struct perf_= cpu_map *cpus) +{ + int ret; + struct cpu_topology *topo; + + topo =3D cpu_topology__new(); + if (!topo) { + pr_err("Failed to allocate CPU topology\n"); + return -ENOMEM; + } + + ret =3D record__init_thread_masks_spec(rec, cpus, topo->core_cpus_list, + topo->core_cpus_list, topo->core_cpus_lists); + cpu_topology__delete(topo); + + return ret; +} + +static int record__init_thread_package_masks(struct record *rec, struct pe= rf_cpu_map *cpus) +{ + int ret; + struct cpu_topology *topo; + + topo =3D cpu_topology__new(); + if (!topo) { + pr_err("Failed to allocate CPU topology\n"); + return -ENOMEM; + } + + ret =3D record__init_thread_masks_spec(rec, cpus, topo->package_cpus_list, + topo->package_cpus_list, topo->package_cpus_lists); + cpu_topology__delete(topo); + + return ret; +} + +static int record__init_thread_numa_masks(struct record *rec, struct perf_= cpu_map *cpus) +{ + u32 s; + int ret; + const char **spec; + struct numa_topology *topo; + + topo =3D numa_topology__new(); + if (!topo) { + pr_err("Failed to allocate NUMA topology\n"); + return -ENOMEM; + } + + spec =3D zalloc(topo->nr * sizeof(char *)); + if (!spec) { + pr_err("Failed to allocate NUMA spec\n"); + ret =3D -ENOMEM; + goto out_delete_topo; + } + for (s =3D 0; s < topo->nr; s++) + spec[s] =3D topo->nodes[s].cpus; + + ret =3D record__init_thread_masks_spec(rec, cpus, spec, spec, topo->nr); + + zfree(&spec); + +out_delete_topo: + numa_topology__delete(topo); + + return ret; +} + +static int record__init_thread_user_masks(struct record *rec, struct perf_= cpu_map *cpus) +{ + int t, ret; + u32 s, nr_spec =3D 0; + char **maps_spec =3D NULL, **affinity_spec =3D NULL, **tmp_spec; + char *user_spec, *spec, *spec_ptr, *mask, *mask_ptr, *dup_mask =3D NULL; + + for (t =3D 0, user_spec =3D (char *)rec->opts.threads_user_spec; ; t++, u= ser_spec =3D NULL) { + spec =3D strtok_r(user_spec, ":", &spec_ptr); + if (spec =3D=3D NULL) + break; + pr_debug2("threads_spec[%d]: %s\n", t, spec); + mask =3D strtok_r(spec, "/", &mask_ptr); + if (mask =3D=3D NULL) + break; + pr_debug2(" maps mask: %s\n", mask); + tmp_spec =3D realloc(maps_spec, (nr_spec + 1) * sizeof(char *)); + if (!tmp_spec) { + pr_err("Failed to reallocate maps spec\n"); + ret =3D -ENOMEM; + goto out_free; + } + maps_spec =3D tmp_spec; + maps_spec[nr_spec] =3D dup_mask =3D strdup(mask); + if (!maps_spec[nr_spec]) { + pr_err("Failed to allocate maps spec[%d]\n", nr_spec); + ret =3D -ENOMEM; + goto out_free; + } + mask =3D strtok_r(NULL, "/", &mask_ptr); + if (mask =3D=3D NULL) { + pr_err("Invalid thread maps or affinity specs\n"); + ret =3D -EINVAL; + goto out_free; + } + pr_debug2(" affinity mask: %s\n", mask); + tmp_spec =3D realloc(affinity_spec, (nr_spec + 1) * sizeof(char *)); + if (!tmp_spec) { + pr_err("Failed to reallocate affinity spec\n"); + ret =3D -ENOMEM; + goto out_free; + } + affinity_spec =3D tmp_spec; + affinity_spec[nr_spec] =3D strdup(mask); + if (!affinity_spec[nr_spec]) { + pr_err("Failed to allocate affinity spec[%d]\n", nr_spec); + ret =3D -ENOMEM; + goto out_free; + } + dup_mask =3D NULL; + nr_spec++; + } + + ret =3D record__init_thread_masks_spec(rec, cpus, (const char **)maps_spe= c, + (const char **)affinity_spec, nr_spec); + +out_free: + free(dup_mask); + for (s =3D 0; s < nr_spec; s++) { + if (maps_spec) + free(maps_spec[s]); + if (affinity_spec) + free(affinity_spec[s]); + } + free(affinity_spec); + free(maps_spec); + + return ret; +} + static int record__init_thread_default_masks(struct record *rec, struct pe= rf_cpu_map *cpus) { int ret; @@ -3352,12 +3645,33 @@ static int record__init_thread_default_masks(struct= record *rec, struct perf_cpu =20 static int record__init_thread_masks(struct record *rec) { + int ret =3D 0; struct perf_cpu_map *cpus =3D rec->evlist->core.cpus; =20 if (!record__threads_enabled(rec)) return record__init_thread_default_masks(rec, cpus); =20 - return record__init_thread_cpu_masks(rec, cpus); + switch (rec->opts.threads_spec) { + case THREAD_SPEC__CPU: + ret =3D record__init_thread_cpu_masks(rec, cpus); + break; + case THREAD_SPEC__CORE: + ret =3D record__init_thread_core_masks(rec, cpus); + break; + case THREAD_SPEC__PACKAGE: + ret =3D record__init_thread_package_masks(rec, cpus); + break; + case THREAD_SPEC__NUMA: + ret =3D record__init_thread_numa_masks(rec, cpus); + break; + case THREAD_SPEC__USER: + ret =3D record__init_thread_user_masks(rec, cpus); + break; + default: + break; + } + + return ret; } =20 int cmd_record(int argc, const char **argv) diff --git a/tools/perf/util/record.h b/tools/perf/util/record.h index ad08c092f3dd..be9a957501f4 100644 --- a/tools/perf/util/record.h +++ b/tools/perf/util/record.h @@ -79,6 +79,7 @@ struct record_opts { bool ctl_fd_close; int synth; int threads_spec; + const char *threads_user_spec; }; =20 extern const char * const *record_usage; --=20 2.19.0 From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1E6A3C433F5 for ; Mon, 17 Jan 2022 18:36:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243004AbiAQSgE (ORCPT ); Mon, 17 Jan 2022 13:36:04 -0500 Received: from mga12.intel.com ([192.55.52.136]:48634 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242696AbiAQSfs (ORCPT ); Mon, 17 Jan 2022 13:35:48 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444547; x=1673980547; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ruM1z206oqtD+FgneKTwLACpX7c/tBRcD7glsFeGSdI=; b=UNj7Pf+Yjx7H8EzIxxRXx/Vp4fHld3MSwmJcvK2hdDcDLdmGqkAHqyQJ OL/VQCIf4dgdfDgx0Xb1IFGQNB+HUzCYQnQfyDEZCJeoTkZNYBviD8moh l8J+l/KcOfYG2hSaix2IcEzwB19gXLGrV0u13S3TSPGuvfAHhLlXLgXus 0A/qFhqoZjRM6YCksZVjGd2pFSkrOvmuf1OhvfOqd+O+b61kq/u3nLr1E ivY4WL9AWWLzPH7JJ3aD9dWfRsUrvyzYriTPsxUYeWDC0jeqU8yI8XnF/ IyYunSq3xATXMcm9l2/PvSkLNtObPp1iDRKvw260mOT2k/xMZCs/+zwjS Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224656062" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224656062" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:35:27 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434310" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:35:24 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 14/16] perf record: Implement compatibility checks Date: Mon, 17 Jan 2022 21:34:34 +0300 Message-Id: X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Implement compatibility checks for other modes and related command line options: asynchronous (--aio) trace streaming and affinity (--affinity) modes, pipe mode, AUX area tracing --snapshot and --aux-sample options, --switch-output, --switch-output-event, --switch-max-files and --timestamp-filename options. Parallel data streaming is compatible with Zstd compression (--compression-level) and external control commands (--control). CPU mask provided via -C option filters --threads specification masks. Acked-by: Namhyung Kim Reviewed-by: Riccardo Mancini Tested-by: Riccardo Mancini Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/perf/builtin-record.c | 49 ++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index e60bf0e3bc25..9b7102262b20 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -805,6 +805,12 @@ static int record__auxtrace_init(struct record *rec) { int err; =20 + if ((rec->opts.auxtrace_snapshot_opts || rec->opts.auxtrace_sample_opts) + && record__threads_enabled(rec)) { + pr_err("AUX area tracing options are not available in parallel streaming= mode.\n"); + return -EINVAL; + } + if (!rec->itr) { rec->itr =3D auxtrace_record__init(rec->evlist, &err); if (err) @@ -2198,6 +2204,17 @@ static int __cmd_record(struct record *rec, int argc= , const char **argv) return PTR_ERR(session); } =20 + if (record__threads_enabled(rec)) { + if (perf_data__is_pipe(&rec->data)) { + pr_err("Parallel trace streaming is not available in pipe mode.\n"); + return -1; + } + if (rec->opts.full_auxtrace) { + pr_err("Parallel trace streaming is not available in AUX area tracing m= ode.\n"); + return -1; + } + } + fd =3D perf_data__fd(data); rec->session =3D session; =20 @@ -2938,12 +2955,22 @@ static int switch_output_setup(struct record *rec) * --switch-output=3Dsignal, as we'll send a SIGUSR2 from the side band * thread to its parent. */ - if (rec->switch_output_event_set) + if (rec->switch_output_event_set) { + if (record__threads_enabled(rec)) { + pr_warning("WARNING: --switch-output-event option is not available in p= arallel streaming mode.\n"); + return 0; + } goto do_signal; + } =20 if (!s->set) return 0; =20 + if (record__threads_enabled(rec)) { + pr_warning("WARNING: --switch-output option is not available in parallel= streaming mode.\n"); + return 0; + } + if (!strcmp(s->str, "signal")) { do_signal: s->signal =3D true; @@ -3262,8 +3289,8 @@ static struct option __record_options[] =3D { "Set affinity mask of trace reading thread to NUMA node cpu mask or= cpu of processed mmap buffer", record__parse_affinity), #ifdef HAVE_ZSTD_SUPPORT - OPT_CALLBACK_OPTARG('z', "compression-level", &record.opts, &comp_level_d= efault, - "n", "Compressed records using specified level (default: 1 - fastes= t compression, 22 - greatest compression)", + OPT_CALLBACK_OPTARG('z', "compression-level", &record.opts, &comp_level_d= efault, "n", + "Compress records using specified level (default: 1 - fastest compr= ession, 22 - greatest compression)", record__parse_comp_level), #endif OPT_CALLBACK(0, "max-size", &record.output_max_size, @@ -3758,6 +3785,17 @@ int cmd_record(int argc, const char **argv) if (rec->opts.kcore || record__threads_enabled(rec)) rec->data.is_dir =3D true; =20 + if (record__threads_enabled(rec)) { + if (rec->opts.affinity !=3D PERF_AFFINITY_SYS) { + pr_err("--affinity option is mutually exclusive to parallel streaming m= ode.\n"); + goto out_opts; + } + if (record__aio_enabled(rec)) { + pr_err("Asynchronous streaming mode (--aio) is mutually exclusive to pa= rallel streaming mode.\n"); + goto out_opts; + } + } + if (rec->opts.comp_level !=3D 0) { pr_debug("Compression enabled, disabling build id collection at the end = of the session.\n"); rec->no_buildid =3D true; @@ -3791,6 +3829,11 @@ int cmd_record(int argc, const char **argv) } } =20 + if (rec->timestamp_filename && record__threads_enabled(rec)) { + rec->timestamp_filename =3D false; + pr_warning("WARNING: --timestamp-filename option is not available in par= allel streaming mode.\n"); + } + /* * Allow aliases to facilitate the lookup of symbols for address * filters. Refer to auxtrace_parse_filters(). --=20 2.19.0 From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5F45DC433EF for ; Mon, 17 Jan 2022 18:36:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242879AbiAQSgK (ORCPT ); Mon, 17 Jan 2022 13:36:10 -0500 Received: from mga12.intel.com ([192.55.52.136]:48629 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242850AbiAQSft (ORCPT ); Mon, 17 Jan 2022 13:35:49 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444549; x=1673980549; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=y+JhqMy1BWptnZIHTMr/PSfF8lE/ShFYAaYTrmke+Tc=; b=dDNj2z40JYTsA2yCh34AnDslSiZxHtGA5f3CzcIw2ZeDgPi28iANSXJ7 xrkyPj/wyEsTSvZr0vbcsXV9ISOoJM9KeHSmHQz6/50EBgpBS8MI2sLXJ YoMUsYu+Uf1/Wy+cF81V9BgzluHq1VruXuqeqSB40u3dgSy13/WN/+WCC dL9TjxnV9kvVoExOeLmhUG3pV9wR3mN3hhC2H2W4TioHxEAxlHLy2z2m/ 9kBv+VqYGaY9a2m79KZWNQQaykMtaAJRgQs72UuIbmZs/bWeqKEdB+yvZ j4P2n1q56GbpqWBkipaoWZmY/UFGOBUOchWWIhJ7s6pjdjMcsPsyrCi3p Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224656068" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224656068" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:35:30 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434326" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:35:27 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 15/16] perf session: Load data directory files for analysis Date: Mon, 17 Jan 2022 21:34:35 +0300 Message-Id: <3f10c13a226c0ceb53e88a082f847b91c1ae2c25.1642440724.git.alexey.v.bayduraev@linux.intel.com> X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Load data directory files and provide basic raw dump and aggregated analysis support of data directories in report mode, still with no memory consumption optimizations. READER_MAX_SIZE is chosen based on the results of measurements on different machines on perf.data directory sizes >1GB. On machines with big core count (192 cores) the difference between 1MB and 2MB is about 4%. Other sizes (>2MB) are quite equal to 2MB. On machines with small core count (4-24) there is no differences between 1-16 MB sizes. So this constant is 2MB. Suggested-by: Jiri Olsa Acked-by: Namhyung Kim Reviewed-by: Riccardo Mancini Tested-by: Riccardo Mancini Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/perf/util/session.c | 133 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index f19348dddd55..c6605eab61c1 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -2185,6 +2185,8 @@ struct reader { u64 file_pos; u64 file_offset; u64 head; + u64 size; + bool done; struct zstd_data zstd_data; struct decomp_data decomp_data; }; @@ -2302,6 +2304,7 @@ reader__read_event(struct reader *rd, struct perf_ses= sion *session, if (skip) size +=3D skip; =20 + rd->size +=3D size; rd->head +=3D size; rd->file_pos +=3D size; =20 @@ -2410,6 +2413,133 @@ static int __perf_session__process_events(struct pe= rf_session *session) return err; } =20 +/* + * Processing 2 MB of data from each reader in sequence, + * because that's the way the ordered events sorting works + * most efficiently. + */ +#define READER_MAX_SIZE (2 * 1024 * 1024) + +/* + * This function reads, merge and process directory data. + * It assumens the version 1 of directory data, where each + * data file holds per-cpu data, already sorted by kernel. + */ +static int __perf_session__process_dir_events(struct perf_session *session) +{ + struct perf_data *data =3D session->data; + struct perf_tool *tool =3D session->tool; + int i, ret, readers, nr_readers; + struct ui_progress prog; + u64 total_size =3D perf_data__size(session->data); + struct reader *rd; + + perf_tool__fill_defaults(tool); + + ui_progress__init_size(&prog, total_size, "Sorting events..."); + + nr_readers =3D 1; + for (i =3D 0; i < data->dir.nr; i++) { + if (data->dir.files[i].size) + nr_readers++; + } + + rd =3D zalloc(nr_readers * sizeof(struct reader)); + if (!rd) + return -ENOMEM; + + rd[0] =3D (struct reader) { + .fd =3D perf_data__fd(session->data), + .data_size =3D session->header.data_size, + .data_offset =3D session->header.data_offset, + .process =3D process_simple, + .in_place_update =3D session->data->in_place_update, + }; + ret =3D reader__init(&rd[0], NULL); + if (ret) + goto out_err; + ret =3D reader__mmap(&rd[0], session); + if (ret) + goto out_err; + readers =3D 1; + + for (i =3D 0; i < data->dir.nr; i++) { + if (!data->dir.files[i].size) + continue; + rd[readers] =3D (struct reader) { + .fd =3D data->dir.files[i].fd, + .data_size =3D data->dir.files[i].size, + .data_offset =3D 0, + .process =3D process_simple, + .in_place_update =3D session->data->in_place_update, + }; + ret =3D reader__init(&rd[readers], NULL); + if (ret) + goto out_err; + ret =3D reader__mmap(&rd[readers], session); + if (ret) + goto out_err; + readers++; + } + + i =3D 0; + while (readers) { + if (session_done()) + break; + + if (rd[i].done) { + i =3D (i + 1) % nr_readers; + continue; + } + if (reader__eof(&rd[i])) { + rd[i].done =3D true; + readers--; + continue; + } + + session->active_decomp =3D &rd[i].decomp_data; + ret =3D reader__read_event(&rd[i], session, &prog); + if (ret < 0) { + goto out_err; + } else if (ret =3D=3D READER_NODATA) { + ret =3D reader__mmap(&rd[i], session); + if (ret) + goto out_err; + } + + if (rd[i].size >=3D READER_MAX_SIZE) { + rd[i].size =3D 0; + i =3D (i + 1) % nr_readers; + } + } + + ret =3D ordered_events__flush(&session->ordered_events, OE_FLUSH__FINAL); + if (ret) + goto out_err; + + ret =3D perf_session__flush_thread_stacks(session); +out_err: + ui_progress__finish(); + + if (!tool->no_warn) + perf_session__warn_about_errors(session); + + /* + * We may switching perf.data output, make ordered_events + * reusable. + */ + ordered_events__reinit(&session->ordered_events); + + session->one_mmap =3D false; + + session->active_decomp =3D &session->decomp_data; + for (i =3D 0; i < nr_readers; i++) + reader__release_decomp(&rd[i]); + zfree(&rd); + + return ret; +} + int perf_session__process_events(struct perf_session *session) { if (perf_session__register_idle_thread(session) < 0) @@ -2418,6 +2548,9 @@ int perf_session__process_events(struct perf_session = *session) if (perf_data__is_pipe(session->data)) return __perf_session__process_pipe_events(session); =20 + if (perf_data__is_dir(session->data)) + return __perf_session__process_dir_events(session); + return __perf_session__process_events(session); } =20 --=20 2.19.0 From nobody Tue Jun 30 12:02:00 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BA278C433F5 for ; Mon, 17 Jan 2022 18:36:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242828AbiAQSgN (ORCPT ); Mon, 17 Jan 2022 13:36:13 -0500 Received: from mga12.intel.com ([192.55.52.136]:48633 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235563AbiAQSfv (ORCPT ); Mon, 17 Jan 2022 13:35:51 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642444551; x=1673980551; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=F6/uif5yigoKupn884cwasBuReUKRGlVQKryDxTSe48=; b=GaTpKPsL52BtV83X5kqG2uBz78B5hzK/mGgFqhooO9BofSzCqDC84fk9 a9Q0Vd1dgwWhGftweg7WcVDTbDnaO/P4xHvEu9KkCnkGoE6I97zt1YrxN fuOu5XAVBALjdn+5quN8zCdHTd+NUTapSPXFAl1i9ml6uMi2G8zsRkudT +2RJcBA7I2GQz8/TingpovWLgXPfEMljnCL+9T5NH906nV2z62IXMbyBt DD+joBgbr2o6bQq8VAhWjCTZMXiZ8GlrmmZ3B1Pu9HLlR14WERhz2qzxg e84a5dFQFtQGTOb+8kHpFQLglwc0Y7WymAsteXyUoazlgN9r5R6XdOgG2 g==; X-IronPort-AV: E=McAfee;i="6200,9189,10229"; a="224656079" X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="224656079" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2022 10:35:34 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,296,1635231600"; d="scan'208";a="492434337" Received: from nntpat99-84.inn.intel.com ([10.125.99.84]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2022 10:35:30 -0800 From: Alexey Bayduraev To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Alexander Shishkin , Peter Zijlstra , Ingo Molnar , linux-kernel , Andi Kleen , Adrian Hunter , Alexander Antonov , Alexei Budankov , Riccardo Mancini Subject: [PATCH v13 16/16] perf report: Output data file name in raw trace dump Date: Mon, 17 Jan 2022 21:34:36 +0300 Message-Id: X-Mailer: git-send-email 2.19.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Print path and name of a data file into raw dump (-D) @: 0x2226a@perf.data [0x30]: event: 9 or 0x15cc36@perf.data/data.7 [0x30]: event: 9 Acked-by: Namhyung Kim Acked-by: Andi Kleen Reviewed-by: Riccardo Mancini Tested-by: Riccardo Mancini Signed-off-by: Alexey Bayduraev Acked-by: Jiri Olsa --- tools/perf/builtin-inject.c | 3 +- tools/perf/builtin-kvm.c | 2 +- tools/perf/builtin-top.c | 2 +- tools/perf/builtin-trace.c | 2 +- tools/perf/util/ordered-events.c | 3 +- tools/perf/util/ordered-events.h | 3 +- tools/perf/util/session.c | 75 ++++++++++++++++++++------------ tools/perf/util/session.h | 3 +- tools/perf/util/tool.h | 3 +- 9 files changed, 59 insertions(+), 37 deletions(-) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 409b721666cb..16acebd62b65 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -110,7 +110,8 @@ static int perf_event__repipe_op2_synth(struct perf_ses= sion *session, =20 static int perf_event__repipe_op4_synth(struct perf_session *session, union perf_event *event, - u64 data __maybe_unused) + u64 data __maybe_unused, + const char *str __maybe_unused) { return perf_event__repipe_synth(session->tool, event); } diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index c6f352ee57e6..b23a1f3eaeda 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -771,7 +771,7 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat= *kvm, int idx, return -1; } =20 - err =3D perf_session__queue_event(kvm->session, event, timestamp, 0); + err =3D perf_session__queue_event(kvm->session, event, timestamp, 0, NUL= L); /* * FIXME: Here we can't consume the event, as perf_session__queue_event = will * point to it, and it'll get possibly overwritten by the kernel. diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 1fc390f136dd..92b314fa7223 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -888,7 +888,7 @@ static void perf_top__mmap_read_idx(struct perf_top *to= p, int idx) if (ret && ret !=3D -1) break; =20 - ret =3D ordered_events__queue(top->qe.in, event, last_timestamp, 0); + ret =3D ordered_events__queue(top->qe.in, event, last_timestamp, 0, NULL= ); if (ret) break; =20 diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 46bca1f9ab9e..a89304b55309 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -3780,7 +3780,7 @@ static int trace__deliver_event(struct trace *trace, = union perf_event *event) if (err && err !=3D -1) return err; =20 - err =3D ordered_events__queue(&trace->oe.data, event, trace->oe.last, 0); + err =3D ordered_events__queue(&trace->oe.data, event, trace->oe.last, 0, = NULL); if (err) return err; =20 diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-eve= nts.c index 48c8f609441b..b887dfeea673 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c @@ -192,7 +192,7 @@ void ordered_events__delete(struct ordered_events *oe, = struct ordered_event *eve } =20 int ordered_events__queue(struct ordered_events *oe, union perf_event *eve= nt, - u64 timestamp, u64 file_offset) + u64 timestamp, u64 file_offset, const char *file_path) { struct ordered_event *oevent; =20 @@ -217,6 +217,7 @@ int ordered_events__queue(struct ordered_events *oe, un= ion perf_event *event, return -ENOMEM; =20 oevent->file_offset =3D file_offset; + oevent->file_path =3D file_path; return 0; } =20 diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-eve= nts.h index 75345946c4b9..0b05c3c0aeaa 100644 --- a/tools/perf/util/ordered-events.h +++ b/tools/perf/util/ordered-events.h @@ -9,6 +9,7 @@ struct perf_sample; struct ordered_event { u64 timestamp; u64 file_offset; + const char *file_path; union perf_event *event; struct list_head list; }; @@ -53,7 +54,7 @@ struct ordered_events { }; =20 int ordered_events__queue(struct ordered_events *oe, union perf_event *eve= nt, - u64 timestamp, u64 file_offset); + u64 timestamp, u64 file_offset, const char *file_path); void ordered_events__delete(struct ordered_events *oe, struct ordered_even= t *event); int ordered_events__flush(struct ordered_events *oe, enum oe_flush how); int ordered_events__flush_time(struct ordered_events *oe, u64 timestamp); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index c6605eab61c1..f4e0944c5a2d 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -39,7 +39,8 @@ =20 #ifdef HAVE_ZSTD_SUPPORT static int perf_session__process_compressed_event(struct perf_session *ses= sion, - union perf_event *event, u64 file_offset) + union perf_event *event, u64 file_offset, + const char *file_path) { void *src; size_t decomp_size, src_size; @@ -61,6 +62,7 @@ static int perf_session__process_compressed_event(struct = perf_session *session, } =20 decomp->file_pos =3D file_offset; + decomp->file_path =3D file_path; decomp->mmap_len =3D mmap_len; decomp->head =3D 0; =20 @@ -100,7 +102,8 @@ static int perf_session__process_compressed_event(struc= t perf_session *session, static int perf_session__deliver_event(struct perf_session *session, union perf_event *event, struct perf_tool *tool, - u64 file_offset); + u64 file_offset, + const char *file_path); =20 static int perf_session__open(struct perf_session *session, int repipe_fd) { @@ -182,7 +185,8 @@ static int ordered_events__deliver_event(struct ordered= _events *oe, ordered_events); =20 return perf_session__deliver_event(session, event->event, - session->tool, event->file_offset); + session->tool, event->file_offset, + event->file_path); } =20 struct perf_session *__perf_session__new(struct perf_data *data, @@ -471,7 +475,8 @@ static int process_event_time_conv_stub(struct perf_ses= sion *perf_session __mayb =20 static int perf_session__process_compressed_event_stub(struct perf_session= *session __maybe_unused, union perf_event *event __maybe_unused, - u64 file_offset __maybe_unused) + u64 file_offset __maybe_unused, + const char *file_path __maybe_unused) { dump_printf(": unhandled!\n"); return 0; @@ -1072,9 +1077,9 @@ static int process_finished_round(struct perf_tool *t= ool __maybe_unused, } =20 int perf_session__queue_event(struct perf_session *s, union perf_event *ev= ent, - u64 timestamp, u64 file_offset) + u64 timestamp, u64 file_offset, const char *file_path) { - return ordered_events__queue(&s->ordered_events, event, timestamp, file_o= ffset); + return ordered_events__queue(&s->ordered_events, event, timestamp, file_o= ffset, file_path); } =20 static void callchain__lbr_callstack_printf(struct perf_sample *sample) @@ -1277,13 +1282,14 @@ static void sample_read__printf(struct perf_sample = *sample, u64 read_format) } =20 static void dump_event(struct evlist *evlist, union perf_event *event, - u64 file_offset, struct perf_sample *sample) + u64 file_offset, struct perf_sample *sample, + const char *file_path) { if (!dump_trace) return; =20 - printf("\n%#" PRIx64 " [%#x]: event: %d\n", - file_offset, event->header.size, event->header.type); + printf("\n%#" PRIx64 "@%s [%#x]: event: %d\n", + file_offset, file_path, event->header.size, event->header.type); =20 trace_event(event); if (event->header.type =3D=3D PERF_RECORD_SAMPLE && evlist->trace_event_s= ample_raw) @@ -1486,12 +1492,13 @@ static int machines__deliver_event(struct machines = *machines, struct evlist *evlist, union perf_event *event, struct perf_sample *sample, - struct perf_tool *tool, u64 file_offset) + struct perf_tool *tool, u64 file_offset, + const char *file_path) { struct evsel *evsel; struct machine *machine; =20 - dump_event(evlist, event, file_offset, sample); + dump_event(evlist, event, file_offset, sample, file_path); =20 evsel =3D evlist__id2evsel(evlist, sample->id); =20 @@ -1572,7 +1579,8 @@ static int machines__deliver_event(struct machines *m= achines, static int perf_session__deliver_event(struct perf_session *session, union perf_event *event, struct perf_tool *tool, - u64 file_offset) + u64 file_offset, + const char *file_path) { struct perf_sample sample; int ret =3D evlist__parse_sample(session->evlist, event, &sample); @@ -1589,7 +1597,7 @@ static int perf_session__deliver_event(struct perf_se= ssion *session, return 0; =20 ret =3D machines__deliver_event(&session->machines, session->evlist, - event, &sample, tool, file_offset); + event, &sample, tool, file_offset, file_path); =20 if (dump_trace && sample.aux_sample.size) auxtrace__dump_auxtrace_sample(session, &sample); @@ -1599,7 +1607,8 @@ static int perf_session__deliver_event(struct perf_se= ssion *session, =20 static s64 perf_session__process_user_event(struct perf_session *session, union perf_event *event, - u64 file_offset) + u64 file_offset, + const char *file_path) { struct ordered_events *oe =3D &session->ordered_events; struct perf_tool *tool =3D session->tool; @@ -1609,7 +1618,7 @@ static s64 perf_session__process_user_event(struct pe= rf_session *session, =20 if (event->header.type !=3D PERF_RECORD_COMPRESSED || tool->compressed =3D=3D perf_session__process_compressed_event_stub) - dump_event(session->evlist, event, file_offset, &sample); + dump_event(session->evlist, event, file_offset, &sample, file_path); =20 /* These events are processed right away */ switch (event->header.type) { @@ -1668,9 +1677,9 @@ static s64 perf_session__process_user_event(struct pe= rf_session *session, case PERF_RECORD_HEADER_FEATURE: return tool->feature(session, event); case PERF_RECORD_COMPRESSED: - err =3D tool->compressed(session, event, file_offset); + err =3D tool->compressed(session, event, file_offset, file_path); if (err) - dump_event(session->evlist, event, file_offset, &sample); + dump_event(session->evlist, event, file_offset, &sample, file_path); return err; default: return -EINVAL; @@ -1687,9 +1696,9 @@ int perf_session__deliver_synth_event(struct perf_ses= sion *session, events_stats__inc(&evlist->stats, event->header.type); =20 if (event->header.type >=3D PERF_RECORD_USER_TYPE_START) - return perf_session__process_user_event(session, event, 0); + return perf_session__process_user_event(session, event, 0, NULL); =20 - return machines__deliver_event(&session->machines, evlist, event, sample,= tool, 0); + return machines__deliver_event(&session->machines, evlist, event, sample,= tool, 0, NULL); } =20 static void event_swap(union perf_event *event, bool sample_id_all) @@ -1786,7 +1795,8 @@ int perf_session__peek_events(struct perf_session *se= ssion, u64 offset, } =20 static s64 perf_session__process_event(struct perf_session *session, - union perf_event *event, u64 file_offset) + union perf_event *event, u64 file_offset, + const char *file_path) { struct evlist *evlist =3D session->evlist; struct perf_tool *tool =3D session->tool; @@ -1801,7 +1811,7 @@ static s64 perf_session__process_event(struct perf_se= ssion *session, events_stats__inc(&evlist->stats, event->header.type); =20 if (event->header.type >=3D PERF_RECORD_USER_TYPE_START) - return perf_session__process_user_event(session, event, file_offset); + return perf_session__process_user_event(session, event, file_offset, fil= e_path); =20 if (tool->ordered_events) { u64 timestamp =3D -1ULL; @@ -1810,12 +1820,12 @@ static s64 perf_session__process_event(struct perf_= session *session, if (ret && ret !=3D -1) return ret; =20 - ret =3D perf_session__queue_event(session, event, timestamp, file_offset= ); + ret =3D perf_session__queue_event(session, event, timestamp, file_offset= , file_path); if (ret !=3D -ETIME) return ret; } =20 - return perf_session__deliver_event(session, event, tool, file_offset); + return perf_session__deliver_event(session, event, tool, file_offset, fil= e_path); } =20 void perf_event_header__bswap(struct perf_event_header *hdr) @@ -2042,7 +2052,7 @@ static int __perf_session__process_pipe_events(struct= perf_session *session) } } =20 - if ((skip =3D perf_session__process_event(session, event, head)) < 0) { + if ((skip =3D perf_session__process_event(session, event, head, "pipe")) = < 0) { pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", head, event->header.size, event->header.type); err =3D -EINVAL; @@ -2139,7 +2149,8 @@ static int __perf_session__process_decomp_events(stru= ct perf_session *session) size =3D event->header.size; =20 if (size < sizeof(struct perf_event_header) || - (skip =3D perf_session__process_event(session, event, decomp->file_p= os)) < 0) { + (skip =3D perf_session__process_event(session, event, decomp->file_p= os, + decomp->file_path)) < 0) { pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", decomp->file_pos + decomp->head, event->header.size, event->header.typ= e); return -EINVAL; @@ -2170,10 +2181,12 @@ struct reader; =20 typedef s64 (*reader_cb_t)(struct perf_session *session, union perf_event *event, - u64 file_offset); + u64 file_offset, + const char *file_path); =20 struct reader { int fd; + const char *path; u64 data_size; u64 data_offset; reader_cb_t process; @@ -2293,7 +2306,7 @@ reader__read_event(struct reader *rd, struct perf_ses= sion *session, skip =3D -EINVAL; =20 if (size < sizeof(struct perf_event_header) || - (skip =3D rd->process(session, event, rd->file_pos)) < 0) { + (skip =3D rd->process(session, event, rd->file_pos, rd->path)) < 0) { pr_err("%#" PRIx64 " [%#x]: failed to process type: %d [%s]\n", rd->file_offset + rd->head, event->header.size, event->header.type, strerror(-skip)); @@ -2361,15 +2374,17 @@ reader__process_events(struct reader *rd, struct pe= rf_session *session, =20 static s64 process_simple(struct perf_session *session, union perf_event *event, - u64 file_offset) + u64 file_offset, + const char *file_path) { - return perf_session__process_event(session, event, file_offset); + return perf_session__process_event(session, event, file_offset, file_path= ); } =20 static int __perf_session__process_events(struct perf_session *session) { struct reader rd =3D { .fd =3D perf_data__fd(session->data), + .path =3D session->data->file.path, .data_size =3D session->header.data_size, .data_offset =3D session->header.data_offset, .process =3D process_simple, @@ -2450,6 +2465,7 @@ static int __perf_session__process_dir_events(struct = perf_session *session) =20 rd[0] =3D (struct reader) { .fd =3D perf_data__fd(session->data), + .path =3D session->data->file.path, .data_size =3D session->header.data_size, .data_offset =3D session->header.data_offset, .process =3D process_simple, @@ -2468,6 +2484,7 @@ static int __perf_session__process_dir_events(struct = perf_session *session) continue; rd[readers] =3D (struct reader) { .fd =3D data->dir.files[i].fd, + .path =3D data->dir.files[i].path, .data_size =3D data->dir.files[i].size, .data_offset =3D 0, .process =3D process_simple, diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 46c854292ad6..34500a3da735 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -52,6 +52,7 @@ struct perf_session { struct decomp { struct decomp *next; u64 file_pos; + const char *file_path; size_t mmap_len; u64 head; size_t size; @@ -87,7 +88,7 @@ int perf_session__peek_events(struct perf_session *sessio= n, u64 offset, int perf_session__process_events(struct perf_session *session); =20 int perf_session__queue_event(struct perf_session *s, union perf_event *ev= ent, - u64 timestamp, u64 file_offset); + u64 timestamp, u64 file_offset, const char *file_path); =20 void perf_tool__fill_defaults(struct perf_tool *tool); =20 diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index ef873f2cc38f..f2352dba1875 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -28,7 +28,8 @@ typedef int (*event_attr_op)(struct perf_tool *tool, =20 typedef int (*event_op2)(struct perf_session *session, union perf_event *e= vent); typedef s64 (*event_op3)(struct perf_session *session, union perf_event *e= vent); -typedef int (*event_op4)(struct perf_session *session, union perf_event *e= vent, u64 data); +typedef int (*event_op4)(struct perf_session *session, union perf_event *e= vent, u64 data, + const char *str); =20 typedef int (*event_oe)(struct perf_tool *tool, union perf_event *event, struct ordered_events *oe); --=20 2.19.0