From mboxrd@z Thu Jan 1 00:00:00 1970 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 D2BBBEE49A0 for ; Wed, 23 Aug 2023 08:11:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230173AbjHWILF (ORCPT ); Wed, 23 Aug 2023 04:11:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59732 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233833AbjHWIJn (ORCPT ); Wed, 23 Aug 2023 04:09:43 -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 98C1D10FB for ; Wed, 23 Aug 2023 01:08:55 -0700 (PDT) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-58f9db8bc1dso67672787b3.3 for ; Wed, 23 Aug 2023 01:08:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1692778134; x=1693382934; h=to:from:subject:references:mime-version:message-id:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=ktZfPGkZyqox+6WbxffaWE9Heu4siEOaYIAlfm46eow=; b=OOR3mHS2J4kz/WgP1oDG6r9Kv4F00+J1X+t5Y4S5w983n3wkEAR5Fh2bR6voWxAK7M PpEM5N+86CZVEDbqTwnp0YjBqH9OnBwMpUc19TFvj+kf7/tQzdMXq/YjE8cZguTtIt15 5r2TKKE65iqHlcAFnTKta0Wshwz7m+g06dDd0uJH4+POJ4Gewb5LZD93LhELLrPvlhwE ssXxqdTWPVjXfntJ4UMg6AYWEddq49fx3mKbjuaOU4nleX9x5AfvHI6RIOAcMu+W6+E/ /MagC+oT0KbNGjH90Rj6TRS3qA2R0BgAAdH629XCpXrPiYTqXnZchMkPOO1Z9A1GZgKC pS1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1692778134; x=1693382934; 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=ktZfPGkZyqox+6WbxffaWE9Heu4siEOaYIAlfm46eow=; b=d8frXYYQBaYsjCSjdlCXLO9Ra2/dKSyz+/PsaZHhGllKg89E45FrvPJXhKABIRqmkE fYf4lUplSpSA6Z3oEt3xHCOnCVzcJAteDhqyCs3R8CQecGDoR2Y8O9OmbOEaDXFdSjXt suPe1afP7mxxy22jb4bhk51VVTThQ7ndEqnzGjCGuX0bbDH2eLW/6dx/b91/86RLnvqv JYMyYwioe+Tw1Ex22FTj+U5AmhkfBRaEqECp3zSMnOgRRSvmyVoAjWT0ioqE5ZsrLVfh 6NaW7J8Ai2cU3jryAKxoHdmvdkv1J24obuEC6VnH9dIUMUJW4O0A+j81u8kYv0ycmIgp +/1w== X-Gm-Message-State: AOJu0YzvleP8wCchg7lCitCxB2OVNV/G6m11DG9C2qOh2xcCOBIRaLji R6WcIns3Wa1Jc7LwC5As87Q3wzQ2IUi8 X-Google-Smtp-Source: AGHT+IGc4hIwyrjGuDTBAnErsZNRaT3kWDvGsISOZV0nkCiN/Gq/xCp+zN3dvbc3JqC1Je7YVBuzZWDnkYFe X-Received: from irogers.svl.corp.google.com ([2620:15c:2a3:200:3971:e84:f508:9a36]) (user=irogers job=sendgmr) by 2002:a05:6902:290:b0:d48:c04:f256 with SMTP id v16-20020a056902029000b00d480c04f256mr137156ybh.11.1692778134435; Wed, 23 Aug 2023 01:08:54 -0700 (PDT) Date: Wed, 23 Aug 2023 01:08:12 -0700 In-Reply-To: <20230823080828.1460376-1-irogers@google.com> Message-Id: <20230823080828.1460376-10-irogers@google.com> Mime-Version: 1.0 References: <20230823080828.1460376-1-irogers@google.com> X-Mailer: git-send-email 2.42.0.rc1.204.g551eb34607-goog Subject: [PATCH v1 09/25] 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 Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-perf-users@vger.kernel.org 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 | 140 +++++++++++++++++++++++++++-------------- tools/perf/util/pmu.h | 5 +- tools/perf/util/pmu.y | 20 +++--- 4 files changed, 102 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_unused, int subtest __maybe } pmu->name = strdup("perf-pmu-test"); - ret = perf_pmu__format_parse(pmu, fd); + ret = perf_pmu__format_parse(pmu, fd, /*eager_load=*/true); if (ret) goto out; diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 42f3249994ab..7c3de51bab08 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -40,6 +40,10 @@ struct perf_pmu perf_pmu__fake; * value=PERF_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,75 @@ 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; }; +static struct perf_pmu_format *perf_pmu__new_format(struct list_head *list, char *name) +{ + struct perf_pmu_format *format; + + format = zalloc(sizeof(*format)); + if (!format) + return NULL; + + format->name = strdup(name); + 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 = vformat; + + format->value = 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 = perf_pmu_lex_init(&scanner); + if (ret) + return; + + perf_pmu_set_in(file, scanner); + ret = perf_pmu_parse(format, scanner); + perf_pmu_lex_destroy(scanner); + format->loaded = true; +} + +static void perf_pmu_format__load(struct perf_pmu *pmu, struct perf_pmu_format *format) +{ + char path[PATH_MAX]; + FILE *file = 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 = 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_load) { struct dirent *evt_ent; DIR *format_dir; @@ -68,37 +129,35 @@ int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd) if (!format_dir) return -EINVAL; - while (!ret && (evt_ent = readdir(format_dir))) { + while ((evt_ent = readdir(format_dir)) != NULL) { + struct perf_pmu_format *format; char *name = evt_ent->d_name; - int fd; - void *scanner; - FILE *file; if (!strcmp(name, ".") || !strcmp(name, "..")) continue; - - ret = -EINVAL; - fd = openat(dirfd, name, O_RDONLY); - if (fd < 0) - break; - - file = fdopen(fd, "r"); - if (!file) { - close(fd); + format = perf_pmu__new_format(&pmu->format, name); + if (!format) { + ret = -ENOMEM; break; } - ret = perf_pmu_lex_init(&scanner); - if (ret) { + if (eager_load) { + FILE *file; + int fd = openat(dirfd, name, O_RDONLY); + + if (fd < 0) { + ret = -errno; + break; + } + file = fdopen(fd, "r"); + if (!file) { + close(fd); + break; + } + __perf_pmu_format__load(format, file); fclose(file); - break; } - - perf_pmu_set_in(file, scanner); - ret = perf_pmu_parse(&pmu->format, name, scanner); - perf_pmu_lex_destroy(scanner); - fclose(file); } closedir(format_dir); @@ -119,7 +178,7 @@ static int pmu_format(struct perf_pmu *pmu, int dirfd, const char *name) return 0; /* it'll close the fd */ - if (perf_pmu__format_parse(pmu, fd)) + if (perf_pmu__format_parse(pmu, fd, /*eager_load=*/false)) return -1; return 0; @@ -962,13 +1021,15 @@ void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu) if (pmu == &perf_pmu__fake) return; - 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 >= 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; } + } } bool evsel__is_aux_event(const struct evsel *evsel) @@ -1041,6 +1102,7 @@ int perf_pmu__format_type(struct perf_pmu *pmu, const char *name) if (!format) return -1; + perf_pmu_format__load(pmu, format); return format->value; } @@ -1177,7 +1239,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 = &attr->config; @@ -1403,24 +1465,6 @@ struct perf_pmu_alias *perf_pmu__find_alias(struct perf_pmu *pmu, const char *ev return NULL; } - -int perf_pmu__new_format(struct list_head *list, char *name, - int config, unsigned long *bits) -{ - struct perf_pmu_format *format; - - format = zalloc(sizeof(*format)); - if (!format) - return -ENOMEM; - - format->name = strdup(name); - format->value = 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 char *event); -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_load); +void perf_pmu_format__set_value(void *format, int config, unsigned long *bits); bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name); 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} @@ -21,7 +20,7 @@ do { \ YYABORT; \ } while (0) -static void perf_pmu_error(struct list_head *list, char *name, void *scanner, char const *msg); +static void perf_pmu_error(void *format, void *scanner, const char *msg); 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); } bits: @@ -95,9 +90,8 @@ PP_VALUE %% -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) { } -- 2.42.0.rc1.204.g551eb34607-goog