From nobody Wed Dec 17 03:00:15 2025 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 D580BC7EE2C for ; Thu, 24 Aug 2023 04:14:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240025AbjHXEN7 (ORCPT ); Thu, 24 Aug 2023 00:13:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55314 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239891AbjHXENp (ORCPT ); Thu, 24 Aug 2023 00:13:45 -0400 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 D2D7D10C4 for ; Wed, 23 Aug 2023 21:13:41 -0700 (PDT) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-58daaa2ba65so81975777b3.1 for ; Wed, 23 Aug 2023 21:13:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1692850421; x=1693455221; h=to:from:subject:references:mime-version:message-id:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=t3FkZtk24eVZPBJL4lg4GGb1/7Xpt8aSUak5SLWJZY8=; b=jxbq6n1Y/JCOGfr3UmCU8NPdmHhY1AMklvN2ablxD/gVypqFbfrU2Wmz9JSoVqx274 08qCNC/fWLrfwHjAhM7qM2mks8Xn3oSEWSQVRoMIpkNIQjLdjCj6ywYlqRtq9RZ1Neb6 CZkyH9qe+9eBk8CYbT6BX7XRjlA+8l33dkaJUcjtGFkQ7jgA9bgSNB1oDfwUZ2dnZHy7 bcCnWu2OVGTEzBUexqKnx29Nb9UPjRivs/H6amKP6Iz5QWsjDZwopAT5gdA0yywaSz0m PCz8m8efa9GDsxNBOGjXGLGz6t1fZ4j0242wHPVpOkbfOLJMi63Fyo6ZFoNw7cD/BMPs LRXg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1692850421; x=1693455221; h=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=t3FkZtk24eVZPBJL4lg4GGb1/7Xpt8aSUak5SLWJZY8=; b=NMxw9GWwrITFEuuqTU1NrsoqllPCgMOxMGxy6yCuiPRF2P71sdUM/LA3YTc3uERFu6 lyIE0ACtMMWtZFSBmr8nl1Bf6epl1lrblleYv61PIiUlqm589nWYDjs/G6gKTBqHF9eD gs8SBI/cfMWVMHeAIwtW3rSTfNL+JMPNCW1p/cDvkHcGl2UApjnYU/u7n+XmNsANEjzQ xLPkeQvbswPS8/1oQURu1rnXsJ+BHoW5q67nnw8TMSCby+OV0K/WM6+bWPjN6GHCAXiX sVtS9f37Dr3juy9YmTOQLuimbQYuEBrPVCl2Ty3fb+afwOxLaPYeXC10lsXO9j2kQKfb 0SzQ== X-Gm-Message-State: AOJu0YzcqScfptky6Y75abHJD9fXxDpLwrimmOla2f5pdFtuccSB7VZg h7EaVVT+94TPHbwF/ERQYudqy11XrHeW X-Google-Smtp-Source: AGHT+IFELTbtRvGgeXP4JpFZSHqQbtQQqwBD1lLrRLrS2eUkBS3uzkr0/Aw9SNiqXJDafDgnqi+QQmZ6i9nc X-Received: from irogers.svl.corp.google.com ([2620:15c:2a3:200:fbb9:d9e7:7405:2651]) (user=irogers job=sendgmr) by 2002:a81:af16:0:b0:57a:793:7fb0 with SMTP id n22-20020a81af16000000b0057a07937fb0mr215495ywh.3.1692850421082; Wed, 23 Aug 2023 21:13:41 -0700 (PDT) Date: Wed, 23 Aug 2023 21:13:13 -0700 In-Reply-To: <20230824041330.266337-1-irogers@google.com> Message-Id: <20230824041330.266337-2-irogers@google.com> Mime-Version: 1.0 References: <20230824041330.266337-1-irogers@google.com> X-Mailer: git-send-email 2.42.0.rc1.204.g551eb34607-goog Subject: [PATCH v2 01/18] perf pmu: Make the loading of formats lazy From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Ian Rogers , Adrian Hunter , James Clark , Kan Liang , John Garry , Kajol Jain , Jing Zhang , Ravi Bangoria , Rob Herring , Gaosheng Cui , linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org 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 sysfs format files are loaded eagerly in a PMU. Add a flag so that we create the format but only load the contents when necessary. Reduce the size of the value in struct perf_pmu_format and avoid holes so there is no additional space requirement. For "perf stat -e cycles true" this reduces the number of openat calls from 648 to 573 (about 12%). The benchmark pmu scan speed is improved by roughly 5%. Before: $ perf bench internals pmu-scan Computing performance of sysfs PMU event scan for 100 times Average core PMU scanning took: 1061.100 usec (+- 9.965 usec) Average PMU scanning took: 4725.300 usec (+- 260.599 usec) After: $ perf bench internals pmu-scan Computing performance of sysfs PMU event scan for 100 times Average core PMU scanning took: 989.170 usec (+- 6.873 usec) Average PMU scanning took: 4520.960 usec (+- 251.272 usec) Signed-off-by: Ian Rogers --- tools/perf/tests/pmu.c | 2 +- tools/perf/util/pmu.c | 144 +++++++++++++++++++++++++++-------------- tools/perf/util/pmu.h | 5 +- tools/perf/util/pmu.y | 20 ++---- 4 files changed, 106 insertions(+), 65 deletions(-) diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c index 2c1c349a42e2..c204ed1f1a8b 100644 --- a/tools/perf/tests/pmu.c +++ b/tools/perf/tests/pmu.c @@ -171,7 +171,7 @@ static int test__pmu(struct test_suite *test __maybe_un= used, int subtest __maybe } =20 pmu->name =3D strdup("perf-pmu-test"); - ret =3D perf_pmu__format_parse(pmu, fd); + ret =3D perf_pmu__format_parse(pmu, fd, /*eager_load=3D*/true); if (ret) goto out; =20 diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 42f3249994ab..3cfd3e58da23 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -40,6 +40,10 @@ struct perf_pmu perf_pmu__fake; * value=3DPERF_PMU_FORMAT_VALUE_CONFIG and bits 0 to 7 will be set. */ struct perf_pmu_format { + /** @list: Element on list within struct perf_pmu. */ + struct list_head list; + /** @bits: Which config bits are set by this format value. */ + DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); /** @name: The modifier/file name. */ char *name; /** @@ -47,18 +51,79 @@ struct perf_pmu_format { * are from PERF_PMU_FORMAT_VALUE_CONFIG to * PERF_PMU_FORMAT_VALUE_CONFIG_END. */ - int value; - /** @bits: Which config bits are set by this format value. */ - DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); - /** @list: Element on list within struct perf_pmu. */ - struct list_head list; + u16 value; + /** @loaded: Has the contents been loaded/parsed. */ + bool loaded; }; =20 +static struct perf_pmu_format *perf_pmu__new_format(struct list_head *list= , char *name) +{ + struct perf_pmu_format *format; + + format =3D zalloc(sizeof(*format)); + if (!format) + return NULL; + + format->name =3D strdup(name); + if (!format->name) { + free(format); + return NULL; + } + list_add_tail(&format->list, list); + return format; +} + +/* Called at the end of parsing a format. */ +void perf_pmu_format__set_value(void *vformat, int config, unsigned long *= bits) +{ + struct perf_pmu_format *format =3D vformat; + + format->value =3D config; + memcpy(format->bits, bits, sizeof(format->bits)); +} + +static void __perf_pmu_format__load(struct perf_pmu_format *format, FILE *= file) +{ + void *scanner; + int ret; + + ret =3D perf_pmu_lex_init(&scanner); + if (ret) + return; + + perf_pmu_set_in(file, scanner); + ret =3D perf_pmu_parse(format, scanner); + perf_pmu_lex_destroy(scanner); + format->loaded =3D true; +} + +static void perf_pmu_format__load(struct perf_pmu *pmu, struct perf_pmu_fo= rmat *format) +{ + char path[PATH_MAX]; + FILE *file =3D NULL; + + if (format->loaded) + return; + + if (!perf_pmu__pathname_scnprintf(path, sizeof(path), pmu->name, "format"= )) + return; + + assert(strlen(path) + strlen(format->name) + 2 < sizeof(path)); + strcat(path, "/"); + strcat(path, format->name); + + file =3D fopen(path, "r"); + if (!file) + return; + __perf_pmu_format__load(format, file); + fclose(file); +} + /* * Parse & process all the sysfs attributes located under * the directory specified in 'dir' parameter. */ -int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd) +int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd, bool eager_loa= d) { struct dirent *evt_ent; DIR *format_dir; @@ -68,37 +133,35 @@ int perf_pmu__format_parse(struct perf_pmu *pmu, int d= irfd) if (!format_dir) return -EINVAL; =20 - while (!ret && (evt_ent =3D readdir(format_dir))) { + while ((evt_ent =3D readdir(format_dir)) !=3D NULL) { + struct perf_pmu_format *format; char *name =3D evt_ent->d_name; - int fd; - void *scanner; - FILE *file; =20 if (!strcmp(name, ".") || !strcmp(name, "..")) continue; =20 - - ret =3D -EINVAL; - fd =3D openat(dirfd, name, O_RDONLY); - if (fd < 0) - break; - - file =3D fdopen(fd, "r"); - if (!file) { - close(fd); + format =3D perf_pmu__new_format(&pmu->format, name); + if (!format) { + ret =3D -ENOMEM; break; } =20 - ret =3D perf_pmu_lex_init(&scanner); - if (ret) { + if (eager_load) { + FILE *file; + int fd =3D openat(dirfd, name, O_RDONLY); + + if (fd < 0) { + ret =3D -errno; + break; + } + file =3D fdopen(fd, "r"); + if (!file) { + close(fd); + break; + } + __perf_pmu_format__load(format, file); fclose(file); - break; } - - perf_pmu_set_in(file, scanner); - ret =3D perf_pmu_parse(&pmu->format, name, scanner); - perf_pmu_lex_destroy(scanner); - fclose(file); } =20 closedir(format_dir); @@ -119,7 +182,7 @@ static int pmu_format(struct perf_pmu *pmu, int dirfd, = const char *name) return 0; =20 /* it'll close the fd */ - if (perf_pmu__format_parse(pmu, fd)) + if (perf_pmu__format_parse(pmu, fd, /*eager_load=3D*/false)) return -1; =20 return 0; @@ -962,13 +1025,15 @@ void perf_pmu__warn_invalid_formats(struct perf_pmu = *pmu) if (pmu =3D=3D &perf_pmu__fake) return; =20 - list_for_each_entry(format, &pmu->format, list) + list_for_each_entry(format, &pmu->format, list) { + perf_pmu_format__load(pmu, format); if (format->value >=3D PERF_PMU_FORMAT_VALUE_CONFIG_END) { pr_warning("WARNING: '%s' format '%s' requires 'perf_event_attr::config= %d'" "which is not supported by this version of perf!\n", pmu->name, format->name, format->value); return; } + } } =20 bool evsel__is_aux_event(const struct evsel *evsel) @@ -1041,6 +1106,7 @@ int perf_pmu__format_type(struct perf_pmu *pmu, const= char *name) if (!format) return -1; =20 + perf_pmu_format__load(pmu, format); return format->value; } =20 @@ -1177,7 +1243,7 @@ static int pmu_config_term(struct perf_pmu *pmu, free(pmu_term); return -EINVAL; } - + perf_pmu_format__load(pmu, format); switch (format->value) { case PERF_PMU_FORMAT_VALUE_CONFIG: vp =3D &attr->config; @@ -1403,24 +1469,6 @@ struct perf_pmu_alias *perf_pmu__find_alias(struct p= erf_pmu *pmu, const char *ev =20 return NULL; } - -int perf_pmu__new_format(struct list_head *list, char *name, - int config, unsigned long *bits) -{ - struct perf_pmu_format *format; - - format =3D zalloc(sizeof(*format)); - if (!format) - return -ENOMEM; - - format->name =3D strdup(name); - format->value =3D config; - memcpy(format->bits, bits, sizeof(format->bits)); - - list_add_tail(&format->list, list); - return 0; -} - static void perf_pmu__del_formats(struct list_head *formats) { struct perf_pmu_format *fmt, *tmp; diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index c4268053c979..675c9b97f7bf 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -227,9 +227,8 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct = list_head *head_terms, struct perf_pmu_info *info); struct perf_pmu_alias *perf_pmu__find_alias(struct perf_pmu *pmu, const ch= ar *event); =20 -int perf_pmu__new_format(struct list_head *list, char *name, - int config, unsigned long *bits); -int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd); +int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd, bool eager_loa= d); +void perf_pmu_format__set_value(void *format, int config, unsigned long *b= its); bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name); =20 bool is_pmu_core(const char *name); diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y index d861a5bfa3bd..600c8c158c8e 100644 --- a/tools/perf/util/pmu.y +++ b/tools/perf/util/pmu.y @@ -1,6 +1,5 @@ %define api.pure full -%parse-param {struct list_head *format} -%parse-param {char *name} +%parse-param {void *format} %parse-param {void *scanner} %lex-param {void* scanner} =20 @@ -21,7 +20,7 @@ do { \ YYABORT; \ } while (0) =20 -static void perf_pmu_error(struct list_head *list, char *name, void *scann= er, char const *msg); +static void perf_pmu_error(void *format, void *scanner, const char *msg); =20 static void perf_pmu__set_format(unsigned long *bits, long from, long to) { @@ -59,16 +58,12 @@ format_term format_term: PP_CONFIG ':' bits { - ABORT_ON(perf_pmu__new_format(format, name, - PERF_PMU_FORMAT_VALUE_CONFIG, - $3)); + perf_pmu_format__set_value(format, PERF_PMU_FORMAT_VALUE_CONFIG, $3); } | PP_CONFIG PP_VALUE ':' bits { - ABORT_ON(perf_pmu__new_format(format, name, - $2, - $4)); + perf_pmu_format__set_value(format, $2, $4); } =20 bits: @@ -95,9 +90,8 @@ PP_VALUE =20 %% =20 -static void perf_pmu_error(struct list_head *list __maybe_unused, - char *name __maybe_unused, - void *scanner __maybe_unused, - char const *msg __maybe_unused) +static void perf_pmu_error(void *format __maybe_unused, + void *scanner __maybe_unused, + const char *msg __maybe_unused) { } --=20 2.42.0.rc1.204.g551eb34607-goog