From nobody Mon Apr 13 14:26:57 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 A3190C43219 for ; Mon, 14 Nov 2022 21:08:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237369AbiKNVH7 (ORCPT ); Mon, 14 Nov 2022 16:07:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44256 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237361AbiKNVHz (ORCPT ); Mon, 14 Nov 2022 16:07:55 -0500 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BB6E095A3 for ; Mon, 14 Nov 2022 13:07:48 -0800 (PST) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-360b9418f64so114894457b3.7 for ; Mon, 14 Nov 2022 13:07:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=2OZhfmPm3XVkECYqwzYQM5F2KZdnyo2PlgH8Orm1zuI=; b=d03dpv19fKYHRy/o0sTKt3d1Ucz5gD7WCqPFOeFJ2EEnrgHjP1F7o+EV5XjAH7uKXx QlhalH9ep4BgRvy+zz8yAUsQpMYQICs3LDhHwH+q5UgWdAFRboeOgd3gMH2tYFWsbrir cG4OYvkuz0+LBYsnJca4j/6wqAc5/FoKYNwrRbFeCYbtO2extKFVChEEuuP97gu1F4fI YlTRuFCf+JNRttBeHgxKWCxX3NgIWs+sZqDWiZOUtj4kn2NerPrZJua9Y6GmjZVdtqBG N6lPgMczC485QLYAXnM1iuRs4lqjm3b/CbiA6x/obus990if35GiEg2TDCzz9DfLnPBR gVvw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=2OZhfmPm3XVkECYqwzYQM5F2KZdnyo2PlgH8Orm1zuI=; b=YW0WSUaOi8HjHOKCxvtc3FPwe+oWIT3+rLwdcA6VlCOD0oyqMm/5sSJy4HNgkc3JFa v6pyFO5RhZCKv57tkn/WGXsaWz/vj29UUZ6znKBYPuaV4qOL9kaPG0rnhw3svowynLlm IQ0tJoLS6Dr6K5kGBGVJ+DYCrjWndG2ZLIwdGVnSAwT+Q+C0Q2PjyPQnFzVamPDi/v4l gZ9hbKt4VL2M+Skc6ZmvXKKuF4leUvWodGJNCqzEho8mZpPTOVgzNoDmHUk++N8yvgtM 9ZoJSM7BK+oOPBxSbjJslPo3qO9a3r97nCMtoqCU5Gphh15vOq4uF9HeCPfq390x4Xbt 0T1g== X-Gm-Message-State: ANoB5pnFdhc449GoM2X5C0XMj4o6jNPVw3HoqYNvV85zPXPHH90/C7FI CL/Ctr2jNsqQOmf6EgWZqFpBi7f2RN+5 X-Google-Smtp-Source: AA0mqf4Ws5KvPAwDSph9djQ4ezg04RclKilEiUPYeGk3HFTdX0NZSHs9URIs8HQP7NTfkDCvXnCqycBcOqHm X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:553:438f:b86a:87f]) (user=irogers job=sendgmr) by 2002:a81:78ca:0:b0:381:22a0:d706 with SMTP id t193-20020a8178ca000000b0038122a0d706mr6329985ywc.440.1668460067934; Mon, 14 Nov 2022 13:07:47 -0800 (PST) Date: Mon, 14 Nov 2022 13:07:14 -0800 In-Reply-To: <20221114210723.2749751-1-irogers@google.com> Message-Id: <20221114210723.2749751-2-irogers@google.com> Mime-Version: 1.0 References: <20221114210723.2749751-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v3 01/10] perf pmu: Remove is_hybrid member From: Ian Rogers To: Weilin Wang , Perry Taylor , Caleb Biggers , Leo Yan , Adrian Hunter , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Sandipan Das , Kajol Jain , Zhengjun Xing , Kan Liang , Ravi Bangoria , Xin Gao , Rob Herring , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org Cc: Stephane Eranian , Ian Rogers Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Replace usage with perf_pmu__is_hybrid. Suggested-by: Kan Liang Signed-off-by: Ian Rogers --- tools/perf/util/evsel.c | 5 +---- tools/perf/util/evsel.h | 2 +- tools/perf/util/pmu.c | 3 +-- tools/perf/util/pmu.h | 1 - tools/perf/util/stat.c | 11 +++-------- 5 files changed, 6 insertions(+), 16 deletions(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index cdde5b5f8ad2..ca6abb64c91d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -3124,11 +3124,8 @@ void evsel__zero_per_pkg(struct evsel *evsel) } } =20 -bool evsel__is_hybrid(struct evsel *evsel) +bool evsel__is_hybrid(const struct evsel *evsel) { - if (evsel->pmu) - return evsel->pmu->is_hybrid; - return evsel->pmu_name && perf_pmu__is_hybrid(evsel->pmu_name); } =20 diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 989865e16aad..467bb0b32fef 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -498,7 +498,7 @@ struct perf_env *evsel__env(struct evsel *evsel); int evsel__store_ids(struct evsel *evsel, struct evlist *evlist); =20 void evsel__zero_per_pkg(struct evsel *evsel); -bool evsel__is_hybrid(struct evsel *evsel); +bool evsel__is_hybrid(const struct evsel *evsel); struct evsel *evsel__leader(struct evsel *evsel); bool evsel__has_leader(struct evsel *evsel, struct evsel *leader); bool evsel__is_leader(struct evsel *evsel); diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 6a86e6af0903..48e7be6f3baa 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -980,7 +980,6 @@ static struct perf_pmu *pmu_lookup(const char *lookup_n= ame) pmu->is_uncore =3D pmu_is_uncore(name); if (pmu->is_uncore) pmu->id =3D pmu_id(name); - pmu->is_hybrid =3D is_hybrid; pmu->max_precise =3D pmu_max_precise(name); pmu_add_cpu_aliases(&aliases, pmu); pmu_add_sys_aliases(&aliases, pmu); @@ -992,7 +991,7 @@ static struct perf_pmu *pmu_lookup(const char *lookup_n= ame) list_splice(&aliases, &pmu->aliases); list_add_tail(&pmu->list, &pmus); =20 - if (pmu->is_hybrid) + if (is_hybrid) list_add_tail(&pmu->hybrid_list, &perf_pmu__hybrid_pmus); =20 pmu->default_config =3D perf_pmu__get_default_config(pmu); diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 68e15c38ae71..0d556d02ce52 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -40,7 +40,6 @@ struct perf_pmu { __u32 type; bool selectable; bool is_uncore; - bool is_hybrid; bool auxtrace; int max_precise; struct perf_event_attr *default_config; diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 3a432a949d46..acf0edf5fdd1 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -604,15 +604,10 @@ static void evsel__merge_aliases(struct evsel *evsel) } } =20 -static bool evsel__should_merge_hybrid(struct evsel *evsel, struct perf_st= at_config *config) +static bool evsel__should_merge_hybrid(const struct evsel *evsel, + const struct perf_stat_config *config) { - struct perf_pmu *pmu; - - if (!config->hybrid_merge) - return false; - - pmu =3D evsel__find_pmu(evsel); - return pmu && pmu->is_hybrid; + return config->hybrid_merge && evsel__is_hybrid(evsel); } =20 static void evsel__merge_stats(struct evsel *evsel, struct perf_stat_confi= g *config) --=20 2.38.1.431.g37b22c650d-goog From nobody Mon Apr 13 14:26:57 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 48554C433FE for ; Mon, 14 Nov 2022 21:08:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237553AbiKNVIR (ORCPT ); Mon, 14 Nov 2022 16:08:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44582 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237465AbiKNVIM (ORCPT ); Mon, 14 Nov 2022 16:08:12 -0500 Received: from mail-pj1-x1049.google.com (mail-pj1-x1049.google.com [IPv6:2607:f8b0:4864:20::1049]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4E67ADF08 for ; Mon, 14 Nov 2022 13:08:06 -0800 (PST) Received: by mail-pj1-x1049.google.com with SMTP id c10-20020a17090aa60a00b00212e91df6acso5298070pjq.5 for ; Mon, 14 Nov 2022 13:08:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=A43/003qhTsv7CHC/gbD1owyfDC6UmPlxbrZ5F9DYHE=; b=rhiXYshjGUJhA/M185y0KXRxAFIdbaKAD3QrfRD1anGpjuQA5GWSsTwg3BBAijbVzn wd5NP29ezESx931htUcdriEcxr8clV6u/URqyID+lKpm/wtxpo6+MLGUtpIwbJj+ctUK xgUpKErT92875LnGyNI0YZJS99XWLRLUTHPLCFS+GsUYiNSUaTq+BHU643NCkHNJAqip l43qsrjQOgq5WNeMVwOCGkISqIieidsvfCXXM6pA7QzpE/YM7diVfV33ToSCLl8m/rTr Y1Ma7jT4qX+YYoNVejap713djXGbd+O7mKCJKaekI3teqI2xHFs9bAcGVy8z8tRTcGMR l91Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=A43/003qhTsv7CHC/gbD1owyfDC6UmPlxbrZ5F9DYHE=; b=zTdp3AK06relnwmPEMA0hBlIjxeZsjKXw3TIK866rsXOab/SeyfJDKK9Y46Ec1v6Gm AQ9pL8YQhsS1xT9OqzyJ2y1egdSQ5Our52QzCu61gKflY24XbIf+dhDEu8MMZmYCxq4T PHXIVMPSp+ETKd9qwyy1JfsGa063pUxvxHdSnN3TPZpfndyWrnaxk/1pV8T9we+PULId Ktk4dcfEeXmpR1jXaDcXXbydrTVsZupN+I2GHIvg5gq4uPr7qYF+9z4IkstLqcjyHyHq FUQZuNBiuuy7mDijMXf53+lwI1mWMsPcKBLtXdArMmcdhojhxuIkWsU9KkKEsdEBnem+ MD4w== X-Gm-Message-State: ANoB5pkRNYFkEbZKnnO1dAt4pTKw3vWhkBG+LQtSiQixLr4JGwJlMxCK +HgGNYRuNeojbo4rcCe1bsbai9Y3gjqZ X-Google-Smtp-Source: AA0mqf5lV1zFCacp1EEd4Fyyl7M+3qTHhzRdycnlZP+7YJB86dxdkSXYY8w2qLFhgLfOWvOCHtLjGxfZib3e X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:553:438f:b86a:87f]) (user=irogers job=sendgmr) by 2002:a05:6a00:848:b0:572:4ea6:ddc7 with SMTP id q8-20020a056a00084800b005724ea6ddc7mr2900518pfk.26.1668460085614; Mon, 14 Nov 2022 13:08:05 -0800 (PST) Date: Mon, 14 Nov 2022 13:07:15 -0800 In-Reply-To: <20221114210723.2749751-1-irogers@google.com> Message-Id: <20221114210723.2749751-3-irogers@google.com> Mime-Version: 1.0 References: <20221114210723.2749751-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v3 02/10] perf pmu: Add documentation From: Ian Rogers To: Weilin Wang , Perry Taylor , Caleb Biggers , Leo Yan , Adrian Hunter , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Sandipan Das , Kajol Jain , Zhengjun Xing , Kan Liang , Ravi Bangoria , Xin Gao , Rob Herring , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org Cc: Stephane Eranian , Ian Rogers Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add documentation to struct perf_pmu and the associated structs of perf_pmu_alias and perf_pmu_format. Signed-off-by: Ian Rogers --- tools/perf/util/pmu.c | 16 ++++++ tools/perf/util/pmu.h | 122 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 132 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 48e7be6f3baa..057e1528c32f 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -31,10 +31,26 @@ =20 struct perf_pmu perf_pmu__fake; =20 +/** + * struct perf_pmu_format - Values from a format file read from + * /devices/cpu/format/ held in struct perf_pmu. + * + * For example, the contents of /devices/cpu/format/event may be + * "config:0-7" and will be represented here as name=3D"event", + * value=3DPERF_PMU_FORMAT_VALUE_CONFIG and bits 0 to 7 will be set. + */ struct perf_pmu_format { + /** @name: The modifier/file name. */ char *name; + /** + * @value : Which config value the format relates to. Supported values + * are from PERF_PMU_FORMAT_VALUE_CONFIG to + * PERF_PMU_FORMAT_VALUE_CONFIG_END. + */ int value; + /** @bits: Which config bits are set by this format value. */ DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); + /** @list: Element on list within struct perf_pmu. */ struct list_head list; }; =20 diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 0d556d02ce52..ee02e1ef9187 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -33,30 +33,101 @@ struct perf_pmu_caps { struct list_head list; }; =20 +/** + * struct perf_pmu - hi + */ struct perf_pmu { + /** @name: The name of the PMU such as "cpu". */ char *name; + /** + * @alias_name: Optional alternate name for the PMU determined in + * architecture specific code. + */ char *alias_name; + /** + * @id: Optional PMU identifier read from + * /bus/event_source/devices//identifier. + */ char *id; + /** + * @type: Perf event attributed type value, read from + * /bus/event_source/devices//type. + */ __u32 type; + /** + * @selectable: Can the PMU name be selected as if it were an event? + */ bool selectable; + /** + * @is_uncore: Is the PMU not within the CPU core? Determined by the + * presence of /bus/event_source/devices//cpumask. + */ bool is_uncore; + /** + * @auxtrace: Are events auxiliary events? Determined in architecture + * specific code. + */ bool auxtrace; + /** + * @max_precise: Number of levels of :ppp precision supported by the + * PMU, read from + * /bus/event_source/devices//caps/max_precise. + */ int max_precise; + /** + * @default_config: Optional default perf_event_attr determined in + * architecture specific code. + */ struct perf_event_attr *default_config; + /** + * @cpus: Empty or the contents of either of: + * /bus/event_source/devices//cpumask. + * /bus/event_source/devices//cpus. + */ struct perf_cpu_map *cpus; - struct list_head format; /* HEAD struct perf_pmu_format -> list */ - struct list_head aliases; /* HEAD struct perf_pmu_alias -> list */ + /** + * @format: Holds the contents of files read from + * /bus/event_source/devices//format/. The contents specify + * which event parameter changes what config, config1 or config2 bits. + */ + struct list_head format; + /** + * @aliases: List of struct perf_pmu_alias. Each alias corresponds to an + * event read from /bus/event_source/devices//events/ or + * from json events in pmu-events.c. + */ + struct list_head aliases; + /** @caps_initialized: Has the list caps been initialized? */ bool caps_initialized; + /** @nr_caps: The length of the list caps. */ u32 nr_caps; - struct list_head caps; /* HEAD struct perf_pmu_caps -> list */ - struct list_head list; /* ELEM */ + /** + * @caps: Holds the contents of files read from + * /bus/event_source/devices//caps/. + * + * The contents are pairs of the filename with the value of its + * contents, for example, max_precise (see above) may have a value of 3. + */ + struct list_head caps; + /** @list: Element on pmus list in pmu.c. */ + struct list_head list; + /** @hybrid_list: Element on perf_pmu__hybrid_pmus. */ struct list_head hybrid_list; =20 + /** + * @missing_features: Features to inhibit when events on this PMU are + * opened. + */ struct { + /** + * @exclude_guest: Disables perf_event_attr exclude_guest and + * exclude_host. + */ bool exclude_guest; } missing_features; }; =20 +/** @perf_pmu__fake: A special global PMU used for testing. */ extern struct perf_pmu perf_pmu__fake; =20 struct perf_pmu_info { @@ -70,21 +141,60 @@ struct perf_pmu_info { =20 #define UNIT_MAX_LEN 31 /* max length for event unit name */ =20 +/** + * struct perf_pmu_alias - An event either read from sysfs or builtin in + * pmu-events.c, created by parsing the pmu-events json files. + */ struct perf_pmu_alias { + /** @name: Name of the event like "mem-loads". */ char *name; + /** @desc: Optional short description of the event. */ char *desc; + /** @long_desc: Optional long description. */ char *long_desc; + /** + * @topic: Optional topic such as cache or pipeline, particularly for + * json events. + */ char *topic; + /** + * @str: Comma separated parameter list like + * "event=3D0xcd,umask=3D0x1,ldlat=3D0x3". + */ char *str; - struct list_head terms; /* HEAD struct parse_events_term -> list */ - struct list_head list; /* ELEM */ + /** @terms: Owned list of the original parsed parameters. */ + struct list_head terms; + /** @list: List element of struct perf_pmu aliases. */ + struct list_head list; + /** @unit: Units for the event, such as bytes or cache lines. */ char unit[UNIT_MAX_LEN+1]; + /** @scale: Value to scale read counter values by. */ double scale; + /** + * @per_pkg: Does the file + * /bus/event_source/devices//events/.per-pkg or + * equivalent json value exist and have the value 1. + */ bool per_pkg; + /** + * @snapshot: Does the file + * /bus/event_source/devices//events/.snapshot + * exist and have the value 1. + */ bool snapshot; + /** + * @deprecated: Is the event hidden and so not shown in perf list by + * default. + */ bool deprecated; + /** + * @metric_expr: A metric expression associated with an event. Doing + * this makes little sense due to scale and unit applying to both. + */ char *metric_expr; + /** @metric_name: A name for the metric. unit applying to both. */ char *metric_name; + /** @pmu_name: The name copied from struct perf_pmu. */ char *pmu_name; }; =20 --=20 2.38.1.431.g37b22c650d-goog From nobody Mon Apr 13 14:26:57 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 B152CC433FE for ; Mon, 14 Nov 2022 21:08:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237518AbiKNVId (ORCPT ); Mon, 14 Nov 2022 16:08:33 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44760 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237492AbiKNVIV (ORCPT ); Mon, 14 Nov 2022 16:08:21 -0500 Received: from mail-pj1-x104a.google.com (mail-pj1-x104a.google.com [IPv6:2607:f8b0:4864:20::104a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1E055BCBF for ; Mon, 14 Nov 2022 13:08:15 -0800 (PST) Received: by mail-pj1-x104a.google.com with SMTP id my9-20020a17090b4c8900b002130d29fd7cso10839437pjb.7 for ; Mon, 14 Nov 2022 13:08:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Se2me6lbjg4dS4DNtZbL4NOOrQgzrO1DuLy7bKVPgtE=; b=pSM7kTnmOSbosw8Hcy1wsfrOJtWX0Vk4M1VXbCfpBsnal65+1d2sh4Bhl/sPSG3WjZ oRq//RYKeswTfgFYSJ4Nv7F1CorCaBz6F1obJiSvGR021sk3+MiS3J0CKDoAThtT7mNL c5XvgVjLnyw/ULU0aatlPRu9cxq7LW4TyrQHf9201uJ5GhHD/OrtslM86NlZo0FNpgY0 JcPC2nd67BGMddaSuKOAOFjPZjksyqaw2aj3O89nIhPVu/bl9Ccf1tqlOp2uQFr7akdO lj4Eu321mO/ZVaguwrY9uNagHeDPUAhFSZNIxiC1unT6sMrpC8hTQ/YF+wfl+wWOmNCc RtMg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Se2me6lbjg4dS4DNtZbL4NOOrQgzrO1DuLy7bKVPgtE=; b=E6FZ0JyQujwzh97ql+Hj9vlqe+3cvel5vp5d/CuibVlp0vm2ZGq4KNj3V00g48TjMO mq7F5Ogat1BYmSxS46AKo6dTfnekDxAfn/yE8A9I3Dv0764S+rO0+VsFCXvHMJtHALYY k08+z/nWWa2h20iTf1qCQz/7IjH6gE1h69LaOjgwoKOvitrkOHhN17HUYiV+ENbLf/g7 OhNJCvVee9W5kzC27+4N2g+MwtMSrz2Pck7He10D9J1/fHcU48qIsTMKRsoZNyHs4/5C 08YiFeW1k1RjmMuHGiVRHWwz8bQ9GvDIzHc3HfgWzzILxuwoA4dAsV8sFvzxy5bIlFqE Iaiw== X-Gm-Message-State: ANoB5pk+G4kTJ3DmFgtf9Lc3EpN5+TBxX8AcmBYmzozvGTXsSCe+T/rN uZVpEHDH9D5Wyo+jaf1fKcRTs3HdBs2R X-Google-Smtp-Source: AA0mqf6Z9g60XXYxfp7n+hZq20oXkSrKY1lCSw9Obhp7yu+rX+Z5SlNdIamZ+6QNg/KExsAVnRH1hkcLDMw5 X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:553:438f:b86a:87f]) (user=irogers job=sendgmr) by 2002:aa7:8a41:0:b0:561:70b3:6a6 with SMTP id n1-20020aa78a41000000b0056170b306a6mr15444394pfa.25.1668460094565; Mon, 14 Nov 2022 13:08:14 -0800 (PST) Date: Mon, 14 Nov 2022 13:07:16 -0800 In-Reply-To: <20221114210723.2749751-1-irogers@google.com> Message-Id: <20221114210723.2749751-4-irogers@google.com> Mime-Version: 1.0 References: <20221114210723.2749751-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v3 03/10] tools lib api fs tracing_path: Add scandir alphasort From: Ian Rogers To: Weilin Wang , Perry Taylor , Caleb Biggers , Leo Yan , Adrian Hunter , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Sandipan Das , Kajol Jain , Zhengjun Xing , Kan Liang , Ravi Bangoria , Xin Gao , Rob Herring , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org Cc: Stephane Eranian , Ian Rogers Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" tracing_events__opendir allows iteration over files in /tracing/events but with an arbitrary sort order. Add a scandir alternative where the results are alphabetically sorted. Signed-off-by: Ian Rogers --- tools/lib/api/fs/tracing_path.c | 16 ++++++++++++++++ tools/lib/api/fs/tracing_path.h | 1 + 2 files changed, 17 insertions(+) diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_pat= h.c index 5afb11b30fca..b8e457c841ab 100644 --- a/tools/lib/api/fs/tracing_path.c +++ b/tools/lib/api/fs/tracing_path.c @@ -113,6 +113,22 @@ DIR *tracing_events__opendir(void) return dir; } =20 +int tracing_events__scandir_alphasort(struct dirent ***namelist) +{ + char *path =3D get_tracing_file("events"); + int ret; + + if (!path) { + *namelist =3D NULL; + return 0; + } + + ret =3D scandir(path, namelist, NULL, alphasort); + put_events_file(path); + + return ret; +} + int tracing_path__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name) { diff --git a/tools/lib/api/fs/tracing_path.h b/tools/lib/api/fs/tracing_pat= h.h index a19136b086dc..fc6347c11deb 100644 --- a/tools/lib/api/fs/tracing_path.h +++ b/tools/lib/api/fs/tracing_path.h @@ -6,6 +6,7 @@ #include =20 DIR *tracing_events__opendir(void); +int tracing_events__scandir_alphasort(struct dirent ***namelist); =20 void tracing_path_set(const char *mountpoint); const char *tracing_path_mount(void); --=20 2.38.1.431.g37b22c650d-goog From nobody Mon Apr 13 14:26:57 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 D89ADC4332F for ; Mon, 14 Nov 2022 21:08:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237653AbiKNVIl (ORCPT ); Mon, 14 Nov 2022 16:08:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44620 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237333AbiKNVI1 (ORCPT ); Mon, 14 Nov 2022 16:08:27 -0500 Received: from mail-pg1-x54a.google.com (mail-pg1-x54a.google.com [IPv6:2607:f8b0:4864:20::54a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 449D7B5D for ; Mon, 14 Nov 2022 13:08:24 -0800 (PST) Received: by mail-pg1-x54a.google.com with SMTP id i19-20020a63e913000000b004705d1506a6so6390324pgh.13 for ; Mon, 14 Nov 2022 13:08:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=FAjkIdGz/j9kJ1xDL5dYREJTueL8AT+RXQYxwRGY3ak=; b=FQaZu3Cbsd2gHnYi5Gx+2DWoUegFSW+qx8oogpEOsCl0/itsxpNpL6S4L435rIus3u q6b3Ob2ArneyTeF0HA+YgEFmbvuDtumr1ySUmpoIIs10e/TfKb/wxXOvpbDlrTyhbOhq XHOyWp/5FngUxk72sQjlstVXlwRWYDUyo3omNZgRnkD0XaUi4OGDXcIMbYfJjvKLlzGe ymzdCAvMa9dZG53WnXm49bUsYWPufMfzD355LyDc/gdh2TuDHlhuiUwmEjUjeeYOijs2 1HIlBxJy6UzLN9xOmiR/Hyk0xKXUFEsAbmRtdqoOUfJSCQkucg8x5AqsWJXJhRpCRS/q HPUQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=FAjkIdGz/j9kJ1xDL5dYREJTueL8AT+RXQYxwRGY3ak=; b=WJ59a0rcHtY+LEuB0YdDCY6CjoNKQ3cPnZRyRK4Sjgj7iCNgusisvZOtXsQe8pwJlg IWB3uBigYm6TpCAU+jCIJ1NVJ4ytCxA5KDPOW1qGSeQH5sgK8j1AreI2FwjOv3gzyoN4 a6IXSEKCxEntvsrVYkYVcf+ZY0A39IK/5IyX8RzV4F6V7imVpamXcXDoyvFiJL3A7hzq K9Iin48My5n7zYBMlzIu0Y1AqeILXh076zLWrqoSv6hQ4j8UURCkgAawToygSETUNqD+ 63FVOXqgapAzBS0kZuerKSbPFA25s4oO+z/5+Yjy0GZ73zosrOWD86/knSoxQbxoNVaS V9DA== X-Gm-Message-State: ANoB5pm/0qZXlrojApMiw9f/PottB/WKzNQoYmIVCZwazqnbBfxmtSev JH9cyPEpRWG/R9Q2fkBhVbWSUpWy/yht X-Google-Smtp-Source: AA0mqf6QC+uDVb70Ja2JWAOwMKIY4s1K9yHM1jmnHAtZGlRo7JIauPQOl9tuqc43FoffxWFIbjbvw08OzAag X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:553:438f:b86a:87f]) (user=irogers job=sendgmr) by 2002:a17:90b:2415:b0:212:cf2e:2b0b with SMTP id nr21-20020a17090b241500b00212cf2e2b0bmr15213568pjb.169.1668460104133; Mon, 14 Nov 2022 13:08:24 -0800 (PST) Date: Mon, 14 Nov 2022 13:07:17 -0800 In-Reply-To: <20221114210723.2749751-1-irogers@google.com> Message-Id: <20221114210723.2749751-5-irogers@google.com> Mime-Version: 1.0 References: <20221114210723.2749751-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v3 04/10] perf tracepoint: Sort events in iterator From: Ian Rogers To: Weilin Wang , Perry Taylor , Caleb Biggers , Leo Yan , Adrian Hunter , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Sandipan Das , Kajol Jain , Zhengjun Xing , Kan Liang , Ravi Bangoria , Xin Gao , Rob Herring , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org Cc: Stephane Eranian , Ian Rogers Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" In print_tracepoint_events use tracing_events__scandir_alphasort and scandir alphasort so that the subsystem and events are sorted and don't need a secondary qsort. Locally this results in the following change: ... ext4:ext4_zero_range [Tracepoint event] - fib6:fib6_table_lookup [Tracepoint event] fib:fib_table_lookup [Tracepoint event] + fib6:fib6_table_lookup [Tracepoint event] filelock:break_lease_block [Tracepoint event] ... ie fib6 now is after fib and not before it. This is more consistent with how numbers are more generally sorted, such as: ... syscalls:sys_enter_renameat [Tracepoint event] syscalls:sys_enter_renameat2 [Tracepoint event] ... and so an improvement over the qsort approach. Signed-off-by: Ian Rogers --- tools/perf/util/print-events.c | 108 +++++++++++---------------------- 1 file changed, 37 insertions(+), 71 deletions(-) diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c index c4d5d87fae2f..fefc025bc259 100644 --- a/tools/perf/util/print-events.c +++ b/tools/perf/util/print-events.c @@ -66,26 +66,21 @@ static int cmp_string(const void *a, const void *b) void print_tracepoint_events(const char *subsys_glob, const char *event_glob, bool name_only) { - DIR *sys_dir, *evt_dir; - struct dirent *sys_dirent, *evt_dirent; - char evt_path[MAXPATHLEN]; - char *dir_path; - char **evt_list =3D NULL; - unsigned int evt_i =3D 0, evt_num =3D 0; - bool evt_num_known =3D false; - -restart: - sys_dir =3D tracing_events__opendir(); - if (!sys_dir) - return; - - if (evt_num_known) { - evt_list =3D zalloc(sizeof(char *) * evt_num); - if (!evt_list) - goto out_close_sys_dir; - } + struct dirent **sys_namelist =3D NULL; + bool printed =3D false; + int sys_items =3D tracing_events__scandir_alphasort(&sys_namelist); + + for (int i =3D 0; i < sys_items; i++) { + struct dirent *sys_dirent =3D sys_namelist[i]; + struct dirent **evt_namelist =3D NULL; + char *dir_path; + int evt_items; + + if (sys_dirent->d_type !=3D DT_DIR || + !strcmp(sys_dirent->d_name, ".") || + !strcmp(sys_dirent->d_name, "..")) + continue; =20 - for_each_subsystem(sys_dir, sys_dirent) { if (subsys_glob !=3D NULL && !strglobmatch(sys_dirent->d_name, subsys_glob)) continue; @@ -93,69 +88,40 @@ void print_tracepoint_events(const char *subsys_glob, dir_path =3D get_events_file(sys_dirent->d_name); if (!dir_path) continue; - evt_dir =3D opendir(dir_path); - if (!evt_dir) - goto next; =20 - for_each_event(dir_path, evt_dir, evt_dirent) { - if (event_glob !=3D NULL && - !strglobmatch(evt_dirent->d_name, event_glob)) + evt_items =3D scandir(dir_path, &evt_namelist, NULL, alphasort); + for (int j =3D 0; j < evt_items; j++) { + struct dirent *evt_dirent =3D evt_namelist[j]; + char evt_path[MAXPATHLEN]; + + if (evt_dirent->d_type !=3D DT_DIR || + !strcmp(evt_dirent->d_name, ".") || + !strcmp(evt_dirent->d_name, "..")) continue; =20 - if (!evt_num_known) { - evt_num++; + if (tp_event_has_id(dir_path, evt_dirent) !=3D 0) + continue; + + if (event_glob !=3D NULL && + !strglobmatch(evt_dirent->d_name, event_glob)) continue; - } =20 snprintf(evt_path, MAXPATHLEN, "%s:%s", sys_dirent->d_name, evt_dirent->d_name); - - evt_list[evt_i] =3D strdup(evt_path); - if (evt_list[evt_i] =3D=3D NULL) { - put_events_file(dir_path); - goto out_close_evt_dir; + if (name_only) + printf("%s ", evt_path); + else { + printf(" %-50s [%s]\n", evt_path, + event_type_descriptors[PERF_TYPE_TRACEPOINT]); } - evt_i++; + printed =3D true; } - closedir(evt_dir); -next: - put_events_file(dir_path); + free(dir_path); + free(evt_namelist); } - closedir(sys_dir); - - if (!evt_num_known) { - evt_num_known =3D true; - goto restart; - } - qsort(evt_list, evt_num, sizeof(char *), cmp_string); - evt_i =3D 0; - while (evt_i < evt_num) { - if (name_only) { - printf("%s ", evt_list[evt_i++]); - continue; - } - printf(" %-50s [%s]\n", evt_list[evt_i++], - event_type_descriptors[PERF_TYPE_TRACEPOINT]); - } - if (evt_num && pager_in_use()) + free(sys_namelist); + if (printed && pager_in_use()) printf("\n"); - -out_free: - evt_num =3D evt_i; - for (evt_i =3D 0; evt_i < evt_num; evt_i++) - zfree(&evt_list[evt_i]); - zfree(&evt_list); - return; - -out_close_evt_dir: - closedir(evt_dir); -out_close_sys_dir: - closedir(sys_dir); - - printf("FATAL: not enough memory to print %s\n", - event_type_descriptors[PERF_TYPE_TRACEPOINT]); - if (evt_list) - goto out_free; } =20 void print_sdt_events(const char *subsys_glob, const char *event_glob, --=20 2.38.1.431.g37b22c650d-goog From nobody Mon Apr 13 14:26:57 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 BA749C433FE for ; Mon, 14 Nov 2022 21:08:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237638AbiKNVIx (ORCPT ); Mon, 14 Nov 2022 16:08:53 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44648 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237606AbiKNVIf (ORCPT ); Mon, 14 Nov 2022 16:08:35 -0500 Received: from mail-pj1-x1049.google.com (mail-pj1-x1049.google.com [IPv6:2607:f8b0:4864:20::1049]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DD1C6B5D for ; Mon, 14 Nov 2022 13:08:33 -0800 (PST) Received: by mail-pj1-x1049.google.com with SMTP id pj8-20020a17090b4f4800b002140219b2b3so50324pjb.0 for ; Mon, 14 Nov 2022 13:08:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=xTvigGR2TZpPyDR4wvE6cl7h65F616i4JiHpM7NGI4g=; b=qh+bQXa8qXtlPKafIbt/qub27YV/6bwdGsur0mog3yFgqhnOu8lpu+FinXZBNRnkh8 GRYVjsVviqHBLQJJwqIK5e/d05fGmLi3qoC4eDX0QINmKP2TbRxN/xi9z+WgVa4hSuPh 2oefMp99D68M0gjQB58HPclQ3d5RjmtPh66ZPEzzu5fyyMUIq+fIS9rNVBebAz4bc514 dqaSAVg6Yz3rc6Xku+nHmKDCCXboQIck5vwSPw35NGGOhHqjLbsdGiIGY+mo5dIP4alF Ug8q0wkajQ4pQsQmCWaDYHDmVW7lgpFJLpc1Da12UF79YVnYy+YCIknYU5uVlDifNew+ fBNw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=xTvigGR2TZpPyDR4wvE6cl7h65F616i4JiHpM7NGI4g=; b=ZTlLdNQl3roLE/QbyxR193gtnscZxvv6Wd/3KT0G0txF3N0JvdM4BiUnSR+WYsBQUn n2EgA9ftSOK8uXfH//fmXngJp37kO9beMl/dZukic0zJwzXqJaELUeT5GNIKl/b9k8qU fDf1hCdE/NhS13R3ipkVeGz4N+vF2NZSidFGJapbqN4jYGVieSLskD/wBgnDbRysbotS gfJWekIPSoh6iUSzDWTYaZm+NMyWSkuBbmDoG9jSd6D/K5EjHHrWqJW0DzL0cScC2nms IJCAKk+0uGWGvkiIE5nkL8MhlbgaZKfE/kxbxK9RRrAzQ+z2yEPN3Aafhmt4eKlDKIXr J7dQ== X-Gm-Message-State: ANoB5pnbr1a+usgu2PHJkHaqkHi5Xpl/vnjQq/rAjs2BJkPvhSwQ0ijG R2n9oF1+0Kc3140hBShLW3Z4JtbxZ8oB X-Google-Smtp-Source: AA0mqf7RcItl+6JEAoD9l+pvnFWhCZiCtWk8U6jOG63njbUTz3DuRQc/WEBDfkDPcydmXrqBtv5NfPD3zWTY X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:553:438f:b86a:87f]) (user=irogers job=sendgmr) by 2002:aa7:86d5:0:b0:56d:3de3:c401 with SMTP id h21-20020aa786d5000000b0056d3de3c401mr15620037pfo.6.1668460113210; Mon, 14 Nov 2022 13:08:33 -0800 (PST) Date: Mon, 14 Nov 2022 13:07:18 -0800 In-Reply-To: <20221114210723.2749751-1-irogers@google.com> Message-Id: <20221114210723.2749751-6-irogers@google.com> Mime-Version: 1.0 References: <20221114210723.2749751-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v3 05/10] perf list: Generalize limiting to a PMU name From: Ian Rogers To: Weilin Wang , Perry Taylor , Caleb Biggers , Leo Yan , Adrian Hunter , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Sandipan Das , Kajol Jain , Zhengjun Xing , Kan Liang , Ravi Bangoria , Xin Gao , Rob Herring , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org Cc: Stephane Eranian , Ian Rogers Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Deprecate the --cputype option and add a --unit option where '--unit cpu_atom' behaves like '--cputype atom'. The --unit option can be used with arbitrary PMUs, for example: ``` $ perf list --unit msr pmu List of pre-defined events (to be used in -e or -M): msr/aperf/ [Kernel PMU event] msr/cpu_thermal_margin/ [Kernel PMU event] msr/mperf/ [Kernel PMU event] msr/pperf/ [Kernel PMU event] msr/smi/ [Kernel PMU event] msr/tsc/ [Kernel PMU event] ``` Signed-off-by: Ian Rogers --- tools/perf/Documentation/perf-list.txt | 6 +++--- tools/perf/builtin-list.c | 18 ++++++++++++------ tools/perf/util/metricgroup.c | 3 ++- tools/perf/util/pmu.c | 4 +--- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentat= ion/perf-list.txt index 57384a97c04f..44a819af573d 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -39,9 +39,9 @@ any extra expressions computed by perf stat. --deprecated:: Print deprecated events. By default the deprecated events are hidden. =20 ---cputype:: -Print events applying cpu with this type for hybrid platform -(e.g. --cputype core or --cputype atom) +--unit:: +Print PMU events and metrics limited to the specific PMU name. +(e.g. --unit cpu, --unit msr, --unit cpu_core, --unit cpu_atom) =20 [[EVENT_MODIFIERS]] EVENT MODIFIERS diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index 58e1ec1654ef..cc84ced6da26 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -21,7 +21,6 @@ =20 static bool desc_flag =3D true; static bool details_flag; -static const char *hybrid_type; =20 int cmd_list(int argc, const char **argv) { @@ -30,6 +29,8 @@ int cmd_list(int argc, const char **argv) bool long_desc_flag =3D false; bool deprecated =3D false; char *pmu_name =3D NULL; + const char *hybrid_name =3D NULL; + const char *unit_name =3D NULL; struct option list_options[] =3D { OPT_BOOLEAN(0, "raw-dump", &raw_dump, "Dump raw events"), OPT_BOOLEAN('d', "desc", &desc_flag, @@ -40,9 +41,10 @@ int cmd_list(int argc, const char **argv) "Print information on the perf event names and expressions used int= ernally by events."), OPT_BOOLEAN(0, "deprecated", &deprecated, "Print deprecated events."), - OPT_STRING(0, "cputype", &hybrid_type, "hybrid cpu type", - "Print events applying cpu with this type for hybrid platform " - "(e.g. core or atom)"), + OPT_STRING(0, "cputype", &hybrid_name, "hybrid cpu type", + "Limit PMU or metric printing to the given hybrid PMU (e.g. core or = atom)."), + OPT_STRING(0, "unit", &unit_name, "PMU name", + "Limit PMU or metric printing to the specified PMU."), OPT_INCR(0, "debug", &verbose, "Enable debugging output"), OPT_END() @@ -53,6 +55,8 @@ int cmd_list(int argc, const char **argv) }; =20 set_option_flag(list_options, 0, "raw-dump", PARSE_OPT_HIDDEN); + /* Hide hybrid flag for the more generic 'unit' flag. */ + set_option_flag(list_options, 0, "cputype", PARSE_OPT_HIDDEN); =20 argc =3D parse_options(argc, argv, list_options, list_usage, PARSE_OPT_STOP_AT_NON_OPTION); @@ -62,8 +66,10 @@ int cmd_list(int argc, const char **argv) if (!raw_dump && pager_in_use()) printf("\nList of pre-defined events (to be used in -e or -M):\n\n"); =20 - if (hybrid_type) { - pmu_name =3D perf_pmu__hybrid_type_to_pmu(hybrid_type); + if (unit_name) + pmu_name =3D strdup(unit_name); + else if (hybrid_name) { + pmu_name =3D perf_pmu__hybrid_type_to_pmu(hybrid_name); if (!pmu_name) pr_warning("WARNING: hybrid cputype is not supported!\n"); } diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 4c98ac29ee13..1943fed9b6d9 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -556,11 +556,12 @@ static int metricgroup__print_callback(const struct p= mu_event *pe, void *vdata) { struct metricgroup_print_data *data =3D vdata; + const char *pmu =3D pe->pmu ?: "cpu"; =20 if (!pe->metric_expr) return 0; =20 - if (data->pmu_name && perf_pmu__is_hybrid(pe->pmu) && strcmp(data->pmu_na= me, pe->pmu)) + if (data->pmu_name && strcmp(data->pmu_name, pmu)) return 0; =20 return metricgroup__print_pmu_event(pe, data->metricgroups, data->filter, diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 057e1528c32f..e6790175307b 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1695,10 +1695,8 @@ void print_pmu_events(const char *event_glob, bool n= ame_only, bool quiet_flag, pmu =3D NULL; j =3D 0; while ((pmu =3D perf_pmu__scan(pmu)) !=3D NULL) { - if (pmu_name && perf_pmu__is_hybrid(pmu->name) && - strcmp(pmu_name, pmu->name)) { + if (pmu_name && pmu->name && strcmp(pmu_name, pmu->name)) continue; - } =20 list_for_each_entry(alias, &pmu->aliases, list) { char *name =3D alias->desc ? alias->name : --=20 2.38.1.431.g37b22c650d-goog From nobody Mon Apr 13 14:26:57 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 48C9FC43217 for ; Mon, 14 Nov 2022 21:09:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237677AbiKNVJE (ORCPT ); Mon, 14 Nov 2022 16:09:04 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45050 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237661AbiKNVIr (ORCPT ); Mon, 14 Nov 2022 16:08:47 -0500 Received: from mail-pg1-x54a.google.com (mail-pg1-x54a.google.com [IPv6:2607:f8b0:4864:20::54a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F0ED71570E for ; Mon, 14 Nov 2022 13:08:43 -0800 (PST) Received: by mail-pg1-x54a.google.com with SMTP id x23-20020a634857000000b0043c700f6441so6399223pgk.21 for ; Mon, 14 Nov 2022 13:08:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=05I6atWVl+qVT8yMUMb7x3GwtdO61HeIYnH9Cn+25jQ=; b=YnLoANQuFjbetHt540UCbpDWKoJh/exzhEQ66FkM0DNj43cS9FdHbXR77YM17jew7x cHvBVFfd+dNUoPSAda91AwQEle/wJoTXMWWSZvQLZpo0WJW7L6mbFQTUaFiZk8Dbot0X ca/91q3+zmW0juc/Ptg3A2A/zfY3FAu6hG26oCaPRIUJ1+ROCn3MLhVGjJyvZrK0e2Pq 7uGzqvVeoni2IXJxk2C4+mqpYpU7FH0vRRkcW01pLZ4l8itOTntfwtgunfq5UUJ68aBq u74OZ02gIHZw/xIg5mxa82EKl9QveFHNCgZA+AJaCTw/1zA4nueSyfnrheYNWnIk5IHL dPhA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=05I6atWVl+qVT8yMUMb7x3GwtdO61HeIYnH9Cn+25jQ=; b=ILFXRjqDZl0CYojT3sXnvqawrWVFm6SDuUxE7S3Dq4UuWU/7csaD0r/YZpaSokXTa7 7XZr9WP8sEngVCooik5TedZ/Eqsz2d4A+QVEhTUmYBVcF/BF1JMmoMJktaxTr3KKgdsa CHplDJSZbKPnc4LcmJ7UGJ7V0iT7d83FXI3V52LAP4+O2pohtZuV4SGp5oS9XpvQqQ6e BRNboVhQ+CJN0i7KQIdOiOrTo4pB1WwtBpMnTCnciUUchmh/7vg1srYjHMGZEw8+YRaS MdVrOAdJK+ZygjaEvfY2upaqBH11PKNDrgOvDs60zj05f9/dKFL0uHxPElpWDLK1QE01 jfBg== X-Gm-Message-State: ANoB5pk5ORSUIqS/vusAvo9oFvt+lP3g6QeNCvI3Dq5dhYzE1X/NYq2D R0MsYsiNzOFHR/jmznkdxo8S72RGfcKG X-Google-Smtp-Source: AA0mqf7J6M37Jt7UM1Lak9n8uZgRwp9XJRQrASOXpg5TUJKhAbrCX/8bwrC1Nv+P6XdAzTdc2pYlG5gJSSJX X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:553:438f:b86a:87f]) (user=irogers job=sendgmr) by 2002:a05:6a00:4211:b0:56b:6936:ddfb with SMTP id cd17-20020a056a00421100b0056b6936ddfbmr15534031pfb.15.1668460123402; Mon, 14 Nov 2022 13:08:43 -0800 (PST) Date: Mon, 14 Nov 2022 13:07:19 -0800 In-Reply-To: <20221114210723.2749751-1-irogers@google.com> Message-Id: <20221114210723.2749751-7-irogers@google.com> Mime-Version: 1.0 References: <20221114210723.2749751-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v3 06/10] perf list: Simplify cache event printing From: Ian Rogers To: Weilin Wang , Perry Taylor , Caleb Biggers , Leo Yan , Adrian Hunter , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Sandipan Das , Kajol Jain , Zhengjun Xing , Kan Liang , Ravi Bangoria , Xin Gao , Rob Herring , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org Cc: Stephane Eranian , Ian Rogers Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The current code computes an array of cache names then sorts and prints them. Use a strlist to create a list of names that is sorted. Keep the hybrid names, it is unclear how to generalize it, but drop the computation of evt_pmus that is never used. Signed-off-by: Ian Rogers --- tools/perf/util/print-events.c | 132 +++++++-------------------------- 1 file changed, 27 insertions(+), 105 deletions(-) diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c index fefc025bc259..ff7793944246 100644 --- a/tools/perf/util/print-events.c +++ b/tools/perf/util/print-events.c @@ -206,137 +206,59 @@ void print_sdt_events(const char *subsys_glob, const= char *event_glob, =20 int print_hwcache_events(const char *event_glob, bool name_only) { - unsigned int type, op, i, evt_i =3D 0, evt_num =3D 0, npmus =3D 0; - char name[64], new_name[128]; - char **evt_list =3D NULL, **evt_pmus =3D NULL; - bool evt_num_known =3D false; - struct perf_pmu *pmu =3D NULL; - - if (perf_pmu__has_hybrid()) { - npmus =3D perf_pmu__hybrid_pmu_num(); - evt_pmus =3D zalloc(sizeof(char *) * npmus); - if (!evt_pmus) - goto out_enomem; - } + struct strlist *evt_name_list =3D strlist__new(NULL, NULL); + struct str_node *nd; =20 -restart: - if (evt_num_known) { - evt_list =3D zalloc(sizeof(char *) * evt_num); - if (!evt_list) - goto out_enomem; + if (!evt_name_list) { + pr_debug("Failed to allocate new strlist for hwcache events\n"); + return -ENOMEM; } - - for (type =3D 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { - for (op =3D 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { + for (int type =3D 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { + for (int op =3D 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { /* skip invalid cache type */ if (!evsel__is_cache_op_valid(type, op)) continue; =20 - for (i =3D 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { - unsigned int hybrid_supported =3D 0, j; - bool supported; + for (int i =3D 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { + struct perf_pmu *pmu =3D NULL; + char name[64]; =20 __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name)); if (event_glob !=3D NULL && !strglobmatch(name, event_glob)) continue; =20 if (!perf_pmu__has_hybrid()) { - if (!is_event_supported(PERF_TYPE_HW_CACHE, - type | (op << 8) | (i << 16))) { - continue; - } - } else { - perf_pmu__for_each_hybrid_pmu(pmu) { - if (!evt_num_known) { - evt_num++; - continue; - } - - supported =3D is_event_supported( - PERF_TYPE_HW_CACHE, - type | (op << 8) | (i << 16) | - ((__u64)pmu->type << PERF_PMU_TYPE_SHIFT)); - if (supported) { - snprintf(new_name, sizeof(new_name), - "%s/%s/", pmu->name, name); - evt_pmus[hybrid_supported] =3D - strdup(new_name); - hybrid_supported++; - } - } - - if (hybrid_supported =3D=3D 0) - continue; - } - - if (!evt_num_known) { - evt_num++; + if (is_event_supported(PERF_TYPE_HW_CACHE, + type | (op << 8) | (i << 16))) + strlist__add(evt_name_list, name); continue; } - - if ((hybrid_supported =3D=3D 0) || - (hybrid_supported =3D=3D npmus)) { - evt_list[evt_i] =3D strdup(name); - if (npmus > 0) { - for (j =3D 0; j < npmus; j++) - zfree(&evt_pmus[j]); - } - } else { - for (j =3D 0; j < hybrid_supported; j++) { - evt_list[evt_i++] =3D evt_pmus[j]; - evt_pmus[j] =3D NULL; + perf_pmu__for_each_hybrid_pmu(pmu) { + if (is_event_supported(PERF_TYPE_HW_CACHE, + type | (op << 8) | (i << 16) | + ((__u64)pmu->type << PERF_PMU_TYPE_SHIFT))) { + char new_name[128]; + snprintf(new_name, sizeof(new_name), + "%s/%s/", pmu->name, name); + strlist__add(evt_name_list, new_name); } - continue; } - - if (evt_list[evt_i] =3D=3D NULL) - goto out_enomem; - evt_i++; } } } =20 - if (!evt_num_known) { - evt_num_known =3D true; - goto restart; - } - - for (evt_i =3D 0; evt_i < evt_num; evt_i++) { - if (!evt_list[evt_i]) - break; - } - - evt_num =3D evt_i; - qsort(evt_list, evt_num, sizeof(char *), cmp_string); - evt_i =3D 0; - while (evt_i < evt_num) { + strlist__for_each_entry(nd, evt_name_list) { if (name_only) { - printf("%s ", evt_list[evt_i++]); + printf("%s ", nd->s); continue; } - printf(" %-50s [%s]\n", evt_list[evt_i++], - event_type_descriptors[PERF_TYPE_HW_CACHE]); + printf(" %-50s [%s]\n", nd->s, event_type_descriptors[PERF_TYPE_HW_CACH= E]); } - if (evt_num && pager_in_use()) + if (!strlist__empty(evt_name_list) && pager_in_use()) printf("\n"); =20 -out_free: - evt_num =3D evt_i; - for (evt_i =3D 0; evt_i < evt_num; evt_i++) - zfree(&evt_list[evt_i]); - zfree(&evt_list); - - for (evt_i =3D 0; evt_i < npmus; evt_i++) - zfree(&evt_pmus[evt_i]); - zfree(&evt_pmus); - return evt_num; - -out_enomem: - printf("FATAL: not enough memory to print %s\n", - event_type_descriptors[PERF_TYPE_HW_CACHE]); - if (evt_list) - goto out_free; - return evt_num; + strlist__delete(evt_name_list); + return 0; } =20 static void print_tool_event(const struct event_symbol *syms, const char *= event_glob, --=20 2.38.1.431.g37b22c650d-goog From nobody Mon Apr 13 14:26:57 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 35C6DC433FE for ; Mon, 14 Nov 2022 21:09:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237576AbiKNVJX (ORCPT ); Mon, 14 Nov 2022 16:09:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45708 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237712AbiKNVIz (ORCPT ); Mon, 14 Nov 2022 16:08:55 -0500 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EC2236556 for ; Mon, 14 Nov 2022 13:08:52 -0800 (PST) Received: by mail-yb1-xb4a.google.com with SMTP id b17-20020a25b851000000b006e32b877068so1820852ybm.16 for ; Mon, 14 Nov 2022 13:08:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=HIf5Y9gptGCDfzfHbnNjnA19mp6qRpBDngBttcXhem0=; b=GZZvStXHmV1H/jsQ47y9n//yaqltl/vwRLrf6lcIZ4n2MbmDx8/ILodhf/TEK75Z8h vXUnxC0uMPqpB2vpMCDlnHSYpQa3dRDuEOq5vKovpKq+6HygbUCE6CxFPDJH2gM7E1Qi FLLrolhCv9gq604BrlQkqDDkLA0ofnmSvLMWXDxOFhh1tp3dzVRpVhvk+6L+WKvrsVor lZZe4gUEvOzHpoof7kQuiiR3Iu6mUFZeHXN9XKZ/SHkRgkMgQxrKpvFCK5p45B5IA+sK mZuaxZ2n64tLPPGQlcOe5C8WIbk7k11MRMslThYNuZJYNMKQH3QxYYmA0Xhgz2/jqeDP fDLg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=HIf5Y9gptGCDfzfHbnNjnA19mp6qRpBDngBttcXhem0=; b=WCfiHuyAtsPUTrVStbc+Yz+7cK/RGJfsgJXkMbpYv4H4aVzu+7frNHrdjx4Xp1Papn fZNyT4p8pY6QzW8hJgfIGyGzm/sbvABP1WFEUngd+Ujof2LrfaiKmHDaZgLTAK41xD2v EcyG5TJ71ZhOgknlbhlVflNyvMzmIlMpI0jMDZrNoKAXWUFVLIXJoD8xCHmA4Q5AsJck yxibkQ3CFgsI+VcQrtWLYNkq2ZUm5DCL0czVKa/jJ3R+fHjNw3R9gfiZqMENr4+8tPG0 JVxm4luREzMM+VbUxeR8jK+AZe9hgn0EQxh2EH/Ovo1Gu4l4nccL9UF7jox2VvxUke8b PrrA== X-Gm-Message-State: ANoB5pmxIfWZ7tDaIPkE0xWT5vrKLxYoF8tiNai591flU/tn1vJ7m1JB lNveU19gU+FILTX+T1f6zMAWzRhgBWUc X-Google-Smtp-Source: AA0mqf4iUCGjqHHy6le8WzwURkFlzhXoc/qhYuUsB8WjG8LnurJrKZI5KTY7Z/hdnQqtsNRqBFQconWgEbKj X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:553:438f:b86a:87f]) (user=irogers job=sendgmr) by 2002:a0d:d596:0:b0:36a:bc93:587c with SMTP id x144-20020a0dd596000000b0036abc93587cmr15112789ywd.59.1668460132140; Mon, 14 Nov 2022 13:08:52 -0800 (PST) Date: Mon, 14 Nov 2022 13:07:20 -0800 In-Reply-To: <20221114210723.2749751-1-irogers@google.com> Message-Id: <20221114210723.2749751-8-irogers@google.com> Mime-Version: 1.0 References: <20221114210723.2749751-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v3 07/10] perf list: Simplify symbol event printing From: Ian Rogers To: Weilin Wang , Perry Taylor , Caleb Biggers , Leo Yan , Adrian Hunter , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Sandipan Das , Kajol Jain , Zhengjun Xing , Kan Liang , Ravi Bangoria , Xin Gao , Rob Herring , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org Cc: Stephane Eranian , Ian Rogers Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The current code computes an array of symbol names then sorts and prints them. Use a strlist to create a list of names that is sorted and then print it. Signed-off-by: Ian Rogers --- tools/perf/util/print-events.c | 79 +++++++++------------------------- 1 file changed, 21 insertions(+), 58 deletions(-) diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c index ff7793944246..d53dba033597 100644 --- a/tools/perf/util/print-events.c +++ b/tools/perf/util/print-events.c @@ -52,14 +52,6 @@ static const struct event_symbol event_symbols_tool[PERF= _TOOL_MAX] =3D { }, }; =20 -static int cmp_string(const void *a, const void *b) -{ - const char * const *as =3D a; - const char * const *bs =3D b; - - return strcmp(*as, *bs); -} - /* * Print the events from /tracing/events */ @@ -298,77 +290,48 @@ void print_symbol_events(const char *event_glob, unsi= gned int type, struct event_symbol *syms, unsigned int max, bool name_only) { - unsigned int i, evt_i =3D 0, evt_num =3D 0; - char name[MAX_NAME_LEN]; - char **evt_list =3D NULL; - bool evt_num_known =3D false; - -restart: - if (evt_num_known) { - evt_list =3D zalloc(sizeof(char *) * evt_num); - if (!evt_list) - goto out_enomem; - syms -=3D max; - } + struct strlist *evt_name_list =3D strlist__new(NULL, NULL); + struct str_node *nd; =20 - for (i =3D 0; i < max; i++, syms++) { + if (!evt_name_list) { + pr_debug("Failed to allocate new strlist for symbol events\n"); + return; + } + for (unsigned int i =3D 0; i < max; i++) { /* * New attr.config still not supported here, the latest * example was PERF_COUNT_SW_CGROUP_SWITCHES */ - if (syms->symbol =3D=3D NULL) + if (syms[i].symbol =3D=3D NULL) continue; =20 - if (event_glob !=3D NULL && !(strglobmatch(syms->symbol, event_glob) || - (syms->alias && strglobmatch(syms->alias, event_glob)))) + if (event_glob !=3D NULL && !(strglobmatch(syms[i].symbol, event_glob) || + (syms[i].alias && strglobmatch(syms[i].alias, event_glob)))) continue; =20 if (!is_event_supported(type, i)) continue; =20 - if (!evt_num_known) { - evt_num++; - continue; - } - - if (!name_only && strlen(syms->alias)) - snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); - else - strlcpy(name, syms->symbol, MAX_NAME_LEN); + if (strlen(syms[i].alias)) { + char name[MAX_NAME_LEN]; =20 - evt_list[evt_i] =3D strdup(name); - if (evt_list[evt_i] =3D=3D NULL) - goto out_enomem; - evt_i++; + snprintf(name, MAX_NAME_LEN, "%s OR %s", syms[i].symbol, syms[i].alias); + strlist__add(evt_name_list, name); + } else + strlist__add(evt_name_list, syms[i].symbol); } =20 - if (!evt_num_known) { - evt_num_known =3D true; - goto restart; - } - qsort(evt_list, evt_num, sizeof(char *), cmp_string); - evt_i =3D 0; - while (evt_i < evt_num) { + strlist__for_each_entry(nd, evt_name_list) { if (name_only) { - printf("%s ", evt_list[evt_i++]); + printf("%s ", nd->s); continue; } - printf(" %-50s [%s]\n", evt_list[evt_i++], event_type_descriptors[type]= ); + printf(" %-50s [%s]\n", nd->s, event_type_descriptors[type]); } - if (evt_num && pager_in_use()) + if (!strlist__empty(evt_name_list) && pager_in_use()) printf("\n"); =20 -out_free: - evt_num =3D evt_i; - for (evt_i =3D 0; evt_i < evt_num; evt_i++) - zfree(&evt_list[evt_i]); - zfree(&evt_list); - return; - -out_enomem: - printf("FATAL: not enough memory to print %s\n", event_type_descriptors[t= ype]); - if (evt_list) - goto out_free; + strlist__delete(evt_name_list); } =20 /* --=20 2.38.1.431.g37b22c650d-goog From nobody Mon Apr 13 14:26:57 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 0827BC4332F for ; Mon, 14 Nov 2022 21:09:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237324AbiKNVJ3 (ORCPT ); Mon, 14 Nov 2022 16:09:29 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45354 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237545AbiKNVJC (ORCPT ); Mon, 14 Nov 2022 16:09:02 -0500 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 21E0BD53 for ; Mon, 14 Nov 2022 13:09:01 -0800 (PST) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-36810cfa61fso115082497b3.6 for ; Mon, 14 Nov 2022 13:09:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Ti+JlRPlvf29szNKHd8D87Ic6A2ZX1BqgklOcnqMgNY=; b=blPMmbozMTkHt9hp+lIjTvLkVtmuKQN72BdaX1ZrrC4/mqEMliU4ct4X4K0d2HE6Wb RZ8KZo+3fKrtkWvRvBmKO7BKz6UvRefkUq4Ug06Za2uyaavxbPbL3zItrcRTugkT5RrA VIiISazbCGrzbB+tK4hGwH3p5VnH9qu6C5lM4EZBboTmB/ppKHRNg4dprTe2pUx54akA BOWSMWMYM3HGlF4BE7wrOAz+ELlzzj0xXOpgJszbkdTwk7I78JGRZE3VoeLPk8/u4+YZ 206IgQip3UhQVm7TCrVlnJsURVzINvFdsxb2V8WuvMT/I4hCezRUF80KDcjhFEB9Xonn qiDg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Ti+JlRPlvf29szNKHd8D87Ic6A2ZX1BqgklOcnqMgNY=; b=FS6zkAqw6Yr6MMSOI1vEjq/FOliiIfwA+PK1lDnCFlNV8iBf0vhJMtrXxE3JKgXJqj a6dhuiCzPa/ufqiq82jYpOHAqLCYq4S5DvSlNkN2vqYT1FdGwOhet+I2sWvLJeM8JXe7 HGgOELyuQEoPp3F6UMJ3j04/JOxVaUAqk6PIyUvL9Yur1N3hEGUFewSRflDRsuvLjeQG gVgfwtxK5km2FxeBpgHvexmdumdtpzNpjSiuJ5wwWjmoxIHbojaTYAS4vkGgxqI7r32/ 5a13OEoZOu7btaOTccWrpHZ6dUPo+YEEDe87cta3SBTqyveqqcYCI2DcUP28ir5EIUxb 2U2A== X-Gm-Message-State: ANoB5pnkq5B3hEhVU5GUYJKha2XnezMcwkm4r96Wme8jvC3pAGCtitjy iYy4GD0Oib79mWGsbsG+QbTrfK29tiJO X-Google-Smtp-Source: AA0mqf6tpHdLVL6fg0kfeQlp8XGR7lcAkLnW8b5mo33GijlwCBB5nOQY6JEbarY2fvIRa5O7AsAs+9xZYaWx X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:553:438f:b86a:87f]) (user=irogers job=sendgmr) by 2002:a25:e812:0:b0:679:6725:3e2c with SMTP id k18-20020a25e812000000b0067967253e2cmr13188809ybd.425.1668460140801; Mon, 14 Nov 2022 13:09:00 -0800 (PST) Date: Mon, 14 Nov 2022 13:07:21 -0800 In-Reply-To: <20221114210723.2749751-1-irogers@google.com> Message-Id: <20221114210723.2749751-9-irogers@google.com> Mime-Version: 1.0 References: <20221114210723.2749751-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v3 08/10] perf pmu: Restructure print_pmu_events From: Ian Rogers To: Weilin Wang , Perry Taylor , Caleb Biggers , Leo Yan , Adrian Hunter , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Sandipan Das , Kajol Jain , Zhengjun Xing , Kan Liang , Ravi Bangoria , Xin Gao , Rob Herring , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org Cc: Stephane Eranian , Ian Rogers Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Previously print_pmu_events would compute the values to be printed, place them in struct sevent, sort them and then print them. Modify the code so that struct sevent holds just the PMU and event, sort these and then in the main print loop calculate aliases for names, etc. This avoids memory allocations for copied values as they are computed then printed. Signed-off-by: Ian Rogers --- tools/perf/util/pmu.c | 208 ++++++++++++++++++++++-------------------- 1 file changed, 110 insertions(+), 98 deletions(-) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index e6790175307b..075c82dd1347 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1553,8 +1553,8 @@ static int sub_non_neg(int a, int b) return a - b; } =20 -static char *format_alias(char *buf, int len, struct perf_pmu *pmu, - struct perf_pmu_alias *alias) +static char *format_alias(char *buf, int len, const struct perf_pmu *pmu, + const struct perf_pmu_alias *alias) { struct parse_events_term *term; int used =3D snprintf(buf, len, "%s/%s", pmu->name, alias->name); @@ -1579,51 +1579,67 @@ static char *format_alias(char *buf, int len, struc= t perf_pmu *pmu, return buf; } =20 -static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, - struct perf_pmu_alias *alias) +static char *format_alias_or(char *buf, int len, const struct perf_pmu *pm= u, + const struct perf_pmu_alias *alias) { snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); return buf; } =20 +/** Struct for ordering events as output in perf list. */ struct sevent { - char *name; - char *desc; - char *topic; - char *str; - char *pmu; - char *metric_expr; - char *metric_name; - int is_cpu; + /** PMU for event. */ + const struct perf_pmu *pmu; + /** + * Optional event for name, desc, etc. If not present then this is a + * selectable PMU and the event name is shown as "//". + */ + const struct perf_pmu_alias *event; + /** Is the PMU for the CPU? */ + bool is_cpu; }; =20 static int cmp_sevent(const void *a, const void *b) { const struct sevent *as =3D a; const struct sevent *bs =3D b; + const char *a_pmu_name, *b_pmu_name; + const char *a_name =3D "//", *a_desc =3D NULL, *a_topic =3D ""; + const char *b_name =3D "//", *b_desc =3D NULL, *b_topic =3D ""; int ret; =20 - /* Put extra events last */ - if (!!as->desc !=3D !!bs->desc) - return !!as->desc - !!bs->desc; - if (as->topic && bs->topic) { - int n =3D strcmp(as->topic, bs->topic); - - if (n) - return n; + if (as->event) { + a_name =3D as->event->name; + a_desc =3D as->event->desc; + a_topic =3D as->event->topic ?: ""; } + if (bs->event) { + b_name =3D bs->event->name; + b_desc =3D bs->event->desc; + b_topic =3D bs->event->topic ?: ""; + } + /* Put extra events last. */ + if (!!a_desc !=3D !!b_desc) + return !!a_desc - !!b_desc; + + /* Order by topics. */ + ret =3D strcmp(a_topic, b_topic); + if (ret) + return ret; =20 /* Order CPU core events to be first */ if (as->is_cpu !=3D bs->is_cpu) return bs->is_cpu - as->is_cpu; =20 - ret =3D strcmp(as->name, bs->name); - if (!ret) { - if (as->pmu && bs->pmu) - return strcmp(as->pmu, bs->pmu); - } + /* Order by PMU name. */ + a_pmu_name =3D as->pmu->name ?: ""; + b_pmu_name =3D bs->pmu->name ?: ""; + ret =3D strcmp(a_pmu_name, b_pmu_name); + if (ret) + return ret; =20 - return ret; + /* Order by event name. */ + return strcmp(a_name, b_name); } =20 static void wordwrap(char *s, int start, int max, int corr) @@ -1655,16 +1671,18 @@ bool is_pmu_core(const char *name) static bool pmu_alias_is_duplicate(struct sevent *alias_a, struct sevent *alias_b) { - /* Different names -> never duplicates */ - if (strcmp(alias_a->name, alias_b->name)) - return false; + const char *a_pmu_name, *b_pmu_name; + const char *a_name =3D alias_a->event ? alias_a->event->name : "//"; + const char *b_name =3D alias_b->event ? alias_b->event->name : "//"; =20 - /* Don't remove duplicates for hybrid PMUs */ - if (perf_pmu__is_hybrid(alias_a->pmu) && - perf_pmu__is_hybrid(alias_b->pmu)) + /* Different names -> never duplicates */ + if (strcmp(a_name, b_name)) return false; =20 - return true; + /* Don't remove duplicates for different PMUs */ + a_pmu_name =3D alias_a->pmu->name ?: ""; + b_pmu_name =3D alias_b->pmu->name ?: ""; + return strcmp(a_pmu_name, b_pmu_name) =3D=3D 0; } =20 void print_pmu_events(const char *event_glob, bool name_only, bool quiet_f= lag, @@ -1690,110 +1708,104 @@ void print_pmu_events(const char *event_glob, boo= l name_only, bool quiet_flag, len++; } aliases =3D zalloc(sizeof(struct sevent) * len); - if (!aliases) - goto out_enomem; + if (!aliases) { + pr_err("FATAL: not enough memory to print PMU events\n"); + return; + } pmu =3D NULL; j =3D 0; while ((pmu =3D perf_pmu__scan(pmu)) !=3D NULL) { + bool is_cpu; + if (pmu_name && pmu->name && strcmp(pmu_name, pmu->name)) continue; =20 - list_for_each_entry(alias, &pmu->aliases, list) { - char *name =3D alias->desc ? alias->name : - format_alias(buf, sizeof(buf), pmu, alias); - bool is_cpu =3D is_pmu_core(pmu->name) || - perf_pmu__is_hybrid(pmu->name); + is_cpu =3D is_pmu_core(pmu->name) || perf_pmu__is_hybrid(pmu->name); =20 + list_for_each_entry(alias, &pmu->aliases, list) { if (alias->deprecated && !deprecated) continue; =20 if (event_glob !=3D NULL && - !(strglobmatch_nocase(name, event_glob) || - (!is_cpu && strglobmatch_nocase(alias->name, - event_glob)) || + !(strglobmatch_nocase(alias->name, event_glob) || + (!is_cpu && + strglobmatch_nocase(alias->name, event_glob)) || (alias->topic && strglobmatch_nocase(alias->topic, event_glob)))) continue; =20 - if (is_cpu && !name_only && !alias->desc) - name =3D format_alias_or(buf, sizeof(buf), pmu, alias); - - aliases[j].name =3D name; - if (is_cpu && !name_only && !alias->desc) - aliases[j].name =3D format_alias_or(buf, - sizeof(buf), - pmu, alias); - aliases[j].name =3D strdup(aliases[j].name); - if (!aliases[j].name) - goto out_enomem; - - aliases[j].desc =3D long_desc ? alias->long_desc : - alias->desc; - aliases[j].topic =3D alias->topic; - aliases[j].str =3D alias->str; - aliases[j].pmu =3D pmu->name; - aliases[j].metric_expr =3D alias->metric_expr; - aliases[j].metric_name =3D alias->metric_name; + aliases[j].event =3D alias; + aliases[j].pmu =3D pmu; aliases[j].is_cpu =3D is_cpu; j++; } if (pmu->selectable && (event_glob =3D=3D NULL || strglobmatch(pmu->name, event_glob))) { - char *s; - if (asprintf(&s, "%s//", pmu->name) < 0) - goto out_enomem; - aliases[j].name =3D s; + aliases[j].event =3D NULL; + aliases[j].pmu =3D pmu; + aliases[j].is_cpu =3D is_cpu; j++; } } len =3D j; qsort(aliases, len, sizeof(struct sevent), cmp_sevent); for (j =3D 0; j < len; j++) { + char *name, *desc; + /* Skip duplicates */ if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1])) continue; =20 + if (!aliases[j].event) { + /* A selectable event. */ + snprintf(buf, sizeof(buf), "%s//", aliases[j].pmu->name); + name =3D buf; + } else if (aliases[j].event->desc) { + name =3D aliases[j].event->name; + } else { + if (!name_only && aliases[j].is_cpu) { + name =3D format_alias_or(buf, sizeof(buf), aliases[j].pmu, + aliases[j].event); + } else { + name =3D format_alias(buf, sizeof(buf), aliases[j].pmu, + aliases[j].event); + } + } if (name_only) { - printf("%s ", aliases[j].name); + printf("%s ", name); continue; } - if (aliases[j].desc && !quiet_flag) { - if (numdesc++ =3D=3D 0) - printf("\n"); - if (aliases[j].topic && (!topic || - strcmp(topic, aliases[j].topic))) { - printf("%s%s:\n", topic ? "\n" : "", - aliases[j].topic); - topic =3D aliases[j].topic; - } - printf(" %-50s\n", aliases[j].name); - printf("%*s", 8, "["); - wordwrap(aliases[j].desc, 8, columns, 0); - printf("]\n"); - if (details_flag) { - printf("%*s%s/%s/ ", 8, "", aliases[j].pmu, aliases[j].str); - if (aliases[j].metric_name) - printf(" MetricName: %s", aliases[j].metric_name); - if (aliases[j].metric_expr) - printf(" MetricExpr: %s", aliases[j].metric_expr); - putchar('\n'); - } - } else - printf(" %-50s [Kernel PMU event]\n", aliases[j].name); printed++; + if (!aliases[j].event || !aliases[j].event->desc || quiet_flag) { + printf(" %-50s [Kernel PMU event]\n", name); + continue; + } + if (numdesc++ =3D=3D 0) + printf("\n"); + if (aliases[j].event->topic && (!topic || + strcmp(topic, aliases[j].event->topic))) { + printf("%s%s:\n", topic ? "\n" : "", aliases[j].event->topic); + topic =3D aliases[j].event->topic; + } + printf(" %-50s\n", name); + printf("%*s", 8, "["); + desc =3D long_desc ? aliases[j].event->long_desc : aliases[j].event->des= c; + wordwrap(desc, 8, columns, 0); + printf("]\n"); + if (details_flag) { + printf("%*s%s/%s/ ", 8, "", aliases[j].pmu->name, aliases[j].event->str= ); + if (aliases[j].event->metric_name) + printf(" MetricName: %s", aliases[j].event->metric_name); + if (aliases[j].event->metric_expr) + printf(" MetricExpr: %s", aliases[j].event->metric_expr); + putchar('\n'); + } } if (printed && pager_in_use()) printf("\n"); -out_free: - for (j =3D 0; j < len; j++) - zfree(&aliases[j].name); + zfree(&aliases); return; - -out_enomem: - printf("FATAL: not enough memory to print PMU events\n"); - if (aliases) - goto out_free; } =20 bool pmu_have_event(const char *pname, const char *name) --=20 2.38.1.431.g37b22c650d-goog From nobody Mon Apr 13 14:26:57 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 193FEC43219 for ; Mon, 14 Nov 2022 21:09:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237750AbiKNVJl (ORCPT ); Mon, 14 Nov 2022 16:09:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46426 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237745AbiKNVJO (ORCPT ); Mon, 14 Nov 2022 16:09:14 -0500 Received: from mail-pg1-x54a.google.com (mail-pg1-x54a.google.com [IPv6:2607:f8b0:4864:20::54a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E0040E084 for ; Mon, 14 Nov 2022 13:09:09 -0800 (PST) Received: by mail-pg1-x54a.google.com with SMTP id 186-20020a6300c3000000b004702c90a4bdso6295521pga.9 for ; Mon, 14 Nov 2022 13:09:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=FbMkm7eVZJ8nydJV3cn0i53k8FmaD8baom4/w9HSfEE=; b=LjetKudPNIvXrNpXy/AjczqbA9ifx6Gj7JIVF/vAMwOuclvOBkxLBWUMAmSQVMrR67 pW+QlOc94yeLtDsDkXtPS2Crnps6f6PHP0E7oQtHwUte1lpucOVa9Vb6jONCUKo0e7o1 S3+rgiosQBBkd2K/kPTxZ9jNBfRJGV+4CCoII1RT03TpqbrlPXRm+cBMB3yzUXXHv82e ehAcFk/jXTLBTSvO4FuWUAIzBJ8j5mUVs+LEQdG5YnnQPgiEMhRTbr914cr3PAq5EAbx PCicNQdxXWrL+A7B0ISYJTwbwyC4AVqr73LM0ns8X5EFpy48BjT17TXYSwrrh5flH8Lw 7Ytw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=FbMkm7eVZJ8nydJV3cn0i53k8FmaD8baom4/w9HSfEE=; b=kHB+YwAA4MSgPOEd/0e3fi9XVmOD1/ui078pKc9KBZlu4AoLzF3eoyKbAZ+QjsYDCS 5bpmVPyPgRVkBYUKq7nnf6TH7bzjxqxWsIfksD29rQZrR52n9/0s32XnccM+4Npnful3 d6rn4m2mFaKjLIzU+rxiLaJIJi8MBGNlcP3gpnqfkLcYPd/K+R+vfdzJ7t2tuNzqZzN3 0piJ33BCI9gwr06p1qGCtYYY1GB1UHOCRiJEgdwBENEdMkdxn9/nitKDtKUACZcGa+yP d5RmHBh4yN8JcxTJt6Dp7qusoICR+cvyzhjSDCmAqaPuTfsggOqmS41JKO0AFrL8BPrz 4nzQ== X-Gm-Message-State: ANoB5pk0sBY33fdgJyuHIJmOwImxzoTW7JrWj/JaHemTGUvrz99STDHA CDk2vRoiZaNeJHe54RVdhWUU3SJum29u X-Google-Smtp-Source: AA0mqf53Gystj3WSoMGDundu8c1pD1WQ1ezYPUTfZbVxMVzYcaPOrx5mMSBl3jn3OObIs+jwkP0RqzndQxSF X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:553:438f:b86a:87f]) (user=irogers job=sendgmr) by 2002:a17:90b:4a8b:b0:212:ca89:41c9 with SMTP id lp11-20020a17090b4a8b00b00212ca8941c9mr15267825pjb.244.1668460149444; Mon, 14 Nov 2022 13:09:09 -0800 (PST) Date: Mon, 14 Nov 2022 13:07:22 -0800 In-Reply-To: <20221114210723.2749751-1-irogers@google.com> Message-Id: <20221114210723.2749751-10-irogers@google.com> Mime-Version: 1.0 References: <20221114210723.2749751-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v3 09/10] perf list: Reorganize to use callbacks From: Ian Rogers To: Weilin Wang , Perry Taylor , Caleb Biggers , Leo Yan , Adrian Hunter , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Sandipan Das , Kajol Jain , Zhengjun Xing , Kan Liang , Ravi Bangoria , Xin Gao , Rob Herring , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org Cc: Stephane Eranian , Ian Rogers Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Rather than controlling the list output with passed flags, add callbacks that are called when an event or metric are encountered. State is passed to the callback so that command line options can be respected, alternatively the callbacks can be changed. Fix a few bugs: - wordwrap to columns metric descriptions and expressions; - remove unnecessary whitespace after PMU event names; - the metric filter is a glob but matched using strstr which will always fail, switch to using a proper globmatch, - the detail flag gives details for extra kernel PMU events like branch-instructions. In metricgroup.c switch from struct mep being a rbtree of metricgroups containing a list of metrics, to the tree directly containing all the metrics. In general the alias for a name is passed to the print routine rather than being contained in the name with OR. Signed-off-by: Ian Rogers --- tools/perf/builtin-list.c | 331 +++++++++++++++++++++++++----- tools/perf/util/metricgroup.c | 243 ++++++---------------- tools/perf/util/metricgroup.h | 4 +- tools/perf/util/pmu.c | 145 +++++-------- tools/perf/util/pmu.h | 5 +- tools/perf/util/print-events.c | 363 +++++++++++++++++---------------- tools/perf/util/print-events.h | 42 ++-- 7 files changed, 621 insertions(+), 512 deletions(-) diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index cc84ced6da26..12811fc40a30 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -15,31 +15,240 @@ #include "util/pmu-hybrid.h" #include "util/debug.h" #include "util/metricgroup.h" +#include "util/string2.h" +#include "util/strlist.h" #include #include #include =20 -static bool desc_flag =3D true; -static bool details_flag; +/** + * struct print_state - State and configuration passed to the default_print + * functions. + */ +struct print_state { + /** + * @pmu_glob: Optionally restrict PMU and metric matching to PMU or + * debugfs subsystem name. + */ + char *pmu_glob; + /** @event_glob: Optional pattern matching glob. */ + char *event_glob; + /** @name_only: Print event or metric names only. */ + bool name_only; + /** @desc: Print the event or metric description. */ + bool desc; + /** @long_desc: Print longer event or metric description. */ + bool long_desc; + /** @deprecated: Print deprecated events or metrics. */ + bool deprecated; + /** + * @detailed: Print extra information on the perf event such as names + * and expressions used internally by events. + */ + bool detailed; + /** @metrics: Controls printing of metric and metric groups. */ + bool metrics; + /** @metricgroups: Controls printing of metric and metric groups. */ + bool metricgroups; + /** @last_topic: The last printed event topic. */ + char *last_topic; + /** @last_metricgroups: The last printed metric group. */ + char *last_metricgroups; + /** @visited_metrics: Metrics that are printed to avoid duplicates. */ + struct strlist *visited_metrics; +}; + +static void default_print_start(void *ps) +{ + struct print_state *print_state =3D ps; + + if (!print_state->name_only && pager_in_use()) + printf("\nList of pre-defined events (to be used in -e or -M):\n\n"); +} + +static void default_print_end(void *print_state __maybe_unused) {} + +static void wordwrap(const char *s, int start, int max, int corr) +{ + int column =3D start; + int n; + + while (*s) { + int wlen =3D strcspn(s, " \t"); + + if (column + wlen >=3D max && column > start) { + printf("\n%*s", start, ""); + column =3D start + corr; + } + n =3D printf("%s%.*s", column > start ? " " : "", wlen, s); + if (n <=3D 0) + break; + s +=3D wlen; + column +=3D n; + s =3D skip_spaces(s); + } +} + +static void default_print_event(void *ps, const char *pmu_name, const char= *topic, + const char *event_name, const char *event_alias, + const char *scale_unit __maybe_unused, + bool deprecated, const char *event_type_desc, + const char *desc, const char *long_desc, + const char *encoding_desc, + const char *metric_name, const char *metric_expr) +{ + struct print_state *print_state =3D ps; + int pos; + + if (deprecated && !print_state->deprecated) + return; + + if (print_state->pmu_glob && !strglobmatch(pmu_name, print_state->pmu_glo= b)) + return; + + if (print_state->event_glob && + (!event_name || !strglobmatch(event_name, print_state->event_glob)) && + (!event_alias || !strglobmatch(event_alias, print_state->event_glob))= && + (!topic || !strglobmatch_nocase(topic, print_state->event_glob))) + return; + + if (print_state->name_only) { + if (event_alias && strlen(event_alias)) + printf("%s ", event_alias); + else + printf("%s ", event_name); + return; + } + + if (strcmp(print_state->last_topic, topic ?: "")) { + if (topic) + printf("\n%s:\n", topic); + free(print_state->last_topic); + print_state->last_topic =3D strdup(topic ?: ""); + } + + if (event_alias && strlen(event_alias)) + pos =3D printf(" %s OR %s", event_name, event_alias); + else + pos =3D printf(" %s", event_name); + + if (!topic && event_type_desc) { + for (; pos < 53; pos++) + putchar(' '); + printf("[%s]\n", event_type_desc); + } else + putchar('\n'); + + if (desc && print_state->desc) { + printf("%*s", 8, "["); + wordwrap(desc, 8, pager_get_columns(), 0); + printf("]\n"); + } + + if (long_desc && print_state->long_desc) { + printf("%*s", 8, "["); + wordwrap(long_desc, 8, pager_get_columns(), 0); + printf("]\n"); + } + + if (print_state->detailed && encoding_desc) { + printf("%*s%s", 8, "", encoding_desc); + if (metric_name) + printf(" MetricName: %s", metric_name); + if (metric_expr) + printf(" MetricExpr: %s", metric_expr); + putchar('\n'); + } +} + +static void default_print_metric(void *ps, + const char *group, + const char *name, + const char *desc, + const char *long_desc, + const char *expr, + const char *unit __maybe_unused) +{ + struct print_state *print_state =3D ps; + + if (print_state->event_glob && + (!print_state->metrics || !name || !strglobmatch(name, print_state->e= vent_glob)) && + (!print_state->metricgroups || !group || !strglobmatch(group, print_s= tate->event_glob))) + return; + + if (!print_state->name_only && !print_state->last_metricgroups) { + if (print_state->metricgroups) { + printf("\nMetric Groups:\n"); + if (!print_state->metrics) + putchar('\n'); + } else { + printf("\nMetrics:\n\n"); + } + } + if (!print_state->last_metricgroups || + strcmp(print_state->last_metricgroups, group ?: "")) { + if (group && print_state->metricgroups) { + if (print_state->name_only) + printf("%s ", group); + else if (print_state->metrics) + printf("\n%s:\n", group); + else + printf("%s\n", group); + } + free(print_state->last_metricgroups); + print_state->last_metricgroups =3D strdup(group ?: ""); + } + if (!print_state->metrics) + return; + + if (print_state->name_only) { + if (print_state->metrics && + !strlist__has_entry(print_state->visited_metrics, name)) { + printf("%s ", name); + strlist__add(print_state->visited_metrics, name); + } + return; + } + printf(" %s\n", name); + + if (desc && print_state->desc) { + printf("%*s", 8, "["); + wordwrap(desc, 8, pager_get_columns(), 0); + printf("]\n"); + } + if (long_desc && print_state->long_desc) { + printf("%*s", 8, "["); + wordwrap(long_desc, 8, pager_get_columns(), 0); + printf("]\n"); + } + if (expr && print_state->detailed) { + printf("%*s", 8, "["); + wordwrap(expr, 8, pager_get_columns(), 0); + printf("]\n"); + } +} =20 int cmd_list(int argc, const char **argv) { int i, ret =3D 0; - bool raw_dump =3D false; - bool long_desc_flag =3D false; - bool deprecated =3D false; - char *pmu_name =3D NULL; + struct print_state ps =3D {}; + struct print_callbacks print_cb =3D { + .print_start =3D default_print_start, + .print_end =3D default_print_end, + .print_event =3D default_print_event, + .print_metric =3D default_print_metric, + }; const char *hybrid_name =3D NULL; const char *unit_name =3D NULL; struct option list_options[] =3D { - OPT_BOOLEAN(0, "raw-dump", &raw_dump, "Dump raw events"), - OPT_BOOLEAN('d', "desc", &desc_flag, + OPT_BOOLEAN(0, "raw-dump", &ps.name_only, "Dump raw events"), + OPT_BOOLEAN('d', "desc", &ps.desc, "Print extra event descriptions. --no-desc to not print."), - OPT_BOOLEAN('v', "long-desc", &long_desc_flag, + OPT_BOOLEAN('v', "long-desc", &ps.long_desc, "Print longer event descriptions."), - OPT_BOOLEAN(0, "details", &details_flag, + OPT_BOOLEAN(0, "details", &ps.detailed, "Print information on the perf event names and expressions used int= ernally by events."), - OPT_BOOLEAN(0, "deprecated", &deprecated, + OPT_BOOLEAN(0, "deprecated", &ps.deprecated, "Print deprecated events."), OPT_STRING(0, "cputype", &hybrid_name, "hybrid cpu type", "Limit PMU or metric printing to the given hybrid PMU (e.g. core or = atom)."), @@ -63,20 +272,28 @@ int cmd_list(int argc, const char **argv) =20 setup_pager(); =20 - if (!raw_dump && pager_in_use()) - printf("\nList of pre-defined events (to be used in -e or -M):\n\n"); + if (!ps.name_only) + setup_pager(); =20 + ps.desc =3D !ps.long_desc; + ps.last_topic =3D strdup(""); + assert(ps.last_topic); + ps.visited_metrics =3D strlist__new(NULL, NULL); + assert(ps.visited_metrics); if (unit_name) - pmu_name =3D strdup(unit_name); + ps.pmu_glob =3D strdup(unit_name); else if (hybrid_name) { - pmu_name =3D perf_pmu__hybrid_type_to_pmu(hybrid_name); - if (!pmu_name) + ps.pmu_glob =3D perf_pmu__hybrid_type_to_pmu(hybrid_name); + if (!ps.pmu_glob) pr_warning("WARNING: hybrid cputype is not supported!\n"); } =20 + print_cb.print_start(&ps); + if (argc =3D=3D 0) { - print_events(NULL, raw_dump, !desc_flag, long_desc_flag, - details_flag, deprecated, pmu_name); + ps.metrics =3D true; + ps.metricgroups =3D true; + print_events(&print_cb, &ps); goto out; } =20 @@ -84,30 +301,33 @@ int cmd_list(int argc, const char **argv) char *sep, *s; =20 if (strcmp(argv[i], "tracepoint") =3D=3D 0) - print_tracepoint_events(NULL, NULL, raw_dump); + print_tracepoint_events(&print_cb, &ps); else if (strcmp(argv[i], "hw") =3D=3D 0 || strcmp(argv[i], "hardware") =3D=3D 0) - print_symbol_events(NULL, PERF_TYPE_HARDWARE, - event_symbols_hw, PERF_COUNT_HW_MAX, raw_dump); + print_symbol_events(&print_cb, &ps, PERF_TYPE_HARDWARE, + event_symbols_hw, PERF_COUNT_HW_MAX); else if (strcmp(argv[i], "sw") =3D=3D 0 || strcmp(argv[i], "software") =3D=3D 0) { - print_symbol_events(NULL, PERF_TYPE_SOFTWARE, - event_symbols_sw, PERF_COUNT_SW_MAX, raw_dump); - print_tool_events(NULL, raw_dump); + print_symbol_events(&print_cb, &ps, PERF_TYPE_SOFTWARE, + event_symbols_sw, PERF_COUNT_SW_MAX); + print_tool_events(&print_cb, &ps); } else if (strcmp(argv[i], "cache") =3D=3D 0 || strcmp(argv[i], "hwcache") =3D=3D 0) - print_hwcache_events(NULL, raw_dump); + print_hwcache_events(&print_cb, &ps); else if (strcmp(argv[i], "pmu") =3D=3D 0) - print_pmu_events(NULL, raw_dump, !desc_flag, - long_desc_flag, details_flag, - deprecated, pmu_name); + print_pmu_events(&print_cb, &ps); else if (strcmp(argv[i], "sdt") =3D=3D 0) - print_sdt_events(NULL, NULL, raw_dump); - else if (strcmp(argv[i], "metric") =3D=3D 0 || strcmp(argv[i], "metrics"= ) =3D=3D 0) - metricgroup__print(true, false, NULL, raw_dump, details_flag, pmu_name); - else if (strcmp(argv[i], "metricgroup") =3D=3D 0 || strcmp(argv[i], "met= ricgroups") =3D=3D 0) - metricgroup__print(false, true, NULL, raw_dump, details_flag, pmu_name); - else if ((sep =3D strchr(argv[i], ':')) !=3D NULL) { + print_sdt_events(&print_cb, &ps); + else if (strcmp(argv[i], "metric") =3D=3D 0 || strcmp(argv[i], "metrics"= ) =3D=3D 0) { + ps.metricgroups =3D false; + ps.metrics =3D true; + metricgroup__print(&print_cb, &ps); + } else if (strcmp(argv[i], "metricgroup") =3D=3D 0 || + strcmp(argv[i], "metricgroups") =3D=3D 0) { + ps.metricgroups =3D true; + ps.metrics =3D false; + metricgroup__print(&print_cb, &ps); + } else if ((sep =3D strchr(argv[i], ':')) !=3D NULL) { int sep_idx; =20 sep_idx =3D sep - argv[i]; @@ -118,34 +338,41 @@ int cmd_list(int argc, const char **argv) } =20 s[sep_idx] =3D '\0'; - print_tracepoint_events(s, s + sep_idx + 1, raw_dump); - print_sdt_events(s, s + sep_idx + 1, raw_dump); - metricgroup__print(true, true, s, raw_dump, details_flag, pmu_name); + ps.pmu_glob =3D s; + ps.event_glob =3D s + sep_idx + 1; + print_tracepoint_events(&print_cb, &ps); + print_sdt_events(&print_cb, &ps); + ps.metrics =3D true; + ps.metricgroups =3D true; + metricgroup__print(&print_cb, &ps); free(s); } else { if (asprintf(&s, "*%s*", argv[i]) < 0) { printf("Critical: Not enough memory! Trying to continue...\n"); continue; } - print_symbol_events(s, PERF_TYPE_HARDWARE, - event_symbols_hw, PERF_COUNT_HW_MAX, raw_dump); - print_symbol_events(s, PERF_TYPE_SOFTWARE, - event_symbols_sw, PERF_COUNT_SW_MAX, raw_dump); - print_tool_events(s, raw_dump); - print_hwcache_events(s, raw_dump); - print_pmu_events(s, raw_dump, !desc_flag, - long_desc_flag, - details_flag, - deprecated, - pmu_name); - print_tracepoint_events(NULL, s, raw_dump); - print_sdt_events(NULL, s, raw_dump); - metricgroup__print(true, true, s, raw_dump, details_flag, pmu_name); + ps.event_glob =3D s; + print_symbol_events(&print_cb, &ps, PERF_TYPE_HARDWARE, + event_symbols_hw, PERF_COUNT_HW_MAX); + print_symbol_events(&print_cb, &ps, PERF_TYPE_SOFTWARE, + event_symbols_sw, PERF_COUNT_SW_MAX); + print_tool_events(&print_cb, &ps); + print_hwcache_events(&print_cb, &ps); + print_pmu_events(&print_cb, &ps); + print_tracepoint_events(&print_cb, &ps); + print_sdt_events(&print_cb, &ps); + ps.metrics =3D true; + ps.metricgroups =3D true; + metricgroup__print(&print_cb, &ps); free(s); } } =20 out: - free(pmu_name); + print_cb.print_end(&ps); + free(ps.pmu_glob); + free(ps.last_topic); + free(ps.last_metricgroups); + strlist__delete(ps.visited_metrics); return ret; } diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 1943fed9b6d9..76501009ead5 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -12,6 +12,7 @@ #include "strbuf.h" #include "pmu.h" #include "pmu-hybrid.h" +#include "print-events.h" #include "expr.h" #include "rblist.h" #include @@ -352,51 +353,65 @@ static bool match_pe_metric(const struct pmu_event *p= e, const char *metric) match_metric(pe->metric_name, metric); } =20 +/** struct mep - RB-tree node for building printing information. */ struct mep { + /** nd - RB-tree element. */ struct rb_node nd; - const char *name; - struct strlist *metrics; + /** @metric_group: Owned metric group name, separated others with ';'. */ + char *metric_group; + const char *metric_name; + const char *metric_desc; + const char *metric_long_desc; + const char *metric_expr; + const char *metric_unit; }; =20 static int mep_cmp(struct rb_node *rb_node, const void *entry) { struct mep *a =3D container_of(rb_node, struct mep, nd); struct mep *b =3D (struct mep *)entry; + int ret; =20 - return strcmp(a->name, b->name); + ret =3D strcmp(a->metric_group, b->metric_group); + if (ret) + return ret; + + return strcmp(a->metric_name, b->metric_name); } =20 -static struct rb_node *mep_new(struct rblist *rl __maybe_unused, - const void *entry) +static struct rb_node *mep_new(struct rblist *rl __maybe_unused, const voi= d *entry) { struct mep *me =3D malloc(sizeof(struct mep)); =20 if (!me) return NULL; + memcpy(me, entry, sizeof(struct mep)); - me->name =3D strdup(me->name); - if (!me->name) - goto out_me; - me->metrics =3D strlist__new(NULL, NULL); - if (!me->metrics) - goto out_name; return &me->nd; -out_name: - zfree(&me->name); -out_me: +} + +static void mep_delete(struct rblist *rl __maybe_unused, + struct rb_node *nd) +{ + struct mep *me =3D container_of(nd, struct mep, nd); + + zfree(&me->metric_group); free(me); - return NULL; } =20 -static struct mep *mep_lookup(struct rblist *groups, const char *name) +static struct mep *mep_lookup(struct rblist *groups, const char *metric_gr= oup, + const char *metric_name) { struct rb_node *nd; struct mep me =3D { - .name =3D name + .metric_group =3D strdup(metric_group), + .metric_name =3D metric_name, }; nd =3D rblist__find(groups, &me); - if (nd) + if (nd) { + free(me.metric_group); return container_of(nd, struct mep, nd); + } rblist__add_node(groups, &me); nd =3D rblist__find(groups, &me); if (nd) @@ -404,107 +419,37 @@ static struct mep *mep_lookup(struct rblist *groups,= const char *name) return NULL; } =20 -static void mep_delete(struct rblist *rl __maybe_unused, - struct rb_node *nd) -{ - struct mep *me =3D container_of(nd, struct mep, nd); - - strlist__delete(me->metrics); - zfree(&me->name); - free(me); -} - -static void metricgroup__print_strlist(struct strlist *metrics, bool raw) -{ - struct str_node *sn; - int n =3D 0; - - strlist__for_each_entry (sn, metrics) { - if (raw) - printf("%s%s", n > 0 ? " " : "", sn->s); - else - printf(" %s\n", sn->s); - n++; - } - if (raw) - putchar('\n'); -} - -static int metricgroup__print_pmu_event(const struct pmu_event *pe, - bool metricgroups, char *filter, - bool raw, bool details, - struct rblist *groups, - struct strlist *metriclist) +static int metricgroup__add_to_mep_groups(const struct pmu_event *pe, + struct rblist *groups) { const char *g; char *omg, *mg; =20 - g =3D pe->metric_group; - if (!g && pe->metric_name) { - if (pe->name) - return 0; - g =3D "No_group"; - } - - if (!g) - return 0; - - mg =3D strdup(g); - + mg =3D strdup(pe->metric_group ?: "No_group"); if (!mg) return -ENOMEM; omg =3D mg; while ((g =3D strsep(&mg, ";")) !=3D NULL) { struct mep *me; - char *s; =20 g =3D skip_spaces(g); - if (*g =3D=3D 0) - g =3D "No_group"; - if (filter && !strstr(g, filter)) - continue; - if (raw) - s =3D (char *)pe->metric_name; - else { - if (asprintf(&s, "%s\n%*s%s]", - pe->metric_name, 8, "[", pe->desc) < 0) - return -1; - if (details) { - if (asprintf(&s, "%s\n%*s%s]", - s, 8, "[", pe->metric_expr) < 0) - return -1; - } - } - - if (!s) - continue; + if (strlen(g)) + me =3D mep_lookup(groups, g, pe->metric_name); + else + me =3D mep_lookup(groups, "No_group", pe->metric_name); =20 - if (!metricgroups) { - strlist__add(metriclist, s); - } else { - me =3D mep_lookup(groups, g); - if (!me) - continue; - strlist__add(me->metrics, s); + if (me) { + me->metric_desc =3D pe->desc; + me->metric_long_desc =3D pe->long_desc; + me->metric_expr =3D pe->metric_expr; + me->metric_unit =3D pe->unit; } - - if (!raw) - free(s); } free(omg); =20 return 0; } =20 -struct metricgroup_print_sys_idata { - struct strlist *metriclist; - char *filter; - struct rblist *groups; - bool metricgroups; - bool raw; - bool details; -}; - struct metricgroup_iter_data { pmu_event_iter_fn fn; void *data; @@ -527,61 +472,26 @@ static int metricgroup__sys_event_iter(const struct p= mu_event *pe, =20 return d->fn(pe, table, d->data); } - return 0; } =20 -static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, - const struct pmu_events_table *table __maybe_unused, - void *data) -{ - struct metricgroup_print_sys_idata *d =3D data; - - return metricgroup__print_pmu_event(pe, d->metricgroups, d->filter, d->ra= w, - d->details, d->groups, d->metriclist); -} - -struct metricgroup_print_data { - const char *pmu_name; - struct strlist *metriclist; - char *filter; - struct rblist *groups; - bool metricgroups; - bool raw; - bool details; -}; - -static int metricgroup__print_callback(const struct pmu_event *pe, - const struct pmu_events_table *table __maybe_unused, - void *vdata) +static int metricgroup__add_to_mep_groups_callback(const struct pmu_event = *pe, + const struct pmu_events_table *table __maybe_unused, + void *vdata) { - struct metricgroup_print_data *data =3D vdata; - const char *pmu =3D pe->pmu ?: "cpu"; + struct rblist *groups =3D vdata; =20 - if (!pe->metric_expr) - return 0; - - if (data->pmu_name && strcmp(data->pmu_name, pmu)) + if (!pe->metric_name) return 0; =20 - return metricgroup__print_pmu_event(pe, data->metricgroups, data->filter, - data->raw, data->details, data->groups, - data->metriclist); + return metricgroup__add_to_mep_groups(pe, groups); } =20 -void metricgroup__print(bool metrics, bool metricgroups, char *filter, - bool raw, bool details, const char *pmu_name) +void metricgroup__print(const struct print_callbacks *print_cb, void *prin= t_state) { struct rblist groups; - struct rb_node *node, *next; - struct strlist *metriclist =3D NULL; const struct pmu_events_table *table; - - if (!metricgroups) { - metriclist =3D strlist__new(NULL, NULL); - if (!metriclist) - return; - } + struct rb_node *node, *next; =20 rblist__init(&groups); groups.node_new =3D mep_new; @@ -589,56 +499,31 @@ void metricgroup__print(bool metrics, bool metricgrou= ps, char *filter, groups.node_delete =3D mep_delete; table =3D pmu_events_table__find(); if (table) { - struct metricgroup_print_data data =3D { - .pmu_name =3D pmu_name, - .metriclist =3D metriclist, - .metricgroups =3D metricgroups, - .filter =3D filter, - .raw =3D raw, - .details =3D details, - .groups =3D &groups, - }; - pmu_events_table_for_each_event(table, - metricgroup__print_callback, - &data); + metricgroup__add_to_mep_groups_callback, + &groups); } { struct metricgroup_iter_data data =3D { - .fn =3D metricgroup__print_sys_event_iter, - .data =3D (void *) &(struct metricgroup_print_sys_idata){ - .metriclist =3D metriclist, - .metricgroups =3D metricgroups, - .filter =3D filter, - .raw =3D raw, - .details =3D details, - .groups =3D &groups, - }, + .fn =3D metricgroup__add_to_mep_groups_callback, + .data =3D &groups, }; - pmu_for_each_sys_event(metricgroup__sys_event_iter, &data); } =20 - if (!filter || !rblist__empty(&groups)) { - if (metricgroups && !raw) - printf("\nMetric Groups:\n\n"); - else if (metrics && !raw) - printf("\nMetrics:\n\n"); - } - for (node =3D rb_first_cached(&groups.entries); node; node =3D next) { struct mep *me =3D container_of(node, struct mep, nd); =20 - if (metricgroups) - printf("%s%s%s", me->name, metrics && !raw ? ":" : "", raw ? " " : "\n"= ); - if (metrics) - metricgroup__print_strlist(me->metrics, raw); + print_cb->print_metric(print_state, + me->metric_group, + me->metric_name, + me->metric_desc, + me->metric_long_desc, + me->metric_expr, + me->metric_unit); next =3D rb_next(node); rblist__remove_node(&groups, node); } - if (!metricgroups) - metricgroup__print_strlist(metriclist, raw); - strlist__delete(metriclist); } =20 static const char *code_characters =3D ",-=3D@"; diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h index 732d3a0d3334..0013cf582173 100644 --- a/tools/perf/util/metricgroup.h +++ b/tools/perf/util/metricgroup.h @@ -10,6 +10,7 @@ struct evlist; struct evsel; struct option; +struct print_callbacks; struct rblist; struct cgroup; =20 @@ -78,8 +79,7 @@ int metricgroup__parse_groups_test(struct evlist *evlist, bool metric_no_merge, struct rblist *metric_events); =20 -void metricgroup__print(bool metrics, bool groups, char *filter, - bool raw, bool details, const char *pmu_name); +void metricgroup__print(const struct print_callbacks *print_cb, void *prin= t_state); bool metricgroup__has_metric(const char *metric); int arch_get_runtimeparam(const struct pmu_event *pe __maybe_unused); void metricgroup__rblist_exit(struct rblist *metric_events); diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 075c82dd1347..e9a4f31926bf 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -23,6 +23,7 @@ #include "evsel.h" #include "pmu.h" #include "parse-events.h" +#include "print-events.h" #include "header.h" #include "string2.h" #include "strbuf.h" @@ -1579,13 +1580,6 @@ static char *format_alias(char *buf, int len, const = struct perf_pmu *pmu, return buf; } =20 -static char *format_alias_or(char *buf, int len, const struct perf_pmu *pm= u, - const struct perf_pmu_alias *alias) -{ - snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); - return buf; -} - /** Struct for ordering events as output in perf list. */ struct sevent { /** PMU for event. */ @@ -1629,7 +1623,7 @@ static int cmp_sevent(const void *a, const void *b) =20 /* Order CPU core events to be first */ if (as->is_cpu !=3D bs->is_cpu) - return bs->is_cpu - as->is_cpu; + return as->is_cpu ? -1 : 1; =20 /* Order by PMU name. */ a_pmu_name =3D as->pmu->name ?: ""; @@ -1642,27 +1636,6 @@ static int cmp_sevent(const void *a, const void *b) return strcmp(a_name, b_name); } =20 -static void wordwrap(char *s, int start, int max, int corr) -{ - int column =3D start; - int n; - - while (*s) { - int wlen =3D strcspn(s, " \t"); - - if (column + wlen >=3D max && column > start) { - printf("\n%*s", start, ""); - column =3D start + corr; - } - n =3D printf("%s%.*s", column > start ? " " : "", wlen, s); - if (n <=3D 0) - break; - s +=3D wlen; - column +=3D n; - s =3D skip_spaces(s); - } -} - bool is_pmu_core(const char *name) { return !strcmp(name, "cpu") || is_arm_pmu_core(name); @@ -1685,24 +1658,19 @@ static bool pmu_alias_is_duplicate(struct sevent *a= lias_a, return strcmp(a_pmu_name, b_pmu_name) =3D=3D 0; } =20 -void print_pmu_events(const char *event_glob, bool name_only, bool quiet_f= lag, - bool long_desc, bool details_flag, bool deprecated, - const char *pmu_name) +void print_pmu_events(const struct print_callbacks *print_cb, void *print_= state) { struct perf_pmu *pmu; - struct perf_pmu_alias *alias; + struct perf_pmu_alias *event; char buf[1024]; int printed =3D 0; int len, j; struct sevent *aliases; - int numdesc =3D 0; - int columns =3D pager_get_columns(); - char *topic =3D NULL; =20 pmu =3D NULL; len =3D 0; while ((pmu =3D perf_pmu__scan(pmu)) !=3D NULL) { - list_for_each_entry(alias, &pmu->aliases, list) + list_for_each_entry(event, &pmu->aliases, list) len++; if (pmu->selectable) len++; @@ -1715,32 +1683,15 @@ void print_pmu_events(const char *event_glob, bool = name_only, bool quiet_flag, pmu =3D NULL; j =3D 0; while ((pmu =3D perf_pmu__scan(pmu)) !=3D NULL) { - bool is_cpu; + bool is_cpu =3D is_pmu_core(pmu->name) || perf_pmu__is_hybrid(pmu->name); =20 - if (pmu_name && pmu->name && strcmp(pmu_name, pmu->name)) - continue; - - is_cpu =3D is_pmu_core(pmu->name) || perf_pmu__is_hybrid(pmu->name); - - list_for_each_entry(alias, &pmu->aliases, list) { - if (alias->deprecated && !deprecated) - continue; - - if (event_glob !=3D NULL && - !(strglobmatch_nocase(alias->name, event_glob) || - (!is_cpu && - strglobmatch_nocase(alias->name, event_glob)) || - (alias->topic && - strglobmatch_nocase(alias->topic, event_glob)))) - continue; - - aliases[j].event =3D alias; + list_for_each_entry(event, &pmu->aliases, list) { + aliases[j].event =3D event; aliases[j].pmu =3D pmu; aliases[j].is_cpu =3D is_cpu; j++; } - if (pmu->selectable && - (event_glob =3D=3D NULL || strglobmatch(pmu->name, event_glob))) { + if (pmu->selectable) { aliases[j].event =3D NULL; aliases[j].pmu =3D pmu; aliases[j].is_cpu =3D is_cpu; @@ -1750,7 +1701,12 @@ void print_pmu_events(const char *event_glob, bool n= ame_only, bool quiet_flag, len =3D j; qsort(aliases, len, sizeof(struct sevent), cmp_sevent); for (j =3D 0; j < len; j++) { - char *name, *desc; + const char *name, *alias =3D NULL, *scale_unit =3D NULL, + *desc =3D NULL, *long_desc =3D NULL, + *encoding_desc =3D NULL, *topic =3D NULL, + *metric_name =3D NULL, *metric_expr =3D NULL; + bool deprecated =3D false; + size_t buf_used; =20 /* Skip duplicates */ if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1])) @@ -1758,48 +1714,51 @@ void print_pmu_events(const char *event_glob, bool = name_only, bool quiet_flag, =20 if (!aliases[j].event) { /* A selectable event. */ - snprintf(buf, sizeof(buf), "%s//", aliases[j].pmu->name); + buf_used =3D snprintf(buf, sizeof(buf), "%s//", aliases[j].pmu->name) += 1; name =3D buf; - } else if (aliases[j].event->desc) { - name =3D aliases[j].event->name; } else { - if (!name_only && aliases[j].is_cpu) { - name =3D format_alias_or(buf, sizeof(buf), aliases[j].pmu, - aliases[j].event); + if (aliases[j].event->desc) { + name =3D aliases[j].event->name; + buf_used =3D 0; } else { name =3D format_alias(buf, sizeof(buf), aliases[j].pmu, aliases[j].event); + if (aliases[j].is_cpu) { + alias =3D name; + name =3D aliases[j].event->name; + } + buf_used =3D strlen(buf) + 1; } - } - if (name_only) { - printf("%s ", name); - continue; - } - printed++; - if (!aliases[j].event || !aliases[j].event->desc || quiet_flag) { - printf(" %-50s [Kernel PMU event]\n", name); - continue; - } - if (numdesc++ =3D=3D 0) - printf("\n"); - if (aliases[j].event->topic && (!topic || - strcmp(topic, aliases[j].event->topic))) { - printf("%s%s:\n", topic ? "\n" : "", aliases[j].event->topic); + if (strlen(aliases[j].event->unit) || aliases[j].event->scale !=3D 1.0)= { + scale_unit =3D buf + buf_used; + buf_used +=3D snprintf(buf + buf_used, sizeof(buf) - buf_used, + "%G%s", aliases[j].event->scale, + aliases[j].event->unit) + 1; + } + desc =3D aliases[j].event->desc; + long_desc =3D aliases[j].event->long_desc; topic =3D aliases[j].event->topic; + encoding_desc =3D buf + buf_used; + buf_used +=3D snprintf(buf + buf_used, sizeof(buf) - buf_used, + "%s/%s/", aliases[j].pmu->name, + aliases[j].event->str) + 1; + metric_name =3D aliases[j].event->metric_name; + metric_expr =3D aliases[j].event->metric_expr; + deprecated =3D aliases[j].event->deprecated; } - printf(" %-50s\n", name); - printf("%*s", 8, "["); - desc =3D long_desc ? aliases[j].event->long_desc : aliases[j].event->des= c; - wordwrap(desc, 8, columns, 0); - printf("]\n"); - if (details_flag) { - printf("%*s%s/%s/ ", 8, "", aliases[j].pmu->name, aliases[j].event->str= ); - if (aliases[j].event->metric_name) - printf(" MetricName: %s", aliases[j].event->metric_name); - if (aliases[j].event->metric_expr) - printf(" MetricExpr: %s", aliases[j].event->metric_expr); - putchar('\n'); - } + print_cb->print_event(print_state, + aliases[j].pmu->name, + topic, + name, + alias, + scale_unit, + deprecated, + "Kernel PMU event", + desc, + long_desc, + encoding_desc, + metric_name, + metric_expr); } if (printed && pager_in_use()) printf("\n"); diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index ee02e1ef9187..69ca0004f94f 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -12,6 +12,7 @@ =20 struct evsel_config_term; struct perf_cpu_map; +struct print_callbacks; =20 enum { PERF_PMU_FORMAT_VALUE_CONFIG, @@ -225,9 +226,7 @@ void perf_pmu__del_formats(struct list_head *formats); struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); =20 bool is_pmu_core(const char *name); -void print_pmu_events(const char *event_glob, bool name_only, bool quiet, - bool long_desc, bool details_flag, - bool deprecated, const char *pmu_name); +void print_pmu_events(const struct print_callbacks *print_cb, void *print_= state); bool pmu_have_event(const char *pname, const char *name); =20 int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char= *fmt, ...) __scanf(3, 4); diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c index d53dba033597..5210a168d54f 100644 --- a/tools/perf/util/print-events.c +++ b/tools/perf/util/print-events.c @@ -28,6 +28,7 @@ =20 #define MAX_NAME_LEN 100 =20 +/** Strings corresponding to enum perf_type_id. */ static const char * const event_type_descriptors[] =3D { "Hardware event", "Software event", @@ -55,11 +56,9 @@ static const struct event_symbol event_symbols_tool[PERF= _TOOL_MAX] =3D { /* * Print the events from /tracing/events */ -void print_tracepoint_events(const char *subsys_glob, - const char *event_glob, bool name_only) +void print_tracepoint_events(const struct print_callbacks *print_cb, void = *print_state) { struct dirent **sys_namelist =3D NULL; - bool printed =3D false; int sys_items =3D tracing_events__scandir_alphasort(&sys_namelist); =20 for (int i =3D 0; i < sys_items; i++) { @@ -73,10 +72,6 @@ void print_tracepoint_events(const char *subsys_glob, !strcmp(sys_dirent->d_name, "..")) continue; =20 - if (subsys_glob !=3D NULL && - !strglobmatch(sys_dirent->d_name, subsys_glob)) - continue; - dir_path =3D get_events_file(sys_dirent->d_name); if (!dir_path) continue; @@ -94,41 +89,41 @@ void print_tracepoint_events(const char *subsys_glob, if (tp_event_has_id(dir_path, evt_dirent) !=3D 0) continue; =20 - if (event_glob !=3D NULL && - !strglobmatch(evt_dirent->d_name, event_glob)) - continue; - snprintf(evt_path, MAXPATHLEN, "%s:%s", sys_dirent->d_name, evt_dirent->d_name); - if (name_only) - printf("%s ", evt_path); - else { - printf(" %-50s [%s]\n", evt_path, - event_type_descriptors[PERF_TYPE_TRACEPOINT]); - } - printed =3D true; + print_cb->print_event(print_state, + /*topic=3D*/NULL, + /*pmu_name=3D*/NULL, + evt_path, + /*event_alias=3D*/NULL, + /*scale_unit=3D*/NULL, + /*deprecated=3D*/false, + "Tracepoint event", + /*desc=3D*/NULL, + /*long_desc=3D*/NULL, + /*encoding_desc=3D*/NULL, + /*metric_name=3D*/NULL, + /*metric_expr=3D*/NULL); } free(dir_path); free(evt_namelist); } free(sys_namelist); - if (printed && pager_in_use()) - printf("\n"); } =20 -void print_sdt_events(const char *subsys_glob, const char *event_glob, - bool name_only) +void print_sdt_events(const struct print_callbacks *print_cb, void *print_= state) { - struct probe_cache *pcache; - struct probe_cache_entry *ent; struct strlist *bidlist, *sdtlist; - struct strlist_config cfg =3D {.dont_dupstr =3D true}; - struct str_node *nd, *nd2; - char *buf, *path, *ptr =3D NULL; - bool show_detail =3D false; - int ret; - - sdtlist =3D strlist__new(NULL, &cfg); + struct str_node *bid_nd, *sdt_name, *next_sdt_name; + const char *last_sdt_name =3D NULL; + + /* + * The implicitly sorted sdtlist will hold the tracepoint name followed + * by @. If the tracepoint name is unique (determined by + * looking at the adjacent nodes) the @ is dropped otherwise + * the executable path and buildid are added to the name. + */ + sdtlist =3D strlist__new(NULL, NULL); if (!sdtlist) { pr_debug("Failed to allocate new strlist for SDT\n"); return; @@ -138,65 +133,77 @@ void print_sdt_events(const char *subsys_glob, const = char *event_glob, pr_debug("Failed to get buildids: %d\n", errno); return; } - strlist__for_each_entry(nd, bidlist) { - pcache =3D probe_cache__new(nd->s, NULL); + strlist__for_each_entry(bid_nd, bidlist) { + struct probe_cache *pcache; + struct probe_cache_entry *ent; + + pcache =3D probe_cache__new(bid_nd->s, NULL); if (!pcache) continue; list_for_each_entry(ent, &pcache->entries, node) { - if (!ent->sdt) - continue; - if (subsys_glob && - !strglobmatch(ent->pev.group, subsys_glob)) - continue; - if (event_glob && - !strglobmatch(ent->pev.event, event_glob)) - continue; - ret =3D asprintf(&buf, "%s:%s@%s", ent->pev.group, - ent->pev.event, nd->s); - if (ret > 0) - strlist__add(sdtlist, buf); + char buf[1024]; + + snprintf(buf, sizeof(buf), "%s:%s@%s", + ent->pev.group, ent->pev.event, bid_nd->s); + strlist__add(sdtlist, buf); } probe_cache__delete(pcache); } strlist__delete(bidlist); =20 - strlist__for_each_entry(nd, sdtlist) { - buf =3D strchr(nd->s, '@'); - if (buf) - *(buf++) =3D '\0'; - if (name_only) { - printf("%s ", nd->s); - continue; - } - nd2 =3D strlist__next(nd); - if (nd2) { - ptr =3D strchr(nd2->s, '@'); - if (ptr) - *ptr =3D '\0'; - if (strcmp(nd->s, nd2->s) =3D=3D 0) - show_detail =3D true; + strlist__for_each_entry(sdt_name, sdtlist) { + bool show_detail =3D false; + char *bid =3D strchr(sdt_name->s, '@'); + char *evt_name =3D NULL; + + if (bid) + *(bid++) =3D '\0'; + + if (last_sdt_name && !strcmp(last_sdt_name, sdt_name->s)) { + show_detail =3D true; + } else { + next_sdt_name =3D strlist__next(sdt_name); + if (next_sdt_name) { + char *bid2 =3D strchr(next_sdt_name->s, '@'); + + if (bid2) + *bid2 =3D '\0'; + if (strcmp(sdt_name->s, next_sdt_name->s) =3D=3D 0) + show_detail =3D true; + if (bid2) + *bid2 =3D '@'; + } } + last_sdt_name =3D sdt_name->s; + if (show_detail) { - path =3D build_id_cache__origname(buf); - ret =3D asprintf(&buf, "%s@%s(%.12s)", nd->s, path, buf); - if (ret > 0) { - printf(" %-50s [%s]\n", buf, "SDT event"); - free(buf); + char *path =3D build_id_cache__origname(bid); + + if (path) { + asprintf(&evt_name, "%s@%s(%.12s)", sdt_name->s, path, bid); + free(path); } - free(path); - } else - printf(" %-50s [%s]\n", nd->s, "SDT event"); - if (nd2) { - if (strcmp(nd->s, nd2->s) !=3D 0) - show_detail =3D false; - if (ptr) - *ptr =3D '@'; } + print_cb->print_event(print_state, + /*topic=3D*/NULL, + /*pmu_name=3D*/NULL, + evt_name ?: sdt_name->s, + /*event_alias=3D*/NULL, + /*deprecated=3D*/false, + /*scale_unit=3D*/NULL, + "SDT event", + /*desc=3D*/NULL, + /*long_desc=3D*/NULL, + /*encoding_desc=3D*/NULL, + /*metric_name=3D*/NULL, + /*metric_expr=3D*/NULL); + + free(evt_name); } strlist__delete(sdtlist); } =20 -int print_hwcache_events(const char *event_glob, bool name_only) +int print_hwcache_events(const struct print_callbacks *print_cb, void *pri= nt_state) { struct strlist *evt_name_list =3D strlist__new(NULL, NULL); struct str_node *nd; @@ -216,9 +223,6 @@ int print_hwcache_events(const char *event_glob, bool n= ame_only) char name[64]; =20 __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name)); - if (event_glob !=3D NULL && !strglobmatch(name, event_glob)) - continue; - if (!perf_pmu__has_hybrid()) { if (is_event_supported(PERF_TYPE_HW_CACHE, type | (op << 8) | (i << 16))) @@ -240,55 +244,47 @@ int print_hwcache_events(const char *event_glob, bool= name_only) } =20 strlist__for_each_entry(nd, evt_name_list) { - if (name_only) { - printf("%s ", nd->s); - continue; - } - printf(" %-50s [%s]\n", nd->s, event_type_descriptors[PERF_TYPE_HW_CACH= E]); + print_cb->print_event(print_state, + "cache", + /*pmu_name=3D*/NULL, + nd->s, + /*event_alias=3D*/NULL, + /*scale_unit=3D*/NULL, + /*deprecated=3D*/false, + event_type_descriptors[PERF_TYPE_HW_CACHE], + /*desc=3D*/NULL, + /*long_desc=3D*/NULL, + /*encoding_desc=3D*/NULL, + /*metric_name=3D*/NULL, + /*metric_expr=3D*/NULL); } - if (!strlist__empty(evt_name_list) && pager_in_use()) - printf("\n"); - strlist__delete(evt_name_list); return 0; } =20 -static void print_tool_event(const struct event_symbol *syms, const char *= event_glob, - bool name_only) -{ - if (syms->symbol =3D=3D NULL) - return; - - if (event_glob && !(strglobmatch(syms->symbol, event_glob) || - (syms->alias && strglobmatch(syms->alias, event_glob)))) - return; - - if (name_only) - printf("%s ", syms->symbol); - else { - char name[MAX_NAME_LEN]; - - if (syms->alias && strlen(syms->alias)) - snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); - else - strlcpy(name, syms->symbol, MAX_NAME_LEN); - printf(" %-50s [%s]\n", name, "Tool event"); - } -} - -void print_tool_events(const char *event_glob, bool name_only) +void print_tool_events(const struct print_callbacks *print_cb, void *print= _state) { // Start at 1 because the first enum entry means no tool event. - for (int i =3D 1; i < PERF_TOOL_MAX; ++i) - print_tool_event(event_symbols_tool + i, event_glob, name_only); - - if (pager_in_use()) - printf("\n"); + for (int i =3D 1; i < PERF_TOOL_MAX; ++i) { + print_cb->print_event(print_state, + "tool", + /*pmu_name=3D*/NULL, + event_symbols_tool[i].symbol, + event_symbols_tool[i].alias, + /*scale_unit=3D*/NULL, + /*deprecated=3D*/false, + "Tool event", + /*desc=3D*/NULL, + /*long_desc=3D*/NULL, + /*encoding_desc=3D*/NULL, + /*metric_name=3D*/NULL, + /*metric_expr=3D*/NULL); + } } =20 -void print_symbol_events(const char *event_glob, unsigned int type, - struct event_symbol *syms, unsigned int max, - bool name_only) +void print_symbol_events(const struct print_callbacks *print_cb, void *pri= nt_state, + unsigned int type, const struct event_symbol *syms, + unsigned int max) { struct strlist *evt_name_list =3D strlist__new(NULL, NULL); struct str_node *nd; @@ -305,10 +301,6 @@ void print_symbol_events(const char *event_glob, unsig= ned int type, if (syms[i].symbol =3D=3D NULL) continue; =20 - if (event_glob !=3D NULL && !(strglobmatch(syms[i].symbol, event_glob) || - (syms[i].alias && strglobmatch(syms[i].alias, event_glob)))) - continue; - if (!is_event_supported(type, i)) continue; =20 @@ -322,63 +314,92 @@ void print_symbol_events(const char *event_glob, unsi= gned int type, } =20 strlist__for_each_entry(nd, evt_name_list) { - if (name_only) { - printf("%s ", nd->s); - continue; + char *alias =3D strstr(nd->s, " OR "); + + if (alias) { + *alias =3D '\0'; + alias +=3D 4; } - printf(" %-50s [%s]\n", nd->s, event_type_descriptors[type]); + print_cb->print_event(print_state, + /*topic=3D*/NULL, + /*pmu_name=3D*/NULL, + nd->s, + alias, + /*scale_unit=3D*/NULL, + /*deprecated=3D*/false, + event_type_descriptors[type], + /*desc=3D*/NULL, + /*long_desc=3D*/NULL, + /*encoding_desc=3D*/NULL, + /*metric_name=3D*/NULL, + /*metric_expr=3D*/NULL); } - if (!strlist__empty(evt_name_list) && pager_in_use()) - printf("\n"); - strlist__delete(evt_name_list); } =20 /* * Print the help text for the event symbols: */ -void print_events(const char *event_glob, bool name_only, bool quiet_flag, - bool long_desc, bool details_flag, bool deprecated, - const char *pmu_name) +void print_events(const struct print_callbacks *print_cb, void *print_stat= e) { - print_symbol_events(event_glob, PERF_TYPE_HARDWARE, - event_symbols_hw, PERF_COUNT_HW_MAX, name_only); - - print_symbol_events(event_glob, PERF_TYPE_SOFTWARE, - event_symbols_sw, PERF_COUNT_SW_MAX, name_only); - print_tool_events(event_glob, name_only); - - print_hwcache_events(event_glob, name_only); - - print_pmu_events(event_glob, name_only, quiet_flag, long_desc, - details_flag, deprecated, pmu_name); - - if (event_glob !=3D NULL) - return; - - if (!name_only) { - printf(" %-50s [%s]\n", - "rNNN", - event_type_descriptors[PERF_TYPE_RAW]); - printf(" %-50s [%s]\n", - "cpu/t1=3Dv1[,t2=3Dv2,t3 ...]/modifier", - event_type_descriptors[PERF_TYPE_RAW]); - if (pager_in_use()) - printf(" (see 'man perf-list' on how to encode it)\n\n"); - - printf(" %-50s [%s]\n", - "mem:[/len][:access]", - event_type_descriptors[PERF_TYPE_BREAKPOINT]); - if (pager_in_use()) - printf("\n"); - } - - print_tracepoint_events(NULL, NULL, name_only); - - print_sdt_events(NULL, NULL, name_only); - - metricgroup__print(true, true, NULL, name_only, details_flag, - pmu_name); - - print_libpfm_events(name_only, long_desc); + print_symbol_events(print_cb, print_state, PERF_TYPE_HARDWARE, + event_symbols_hw, PERF_COUNT_HW_MAX); + print_symbol_events(print_cb, print_state, PERF_TYPE_SOFTWARE, + event_symbols_sw, PERF_COUNT_SW_MAX); + + print_tool_events(print_cb, print_state); + + print_hwcache_events(print_cb, print_state); + + print_pmu_events(print_cb, print_state); + + print_cb->print_event(print_state, + /*topic=3D*/NULL, + /*pmu_name=3D*/NULL, + "rNNN", + /*event_alias=3D*/NULL, + /*scale_unit=3D*/NULL, + /*deprecated=3D*/false, + event_type_descriptors[PERF_TYPE_RAW], + /*desc=3D*/NULL, + /*long_desc=3D*/NULL, + /*encoding_desc=3D*/NULL, + /*metric_name=3D*/NULL, + /*metric_expr=3D*/NULL); + + print_cb->print_event(print_state, + /*topic=3D*/NULL, + /*pmu_name=3D*/NULL, + "cpu/t1=3Dv1[,t2=3Dv2,t3 ...]/modifier", + /*event_alias=3D*/NULL, + /*scale_unit=3D*/NULL, + /*deprecated=3D*/false, + event_type_descriptors[PERF_TYPE_RAW], + "(see 'man perf-list' on how to encode it)", + /*long_desc=3D*/NULL, + /*encoding_desc=3D*/NULL, + /*metric_name=3D*/NULL, + /*metric_expr=3D*/NULL); + + print_cb->print_event(print_state, + /*topic=3D*/NULL, + /*pmu_name=3D*/NULL, + "mem:[/len][:access]", + /*scale_unit=3D*/NULL, + /*event_alias=3D*/NULL, + /*deprecated=3D*/false, + event_type_descriptors[PERF_TYPE_BREAKPOINT], + /*desc=3D*/NULL, + /*long_desc=3D*/NULL, + /*encoding_desc=3D*/NULL, + /*metric_name=3D*/NULL, + /*metric_expr=3D*/NULL); + + print_tracepoint_events(print_cb, print_state); + + print_sdt_events(print_cb, print_state); + + metricgroup__print(print_cb, print_state); + + print_libpfm_events(print_cb, print_state); } diff --git a/tools/perf/util/print-events.h b/tools/perf/util/print-events.h index 1da9910d83a6..c237e53c4487 100644 --- a/tools/perf/util/print-events.h +++ b/tools/perf/util/print-events.h @@ -2,21 +2,39 @@ #ifndef __PERF_PRINT_EVENTS_H #define __PERF_PRINT_EVENTS_H =20 +#include #include =20 struct event_symbol; =20 -void print_events(const char *event_glob, bool name_only, bool quiet_flag, - bool long_desc, bool details_flag, bool deprecated, - const char *pmu_name); -int print_hwcache_events(const char *event_glob, bool name_only); -void print_sdt_events(const char *subsys_glob, const char *event_glob, - bool name_only); -void print_symbol_events(const char *event_glob, unsigned int type, - struct event_symbol *syms, unsigned int max, - bool name_only); -void print_tool_events(const char *event_glob, bool name_only); -void print_tracepoint_events(const char *subsys_glob, const char *event_gl= ob, - bool name_only); +struct print_callbacks { + void (*print_start)(void *print_state); + void (*print_end)(void *print_state); + void (*print_event)(void *print_state, const char *topic, + const char *pmu_name, + const char *event_name, const char *event_alias, + const char *scale_unit, + bool deprecated, const char *event_type_desc, + const char *desc, const char *long_desc, + const char *encoding_desc, + const char *metric_name, const char *metric_expr); + void (*print_metric)(void *print_state, + const char *group, + const char *name, + const char *desc, + const char *long_desc, + const char *expr, + const char *unit); +}; + +/** Print all events, the default when no options are specified. */ +void print_events(const struct print_callbacks *print_cb, void *print_stat= e); +int print_hwcache_events(const struct print_callbacks *print_cb, void *pri= nt_state); +void print_sdt_events(const struct print_callbacks *print_cb, void *print_= state); +void print_symbol_events(const struct print_callbacks *print_cb, void *pri= nt_state, + unsigned int type, const struct event_symbol *syms, + unsigned int max); +void print_tool_events(const struct print_callbacks *print_cb, void *print= _state); +void print_tracepoint_events(const struct print_callbacks *print_cb, void = *print_state); =20 #endif /* __PERF_PRINT_EVENTS_H */ --=20 2.38.1.431.g37b22c650d-goog From nobody Mon Apr 13 14:26:57 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 0BA76C433FE for ; Mon, 14 Nov 2022 21:09:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237610AbiKNVJq (ORCPT ); Mon, 14 Nov 2022 16:09:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45702 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237556AbiKNVJU (ORCPT ); Mon, 14 Nov 2022 16:09:20 -0500 Received: from mail-pf1-x44a.google.com (mail-pf1-x44a.google.com [IPv6:2607:f8b0:4864:20::44a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 38AE7F01C for ; Mon, 14 Nov 2022 13:09:18 -0800 (PST) Received: by mail-pf1-x44a.google.com with SMTP id cw4-20020a056a00450400b00561ec04e77aso6671790pfb.12 for ; Mon, 14 Nov 2022 13:09:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=EZnzM6HV3BgbBycTCsM2gbe0FFNFRdGwj//bA/m+O8Y=; b=eRkzWvFLUemkH6BcT+JLRuVOTwZY5HaqVQUVJsjop2oOPdRwgcYwOc/2o/EKY762K8 qJEDKBgHgRZNp6e81MxqPjSwZ3cqHtmmycDj4l+YJygUhBmEJRWOp+mex2uTmAQVLrh9 9kJByM4oXQ+gWZbXdrLfgKi8PRgNRLqwqOHnNGmWtocEyisQdy71kqAl2WQcF8XGoIxY hVSeb0iQ5Wf4nw9cZoH9yfx/d4DI6pIwrO61Jk4qrRvzARYP+G4BR8I5UVJAg2FgOxye zX11sBlS+/Ba3XsqQliSus04XyHVjvVwkuMquby/mQt6fXfYixf2mTuNpUqCP4L4HB0Q 125A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=EZnzM6HV3BgbBycTCsM2gbe0FFNFRdGwj//bA/m+O8Y=; b=V5mTXaG4qP+ksRBfcva3i7HLrfzTqX4T0RCeM2RFtoKHg9NxlJx1a465+bSwhX6qYW QCUn9NoXbVzbTLdOrRKgNTT3dOl/kz4SGHHvoyw6edB0x+N4bAvMFpJBE4Et/AcCA13E LRArOJS3MJz1Ni9UPrRsspYUOvXXcrEnTpurGL3qOJpYI7fB7pNnLqU8Opue38GbcQLd lPNL/1VHY3yfsS+Y9FP3KVcJC1q6yhv5mYMScsrw+rFJMxcLjOyXCGYb7vwbBI+bfmmU HfG0rO/N2AVKxhsb9ETNeEKVW4HlmjiX99pYBwfnC13L2cherWmgigBgZm/CFXnjV928 5THg== X-Gm-Message-State: ANoB5pm4MzVFCnEZmmKccfNG7PfMBmG46X0+wE11xKXl1haXLqeKNCkp BtoF3QA43CcMbcGIyaMl3wQi42jgp5zm X-Google-Smtp-Source: AA0mqf7tqo7a1oMDS2CUc5SH8zur9ItiylG+U9LZh0MyrGN4/zypb6UhLcBYL9L9w/PaHAt9qLzeaaNlv7qB X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:553:438f:b86a:87f]) (user=irogers job=sendgmr) by 2002:a62:6446:0:b0:565:c122:b63 with SMTP id y67-20020a626446000000b00565c1220b63mr14979790pfb.49.1668460157676; Mon, 14 Nov 2022 13:09:17 -0800 (PST) Date: Mon, 14 Nov 2022 13:07:23 -0800 In-Reply-To: <20221114210723.2749751-1-irogers@google.com> Message-Id: <20221114210723.2749751-11-irogers@google.com> Mime-Version: 1.0 References: <20221114210723.2749751-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v3 10/10] perf list: Add json output option From: Ian Rogers To: Weilin Wang , Perry Taylor , Caleb Biggers , Leo Yan , Adrian Hunter , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Sandipan Das , Kajol Jain , Zhengjun Xing , Kan Liang , Ravi Bangoria , Xin Gao , Rob Herring , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org Cc: Stephane Eranian , Ian Rogers Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Output events and metrics in a json format by overriding the print callbacks. Currently other command line options aren't supported and metrics are repeated once per metric group. Signed-off-by: Ian Rogers --- tools/perf/Documentation/perf-list.txt | 4 + tools/perf/builtin-list.c | 294 ++++++++++++++++++++----- 2 files changed, 240 insertions(+), 58 deletions(-) diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentat= ion/perf-list.txt index 44a819af573d..43263ca88ff7 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -43,6 +43,10 @@ Print deprecated events. By default the deprecated event= s are hidden. Print PMU events and metrics limited to the specific PMU name. (e.g. --unit cpu, --unit msr, --unit cpu_core, --unit cpu_atom) =20 +-j:: +--json:: +Output in json format. + [[EVENT_MODIFIERS]] EVENT MODIFIERS --------------- diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index 12811fc40a30..aec139f7fbb2 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -19,6 +19,7 @@ #include "util/strlist.h" #include #include +#include #include =20 /** @@ -228,10 +229,176 @@ static void default_print_metric(void *ps, } } =20 +struct json_print_state { + /** Should a separator be printed prior to the next item? */ + bool need_sep; +}; + +static void json_print_start(void *print_state __maybe_unused) +{ + printf("[\n"); +} + +static void json_print_end(void *ps) +{ + struct json_print_state *print_state =3D ps; + + printf("%s]\n", print_state->need_sep ? "\n" : ""); +} + +static void fix_escape_printf(const char *fmt, ...) +{ + va_list args; + char buf[2048]; + size_t buf_pos =3D 0; + + va_start(args, fmt); + for (size_t fmt_pos =3D 0; fmt_pos < strlen(fmt); fmt_pos++) { + switch (fmt[fmt_pos]) { + case '%': { + const char *s =3D va_arg(args, const char*); + + fmt_pos++; + assert(fmt[fmt_pos] =3D=3D 's'); + for (size_t s_pos =3D 0; s_pos < strlen(s); s_pos++) { + switch (s[s_pos]) { + case '\\': + __fallthrough; + case '\"': + buf[buf_pos++] =3D '\\'; + assert(buf_pos < sizeof(buf)); + __fallthrough; + default: + buf[buf_pos++] =3D s[s_pos]; + assert(buf_pos < sizeof(buf)); + break; + } + } + break; + } + default: + buf[buf_pos++] =3D fmt[fmt_pos]; + assert(buf_pos < sizeof(buf)); + break; + } + } + va_end(args); + buf[buf_pos] =3D '\0'; + fputs(buf, stdout); +} + +static void json_print_event(void *ps, const char *pmu_name, const char *t= opic, + const char *event_name, const char *event_alias, + const char *scale_unit, + bool deprecated, const char *event_type_desc, + const char *desc, const char *long_desc, + const char *encoding_desc, + const char *metric_name, const char *metric_expr) +{ + struct json_print_state *print_state =3D ps; + bool need_sep =3D false; + + printf("%s{\n", print_state->need_sep ? ",\n" : ""); + print_state->need_sep =3D true; + if (pmu_name) { + fix_escape_printf("\t\"Unit\": \"%s\"", pmu_name); + need_sep =3D true; + } + if (topic) { + fix_escape_printf("%s\t\"Topic\": \"%s\"", need_sep ? ",\n" : "", topic); + need_sep =3D true; + } + if (event_name) { + fix_escape_printf("%s\t\"EventName\": \"%s\"", need_sep ? ",\n" : "", ev= ent_name); + need_sep =3D true; + } + if (event_alias && strlen(event_alias)) { + fix_escape_printf("%s\t\"EventAlias\": \"%s\"", need_sep ? ",\n" : "", e= vent_alias); + need_sep =3D true; + } + if (scale_unit && strlen(scale_unit)) { + fix_escape_printf("%s\t\"ScaleUnit\": \"%s\"", need_sep ? ",\n" : "", + scale_unit); + need_sep =3D true; + } + if (event_type_desc) { + fix_escape_printf("%s\t\"EventType\": \"%s\"", need_sep ? ",\n" : "", + event_type_desc); + need_sep =3D true; + } + if (deprecated) { + fix_escape_printf("%s\t\"Deprecated\": \"%s\"", need_sep ? ",\n" : "", + deprecated ? "1" : "0"); + need_sep =3D true; + } + if (desc) { + fix_escape_printf("%s\t\"BriefDescription\": \"%s\"", need_sep ? ",\n" := "", desc); + need_sep =3D true; + } + if (long_desc) { + fix_escape_printf("%s\t\"PublicDescription\": \"%s\"", need_sep ? ",\n" = : "", + long_desc); + need_sep =3D true; + } + if (encoding_desc) { + fix_escape_printf("%s\t\"Encoding\": \"%s\"", need_sep ? ",\n" : "", enc= oding_desc); + need_sep =3D true; + } + if (metric_name) { + fix_escape_printf("%s\t\"MetricName\": \"%s\"", need_sep ? ",\n" : "", m= etric_name); + need_sep =3D true; + } + if (metric_expr) { + fix_escape_printf("%s\t\"MetricExpr\": \"%s\"", need_sep ? ",\n" : "", m= etric_expr); + need_sep =3D true; + } + printf("%s}", need_sep ? "\n" : ""); +} + +static void json_print_metric(void *ps __maybe_unused, const char *group, + const char *name, const char *desc, + const char *long_desc, const char *expr, + const char *unit) +{ + struct json_print_state *print_state =3D ps; + bool need_sep =3D false; + + printf("%s{\n", print_state->need_sep ? ",\n" : ""); + print_state->need_sep =3D true; + if (group) { + fix_escape_printf("\t\"MetricGroup\": \"%s\"", group); + need_sep =3D true; + } + if (name) { + fix_escape_printf("%s\t\"MetricName\": \"%s\"", need_sep ? ",\n" : "", n= ame); + need_sep =3D true; + } + if (expr) { + fix_escape_printf("%s\t\"MetricExpr\": \"%s\"", need_sep ? ",\n" : "", e= xpr); + need_sep =3D true; + } + if (unit) { + fix_escape_printf("%s\t\"ScaleUnit\": \"%s\"", need_sep ? ",\n" : "", un= it); + need_sep =3D true; + } + if (desc) { + fix_escape_printf("%s\t\"BriefDescription\": \"%s\"", need_sep ? ",\n" := "", desc); + need_sep =3D true; + } + if (long_desc) { + fix_escape_printf("%s\t\"PublicDescription\": \"%s\"", need_sep ? ",\n" = : "", + long_desc); + need_sep =3D true; + } + printf("%s}", need_sep ? "\n" : ""); +} + int cmd_list(int argc, const char **argv) { int i, ret =3D 0; - struct print_state ps =3D {}; + struct print_state default_ps =3D {}; + struct print_state json_ps =3D {}; + void *ps =3D &default_ps; struct print_callbacks print_cb =3D { .print_start =3D default_print_start, .print_end =3D default_print_end, @@ -240,15 +407,17 @@ int cmd_list(int argc, const char **argv) }; const char *hybrid_name =3D NULL; const char *unit_name =3D NULL; + bool json =3D false; struct option list_options[] =3D { - OPT_BOOLEAN(0, "raw-dump", &ps.name_only, "Dump raw events"), - OPT_BOOLEAN('d', "desc", &ps.desc, + OPT_BOOLEAN(0, "raw-dump", &default_ps.name_only, "Dump raw events"), + OPT_BOOLEAN('j', "json", &json, "JSON encode events and metrics"), + OPT_BOOLEAN('d', "desc", &default_ps.desc, "Print extra event descriptions. --no-desc to not print."), - OPT_BOOLEAN('v', "long-desc", &ps.long_desc, + OPT_BOOLEAN('v', "long-desc", &default_ps.long_desc, "Print longer event descriptions."), - OPT_BOOLEAN(0, "details", &ps.detailed, + OPT_BOOLEAN(0, "details", &default_ps.detailed, "Print information on the perf event names and expressions used int= ernally by events."), - OPT_BOOLEAN(0, "deprecated", &ps.deprecated, + OPT_BOOLEAN(0, "deprecated", &default_ps.deprecated, "Print deprecated events."), OPT_STRING(0, "cputype", &hybrid_name, "hybrid cpu type", "Limit PMU or metric printing to the given hybrid PMU (e.g. core or = atom)."), @@ -272,28 +441,37 @@ int cmd_list(int argc, const char **argv) =20 setup_pager(); =20 - if (!ps.name_only) + if (!default_ps.name_only) setup_pager(); =20 - ps.desc =3D !ps.long_desc; - ps.last_topic =3D strdup(""); - assert(ps.last_topic); - ps.visited_metrics =3D strlist__new(NULL, NULL); - assert(ps.visited_metrics); - if (unit_name) - ps.pmu_glob =3D strdup(unit_name); - else if (hybrid_name) { - ps.pmu_glob =3D perf_pmu__hybrid_type_to_pmu(hybrid_name); - if (!ps.pmu_glob) - pr_warning("WARNING: hybrid cputype is not supported!\n"); + if (json) { + print_cb =3D (struct print_callbacks){ + .print_start =3D json_print_start, + .print_end =3D json_print_end, + .print_event =3D json_print_event, + .print_metric =3D json_print_metric, + }; + ps =3D &json_ps; + } else { + default_ps.desc =3D !default_ps.long_desc; + default_ps.last_topic =3D strdup(""); + assert(default_ps.last_topic); + default_ps.visited_metrics =3D strlist__new(NULL, NULL); + assert(default_ps.visited_metrics); + if (unit_name) + default_ps.pmu_glob =3D strdup(unit_name); + else if (hybrid_name) { + default_ps.pmu_glob =3D perf_pmu__hybrid_type_to_pmu(hybrid_name); + if (!default_ps.pmu_glob) + pr_warning("WARNING: hybrid cputype is not supported!\n"); + } } - print_cb.print_start(&ps); =20 if (argc =3D=3D 0) { - ps.metrics =3D true; - ps.metricgroups =3D true; - print_events(&print_cb, &ps); + default_ps.metrics =3D true; + default_ps.metricgroups =3D true; + print_events(&print_cb, ps); goto out; } =20 @@ -301,32 +479,32 @@ int cmd_list(int argc, const char **argv) char *sep, *s; =20 if (strcmp(argv[i], "tracepoint") =3D=3D 0) - print_tracepoint_events(&print_cb, &ps); + print_tracepoint_events(&print_cb, ps); else if (strcmp(argv[i], "hw") =3D=3D 0 || strcmp(argv[i], "hardware") =3D=3D 0) - print_symbol_events(&print_cb, &ps, PERF_TYPE_HARDWARE, + print_symbol_events(&print_cb, ps, PERF_TYPE_HARDWARE, event_symbols_hw, PERF_COUNT_HW_MAX); else if (strcmp(argv[i], "sw") =3D=3D 0 || strcmp(argv[i], "software") =3D=3D 0) { - print_symbol_events(&print_cb, &ps, PERF_TYPE_SOFTWARE, + print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE, event_symbols_sw, PERF_COUNT_SW_MAX); - print_tool_events(&print_cb, &ps); + print_tool_events(&print_cb, ps); } else if (strcmp(argv[i], "cache") =3D=3D 0 || strcmp(argv[i], "hwcache") =3D=3D 0) - print_hwcache_events(&print_cb, &ps); + print_hwcache_events(&print_cb, ps); else if (strcmp(argv[i], "pmu") =3D=3D 0) - print_pmu_events(&print_cb, &ps); + print_pmu_events(&print_cb, ps); else if (strcmp(argv[i], "sdt") =3D=3D 0) - print_sdt_events(&print_cb, &ps); + print_sdt_events(&print_cb, ps); else if (strcmp(argv[i], "metric") =3D=3D 0 || strcmp(argv[i], "metrics"= ) =3D=3D 0) { - ps.metricgroups =3D false; - ps.metrics =3D true; - metricgroup__print(&print_cb, &ps); + default_ps.metricgroups =3D false; + default_ps.metrics =3D true; + metricgroup__print(&print_cb, ps); } else if (strcmp(argv[i], "metricgroup") =3D=3D 0 || strcmp(argv[i], "metricgroups") =3D=3D 0) { - ps.metricgroups =3D true; - ps.metrics =3D false; - metricgroup__print(&print_cb, &ps); + default_ps.metricgroups =3D true; + default_ps.metrics =3D false; + metricgroup__print(&print_cb, ps); } else if ((sep =3D strchr(argv[i], ':')) !=3D NULL) { int sep_idx; =20 @@ -338,41 +516,41 @@ int cmd_list(int argc, const char **argv) } =20 s[sep_idx] =3D '\0'; - ps.pmu_glob =3D s; - ps.event_glob =3D s + sep_idx + 1; - print_tracepoint_events(&print_cb, &ps); - print_sdt_events(&print_cb, &ps); - ps.metrics =3D true; - ps.metricgroups =3D true; - metricgroup__print(&print_cb, &ps); + default_ps.pmu_glob =3D s; + default_ps.event_glob =3D s + sep_idx + 1; + print_tracepoint_events(&print_cb, ps); + print_sdt_events(&print_cb, ps); + default_ps.metrics =3D true; + default_ps.metricgroups =3D true; + metricgroup__print(&print_cb, ps); free(s); } else { if (asprintf(&s, "*%s*", argv[i]) < 0) { printf("Critical: Not enough memory! Trying to continue...\n"); continue; } - ps.event_glob =3D s; - print_symbol_events(&print_cb, &ps, PERF_TYPE_HARDWARE, + default_ps.event_glob =3D s; + print_symbol_events(&print_cb, ps, PERF_TYPE_HARDWARE, event_symbols_hw, PERF_COUNT_HW_MAX); - print_symbol_events(&print_cb, &ps, PERF_TYPE_SOFTWARE, + print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE, event_symbols_sw, PERF_COUNT_SW_MAX); - print_tool_events(&print_cb, &ps); - print_hwcache_events(&print_cb, &ps); - print_pmu_events(&print_cb, &ps); - print_tracepoint_events(&print_cb, &ps); - print_sdt_events(&print_cb, &ps); - ps.metrics =3D true; - ps.metricgroups =3D true; - metricgroup__print(&print_cb, &ps); + print_tool_events(&print_cb, ps); + print_hwcache_events(&print_cb, ps); + print_pmu_events(&print_cb, ps); + print_tracepoint_events(&print_cb, ps); + print_sdt_events(&print_cb, ps); + default_ps.metrics =3D true; + default_ps.metricgroups =3D true; + metricgroup__print(&print_cb, ps); free(s); } } =20 out: - print_cb.print_end(&ps); - free(ps.pmu_glob); - free(ps.last_topic); - free(ps.last_metricgroups); - strlist__delete(ps.visited_metrics); + print_cb.print_end(ps); + free(default_ps.pmu_glob); + free(default_ps.last_topic); + free(default_ps.last_metricgroups); + strlist__delete(default_ps.visited_metrics); return ret; } --=20 2.38.1.431.g37b22c650d-goog