From nobody Mon Apr 13 14:27:12 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 E1643C4332F for ; Mon, 14 Nov 2022 07:52:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236042AbiKNHwK (ORCPT ); Mon, 14 Nov 2022 02:52:10 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44810 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236046AbiKNHvz (ORCPT ); Mon, 14 Nov 2022 02:51: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 999E21929D for ; Sun, 13 Nov 2022 23:51:54 -0800 (PST) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-37010fefe48so99354327b3.19 for ; Sun, 13 Nov 2022 23:51:54 -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=kfq7MOLKAIqDxqx4rLeUrwOnMwpKcW1Ol+sZHsc45dM=; b=MA1qCyfua+1dcVUN8bEXa2QfV9Eq8wlr3ZBvzLA/YEztRzgbvLXyBUQCStCfD2ynyt QqiEBTdTZxgUeGYH810tRqUiYSJ0A1TKMm4yhdXq8cTEfdJZsPWZhKMs7CVVA5XgUiXU nWGDxXDau5E093ERmkGLQ24TejdoUyHrpdVKlquPSrsH7dBeMKMn0caqdWOEqZyq9EER q87bSLyYJShFle6WbZL+0ai17FVM4oyibX+5bm0o+YQaQpt8YyOJvO+x3q23NEoHYPIl YkSwF4WugbGOuPZdOUk6/h9O3e5kWy/iLt8uihIKGhjxD5I5Ez1D8Veo5Z9k3Q/vT1Iz MKDA== 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=kfq7MOLKAIqDxqx4rLeUrwOnMwpKcW1Ol+sZHsc45dM=; b=vNtnpRziq11oWspf0KXHHdslIBgnFHMz7Im4mrF/aN1TbRhQB+JPIsrv7zk3sb/PNN /+5mYr3Hl3I6wy3sJaWnZHkgFM7es/1+G1QsyMwN2XwDF8rKwrAyH64LxhnU1sWzkdHN Y1ewvOM6rS11r+LG4SajhiVRW9FHa6d0sepZ0SE9ye9mqDatdhKZRsXtIX57Q0xPTAhl SIjSpX1THd7amFofy0oqgAyVHNJa1VSPmES6lyPdezhfENNob70FIZSTx2qwiUtJvN9W /d259uOCxh13ssaMJn0W/832wXSMIw8LEwG9FQEaUSudB2nPe1E/0+Rsv/t805jm6deb diLg== X-Gm-Message-State: ANoB5pmjV77lPz/m1Fu90kJgnSXd2TDY2C2RBC3yZkayi0f8/qj4pmTE csnuWQq0Nh16vg9j6/aEqmzBoJMRUx+q X-Google-Smtp-Source: AA0mqf7JwK+fWKCbE5LGrxgMLJrvuuIzw20afLOew1pWQJVeZdcIVET0GmnVaLWd3lZ4b1us9Je+mqKGa8pD X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:cba6:8279:98e6:3d6e]) (user=irogers job=sendgmr) by 2002:a25:7347:0:b0:6d4:84c5:8549 with SMTP id o68-20020a257347000000b006d484c58549mr11313671ybc.376.1668412313851; Sun, 13 Nov 2022 23:51:53 -0800 (PST) Date: Sun, 13 Nov 2022 23:51:19 -0800 In-Reply-To: <20221114075127.2650315-1-irogers@google.com> Message-Id: <20221114075127.2650315-2-irogers@google.com> Mime-Version: 1.0 References: <20221114075127.2650315-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v1 1/9] 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 | 14 ++++++ tools/perf/util/pmu.h | 105 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 113 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 6a86e6af0903..a8f9f47c6ed9 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -31,10 +31,24 @@ =20 struct perf_pmu perf_pmu__fake; =20 +/** + * 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 repres= ented + * here as name=3D"event", value=3DPERF_PMU_FORMAT_VALUE_CONFIG and bits 0= to 7 will + * be set. + */ struct perf_pmu_format { + /** The modifier/file name. */ char *name; + /** + * 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; + /** Which config bits are set by this format value. */ DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); + /** 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 68e15c38ae71..29571c0f9d15 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -34,30 +34,91 @@ struct perf_pmu_caps { }; =20 struct perf_pmu { + /** The name of the PMU such as "cpu". */ char *name; + /** + * Optional alternate name for the PMU determined in architecture + * specific code. + */ char *alias_name; + /** + * Optional PMU identifier read from + * /bus/event_source/devices//identifier. + */ char *id; + /** + * Perf event attributed type value, read from + * /bus/event_source/devices//type. + */ __u32 type; + /** + * Can the PMU name be selected as if it were an event? + */ bool selectable; + /** + * Is the PMU not within the CPU core? Determined by the presence of + * /bus/event_source/devices//cpumask. + */ bool is_uncore; + /** Is the PMU name either cpu_core or cpu_atom. */ bool is_hybrid; + /** + * Are events auxiliary events? Determined in architecture specific + * code. + */ bool auxtrace; + /** + * Number of levels of :ppp precision supported by the PMU, read from + * /bus/event_source/devices//caps/max_precise. + */ int max_precise; + /** + * Optional default perf_event_attr determined in architecture specific + * code. + */ struct perf_event_attr *default_config; + /** + * 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 */ + /** + * 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; + /** + * 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; + /** Has the list caps been initialized? */ bool caps_initialized; + /** The length of the list caps. */ u32 nr_caps; - struct list_head caps; /* HEAD struct perf_pmu_caps -> list */ - struct list_head list; /* ELEM */ + /** + * 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; + /** Element on pmus list in pmu.c. */ + struct list_head list; + /** Element on perf_pmu__hybrid_pmus. */ struct list_head hybrid_list; =20 + /** Features to inhibit when events on this PMU are opened. */ struct { + /** Disables perf_event_attr exclude_guest and exclude_host. */ bool exclude_guest; } missing_features; }; =20 +/** A special global PMU used for testing. */ extern struct perf_pmu perf_pmu__fake; =20 struct perf_pmu_info { @@ -71,21 +132,53 @@ struct perf_pmu_info { =20 #define UNIT_MAX_LEN 31 /* max length for event unit name */ =20 +/** + * An event either read from sysfs or builtin in pmu-events.c, created by + * parsing the pmu-events json files. + */ struct perf_pmu_alias { char *name; + /** Optional short description of the event. */ char *desc; + /** Optional long description. */ char *long_desc; + /** + * Optional topic such as cache or pipeline, particularly for json + * events. + */ char *topic; + /** Comma separated parameter list. */ char *str; - struct list_head terms; /* HEAD struct parse_events_term -> list */ - struct list_head list; /* ELEM */ + /** Owned list of the original parsed parameters. */ + struct list_head terms; + /** List element of struct perf_pmu aliases. */ + struct list_head list; + /** Units for the event, such as bytes or cache lines. */ char unit[UNIT_MAX_LEN+1]; + /** Value to scale read counter values by. */ double scale; + /** + * Does the file + * /bus/event_source/devices//events/.per-pkg or + * equivalent json value exist and have the value 1. + */ bool per_pkg; + /** + * Does the file + * /bus/event_source/devices//events/.snapshot + * exist and have the value 1. + */ bool snapshot; + /** Is the event hidden and so not shown in perf list by default. */ bool deprecated; + /** + * A metric expression associated with an event. Doing this makes little + * sense due to scale and unit applying to both. + */ char *metric_expr; + /** A name for the metric. unit applying to both. */ char *metric_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:27:12 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 62C82C4332F for ; Mon, 14 Nov 2022 07:52:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236070AbiKNHwO (ORCPT ); Mon, 14 Nov 2022 02:52:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44810 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236110AbiKNHwF (ORCPT ); Mon, 14 Nov 2022 02:52:05 -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 782C718E2A for ; Sun, 13 Nov 2022 23:52:04 -0800 (PST) Received: by mail-yb1-xb4a.google.com with SMTP id h4-20020a5b02c4000000b006bc192d672bso9924412ybp.22 for ; Sun, 13 Nov 2022 23:52:04 -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=skjOcOVezhkNivzHdrlRJj9IRahl3h/VWNzo5hRIj2w30ZYRyRGjfWfsWLvsahiBzK TEnJ+26u6RFvrOCPo6OV4bihXGHHzAipuVWws+yB7a4NEACFZI2Q7dDlqmu6HYAIy1qa wONNR/kCNcjucqXIUpHaLv9wK4bY35su0XQUfN7U9WQ+x8e928GvxlpsO5S2ov3m23Ol v/2UXAyYNW+8yapyGvQjg93m7nzrSIKO6RzlOF7n76/SmP0tzX5F1rVsUv66I7RR1YO1 Y8bepBwfBkh3DS1sysq3x/XdOVR5mjE1mk/l/VQBJRmu6SYD+rnIKXEwOmli8N9iqYWT Wa/Q== 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=Nyqay2SP1sx5z8WWab7bX/ERhdYpDUcpBmoUlC/aG4/nEJ4lwB7pMJRIUDlNmHAezR r1rdLIgsxkiSI4s35rLKSoC0DvUM4bqbc3Y6aVRk5Tqjq68NB320PS1Euku5ZS8yrd84 CT8V0ScGX1zb/eJ5e/okoXyGg5rlpQUFyr7beUU17/gP9XWpnkjT52b4S4W02wxJvBJN sGslF8Ar4tGoDedihNhlzAYmVnPXt5LcqyVXq8rKiTFFZj7MyYYq896uJ73BhXLy8YBi gFwPEA91IDX6COdU5uMlkqv89qvmQm64t+AQTqcTdZvdvKOWFp8xgv+IlWiORqto7qpC Mtvg== X-Gm-Message-State: ANoB5plOF7D9KK/HcgoZG5fyABnkhGY4jQp8OIUKcaeuWF3rac4AUswA EeFCJ/hngAjkgxepYxF41OuIkVrR0j1X X-Google-Smtp-Source: AA0mqf7WN3Yxf6tqN8xl9/ktJuMPykKkIqFppU42Xdn3/s9U2LduWEUC6QQNBKgNDSup0fpzwljf+fEXGQe9 X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:cba6:8279:98e6:3d6e]) (user=irogers job=sendgmr) by 2002:a81:61d7:0:b0:383:e534:3a7a with SMTP id v206-20020a8161d7000000b00383e5343a7amr0ywb.24.1668412323327; Sun, 13 Nov 2022 23:52:03 -0800 (PST) Date: Sun, 13 Nov 2022 23:51:20 -0800 In-Reply-To: <20221114075127.2650315-1-irogers@google.com> Message-Id: <20221114075127.2650315-3-irogers@google.com> Mime-Version: 1.0 References: <20221114075127.2650315-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v1 2/9] 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:27:12 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 A23AAC433FE for ; Mon, 14 Nov 2022 07:52:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235741AbiKNHw3 (ORCPT ); Mon, 14 Nov 2022 02:52:29 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45264 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236080AbiKNHwU (ORCPT ); Mon, 14 Nov 2022 02:52:20 -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 714E519297 for ; Sun, 13 Nov 2022 23:52:16 -0800 (PST) Received: by mail-yb1-xb4a.google.com with SMTP id h67-20020a252146000000b006ccc4702068so9855587ybh.12 for ; Sun, 13 Nov 2022 23:52:16 -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=CSUl/cD/WDzvyy7/gVUJxkLFomwzeS2nfA2va4W4NOvQegNB7iMnKzJhKFfJpEj0XS Yi3vAR5g5YbGcWE3BONv9feINe2WcX8c2NFXbZNEMPrx+45SI/gJp6X4t6vh//8PnT6n dE5Q6xxF1+8mEwQ370g22QepR6tznIJLx5XI8y2pLhkGx+t33L0CB+H8QXI0vu6DKsC0 DPzogliilSztWZGhb7C88kERACUOPi8sr9nM/q++dJ+iPOhx3b65FNgRjZto52bU8P9K F2J7g25KWkIcP+YMEiSZJGWvDqxXDMsYIAGhIgKNCzEWMfKqjgpg9sENyPY0L+7/nT+d sCmQ== 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=lIL+4fZg73nHoCzLEou3PFezb0pCoLZlOrCTqC7jgZ8LlOAOodn7/KeVTk2opTMpSM KYDRan7Jl61O6cRGtvaKvdM+7tuoGIk8GSpOLnd4q9cSIgDM+spxdZigk5CSLjdfKJrY o4G7w/jgBVy2ZS/IlndiRe2q8awdb+EZmP+KPzbNm1kpC6Wnq9XVRm8SExsqkfN67Po8 a0JwzDrcEAi9hvOj7+D3SB7gOUrIOHG+fl3D4JCBOoUxxlswPhn6WgGjcqNHfYaaDWji 6AA+nDRxIQ+2DD5c2m1yCN6OJ1NjSnMjQj7JyTJhiG/ppD+7QXnaqjdVPoDoGKEWWlwh oEeA== X-Gm-Message-State: ACrzQf3q993mzNO2dFKgkONHhwvLBXPKVQr+4TZ8dLgtebWCT937cEEU tG0XFLS2DASWHZ0Z+R29Mn1V0nevFBC1 X-Google-Smtp-Source: AMsMyM5JWY5Cagk3ev3ZTGWwFhYDrZbIwwHb/UZnn/RNqDB2WORgxG4dVfMFdU+Fkruz/OQNdmpNsqNDR3KX X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:cba6:8279:98e6:3d6e]) (user=irogers job=sendgmr) by 2002:a0d:eac3:0:b0:36a:dfbf:3ee0 with SMTP id t186-20020a0deac3000000b0036adfbf3ee0mr64843865ywe.451.1668412334840; Sun, 13 Nov 2022 23:52:14 -0800 (PST) Date: Sun, 13 Nov 2022 23:51:21 -0800 In-Reply-To: <20221114075127.2650315-1-irogers@google.com> Message-Id: <20221114075127.2650315-4-irogers@google.com> Mime-Version: 1.0 References: <20221114075127.2650315-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v1 3/9] 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:27:12 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 81F63C433FE for ; Mon, 14 Nov 2022 07:52:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235811AbiKNHwt (ORCPT ); Mon, 14 Nov 2022 02:52:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45832 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235893AbiKNHwe (ORCPT ); Mon, 14 Nov 2022 02:52:34 -0500 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C4491192BD for ; Sun, 13 Nov 2022 23:52:26 -0800 (PST) Received: by mail-yb1-xb49.google.com with SMTP id t5-20020a5b07c5000000b006dfa2102debso4423102ybq.4 for ; Sun, 13 Nov 2022 23:52:26 -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=Rl5NpkjPzTE4Fls6Plwx5I6VTiNxD2kr5kHqIS0Pzx4=; b=XqSweAfbUuRwICXIEsBeKYZgc/LZnmTQ0jtybP/LAJRBtvNF8yizWk+du66+43CYAB 70Wgy4NzWRXDr0jfMtDjaRHxCjP4yFrs4WKPOvp1HcGBc0g+8uXlSxEKjBg1c0c4kReJ AcHw7AwS1ocCNsFNrNbrvxgkILE9yXqtP1byzrPNavv2mhY25kLKt/UFQSksaUyGsJbe bMn3dJjhi+oFn/6p77bSuXHQYhHVr3srtwHYOIHWDUvCEu5mzrF+VVacpvX+mPHokLk6 KE2hj2mJLHDTa5bMUwl7+kCgGPjfPgC7Po3yE/BsN/oTYMraNoOQ8Mcht3sMHZ/XD9dd lqYQ== 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=Rl5NpkjPzTE4Fls6Plwx5I6VTiNxD2kr5kHqIS0Pzx4=; b=Y4fyHGFm/8adZ+9GLEWleApLualbElzxZ2yFZS/tjJurACnhIyPvXAAWkJ2spePanF lC0vG42lTvm9PaKiWmmND3LsXZokZWyLO1P5nDFpTI/UzlFlaDv0UvpfesRUd6Ao4UG8 UrUx9BDk3ifeJhf8plNIZahWG4wTNKQln51pQelTO2gUJYSMzz0B0bV5beGsHUFW1AFu /ChKFqW4srdugzBAZ5GFu2cZ+C5LYH4AbxkLJESI+GqJmcvKVC1xhXHxmz2rNrHAfCd5 Fihf28iCr99aeaaCovNms7vYe9JZ8e+MrWfF7w5kYqbscCVvYOUeKIhAXnj52ueC9qyE q5tA== X-Gm-Message-State: ANoB5pmK+CoLe5msKpB/ZRQ4S01eJBVpk3mHQsK2EONQb0lisKEwT+GO 2nurH68ez8dfph5d2t2dXZZ7ttJ8/N8k X-Google-Smtp-Source: AA0mqf79aD0/uo7D00ZVL1Io9KSSYcuptA4m3js37yU+UiYYLhONp0PF+ZQPwA4uT8IS1JFObFuy0zZUn87H X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:cba6:8279:98e6:3d6e]) (user=irogers job=sendgmr) by 2002:a81:3804:0:b0:370:7cf2:9c5a with SMTP id f4-20020a813804000000b003707cf29c5amr12143856ywa.211.1668412346044; Sun, 13 Nov 2022 23:52:26 -0800 (PST) Date: Sun, 13 Nov 2022 23:51:22 -0800 In-Reply-To: <20221114075127.2650315-1-irogers@google.com> Message-Id: <20221114075127.2650315-5-irogers@google.com> Mime-Version: 1.0 References: <20221114075127.2650315-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v1 4/9] 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 a8f9f47c6ed9..9c771f136b81 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1694,10 +1694,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:27:12 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 57F94C43217 for ; Mon, 14 Nov 2022 07:53:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236054AbiKNHw7 (ORCPT ); Mon, 14 Nov 2022 02:52:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45336 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235760AbiKNHwj (ORCPT ); Mon, 14 Nov 2022 02:52:39 -0500 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5DEF91902C for ; Sun, 13 Nov 2022 23:52:35 -0800 (PST) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-3697bd55974so98780377b3.15 for ; Sun, 13 Nov 2022 23:52:35 -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=T0jkusDStyZ5/LfkNXjH/BXHbYl87NUVAuai8Eb9QK+OjW9SzYud+mHfaAgyfrg49J ae8S2lWcCKQFdHcgjmOUDbBG/MIQrsnTZTfKKBMAUn639i9VKnbjpDoprEhOnH5hg41K pYshKmLqGxMEwyoCjjq0Koph/XSqa2aMS6vA/fY5ZLH2v23JH7hItMbqKk/EfCH7n9tg 8PcP2aL0Za63hIZ8UZFMqmlgd6p1UBpfg5r/dZNN7inw1DThRx4uIGo6hjPUx0PN/yIY u2uwbeI9IPmakOKA41aErduofz3wpJY7gSwcr4C5NaibG3IEppDWDkmgoDErpwc2eJKG E3Ww== 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=S/Q9apHTFJ4R1e+/zRoVNw/6Fc+ba3zk7oRdJbQZNJiXl+Q++RCcRofoORRzbm2E2g nA+bwYbqL1+rjj7/b7RgkW7G+KMK+vmG8bxmLQK4/HmsLc5dr0mEbgUwRn6UxcLDoPma Xw6CECi/PvdNeCyDIhqrjLC2I9nWzow8UW25E9kg1roSJW/VbPf4lAVrdak2/68IiW4G CEwxzRvTN3LtXxOUhXvl84SvGDax02+Woy0Yzy5IMNnQQ1rnm1uSg4h9dK3NWZbbvsge fcmUw18aEtROocc1OOCZvTE1bo9GkzAwI/dAPLEH9JnYLL1WCz0mfBKUlCbZrzffCwz7 p4Dw== X-Gm-Message-State: ANoB5plLWwYyAaUGOSG1gn2EcjrDi/hqLaXjhgKP9IOqTLkYMwRQT9kJ e1Af5FEk0ci4IiZnvMjhcJnwTHEI7nIe X-Google-Smtp-Source: AA0mqf7QLzKGbOAI8epex2XRhwy0tz6GIzt4i1Wu+eMqIfn0DEkrm5R2V0TyMrzQyKUWiUfPsBgt1T+rEfqN X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:cba6:8279:98e6:3d6e]) (user=irogers job=sendgmr) by 2002:a0d:c485:0:b0:36e:92cf:58a2 with SMTP id g127-20020a0dc485000000b0036e92cf58a2mr12033456ywd.504.1668412354663; Sun, 13 Nov 2022 23:52:34 -0800 (PST) Date: Sun, 13 Nov 2022 23:51:23 -0800 In-Reply-To: <20221114075127.2650315-1-irogers@google.com> Message-Id: <20221114075127.2650315-6-irogers@google.com> Mime-Version: 1.0 References: <20221114075127.2650315-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v1 5/9] 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:27:12 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 BF68FC433FE for ; Mon, 14 Nov 2022 07:53:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236090AbiKNHxK (ORCPT ); Mon, 14 Nov 2022 02:53:10 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45570 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236099AbiKNHwt (ORCPT ); Mon, 14 Nov 2022 02:52:49 -0500 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3CA9719C28 for ; Sun, 13 Nov 2022 23:52:45 -0800 (PST) Received: by mail-yb1-xb49.google.com with SMTP id e8-20020a5b0cc8000000b006bca0fa3ab6so9790169ybr.0 for ; Sun, 13 Nov 2022 23:52:45 -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=lZg8XR9rikMPVUaFqH/pduhN9NiqpmRBLJZPpTe2SkaCZZo9Qs/Hp/RFLCAp+mFkx9 lGuvUrwFTHlGZVfm2+G3HqL9/POx1pN3vv90zCejS2/nyihHFSaGyNfTMFnDKGQScODi IXWwCxxlDC6sVqn5lXwCYbIoBKwiLJbZt4FgxUpXjfo4ez5sZG/uI919jUZBoYP6tlTh 1QJm1kAw8xF8wg4+9qQE29f1a6EemftrmcfUv8v0xwGRUsijsRo8XcCXX8IhYuqTsp+f rNKtmYdkvUc/zYmSkJenNFWeVbykk/cWU5DjSmGtkoH2ECbul3q+2Ojn5X4f8P3Bl7Fz kcow== 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=pyVEfNJBIGywp6U6b4dzErQ7DA263qU27gqpcAAlFlksO7Vb2Hy8bOUSk78k5TgcCk VP9l1XqSznPe7kotmYXT9LupgS8e+LytdaULaggWtakwgua1pQ3GYFzLqnLLrtflNlnw QqodXM7qs6FO1BwHMlaFDhV53/gT1ank1lyJmH63dPpLomY6iltQOFVK3MuYxlzaI1LA 4uyYP8hrNDEOoJjmu73tiHa06GFddHOf6RDFhbk3YocknNjIuSiklUZH6XTLfbNsEqEL 1FNy1lB/mTQNoz4oD4EWJ5AwSXAkr2hutyCDw6oxLEDCjIen0KnDXGf1IfwCtpjtOJDI 1jvg== X-Gm-Message-State: ANoB5pmrMlrAjVRUriDLCPEjX7fODCyR424fqqI3XnloPLJBMDCi7eia DhZd5G9vQw77L/06FwppBs2e+m15OJD+ X-Google-Smtp-Source: AA0mqf57AZUJUVhHtCp40peKGAKFZ94n72xGc6XyQ0CA4X0cDyG4nIWE8vcK24czX4WgLAV/MywlhtRc8aMe X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:cba6:8279:98e6:3d6e]) (user=irogers job=sendgmr) by 2002:a25:320e:0:b0:6d1:a39d:637 with SMTP id y14-20020a25320e000000b006d1a39d0637mr11858110yby.335.1668412364529; Sun, 13 Nov 2022 23:52:44 -0800 (PST) Date: Sun, 13 Nov 2022 23:51:24 -0800 In-Reply-To: <20221114075127.2650315-1-irogers@google.com> Message-Id: <20221114075127.2650315-7-irogers@google.com> Mime-Version: 1.0 References: <20221114075127.2650315-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v1 6/9] 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:27:12 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 899C3C4332F for ; Mon, 14 Nov 2022 07:53:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235790AbiKNHxO (ORCPT ); Mon, 14 Nov 2022 02:53:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45492 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236103AbiKNHw5 (ORCPT ); Mon, 14 Nov 2022 02:52:57 -0500 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F2449192B9 for ; Sun, 13 Nov 2022 23:52:55 -0800 (PST) Received: by mail-yb1-xb49.google.com with SMTP id o2-20020a5b0502000000b006cade5e7c07so9898813ybp.10 for ; Sun, 13 Nov 2022 23:52:55 -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=lTIHSMroaHgB/iMQ3IvinP/fljLnemrJKwp3rOoSeAs=; b=KyT0SnrmMbJyp+ALYoXvpui2u47FKZCPPFG7HcEtUJ1he5eLAItPfBQsWEVZsFkY76 l2TprOg3tRYYUfBjZP5ZkKy5GX0NWMaY0kcrRbhQeV3cJj1hJOoCAM7EemXdcb5oPEFI d5LaFIVgHZEB7B50W8Xfy70975gh9A5v0+MVr8FGe6I49yC9Kg0zuEvF8ihnwgcKSOnH rvvLiWfSpNwU30/wx/rQu3X2/O6Xv6oEkpS6uqidjJjA2TQHOHLI2LyWiu3+bndSTMYA VqErpCGGC8W1RKFPpZs2F2Xg/jcXeVFLUzIliNRMqVnDKHVJacWgc9UfhNyHl5N0zW7U OCPg== 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=lTIHSMroaHgB/iMQ3IvinP/fljLnemrJKwp3rOoSeAs=; b=ZX8eL+YplZK+Zwd1UlsSulI+T36+kmYT4JC6Qf2Sl60KeKBioKR4/G/rA6zjZvbRDQ BSXQ2wfUyR0dEXi5MP6LrxiQVBaHWVZ3iF/1+QzSC+fvGRxrRJ7tFNAs0Rssj3DvGLg4 bKNgYSqAklfPZdPosRbsRXCIQpn/MHruNoar1UUnN8PPxXQMdH6X23ls5GRLAz0riI/N Mp95meXXtQlfKDWyAVdgc6z1a8KjiZhrc0UpswELBW6hJ5t6pdwppQ3P5+j+XWqJ1jci o8U7utpy4Kbi6WXNV0TTWS6/GvWTJJ/RDXwKtjJ/iC1SGKeaTMSc0T3SgTRk5wQ4nOc2 asMg== X-Gm-Message-State: ACrzQf2HzfoCHGkRtvn6wmBbBbYExIv4E0HTA0fA5Ma8cv+Uiapsq3MR 7T+Img0G0ie6IHmK0xY/AQh/a25hlPfF X-Google-Smtp-Source: AMsMyM6TYmzNp2OlYaFfBsiynO+dL9+o7Ih96UUHiQMM/dSOWBICoqYQNmv7aKAa8/+RtfEXaFgDP53sfvHh X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:cba6:8279:98e6:3d6e]) (user=irogers job=sendgmr) by 2002:a05:6902:1352:b0:6bb:3f4b:9666 with SMTP id g18-20020a056902135200b006bb3f4b9666mr61574188ybu.101.1668412374640; Sun, 13 Nov 2022 23:52:54 -0800 (PST) Date: Sun, 13 Nov 2022 23:51:25 -0800 In-Reply-To: <20221114075127.2650315-1-irogers@google.com> Message-Id: <20221114075127.2650315-8-irogers@google.com> Mime-Version: 1.0 References: <20221114075127.2650315-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v1 7/9] 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 9c771f136b81..8322395c9cf7 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1552,8 +1552,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); @@ -1578,51 +1578,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) @@ -1654,16 +1670,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, @@ -1689,110 +1707,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) || pmu->is_hybrid; =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:27:12 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 455C4C433FE for ; Mon, 14 Nov 2022 07:53:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235724AbiKNHxa (ORCPT ); Mon, 14 Nov 2022 02:53:30 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45568 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236053AbiKNHxJ (ORCPT ); Mon, 14 Nov 2022 02:53:09 -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 D819D192BC for ; Sun, 13 Nov 2022 23:53:05 -0800 (PST) Received: by mail-yb1-xb4a.google.com with SMTP id e8-20020a5b0cc8000000b006bca0fa3ab6so9790776ybr.0 for ; Sun, 13 Nov 2022 23:53:05 -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=P7CdsK7LKGmaK29paCv9s5r815Q4tV1Nmy/lNeV4sxg=; b=eWZQIXxY73fPABNoV2qENjPke7AOayGeJD07h8nWq9f/2Bf4UyYwnnBZab/qmyknVh i4PjxUYaw7PBRWbgfGhISMNCdGx0Co7sj3SLembWQWvvsPaGndP132LJrBmkL6S4rDRc uA0mGBqLmdH1FLyjkD2pYVTp0B9FKB3jYW69PL79Vmu2XZLmqXDlw5+sgTIh0Tel9g6K 8+xAXyKlSN9NkdQvucx+9WN0Tfy+umxYmwA0wJgDEUObPxex23hAlSomsfVLbzSSTqrR mZIslosHxaa1GaCWLDXmdJ/yc7kZuos7YnmMpBC6bm4tJztnruZoDrJKgLd5g399v58D lHNw== 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=P7CdsK7LKGmaK29paCv9s5r815Q4tV1Nmy/lNeV4sxg=; b=E9sK65I89Dc01u+l2uq0iTgADZZi1X587mXEQR7O//aqmjOPbY2Yq46hWoh/y3ORq1 a4cIPMlvWwmKsczz27/7+vYwRL+Ms7BoQTrqAXNgILJ1crrL28s+gPezZsq0ySfJtvFE BPKI/QvCkKQVBp0BBS/eN8GBAPNVl3SaA5o3IVVk15vWnLghqAhEec2jY8jeZ0Nity67 oXrlds6r3aemaUPg2gqFvyg8Dl+Z7PI3tqLloCRrgHXkgPB4AB7ZAI6vhVaKrj/RzpRg 43avzbBBuFGRP6NmMsgC/ZGBmKFcqcOMpo02eHu2aZZ+y18Cf2TayoaEhUEkfCH2t17w 2bYA== X-Gm-Message-State: ANoB5pnpSDo1FOqWoN5hweX9Wl0nxgAfry1uZsCgZenjOc1xaPrnGOYw NhKSI57wKSsEoNx5aHyGWP10Yd5OMWJw X-Google-Smtp-Source: AA0mqf6XNMkvIuO/Xl03pMDPHJeay/bDsXGdGIUC/6U2/wE5RxZgXhk/80OwFT4XInEZ2vNqMjKnn6YUMCLF X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:cba6:8279:98e6:3d6e]) (user=irogers job=sendgmr) by 2002:a5b:886:0:b0:6cb:7ce0:9e8e with SMTP id e6-20020a5b0886000000b006cb7ce09e8emr11220659ybq.55.1668412385156; Sun, 13 Nov 2022 23:53:05 -0800 (PST) Date: Sun, 13 Nov 2022 23:51:26 -0800 In-Reply-To: <20221114075127.2650315-1-irogers@google.com> Message-Id: <20221114075127.2650315-9-irogers@google.com> Mime-Version: 1.0 References: <20221114075127.2650315-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v1 8/9] 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 | 320 ++++++++++++++++++++++++----- tools/perf/util/metricgroup.c | 239 ++++++---------------- tools/perf/util/metricgroup.h | 4 +- tools/perf/util/pmu.c | 137 ++++--------- tools/perf/util/pmu.h | 5 +- tools/perf/util/print-events.c | 355 +++++++++++++++++---------------- tools/perf/util/print-events.h | 40 ++-- 7 files changed, 588 insertions(+), 512 deletions(-) diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index cc84ced6da26..91e2b6f52548 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -15,31 +15,229 @@ #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 { + /** + * Optionally restrict PMU and metric matching to PMU or debugfs + * subsystem name. + */ + char *pmu_glob; + /** Optional pattern matching glob. */ + char *event_glob; + /** Print event or metric names only. */ + bool name_only; + /** Print the event or metric description. */ + bool desc; + /** Print longer event or metric description. */ + bool long_desc; + /** Print deprecated events or metrics. */ + bool deprecated; + /** + * Print extra information on the perf event such as names and + * expressions used internally by events. + */ + bool detailed; + bool metrics; + bool metricgroups; + char *last_topic; + char *last_metricgroups; + 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, + 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) +{ + 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 +261,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 +290,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 +327,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..4cb2a193c0f2 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,63 @@ static bool match_pe_metric(const struct pmu_event *p= e, const char *metric) match_metric(pe->metric_name, metric); } =20 +/** RB-tree node for building printing information. */ struct mep { struct rb_node nd; - const char *name; - struct strlist *metrics; + /** 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; }; =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 +417,36 @@ 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; } - - 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 +469,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) + if (!pe->metric_name) return 0; =20 - if (data->pmu_name && strcmp(data->pmu_name, pmu)) - return 0; - - 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 +496,30 @@ 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); 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 8322395c9cf7..b7a34dd28875 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" @@ -1578,13 +1579,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. */ @@ -1628,7 +1622,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 ?: ""; @@ -1641,27 +1635,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); @@ -1684,24 +1657,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++; @@ -1714,32 +1682,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) || pmu->is_hybrid; =20 - if (pmu_name && pmu->name && strcmp(pmu_name, pmu->name)) - continue; - - is_cpu =3D is_pmu_core(pmu->name) || pmu->is_hybrid; - - 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; @@ -1749,7 +1700,11 @@ 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, *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])) @@ -1757,48 +1712,44 @@ 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); + 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, + 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 29571c0f9d15..4f9b0202be2d 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, @@ -209,9 +210,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..9aa53e43bda0 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,40 @@ 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, + /*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 +132,76 @@ 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, + "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 +221,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 +242,45 @@ 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, + /*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, + /*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 +297,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 +310,88 @@ 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, + /*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, + /*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, + /*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]", + /*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..235c3e123079 100644 --- a/tools/perf/util/print-events.h +++ b/tools/perf/util/print-events.h @@ -2,21 +2,37 @@ #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, + 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); +}; + +/** 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:27:12 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 A152CC433FE for ; Mon, 14 Nov 2022 07:53:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236126AbiKNHxs (ORCPT ); Mon, 14 Nov 2022 02:53:48 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46898 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236077AbiKNHxQ (ORCPT ); Mon, 14 Nov 2022 02:53:16 -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 3BB79192B8 for ; Sun, 13 Nov 2022 23:53:15 -0800 (PST) Received: by mail-pg1-x54a.google.com with SMTP id f132-20020a636a8a000000b00473d0b600ebso5512795pgc.14 for ; Sun, 13 Nov 2022 23:53: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=nAX60ecFtxgT+PDunRPYKAFBfhjC2kUCNn7e5xMw2JM=; b=buGqKnielvJwFkIZh5KnRlsCoQyiK3G1y/CNoBamUlBH5JV/Cifos89LeN123Ozmac axidpKkzBNDMZ8jNK7z1suD0cOyTqRSvsrcCILT79EzFnqwxip2ae74Mlq8BrSo5jcwI ZHsi2k1DudB15Aq/+cBACKSzIpjYKCt1MZhizZtuANMRZQSjSFNX2kXH3V5nt/FghEj0 0WtRXgCbXKB+dwW9AxCJ/auGvTPBaEuNNNOgef9BYRY+5k6D1JQR5IzBwWEyJleInXvN jGjbQacFrVPHuduF3QhjeeQ5//PL3CFx/FQKlLU6I300gDhM/XAo/zWD9s/g4v+GNg2z qH1Q== 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=nAX60ecFtxgT+PDunRPYKAFBfhjC2kUCNn7e5xMw2JM=; b=ix7TlGg6BA4rmAxoE6jLS2NpG05Ms5fz+fGn8/+NJAOJJRh1BLsr8A/tdnW3KUe3v4 uwBz5G4EY31gSxRyu1Hewihhob7eiGAkBMmwHbjgPUFVj76G7cIrv9c+6M08o8WNmaSh EEpSFdsOZZp+NkcXlZDJmwXsE939KWzVmrpTCMVPzZMSLwacO2pRkLbfxY2iOi+ZHQJr SEd7U2UKV6m5qqbMTELzWTiZzie/xt5i1jcaB6eMgry8QQlWJ67QOIpyICojCcqCdBIn dv22YG//qSwYXsvjK5WPzaQBskxtt4q2Tww1Z6kCB7CCavf7sBbhstDbtBXcp1/oHIte Pnlg== X-Gm-Message-State: ANoB5pn52nA4SOEEbhWSugn/mJvAV3Fy29I3q4SYw6kUGHVbsQr8/fyM UPXxkRD0SILK+POmw2NmDEwoK+w2TobX X-Google-Smtp-Source: AA0mqf5LtZ/I3nyYUy9i7XP06eUtsBJJ2jH8YLuDJ+643JLOqdp4Fpwgv/Ycvqsz8UGnevFML5okx/OFKn5q X-Received: from irogers.svl.corp.google.com ([2620:15c:2d4:203:cba6:8279:98e6:3d6e]) (user=irogers job=sendgmr) by 2002:a62:442:0:b0:562:86a3:12fc with SMTP id 63-20020a620442000000b0056286a312fcmr13130193pfe.8.1668412394679; Sun, 13 Nov 2022 23:53:14 -0800 (PST) Date: Sun, 13 Nov 2022 23:51:27 -0800 In-Reply-To: <20221114075127.2650315-1-irogers@google.com> Message-Id: <20221114075127.2650315-10-irogers@google.com> Mime-Version: 1.0 References: <20221114075127.2650315-1-irogers@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Subject: [PATCH v1 9/9] 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 | 283 ++++++++++++++++++++----- 2 files changed, 229 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 91e2b6f52548..910b5c3a7365 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 struct print_state { @@ -217,10 +218,165 @@ 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, + 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 (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) +{ + 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 (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, @@ -229,15 +385,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)."), @@ -261,28 +419,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 @@ -290,32 +457,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 @@ -327,41 +494,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