From nobody Wed Apr 8 02:48:23 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 792E1C3F6B0 for ; Wed, 24 Aug 2022 07:28:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234938AbiHXH2s (ORCPT ); Wed, 24 Aug 2022 03:28:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45134 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232752AbiHXH2m (ORCPT ); Wed, 24 Aug 2022 03:28:42 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6098269F4D for ; Wed, 24 Aug 2022 00:28:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1661326121; x=1692862121; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Q3tbz1NaUEC/rY8ldWb5Y5evI0RmSTZjOIOG8xF0v8Q=; b=FDvsw6EJCWPW7GGSwb10QwsB8/N5ooyKN8mAmlEsCyZuwliHf2uaT4wP QU51SYnJGne/jxWBsnXuJwdbhyCDR7Q57xXshtUudF23rxfMI7uXxS3bk HRa738CCiOVReGcka9TAZOi535Bd0km26kqQlBpE0FsL//2BT08hCraVj X2E+8lAeNgQCt6yIJ3ey0N6xQM4aclnptHgxNTMSnrYTf7AZVaAdyU/ae y5L0weq/HBAvsrb7b9qa2BGlbX3QwmX8rLpBnjSVc05KiTAoAs4lRrAFd jLr6FTNRTpAgGPsNyxc7z9HxRYHmOssfzWutUWAecgAUFzxDtZNFp75BQ A==; X-IronPort-AV: E=McAfee;i="6500,9779,10448"; a="295173945" X-IronPort-AV: E=Sophos;i="5.93,260,1654585200"; d="scan'208";a="295173945" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 24 Aug 2022 00:28:41 -0700 X-IronPort-AV: E=Sophos;i="5.93,260,1654585200"; d="scan'208";a="605939141" Received: from ahunter6-mobl1.ger.corp.intel.com (HELO ahunter-VirtualBox.home\044ger.corp.intel.com) ([10.252.51.108]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 24 Aug 2022 00:28:38 -0700 From: Adrian Hunter To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Ian Rogers , Andi Kleen , Alexey Bayduraev , linux-kernel@vger.kernel.org Subject: [PATCH 1/5] perf record: Fix way of handling non-perf-event pollfds Date: Wed, 24 Aug 2022 10:28:10 +0300 Message-Id: <20220824072814.16422-2-adrian.hunter@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824072814.16422-1-adrian.hunter@intel.com> References: <20220824072814.16422-1-adrian.hunter@intel.com> MIME-Version: 1.0 Organization: Intel Finland Oy, Registered Address: PL 281, 00181 Helsinki, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" perf record __cmd_record() does not poll evlist pollfds. Instead it polls thread_data[0].pollfd. That happens whether or not threads are being used. perf record duplicates evlist mmap pollfds as needed for separate threads. The non-perf-event represented by evlist->ctl_fd has to handled separately, which is done explicitly, duplicating it into the thread_data[0] pollfds. That approach neglects any other non-perf-event file descriptors. Currently there is also done_fd which needs the same handling. Add a new generalized approach. Add fdarray_flag__non_perf_event to identify the file descriptors that need the special handling. For those cases, also keep a mapping of the evlist pollfd index and thread pollfd index, so that the evlist revents can be updated. Although this patch adds the new handling, it does not take it into use. There is no functional change, but it is the precursor to a fix, so is marked as a fix. Fixes: 415ccb58f68a ("perf record: Introduce thread specific data array") Signed-off-by: Adrian Hunter Acked-by: Ian Rogers --- tools/lib/api/fd/array.h | 5 ++- tools/perf/builtin-record.c | 80 +++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/tools/lib/api/fd/array.h b/tools/lib/api/fd/array.h index 60ad197c8ee9..5c01f7b05dfb 100644 --- a/tools/lib/api/fd/array.h +++ b/tools/lib/api/fd/array.h @@ -31,8 +31,9 @@ struct fdarray { }; =20 enum fdarray_flags { - fdarray_flag__default =3D 0x00000000, - fdarray_flag__nonfilterable =3D 0x00000001 + fdarray_flag__default =3D 0x00000000, + fdarray_flag__nonfilterable =3D 0x00000001, + fdarray_flag__non_perf_event =3D 0x00000002, }; =20 void fdarray__init(struct fdarray *fda, int nr_autogrow); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 4713f0f3a6cf..e0be48c47f65 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -143,6 +143,11 @@ static const char *thread_spec_tags[THREAD_SPEC__MAX] = =3D { "undefined", "cpu", "core", "package", "numa", "user" }; =20 +struct pollfd_index_map { + int evlist_pollfd_index; + int thread_pollfd_index; +}; + struct record { struct perf_tool tool; struct record_opts opts; @@ -171,6 +176,9 @@ struct record { int nr_threads; struct thread_mask *thread_masks; struct record_thread *thread_data; + struct pollfd_index_map *index_map; + size_t index_map_sz; + size_t index_map_cnt; }; =20 static volatile int done; @@ -1074,6 +1082,70 @@ static void record__free_thread_data(struct record *= rec) zfree(&rec->thread_data); } =20 +static int record__map_thread_evlist_pollfd_indexes(struct record *rec, + int evlist_pollfd_index, + int thread_pollfd_index) +{ + size_t x =3D rec->index_map_cnt; + + if (realloc_array_as_needed(rec->index_map, rec->index_map_sz, x, NULL)) + return -ENOMEM; + rec->index_map[x].evlist_pollfd_index =3D evlist_pollfd_index; + rec->index_map[x].thread_pollfd_index =3D thread_pollfd_index; + rec->index_map_cnt +=3D 1; + return 0; +} + +static int record__update_evlist_pollfd_from_thread(struct record *rec, + struct evlist *evlist, + struct record_thread *thread_data) +{ + struct pollfd *e_entries =3D evlist->core.pollfd.entries; + struct pollfd *t_entries =3D thread_data->pollfd.entries; + int err =3D 0; + size_t i; + + for (i =3D 0; i < rec->index_map_cnt; i++) { + int e_pos =3D rec->index_map[i].evlist_pollfd_index; + int t_pos =3D rec->index_map[i].thread_pollfd_index; + + if (e_entries[e_pos].fd !=3D t_entries[t_pos].fd || + e_entries[e_pos].events !=3D t_entries[t_pos].events) { + pr_err("Thread and evlist pollfd index mismatch\n"); + err =3D -EINVAL; + continue; + } + e_entries[e_pos].revents =3D t_entries[t_pos].revents; + } + return err; +} + +static int record__dup_non_perf_events(struct record *rec, + struct evlist *evlist, + struct record_thread *thread_data) +{ + struct fdarray *fda =3D &evlist->core.pollfd; + int i, ret; + + for (i =3D 0; i < fda->nr; i++) { + if (!(fda->priv[i].flags & fdarray_flag__non_perf_event)) + continue; + ret =3D fdarray__dup_entry_from(&thread_data->pollfd, i, fda); + if (ret < 0) { + pr_err("Failed to duplicate descriptor in main thread pollfd\n"); + return ret; + } + pr_debug2("thread_data[%p]: pollfd[%d] <- non_perf_event fd=3D%d\n", + thread_data, ret, fda->entries[i].fd); + ret =3D record__map_thread_evlist_pollfd_indexes(rec, i, ret); + if (ret < 0) { + pr_err("Failed to map thread and evlist pollfd indexes\n"); + return ret; + } + } + return 0; +} + static int record__alloc_thread_data(struct record *rec, struct evlist *ev= list) { int t, ret; @@ -1121,6 +1193,11 @@ static int record__alloc_thread_data(struct record *= rec, struct evlist *evlist) thread_data[t].pipes.msg[0]); } else { thread_data[t].tid =3D gettid(); + + ret =3D record__dup_non_perf_events(rec, evlist, &thread_data[t]); + if (ret < 0) + goto out_free; + if (evlist->ctl_fd.pos =3D=3D -1) continue; ret =3D fdarray__dup_entry_from(&thread_data[t].pollfd, evlist->ctl_fd.= pos, @@ -2530,6 +2607,9 @@ static int __cmd_record(struct record *rec, int argc,= const char **argv) record__thread_munmap_filtered, NULL) =3D=3D 0) draining =3D true; =20 + err =3D record__update_evlist_pollfd_from_thread(rec, rec->evlist, thre= ad); + if (err) + goto out_child; evlist__ctlfd_update(rec->evlist, &thread->pollfd.entries[thread->ctlfd_pos]); } --=20 2.25.1 From nobody Wed Apr 8 02:48:23 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 9BA93C3F6B0 for ; Wed, 24 Aug 2022 07:28:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234121AbiHXH2w (ORCPT ); Wed, 24 Aug 2022 03:28:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45140 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229445AbiHXH2o (ORCPT ); Wed, 24 Aug 2022 03:28:44 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CD4F8696DC for ; Wed, 24 Aug 2022 00:28:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1661326123; x=1692862123; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=sMAI0paEwMNkWOpIvOSga/g7PIdnTgXjKKnkRCyvU/E=; b=F1ACD/BjcJq+KD8pVr9Fg7KwFh5VQ+ky00RHa+1XuQV6OP8vdi5jgHzg qwlGIkE+ZiHzFEmzX/MvrJIn4svAsLjNjXQ/YjQqlCBz+BQQAaWjEe1vT lCgVB03OjkmOEmaks3G5DccEIFacazWrzqB9E0uD8S+3OxaCCYe+ngBzr SeI5/fmUebsmaFLh21lHPcy1zdPrIz6KD2Qb1GPFJ7B/MGYEV1Jmxo8FO KK+MFUsLqpS6ZTkTPtA7nfE3aA4NfBVW0IvrFSedwqRDeWFkPr9rvqkNy XtIoCSHQWaRGJ9EP6mqL0yC79zkNBpo0pR/9SRVebSPGmbtOnL9bVPLcl w==; X-IronPort-AV: E=McAfee;i="6500,9779,10448"; a="295173956" X-IronPort-AV: E=Sophos;i="5.93,260,1654585200"; d="scan'208";a="295173956" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 24 Aug 2022 00:28:43 -0700 X-IronPort-AV: E=Sophos;i="5.93,260,1654585200"; d="scan'208";a="605939150" Received: from ahunter6-mobl1.ger.corp.intel.com (HELO ahunter-VirtualBox.home\044ger.corp.intel.com) ([10.252.51.108]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 24 Aug 2022 00:28:41 -0700 From: Adrian Hunter To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Ian Rogers , Andi Kleen , Alexey Bayduraev , linux-kernel@vger.kernel.org Subject: [PATCH 2/5] perf record: Fix done_fd wakeup event Date: Wed, 24 Aug 2022 10:28:11 +0300 Message-Id: <20220824072814.16422-3-adrian.hunter@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824072814.16422-1-adrian.hunter@intel.com> References: <20220824072814.16422-1-adrian.hunter@intel.com> MIME-Version: 1.0 Organization: Intel Finland Oy, Registered Address: PL 281, 00181 Helsinki, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" evlist__add_wakeup_eventfd() calls perf_evlist__add_pollfd() to add a non-perf-event to the evlist pollfds. Since commit 415ccb58f68a ("perf record: Introduce thread specific data array") that doesn't work because evlist pollfs is not polled and done_fd is not duplicated into thread-data. Patch "perf record: Fix way of handling non-perf-event pollfds" added a new approach that ensures file descriptors like done_fd are handled correctly by flagging them as fdarray_flag__non_perf_event. Fix by flagging done_fd as fdarray_flag__non_perf_event. Example: Before: $ sleep 3 & perf record -vv -p $! ... thread_data[0x55f44bd34140]: pollfd[0] <- event_fd=3D5 thread_data[0x55f44bd34140]: pollfd[1] <- event_fd=3D6 thread_data[0x55f44bd34140]: pollfd[2] <- event_fd=3D7 thread_data[0x55f44bd34140]: pollfd[3] <- event_fd=3D8 thread_data[0x55f44bd34140]: pollfd[4] <- event_fd=3D9 thread_data[0x55f44bd34140]: pollfd[5] <- event_fd=3D10 thread_data[0x55f44bd34140]: pollfd[6] <- event_fd=3D11 thread_data[0x55f44bd34140]: pollfd[7] <- event_fd=3D12 ... After: $ sleep 3 & perf record -vv -p $! ... thread_data[0x55a8ded89140]: pollfd[0] <- event_fd=3D5 thread_data[0x55a8ded89140]: pollfd[1] <- event_fd=3D6 thread_data[0x55a8ded89140]: pollfd[2] <- event_fd=3D7 thread_data[0x55a8ded89140]: pollfd[3] <- event_fd=3D8 thread_data[0x55a8ded89140]: pollfd[4] <- event_fd=3D9 thread_data[0x55a8ded89140]: pollfd[5] <- event_fd=3D10 thread_data[0x55a8ded89140]: pollfd[6] <- event_fd=3D11 thread_data[0x55a8ded89140]: pollfd[7] <- event_fd=3D12 thread_data[0x55a8ded89140]: pollfd[8] <- non_perf_event fd=3D4 ... This patch depends on "perf record: Fix way of handling non-perf-event pollfds". Fixes: 415ccb58f68a ("perf record: Introduce thread specific data array") Signed-off-by: Adrian Hunter Acked-by: Ian Rogers --- tools/perf/util/evlist.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 48167f3941a6..0b2222d05577 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -608,7 +608,8 @@ int evlist__filter_pollfd(struct evlist *evlist, short = revents_and_mask) int evlist__add_wakeup_eventfd(struct evlist *evlist, int fd) { return perf_evlist__add_pollfd(&evlist->core, fd, NULL, POLLIN, - fdarray_flag__nonfilterable); + fdarray_flag__nonfilterable | + fdarray_flag__non_perf_event); } #endif =20 --=20 2.25.1 From nobody Wed Apr 8 02:48:23 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 14ED0C00140 for ; Wed, 24 Aug 2022 07:28:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235309AbiHXH25 (ORCPT ); Wed, 24 Aug 2022 03:28:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45182 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234852AbiHXH2r (ORCPT ); Wed, 24 Aug 2022 03:28:47 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5E55F9353F for ; Wed, 24 Aug 2022 00:28:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1661326126; x=1692862126; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ymNBeq5PNnzjxJsogOGJR+feFiumi+DIqlDgOH2VXUc=; b=QvxBvIbXDPQXG44hjoFbYATlfKLSweO0pq3N8RO96un1PCAcdmpv7OZz fbRc+gyeCV5b7U/NoxlUNpF5UIzSagZNLx+TV0RFzXsak5KZu5g0Dt34J mzxGO+evucDvMSro3VreOBH/+FbRDcXpv4D7mODjRFyx3pu4uDjwMvkIs nSTcruROTjqbOOwmSYqXC0EdlJh50TGQKwQYLv8ekngy/qHYoW3dgcnY2 8zvCEDO4PF1r0Kdb1bBxAkO5qKBYn0bsaa74eprLZAxb77Ri6ABubIsT5 qU8VF42chtdC13T2gybGn3pJ0WvVPeAjxYKbbY/tQIa2zIPY4uUJF1zNQ Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10448"; a="295173969" X-IronPort-AV: E=Sophos;i="5.93,260,1654585200"; d="scan'208";a="295173969" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 24 Aug 2022 00:28:46 -0700 X-IronPort-AV: E=Sophos;i="5.93,260,1654585200"; d="scan'208";a="605939162" Received: from ahunter6-mobl1.ger.corp.intel.com (HELO ahunter-VirtualBox.home\044ger.corp.intel.com) ([10.252.51.108]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 24 Aug 2022 00:28:43 -0700 From: Adrian Hunter To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Ian Rogers , Andi Kleen , Alexey Bayduraev , linux-kernel@vger.kernel.org Subject: [PATCH 3/5] perf record: Change evlist->ctl_fd to use fdarray_flag__non_perf_event Date: Wed, 24 Aug 2022 10:28:12 +0300 Message-Id: <20220824072814.16422-4-adrian.hunter@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824072814.16422-1-adrian.hunter@intel.com> References: <20220824072814.16422-1-adrian.hunter@intel.com> MIME-Version: 1.0 Organization: Intel Finland Oy, Registered Address: PL 281, 00181 Helsinki, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Patch "perf record: Fix way of handling non-perf-event pollfds" added a generic way to handle non-perf-event file descriptors like evlist->ctl_fd. Use it instead of handling evlist->ctl_fd separately. Signed-off-by: Adrian Hunter Acked-by: Ian Rogers --- tools/perf/builtin-record.c | 15 +-------------- tools/perf/util/evlist.c | 19 ++----------------- tools/perf/util/evlist.h | 1 - 3 files changed, 3 insertions(+), 32 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index e0be48c47f65..cefb3028f565 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1198,18 +1198,7 @@ static int record__alloc_thread_data(struct record *= rec, struct evlist *evlist) if (ret < 0) goto out_free; =20 - 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); + thread_data[t].ctlfd_pos =3D -1; /* Not used */ } } =20 @@ -2610,8 +2599,6 @@ static int __cmd_record(struct record *rec, int argc,= const char **argv) err =3D record__update_evlist_pollfd_from_thread(rec, rec->evlist, thre= ad); if (err) goto out_child; - evlist__ctlfd_update(rec->evlist, - &thread->pollfd.entries[thread->ctlfd_pos]); } =20 if (evlist__ctlfd_process(rec->evlist, &cmd) > 0) { diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 0b2222d05577..4c5e6e9f8d11 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1898,7 +1898,8 @@ int evlist__initialize_ctlfd(struct evlist *evlist, i= nt fd, int ack) } =20 evlist->ctl_fd.pos =3D perf_evlist__add_pollfd(&evlist->core, fd, NULL, P= OLLIN, - fdarray_flag__nonfilterable); + fdarray_flag__nonfilterable | + fdarray_flag__non_perf_event); if (evlist->ctl_fd.pos < 0) { evlist->ctl_fd.pos =3D -1; pr_err("Failed to add ctl fd entry: %m\n"); @@ -2148,22 +2149,6 @@ 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 351ba2887a79..3a464585d397 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -418,7 +418,6 @@ 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.25.1 From nobody Wed Apr 8 02:48:23 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 B284AC00140 for ; Wed, 24 Aug 2022 07:29:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235480AbiHXH3B (ORCPT ); Wed, 24 Aug 2022 03:29:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45218 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235088AbiHXH2t (ORCPT ); Wed, 24 Aug 2022 03:28:49 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E5B1A9569B for ; Wed, 24 Aug 2022 00:28:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1661326128; x=1692862128; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Cqkndv1Yn7D3YXugKtRw1N3dr5xiJQHYcNHcQTNkS5k=; b=MGDwso7v9o4B9FMiLF5XnlDQtkX81k+oAa+uKuLCmcNgI1fA5UKiv9G8 dQdkFmdpHkIFE5WNd8/ZqMSrOLVOKff9Udv0YIRww6oO59dS3JmAKXTTq LFBxXcTEhNlXcZkpX01n6VACF2A+iqJZ38+d+a8dpN6pnNjPcQj8ayQdv pqYxXyBDq3x5Cy1pQssnk9gtd6NOugqAoFFZtQIJ9d6dhjnDch+h9ZxwQ bN7IhCi5U81mvZM+K2zcnn+ySU9PQvIeaHuCPGCY0jXMvepCaoL2WPmfy UiXhkYcIouY8LHk0qHS4ePUz8uQUYUGnS6rztNhhnCVSz6CfCIahERqXH A==; X-IronPort-AV: E=McAfee;i="6500,9779,10448"; a="295173982" X-IronPort-AV: E=Sophos;i="5.93,260,1654585200"; d="scan'208";a="295173982" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 24 Aug 2022 00:28:48 -0700 X-IronPort-AV: E=Sophos;i="5.93,260,1654585200"; d="scan'208";a="605939172" Received: from ahunter6-mobl1.ger.corp.intel.com (HELO ahunter-VirtualBox.home\044ger.corp.intel.com) ([10.252.51.108]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 24 Aug 2022 00:28:46 -0700 From: Adrian Hunter To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Ian Rogers , Andi Kleen , Alexey Bayduraev , linux-kernel@vger.kernel.org Subject: [PATCH 4/5] perf evlist: Add evlist__{en/dis}able_non_dummy() Date: Wed, 24 Aug 2022 10:28:13 +0300 Message-Id: <20220824072814.16422-5-adrian.hunter@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824072814.16422-1-adrian.hunter@intel.com> References: <20220824072814.16422-1-adrian.hunter@intel.com> MIME-Version: 1.0 Organization: Intel Finland Oy, Registered Address: PL 281, 00181 Helsinki, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Dummy events are used to provide sideband information like MMAP events that are always needed even when main events are disabled. Add functions that take that into account. Signed-off-by: Adrian Hunter Acked-by: Ian Rogers --- tools/perf/util/evlist.c | 30 ++++++++++++++++++++++++------ tools/perf/util/evlist.h | 2 ++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 4c5e6e9f8d11..3cfe730c12b8 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -480,7 +480,7 @@ static int evlist__is_enabled(struct evlist *evlist) return false; } =20 -static void __evlist__disable(struct evlist *evlist, char *evsel_name) +static void __evlist__disable(struct evlist *evlist, char *evsel_name, boo= l excl_dummy) { struct evsel *pos; struct evlist_cpu_iterator evlist_cpu_itr; @@ -502,6 +502,8 @@ static void __evlist__disable(struct evlist *evlist, ch= ar *evsel_name) continue; if (pos->disabled || !evsel__is_group_leader(pos) || !pos->core.fd) continue; + if (excl_dummy && evsel__is_dummy_event(pos)) + continue; if (pos->immediate) has_imm =3D true; if (pos->immediate !=3D imm) @@ -518,6 +520,8 @@ static void __evlist__disable(struct evlist *evlist, ch= ar *evsel_name) continue; if (!evsel__is_group_leader(pos) || !pos->core.fd) continue; + if (excl_dummy && evsel__is_dummy_event(pos)) + continue; pos->disabled =3D true; } =20 @@ -533,15 +537,20 @@ static void __evlist__disable(struct evlist *evlist, = char *evsel_name) =20 void evlist__disable(struct evlist *evlist) { - __evlist__disable(evlist, NULL); + __evlist__disable(evlist, NULL, false); +} + +void evlist__disable_non_dummy(struct evlist *evlist) +{ + __evlist__disable(evlist, NULL, true); } =20 void evlist__disable_evsel(struct evlist *evlist, char *evsel_name) { - __evlist__disable(evlist, evsel_name); + __evlist__disable(evlist, evsel_name, false); } =20 -static void __evlist__enable(struct evlist *evlist, char *evsel_name) +static void __evlist__enable(struct evlist *evlist, char *evsel_name, bool= excl_dummy) { struct evsel *pos; struct evlist_cpu_iterator evlist_cpu_itr; @@ -560,6 +569,8 @@ static void __evlist__enable(struct evlist *evlist, cha= r *evsel_name) continue; if (!evsel__is_group_leader(pos) || !pos->core.fd) continue; + if (excl_dummy && evsel__is_dummy_event(pos)) + continue; evsel__enable_cpu(pos, evlist_cpu_itr.cpu_map_idx); } affinity__cleanup(affinity); @@ -568,6 +579,8 @@ static void __evlist__enable(struct evlist *evlist, cha= r *evsel_name) continue; if (!evsel__is_group_leader(pos) || !pos->core.fd) continue; + if (excl_dummy && evsel__is_dummy_event(pos)) + continue; pos->disabled =3D false; } =20 @@ -581,12 +594,17 @@ static void __evlist__enable(struct evlist *evlist, c= har *evsel_name) =20 void evlist__enable(struct evlist *evlist) { - __evlist__enable(evlist, NULL); + __evlist__enable(evlist, NULL, false); +} + +void evlist__enable_non_dummy(struct evlist *evlist) +{ + __evlist__enable(evlist, NULL, true); } =20 void evlist__enable_evsel(struct evlist *evlist, char *evsel_name) { - __evlist__enable(evlist, evsel_name); + __evlist__enable(evlist, evsel_name, false); } =20 void evlist__toggle_enable(struct evlist *evlist) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 3a464585d397..3a8474406738 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -205,6 +205,8 @@ void evlist__enable(struct evlist *evlist); void evlist__toggle_enable(struct evlist *evlist); void evlist__disable_evsel(struct evlist *evlist, char *evsel_name); void evlist__enable_evsel(struct evlist *evlist, char *evsel_name); +void evlist__disable_non_dummy(struct evlist *evlist); +void evlist__enable_non_dummy(struct evlist *evlist); =20 void evlist__set_selected(struct evlist *evlist, struct evsel *evsel); =20 --=20 2.25.1 From nobody Wed Apr 8 02:48:23 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 BA092C00140 for ; Wed, 24 Aug 2022 07:29:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235232AbiHXH3F (ORCPT ); Wed, 24 Aug 2022 03:29:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45276 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234991AbiHXH2x (ORCPT ); Wed, 24 Aug 2022 03:28:53 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4607569F4D for ; Wed, 24 Aug 2022 00:28:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1661326131; x=1692862131; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=P+4pijulD/l64/rqj9YBxfBxxfkPRhc4iZV2wxukILA=; b=CnQQC1jT/qgAXWGFKXHWgPQKikKcYZNNCVEofeqac5+rGeVn1mNN5Bf3 w1h8/Lz313uvGMTiubOyV80yqJrHFb8wh8dsKOl2IHBJtl3i8nsC1uc6R FXfQupXm7BVav1Yy5vUpjE/5kOeZGREBTKAm6EQz3K8xFGCvd2IPsUgsr 8ng/U33Do1TPmWhQGJm3Ejeq7BCuARsJvZJfqWplFztsYRqa+kIHxJibd nDb/+HQizQ8/qGxHpTyIxtFRyW243UVo+5WkGW9e83KZf/FjyhEELXCTt IFj/WFibb5HR/f8G7nA01YZutwenQdfT4p1/ORce9gYtNyCT4on/f8zoL Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10448"; a="295173990" X-IronPort-AV: E=Sophos;i="5.93,260,1654585200"; d="scan'208";a="295173990" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 24 Aug 2022 00:28:51 -0700 X-IronPort-AV: E=Sophos;i="5.93,260,1654585200"; d="scan'208";a="605939186" Received: from ahunter6-mobl1.ger.corp.intel.com (HELO ahunter-VirtualBox.home\044ger.corp.intel.com) ([10.252.51.108]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 24 Aug 2022 00:28:48 -0700 From: Adrian Hunter To: Arnaldo Carvalho de Melo Cc: Jiri Olsa , Namhyung Kim , Ian Rogers , Andi Kleen , Alexey Bayduraev , linux-kernel@vger.kernel.org Subject: [PATCH 5/5] perf record: Allow multiple recording time ranges Date: Wed, 24 Aug 2022 10:28:14 +0300 Message-Id: <20220824072814.16422-6-adrian.hunter@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824072814.16422-1-adrian.hunter@intel.com> References: <20220824072814.16422-1-adrian.hunter@intel.com> MIME-Version: 1.0 Organization: Intel Finland Oy, Registered Address: PL 281, 00181 Helsinki, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" AUX area traces can produce too much data to record successfully or analyze subsequently. Add another means to reduce data collection by allowing multiple recording time ranges. This is useful, for instance, in cases where a workload produces predictably reproducible events in specific time ranges. Today we only have perf record -D to start at a specific region, or some complicated approach using snapshot mode and external scripts sending signals or using the fifos. But these approaches are difficult to set up compared with simply having perf do it. Extend perf record option -D/--delay option to specifying relative time stamps for start stop controlled by perf with the right time offset, for instance: perf record -e intel_pt// -D 10-20,30-40 to record 10ms to 20ms into the trace and 30ms to 40ms. Example: The example workload is: $ cat repeat-usleep.c int usleep(useconds_t usec); int usage(int ret, const char *msg) { if (msg) fprintf(stderr, "%s\n", msg); fprintf(stderr, "Usage is: repeat-usleep \n"); return ret; } int main(int argc, char *argv[]) { unsigned long usecs; char *end_ptr; if (argc !=3D 2) return usage(1, "Error: Wrong number of arguments!"); errno =3D 0; usecs =3D strtoul(argv[1], &end_ptr, 0); if (errno || *end_ptr || usecs > UINT_MAX) return usage(1, "Error: Invalid argument!"); while (1) { int ret =3D usleep(usecs); if (ret & errno !=3D EINTR) return usage(1, "Error: usleep() failed!"); } return 0; } $ perf record -e intel_pt//u --delay 10-20,40-70,110-160 -- ./repeat-uslee= p 500 Events disabled Events enabled Events disabled Events enabled Events disabled Events enabled Events disabled [ perf record: Woken up 5 times to write data ] [ perf record: Captured and wrote 0.204 MB perf.data ] Terminated A dlfilter is used to determine continuous data collection (timestamps less than 1ms apart): $ cat dlfilter-show-delays.c static __u64 start_time; static __u64 last_time; int start(void **data, void *ctx) { printf("%-17s\t%-9s\t%-6s\n", " Time", " Duration", " Delay"); return 0; } int filter_event_early(void *data, const struct perf_dlfilter_sample *samp= le, void *ctx) { __u64 delta; if (!sample->time) return 1; if (!last_time) goto out; delta =3D sample->time - last_time; if (delta < 1000000) goto out2;; printf("%17.9f\t%9.1f\t%6.1f\n", start_time / 1000000000.0, (last_= time - start_time) / 1000000.0, delta / 1000000.0); out: start_time =3D sample->time; out2: last_time =3D sample->time; return 1; } int stop(void *data, void *ctx) { printf("%17.9f\t%9.1f\n", start_time / 1000000000.0, (last_time - = start_time) / 1000000.0); return 0; } The result shows the times roughly match the --delay option: $ perf script --itrace=3Dqb --dlfilter dlfilter-show-delays.so Time Duration Delay 39215.302317300 9.7 20.5 39215.332480217 30.4 40.9 39215.403837717 49.8 Signed-off-by: Adrian Hunter --- tools/perf/Documentation/perf-record.txt | 6 +- tools/perf/builtin-record.c | 24 ++- tools/perf/util/evlist.c | 234 +++++++++++++++++++++++ tools/perf/util/evlist.h | 9 + 4 files changed, 269 insertions(+), 4 deletions(-) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Document= ation/perf-record.txt index 099817ef5150..953b9663522a 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -430,8 +430,10 @@ if combined with -a or -C options. -D:: --delay=3D:: After starting the program, wait msecs before measuring (-1: start with ev= ents -disabled). This is useful to filter out the startup phase of the program, = which -is often very different. +disabled), or enable events only for specified ranges of msecs (e.g. +-D 10-20,30-40 means wait 10 msecs, enable for 10 msecs, wait 10 msecs, en= able +for 10 msecs, then stop). Note, delaying enabling of events is useful to f= ilter +out the startup phase of the program, which is often very different. =20 -I:: --intr-regs:: diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index cefb3028f565..7fdb1dd9a0a8 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -2498,6 +2498,10 @@ static int __cmd_record(struct record *rec, int argc= , const char **argv) } } =20 + err =3D event_enable_timer__start(rec->evlist->eet); + if (err) + goto out_child; + trigger_ready(&auxtrace_snapshot_trigger); trigger_ready(&switch_output_trigger); perf_hooks__invoke_record_start(); @@ -2621,6 +2625,14 @@ static int __cmd_record(struct record *rec, int argc= , const char **argv) } } =20 + err =3D event_enable_timer__process(rec->evlist->eet); + if (err < 0) + goto out_child; + if (err) { + err =3D 0; + done =3D 1; + } + /* * When perf is starting the traced process, at the end events * die with the process and we wait for that. Thus no need to @@ -2842,6 +2854,12 @@ static int perf_record_config(const char *var, const= char *value, void *cb) return 0; } =20 +static int record__parse_event_enable_time(const struct option *opt, const= char *str, int unset) +{ + struct record *rec =3D (struct record *)opt->value; + + return evlist__parse_event_enable_time(rec->evlist, &rec->opts, str, unse= t); +} =20 static int record__parse_affinity(const struct option *opt, const char *st= r, int unset) { @@ -3303,8 +3321,10 @@ static struct option __record_options[] =3D { OPT_CALLBACK('G', "cgroup", &record.evlist, "name", "monitor event in cgroup name only", parse_cgroups), - OPT_INTEGER('D', "delay", &record.opts.initial_delay, - "ms to wait before starting measurement after program start (-1: start= with events disabled)"), + OPT_CALLBACK('D', "delay", &record, "ms", + "ms to wait before starting measurement after program start (-1: st= art with events disabled), " + "or ranges of time to enable events e.g. '-D 10-20,30-40'", + record__parse_event_enable_time), OPT_BOOLEAN(0, "kcore", &record.opts.kcore, "copy /proc/kcore"), OPT_STRING('u', "uid", &record.opts.target.uid_str, "user", "user to profile"), diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 3cfe730c12b8..fcfe5bcc0bcf 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -15,6 +15,7 @@ #include "target.h" #include "evlist.h" #include "evsel.h" +#include "record.h" #include "debug.h" #include "units.h" #include "bpf_counter.h" @@ -40,12 +41,14 @@ #include #include #include +#include =20 #include #include #include #include #include +#include #include #include #include @@ -147,6 +150,7 @@ static void evlist__purge(struct evlist *evlist) =20 void evlist__exit(struct evlist *evlist) { + event_enable_timer__exit(&evlist->eet); zfree(&evlist->mmap); zfree(&evlist->overwrite_mmap); perf_evlist__exit(&evlist->core); @@ -2167,6 +2171,236 @@ int evlist__ctlfd_process(struct evlist *evlist, en= um evlist_ctl_cmd *cmd) return err; } =20 +/** + * struct event_enable_time - perf record -D/--delay single time range. + * @start: start of time range to enable events in milliseconds + * @end: end of time range to enable events in milliseconds + * + * N.B. this structure is also accessed as an array of int. + */ +struct event_enable_time { + int start; + int end; +}; + +static int parse_event_enable_time(const char *str, struct event_enable_ti= me *range, bool first) +{ + const char *fmt =3D first ? "%u - %u %n" : " , %u - %u %n"; + int ret, start, end, n; + + ret =3D sscanf(str, fmt, &start, &end, &n); + if (ret !=3D 2 || end <=3D start) + return -EINVAL; + if (range) { + range->start =3D start; + range->end =3D end; + } + return n; +} + +static ssize_t parse_event_enable_times(const char *str, struct event_enab= le_time *range) +{ + int incr =3D !!range; + bool first =3D true; + ssize_t ret, cnt; + + for (cnt =3D 0; *str; cnt++) { + ret =3D parse_event_enable_time(str, range, first); + if (ret < 0) + return ret; + /* Check no overlap */ + if (!first && range && range->start <=3D range[-1].end) + return -EINVAL; + str +=3D ret; + range +=3D incr; + first =3D false; + } + return cnt; +} + +/** + * struct event_enable_timer - control structure for perf record -D/--dela= y. + * @evlist: event list + * @times: time ranges that events are enabled (N.B. this is also accessed= as an + * array of int) + * @times_cnt: number of time ranges + * @timerfd: timer file descriptor + * @pollfd_pos: position in @evlist array of file descriptors to poll (fda= rray) + * @times_step: current position in (int *)@times)[], + * refer event_enable_timer__process() + * + * Note, this structure is only used when there are time ranges, not when = there + * is only an initial delay. + */ +struct event_enable_timer { + struct evlist *evlist; + struct event_enable_time *times; + size_t times_cnt; + int timerfd; + int pollfd_pos; + size_t times_step; +}; + +static int str_to_delay(const char *str) +{ + char *endptr; + long d; + + d =3D strtol(str, &endptr, 10); + if (*endptr || d > INT_MAX || d < -1) + return 0; + return d; +} + +int evlist__parse_event_enable_time(struct evlist *evlist, struct record_o= pts *opts, + const char *str, int unset) +{ + enum fdarray_flags flags =3D fdarray_flag__nonfilterable | fdarray_flag__= non_perf_event; + struct event_enable_timer *eet; + ssize_t times_cnt; + ssize_t ret; + int err; + + if (unset) + return 0; + + opts->initial_delay =3D str_to_delay(str); + if (opts->initial_delay) + return 0; + + ret =3D parse_event_enable_times(str, NULL); + if (ret < 0) + return ret; + + times_cnt =3D ret; + if (times_cnt =3D=3D 0) + return -EINVAL; + + eet =3D zalloc(sizeof(*eet)); + if (!eet) + return -ENOMEM; + + eet->times =3D calloc(times_cnt, sizeof(*eet->times)); + if (!eet->times) { + err =3D -ENOMEM; + goto free_eet; + } + + if (parse_event_enable_times(str, eet->times) !=3D times_cnt) { + err =3D -EINVAL; + goto free_eet_times; + } + + eet->times_cnt =3D times_cnt; + + eet->timerfd =3D timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); + if (eet->timerfd =3D=3D -1) { + err =3D -errno; + pr_err("timerfd_create failed: %s\n", strerror(errno)); + goto free_eet_times; + } + + eet->pollfd_pos =3D perf_evlist__add_pollfd(&evlist->core, eet->timerfd, = NULL, POLLIN, flags); + if (eet->pollfd_pos < 0) { + err =3D eet->pollfd_pos; + goto close_timerfd; + } + + eet->evlist =3D evlist; + evlist->eet =3D eet; + opts->initial_delay =3D eet->times[0].start; + + return 0; + +close_timerfd: + close(eet->timerfd); +free_eet_times: + free(eet->times); +free_eet: + free(eet); + return err; +} + +static int event_enable_timer__set_timer(struct event_enable_timer *eet, i= nt ms) +{ + struct itimerspec its =3D { + .it_value.tv_sec =3D ms / MSEC_PER_SEC, + .it_value.tv_nsec =3D (ms % MSEC_PER_SEC) * NSEC_PER_MSEC, + }; + int err =3D 0; + + if (timerfd_settime(eet->timerfd, 0, &its, NULL) < 0) { + err =3D -errno; + pr_err("timerfd_settime failed: %s\n", strerror(errno)); + } + return err; +} + +int event_enable_timer__start(struct event_enable_timer *eet) +{ + int ms; + + if (!eet) + return 0; + + ms =3D eet->times[0].end - eet->times[0].start; + eet->times_step =3D 1; + + return event_enable_timer__set_timer(eet, ms); +} + +int event_enable_timer__process(struct event_enable_timer *eet) +{ + struct pollfd *entries; + short revents; + + if (!eet) + return 0; + + entries =3D eet->evlist->core.pollfd.entries; + revents =3D entries[eet->pollfd_pos].revents; + entries[eet->pollfd_pos].revents =3D 0; + + if (revents & POLLIN) { + size_t step =3D eet->times_step; + size_t pos =3D step / 2; + + if (step & 1) { + evlist__disable_non_dummy(eet->evlist); + pr_info(EVLIST_DISABLED_MSG); + if (pos >=3D eet->times_cnt - 1) { + /* Disarm timer */ + event_enable_timer__set_timer(eet, 0); + return 1; /* Stop */ + } + } else { + evlist__enable_non_dummy(eet->evlist); + pr_info(EVLIST_ENABLED_MSG); + } + + step +=3D 1; + pos =3D step / 2; + + if (pos < eet->times_cnt) { + int *times =3D (int *)eet->times; /* Accessing 'times' as array of int = */ + int ms =3D times[step] - times[step - 1]; + + eet->times_step =3D step; + return event_enable_timer__set_timer(eet, ms); + } + } + + return 0; +} + +void event_enable_timer__exit(struct event_enable_timer **ep) +{ + if (!ep || !*ep) + return; + free((*ep)->times); + zfree(ep); +} + 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 3a8474406738..9d967fe3953a 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -48,6 +48,8 @@ enum bkw_mmap_state { BKW_MMAP_EMPTY, }; =20 +struct event_enable_timer; + struct evlist { struct perf_evlist core; bool enabled; @@ -79,6 +81,7 @@ struct evlist { int ack; /* ack file descriptor for control commands */ int pos; /* index at evlist core object to check signals */ } ctl_fd; + struct event_enable_timer *eet; }; =20 struct evsel_str_handler { @@ -426,6 +429,12 @@ int evlist__ctlfd_ack(struct evlist *evlist); #define EVLIST_ENABLED_MSG "Events enabled\n" #define EVLIST_DISABLED_MSG "Events disabled\n" =20 +int evlist__parse_event_enable_time(struct evlist *evlist, struct record_o= pts *opts, + const char *str, int unset); +int event_enable_timer__start(struct event_enable_timer *eet); +void event_enable_timer__exit(struct event_enable_timer **ep); +int event_enable_timer__process(struct event_enable_timer *eet); + struct evsel *evlist__find_evsel(struct evlist *evlist, int idx); =20 int evlist__scnprintf_evsels(struct evlist *evlist, size_t size, char *bf); --=20 2.25.1