[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <Zy3fem1TVYdYJAeF@BLRRASHENOY1.amd.com>
Date: Fri, 8 Nov 2024 15:22:58 +0530
From: "Gautham R. Shenoy" <gautham.shenoy@....com>
To: Dhananjay Ugwekar <Dhananjay.Ugwekar@....com>
Cc: peterz@...radead.org, mingo@...hat.com, rui.zhang@...el.com,
acme@...nel.org, namhyung@...nel.org, mark.rutland@....com,
alexander.shishkin@...ux.intel.com, jolsa@...nel.org,
irogers@...gle.com, adrian.hunter@...el.com,
kan.liang@...ux.intel.com, tglx@...utronix.de, bp@...en8.de,
dave.hansen@...ux.intel.com, ananth.narayan@....com,
kprateek.nayak@....com, ravi.bangoria@....com, x86@...nel.org,
linux-perf-users@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH v6 10/10] perf/x86/rapl: Add core energy counter support
for AMD CPUs
Hello Dhananjay,
On Fri, Oct 25, 2024 at 11:13:48AM +0000, Dhananjay Ugwekar wrote:
> Add a new "power_core" PMU and "energy-core" event for monitoring
> energy consumption by each individual core. The existing energy-cores
> event aggregates the energy consumption of CPU cores at the package level.
> This new event aligns with the AMD's per-core energy counters.
>
> Tested the package level and core level PMU counters with workloads
> pinned to different CPUs.
>
> Results with workload pinned to CPU 4 in core 4 on an AMD Zen4 Genoa
> machine:
>
> $ sudo perf stat --per-core -e power_core/energy-core/ -- taskset -c 4 stress-ng --matrix 1 --timeout 5s
> stress-ng: info: [21250] setting to a 5 second run per stressor
> stress-ng: info: [21250] dispatching hogs: 1 matrix
> stress-ng: info: [21250] successful run completed in 5.00s
>
> Performance counter stats for 'system wide':
>
> S0-D0-C0 1 0.00 Joules power_core/energy-core/
> S0-D0-C1 1 0.00 Joules power_core/energy-core/
> S0-D0-C2 1 0.00 Joules power_core/energy-core/
> S0-D0-C3 1 0.00 Joules power_core/energy-core/
> S0-D0-C4 1 8.43 Joules power_core/energy-core/
> S0-D0-C5 1 0.00 Joules power_core/energy-core/
> S0-D0-C6 1 0.00 Joules power_core/energy-core/
> S0-D0-C7 1 0.00 Joules power_core/energy-core/
> S0-D1-C8 1 0.00 Joules power_core/energy-core/
> S0-D1-C9 1 0.00 Joules power_core/energy-core/
> S0-D1-C10 1 0.00 Joules power_core/energy-core/
>
> Signed-off-by: Dhananjay Ugwekar <Dhananjay.Ugwekar@....com>
Looks like my response to this patch never made it to the list.
The patch looks good to me.
Reviewed-by: Gautham R. Shenoy <gautham.shenoy@....com>
--
Thanks and Regards
gautham.
> ---
> v6 changes:
> * Replaced the if-ladder in get_rapl_pmu_idx() with a switch case. (Gautham)
> * Added the error if condition in init_rapl_pmus().
> * Modify the PMU name from "power_per_core" to "power_core" and event name
> from "event_per_core" to "event_core"
> ---
> arch/x86/events/rapl.c | 182 +++++++++++++++++++++++++++++++++--------
> 1 file changed, 150 insertions(+), 32 deletions(-)
>
> diff --git a/arch/x86/events/rapl.c b/arch/x86/events/rapl.c
> index d3acc70a3d31..57cf15a19b7c 100644
> --- a/arch/x86/events/rapl.c
> +++ b/arch/x86/events/rapl.c
> @@ -39,6 +39,10 @@
> * event: rapl_energy_psys
> * perf code: 0x5
> *
> + * core counter: consumption of a single physical core
> + * event: rapl_energy_core (power_core PMU)
> + * perf code: 0x1
> + *
> * We manage those counters as free running (read-only). They may be
> * use simultaneously by other tools, such as turbostat.
> *
> @@ -81,6 +85,10 @@ enum perf_rapl_pkg_events {
> NR_RAPL_PKG_DOMAINS = PERF_RAPL_PKG_EVENTS_MAX,
> };
>
> +#define PERF_RAPL_CORE 0 /* single core */
> +#define PERF_RAPL_CORE_EVENTS_MAX 1
> +#define NR_RAPL_CORE_DOMAINS PERF_RAPL_CORE_EVENTS_MAX
> +
> static const char *const rapl_pkg_domain_names[NR_RAPL_PKG_DOMAINS] __initconst = {
> "pp0-core",
> "package",
> @@ -89,6 +97,8 @@ static const char *const rapl_pkg_domain_names[NR_RAPL_PKG_DOMAINS] __initconst
> "psys",
> };
>
> +static const char *const rapl_core_domain_name __initconst = "core";
> +
> /*
> * event code: LSB 8 bits, passed in attr->config
> * any other bit is reserved
> @@ -141,14 +151,18 @@ enum rapl_unit_quirk {
>
> struct rapl_model {
> struct perf_msr *rapl_pkg_msrs;
> + struct perf_msr *rapl_core_msrs;
> unsigned long pkg_events;
> + unsigned long core_events;
> unsigned int msr_power_unit;
> enum rapl_unit_quirk unit_quirk;
> };
>
> /* 1/2^hw_unit Joule */
> static int rapl_pkg_hw_unit[NR_RAPL_PKG_DOMAINS] __read_mostly;
> +static int rapl_core_hw_unit __read_mostly;
> static struct rapl_pmus *rapl_pmus_pkg;
> +static struct rapl_pmus *rapl_pmus_core;
> static u64 rapl_timer_ms;
> static struct rapl_model *rapl_model;
>
> @@ -156,10 +170,18 @@ static struct rapl_model *rapl_model;
> * Helper function to get the correct topology id according to the
> * RAPL PMU scope.
> */
> -static inline unsigned int get_rapl_pmu_idx(int cpu)
> +static inline unsigned int get_rapl_pmu_idx(int cpu, int scope)
> {
> - return rapl_pkg_pmu_is_pkg_scope() ? topology_logical_package_id(cpu) :
> - topology_logical_die_id(cpu);
> + switch (scope) {
> + case PERF_PMU_SCOPE_PKG:
> + return topology_logical_package_id(cpu);
> + case PERF_PMU_SCOPE_DIE:
> + return topology_logical_die_id(cpu);
> + case PERF_PMU_SCOPE_CORE:
> + return topology_logical_core_id(cpu);
> + default:
> + return -EINVAL;
> + }
> }
>
> static inline u64 rapl_read_counter(struct perf_event *event)
> @@ -169,19 +191,20 @@ static inline u64 rapl_read_counter(struct perf_event *event)
> return raw;
> }
>
> -static inline u64 rapl_scale(u64 v, int cfg)
> +static inline u64 rapl_scale(u64 v, struct perf_event *event)
> {
> - if (cfg > NR_RAPL_PKG_DOMAINS) {
> - pr_warn("Invalid domain %d, failed to scale data\n", cfg);
> - return v;
> - }
> + int hw_unit = rapl_pkg_hw_unit[event->hw.config - 1];
> +
> + if (event->pmu->scope == PERF_PMU_SCOPE_CORE)
> + hw_unit = rapl_core_hw_unit;
> +
> /*
> * scale delta to smallest unit (1/2^32)
> * users must then scale back: count * 1/(1e9*2^32) to get Joules
> * or use ldexp(count, -32).
> * Watts = Joules/Time delta
> */
> - return v << (32 - rapl_pkg_hw_unit[cfg - 1]);
> + return v << (32 - hw_unit);
> }
>
> static u64 rapl_event_update(struct perf_event *event)
> @@ -208,7 +231,7 @@ static u64 rapl_event_update(struct perf_event *event)
> delta = (new_raw_count << shift) - (prev_raw_count << shift);
> delta >>= shift;
>
> - sdelta = rapl_scale(delta, event->hw.config);
> + sdelta = rapl_scale(delta, event);
>
> local64_add(sdelta, &event->count);
>
> @@ -337,12 +360,13 @@ static void rapl_pmu_event_del(struct perf_event *event, int flags)
> static int rapl_pmu_event_init(struct perf_event *event)
> {
> u64 cfg = event->attr.config & RAPL_EVENT_MASK;
> - int bit, rapl_pmu_idx, ret = 0;
> + int bit, rapl_pmus_scope, rapl_pmu_idx, ret = 0;
> struct rapl_pmu *rapl_pmu;
> + struct rapl_pmus *rapl_pmus;
>
> - /* only look at RAPL events */
> - if (event->attr.type != rapl_pmus_pkg->pmu.type)
> - return -ENOENT;
> + /* unsupported modes and filters */
> + if (event->attr.sample_period) /* no sampling */
> + return -EINVAL;
>
> /* check only supported bits are set */
> if (event->attr.config & ~RAPL_EVENT_MASK)
> @@ -351,31 +375,49 @@ static int rapl_pmu_event_init(struct perf_event *event)
> if (event->cpu < 0)
> return -EINVAL;
>
> - if (!cfg || cfg >= NR_RAPL_PKG_DOMAINS + 1)
> + rapl_pmus = container_of(event->pmu, struct rapl_pmus, pmu);
> + if (!rapl_pmus)
> return -EINVAL;
> -
> - cfg = array_index_nospec((long)cfg, NR_RAPL_PKG_DOMAINS + 1);
> - bit = cfg - 1;
> -
> - /* check event supported */
> - if (!(rapl_pmus_pkg->cntr_mask & (1 << bit)))
> + rapl_pmus_scope = rapl_pmus->pmu.scope;
> +
> + if (rapl_pmus_scope == PERF_PMU_SCOPE_PKG || rapl_pmus_scope == PERF_PMU_SCOPE_DIE) {
> + /* only look at RAPL package events */
> + if (event->attr.type != rapl_pmus_pkg->pmu.type)
> + return -ENOENT;
> +
> + cfg = array_index_nospec((long)cfg, NR_RAPL_PKG_DOMAINS + 1);
> + if (!cfg || cfg >= NR_RAPL_PKG_DOMAINS + 1)
> + return -EINVAL;
> +
> + bit = cfg - 1;
> + event->hw.event_base = rapl_model->rapl_pkg_msrs[bit].msr;
> + } else if (rapl_pmus_scope == PERF_PMU_SCOPE_CORE) {
> + /* only look at RAPL core events */
> + if (event->attr.type != rapl_pmus_core->pmu.type)
> + return -ENOENT;
> +
> + cfg = array_index_nospec((long)cfg, NR_RAPL_CORE_DOMAINS + 1);
> + if (!cfg || cfg >= NR_RAPL_PKG_DOMAINS + 1)
> + return -EINVAL;
> +
> + bit = cfg - 1;
> + event->hw.event_base = rapl_model->rapl_core_msrs[bit].msr;
> + } else
> return -EINVAL;
>
> - /* unsupported modes and filters */
> - if (event->attr.sample_period) /* no sampling */
> + /* check event supported */
> + if (!(rapl_pmus->cntr_mask & (1 << bit)))
> return -EINVAL;
>
> - rapl_pmu_idx = get_rapl_pmu_idx(event->cpu);
> - if (rapl_pmu_idx >= rapl_pmus_pkg->nr_rapl_pmu)
> + rapl_pmu_idx = get_rapl_pmu_idx(event->cpu, rapl_pmus_scope);
> + if (rapl_pmu_idx >= rapl_pmus->nr_rapl_pmu)
> return -EINVAL;
> -
> /* must be done before validate_group */
> - rapl_pmu = rapl_pmus_pkg->rapl_pmu[rapl_pmu_idx];
> + rapl_pmu = rapl_pmus->rapl_pmu[rapl_pmu_idx];
> if (!rapl_pmu)
> return -EINVAL;
>
> event->pmu_private = rapl_pmu;
> - event->hw.event_base = rapl_model->rapl_pkg_msrs[bit].msr;
> event->hw.config = cfg;
> event->hw.idx = bit;
>
> @@ -392,12 +434,14 @@ RAPL_EVENT_ATTR_STR(energy-pkg , rapl_pkg, "event=0x02");
> RAPL_EVENT_ATTR_STR(energy-ram , rapl_ram, "event=0x03");
> RAPL_EVENT_ATTR_STR(energy-gpu , rapl_gpu, "event=0x04");
> RAPL_EVENT_ATTR_STR(energy-psys, rapl_psys, "event=0x05");
> +RAPL_EVENT_ATTR_STR(energy-core, rapl_core, "event=0x01");
>
> RAPL_EVENT_ATTR_STR(energy-cores.unit, rapl_cores_unit, "Joules");
> RAPL_EVENT_ATTR_STR(energy-pkg.unit , rapl_pkg_unit, "Joules");
> RAPL_EVENT_ATTR_STR(energy-ram.unit , rapl_ram_unit, "Joules");
> RAPL_EVENT_ATTR_STR(energy-gpu.unit , rapl_gpu_unit, "Joules");
> RAPL_EVENT_ATTR_STR(energy-psys.unit, rapl_psys_unit, "Joules");
> +RAPL_EVENT_ATTR_STR(energy-core.unit, rapl_core_unit, "Joules");
>
> /*
> * we compute in 0.23 nJ increments regardless of MSR
> @@ -407,6 +451,7 @@ RAPL_EVENT_ATTR_STR(energy-pkg.scale, rapl_pkg_scale, "2.3283064365386962890
> RAPL_EVENT_ATTR_STR(energy-ram.scale, rapl_ram_scale, "2.3283064365386962890625e-10");
> RAPL_EVENT_ATTR_STR(energy-gpu.scale, rapl_gpu_scale, "2.3283064365386962890625e-10");
> RAPL_EVENT_ATTR_STR(energy-psys.scale, rapl_psys_scale, "2.3283064365386962890625e-10");
> +RAPL_EVENT_ATTR_STR(energy-core.scale, rapl_core_scale, "2.3283064365386962890625e-10");
>
> /*
> * There are no default events, but we need to create
> @@ -439,6 +484,12 @@ static const struct attribute_group *rapl_attr_groups[] = {
> NULL,
> };
>
> +static const struct attribute_group *rapl_core_attr_groups[] = {
> + &rapl_pmu_format_group,
> + &rapl_pmu_events_group,
> + NULL,
> +};
> +
> static struct attribute *rapl_events_cores[] = {
> EVENT_PTR(rapl_cores),
> EVENT_PTR(rapl_cores_unit),
> @@ -499,6 +550,18 @@ static struct attribute_group rapl_events_psys_group = {
> .attrs = rapl_events_psys,
> };
>
> +static struct attribute *rapl_events_core[] = {
> + EVENT_PTR(rapl_core),
> + EVENT_PTR(rapl_core_unit),
> + EVENT_PTR(rapl_core_scale),
> + NULL,
> +};
> +
> +static struct attribute_group rapl_events_core_group = {
> + .name = "events",
> + .attrs = rapl_events_core,
> +};
> +
> static bool test_msr(int idx, void *data)
> {
> return test_bit(idx, (unsigned long *) data);
> @@ -536,6 +599,11 @@ static struct perf_msr amd_rapl_pkg_msrs[] = {
> [PERF_RAPL_PSYS] = { 0, &rapl_events_psys_group, NULL, false, 0 },
> };
>
> +static struct perf_msr amd_rapl_core_msrs[] = {
> + [PERF_RAPL_CORE] = { MSR_AMD_CORE_ENERGY_STATUS, &rapl_events_core_group,
> + test_msr, false, RAPL_MSR_MASK },
> +};
> +
> static int rapl_check_hw_unit(void)
> {
> u64 msr_rapl_power_unit_bits;
> @@ -547,6 +615,8 @@ static int rapl_check_hw_unit(void)
> for (i = 0; i < NR_RAPL_PKG_DOMAINS; i++)
> rapl_pkg_hw_unit[i] = (msr_rapl_power_unit_bits >> 8) & 0x1FULL;
>
> + rapl_core_hw_unit = (msr_rapl_power_unit_bits >> 8) & 0x1FULL;
> +
> switch (rapl_model->unit_quirk) {
> /*
> * DRAM domain on HSW server and KNL has fixed energy unit which can be
> @@ -565,7 +635,6 @@ static int rapl_check_hw_unit(void)
> break;
> }
>
> -
> /*
> * Calculate the timer rate:
> * Use reference of 200W for scaling the timeout to avoid counter
> @@ -584,9 +653,13 @@ static int rapl_check_hw_unit(void)
> static void __init rapl_advertise(void)
> {
> int i;
> + int num_counters = hweight32(rapl_pmus_pkg->cntr_mask);
> +
> + if (rapl_pmus_core)
> + num_counters += hweight32(rapl_pmus_core->cntr_mask);
>
> pr_info("API unit is 2^-32 Joules, %d fixed counters, %llu ms ovfl timer\n",
> - hweight32(rapl_pmus_pkg->cntr_mask), rapl_timer_ms);
> + num_counters, rapl_timer_ms);
>
> for (i = 0; i < NR_RAPL_PKG_DOMAINS; i++) {
> if (rapl_pmus_pkg->cntr_mask & (1 << i)) {
> @@ -594,6 +667,10 @@ static void __init rapl_advertise(void)
> rapl_pkg_domain_names[i], rapl_pkg_hw_unit[i]);
> }
> }
> +
> + if (rapl_pmus_core && (rapl_pmus_core->cntr_mask & (1 << PERF_RAPL_CORE)))
> + pr_info("hw unit of domain %s 2^-%d Joules\n",
> + rapl_core_domain_name, rapl_core_hw_unit);
> }
>
> static void cleanup_rapl_pmus(struct rapl_pmus *rapl_pmus)
> @@ -614,6 +691,10 @@ static const struct attribute_group *rapl_attr_update[] = {
> NULL,
> };
>
> +static const struct attribute_group *rapl_core_attr_update[] = {
> + &rapl_events_core_group,
> +};
> +
> static int __init init_rapl_pmu(struct rapl_pmus *rapl_pmus)
> {
> struct rapl_pmu *rapl_pmu;
> @@ -640,13 +721,22 @@ static int __init init_rapl_pmu(struct rapl_pmus *rapl_pmus)
> return -ENOMEM;
> }
>
> -static int __init init_rapl_pmus(struct rapl_pmus **rapl_pmus_ptr, int rapl_pmu_scope)
> +static int __init init_rapl_pmus(struct rapl_pmus **rapl_pmus_ptr, int rapl_pmu_scope,
> + const struct attribute_group **rapl_attr_groups,
> + const struct attribute_group **rapl_attr_update)
> {
> int nr_rapl_pmu = topology_max_packages();
> struct rapl_pmus *rapl_pmus;
>
> + /*
> + * rapl_pmu_scope must be either PKG, DIE or CORE
> + */
> if (rapl_pmu_scope == PERF_PMU_SCOPE_DIE)
> nr_rapl_pmu *= topology_max_dies_per_package();
> + else if (rapl_pmu_scope == PERF_PMU_SCOPE_CORE)
> + nr_rapl_pmu *= topology_num_cores_per_package();
> + else if (rapl_pmu_scope != PERF_PMU_SCOPE_PKG)
> + return -EINVAL;
>
> rapl_pmus = kzalloc(struct_size(rapl_pmus, rapl_pmu, nr_rapl_pmu), GFP_KERNEL);
> if (!rapl_pmus)
> @@ -735,8 +825,10 @@ static struct rapl_model model_spr = {
>
> static struct rapl_model model_amd_hygon = {
> .pkg_events = BIT(PERF_RAPL_PKG),
> + .core_events = BIT(PERF_RAPL_CORE),
> .msr_power_unit = MSR_AMD_RAPL_POWER_UNIT,
> .rapl_pkg_msrs = amd_rapl_pkg_msrs,
> + .rapl_core_msrs = amd_rapl_core_msrs,
> };
>
> static const struct x86_cpu_id rapl_model_match[] __initconst = {
> @@ -808,7 +900,8 @@ static int __init rapl_pmu_init(void)
> if (ret)
> return ret;
>
> - ret = init_rapl_pmus(&rapl_pmus_pkg, rapl_pkg_pmu_scope);
> + ret = init_rapl_pmus(&rapl_pmus_pkg, rapl_pkg_pmu_scope, rapl_attr_groups,
> + rapl_attr_update);
> if (ret)
> return ret;
>
> @@ -820,6 +913,27 @@ static int __init rapl_pmu_init(void)
> if (ret)
> goto out;
>
> + if (rapl_model->core_events) {
> + ret = init_rapl_pmus(&rapl_pmus_core, PERF_PMU_SCOPE_CORE,
> + rapl_core_attr_groups,
> + rapl_core_attr_update);
> + if (ret) {
> + pr_warn("power-core PMU initialization failed (%d)\n", ret);
> + goto core_init_failed;
> + }
> +
> + rapl_pmus_core->cntr_mask = perf_msr_probe(rapl_model->rapl_core_msrs,
> + PERF_RAPL_CORE_EVENTS_MAX, false,
> + (void *) &rapl_model->core_events);
> +
> + ret = perf_pmu_register(&rapl_pmus_core->pmu, "power_core", -1);
> + if (ret) {
> + pr_warn("power-core PMU registration failed (%d)\n", ret);
> + cleanup_rapl_pmus(rapl_pmus_core);
> + }
> + }
> +
> +core_init_failed:
> rapl_advertise();
> return 0;
>
> @@ -832,6 +946,10 @@ module_init(rapl_pmu_init);
>
> static void __exit intel_rapl_exit(void)
> {
> + if (rapl_pmus_core) {
> + perf_pmu_unregister(&rapl_pmus_core->pmu);
> + cleanup_rapl_pmus(rapl_pmus_core);
> + }
> perf_pmu_unregister(&rapl_pmus_pkg->pmu);
> cleanup_rapl_pmus(rapl_pmus_pkg);
> }
> --
> 2.34.1
>
Powered by blists - more mailing lists