The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH v6 0/2] perf/x86/power: Introduce AMD accumlated power reporting mechanism
@ 2016-03-03  8:04 Huang Rui
  2016-03-03  8:04 ` [PATCH v6 1/2] perf/x86: Export events_sysfs_show() Huang Rui
  2016-03-03  8:04 ` [PATCH v6 2/2] perf/x86/amd/power: Add AMD accumulated power reporting mechanism Huang Rui
  0 siblings, 2 replies; 9+ messages in thread
From: Huang Rui @ 2016-03-03  8:04 UTC (permalink / raw)
  To: Borislav Petkov, Thomas Gleixner, Peter Zijlstra, Ingo Molnar,
	Andy Lutomirski, Robert Richter, Jacob Shin,
	Arnaldo Carvalho de Melo, Kan Liang
  Cc: linux-kernel, spg_linux_kernel, x86, Suravee Suthikulpanit,
	Aravind Gopalakrishnan, Borislav Petkov, Fengguang Wu, Huang Rui

Hi,

This series of patches introduces the perf implementation of
accumulated power reporting algorithm. It will calculate the average
power consumption for the processor. The CPU feature flag is
CPUID.8000_0007H:EDX[12].

The V6 is rebased on bp/tip-perf. And need two dependent patches at
tip because of modular perf driver:
http://git.kernel.org/tip/675965b00d734c985e4285f5bec7e524d15fc4e1
http://git.kernel.org/tip/3712bba1a260ad851f3aa8ddea9cb7326f6aa0b3


Changes from v1 -> v2:
- Add a patch to fix the build issue which is reported by kbuild test
  robot.

Changes from v2 -> v3:
- Use raw_spinlock_t instead of spinlock_t, because it need meet the
  -rt mode use case.
- Use topology_sibling_cpumask to make the cpumask operation easier.

Changes from v3 -> v4:
- Remove active_list, because it is not iterated.
- Capitalize sentences consistently and fix some typos.
- Fix some code style issues.
- Initialize structures in a vertically aligned manner.
- Remove unnecessary comment.
- Fix the runtime bug, and do some testing on CPU-hotplug scenario.

Changes from v4 -> v5:
- Remove "struct pmu" and lock from power_pmu, and rename it to
  power_pmu_masks
- As Peter's suggestion, add a new struct to hw_perf_event, and track
  these values from per-event.

Changes from v5 -> v6:
- Remove MAX_CUS check
- Remove DEFINE_PER_CPU(struct power_pmu_masks *, amd_power_pmu)
- Remove power_cpu_prepare power_cpu_free and refine power_cpu_init
  and power_cpu_exit
- Use smp_num_siblings instead of cores_per_cu variable.
- Make this driver as a module.
- Add a patch to export events_sysfs_show.

Thanks,
Rui

Huang Rui (2):
  perf/x86: Export events_sysfs_show()
  perf/x86/amd/power: Add AMD accumulated power reporting mechanism

 arch/x86/Kconfig                           |   9 +
 arch/x86/kernel/cpu/Makefile               |   1 +
 arch/x86/kernel/cpu/perf_event.c           |   1 +
 arch/x86/kernel/cpu/perf_event_amd_power.c | 360 +++++++++++++++++++++++++++++
 include/linux/perf_event.h                 |   4 +
 5 files changed, 375 insertions(+)
 create mode 100644 arch/x86/kernel/cpu/perf_event_amd_power.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v6 1/2] perf/x86: Export events_sysfs_show()
  2016-03-03  8:04 [PATCH v6 0/2] perf/x86/power: Introduce AMD accumlated power reporting mechanism Huang Rui
@ 2016-03-03  8:04 ` Huang Rui
  2016-03-03  8:04 ` [PATCH v6 2/2] perf/x86/amd/power: Add AMD accumulated power reporting mechanism Huang Rui
  1 sibling, 0 replies; 9+ messages in thread
From: Huang Rui @ 2016-03-03  8:04 UTC (permalink / raw)
  To: Borislav Petkov, Thomas Gleixner, Peter Zijlstra, Ingo Molnar,
	Andy Lutomirski, Robert Richter, Jacob Shin,
	Arnaldo Carvalho de Melo, Kan Liang
  Cc: linux-kernel, spg_linux_kernel, x86, Suravee Suthikulpanit,
	Aravind Gopalakrishnan, Borislav Petkov, Fengguang Wu, Huang Rui

This interface will be used in modular perf drivers.

Signed-off-by: Huang Rui <ray.huang@amd.com>
---
 arch/x86/kernel/cpu/perf_event.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 1b443db..47f673c 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -1601,6 +1601,7 @@ ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr,
 
 	return x86_pmu.events_sysfs_show(page, config);
 }
+EXPORT_SYMBOL_GPL(events_sysfs_show);
 
 EVENT_ATTR(cpu-cycles,			CPU_CYCLES		);
 EVENT_ATTR(instructions,		INSTRUCTIONS		);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v6 2/2] perf/x86/amd/power: Add AMD accumulated power reporting mechanism
  2016-03-03  8:04 [PATCH v6 0/2] perf/x86/power: Introduce AMD accumlated power reporting mechanism Huang Rui
  2016-03-03  8:04 ` [PATCH v6 1/2] perf/x86: Export events_sysfs_show() Huang Rui
@ 2016-03-03  8:04 ` Huang Rui
  2016-03-03  8:50   ` Thomas Gleixner
  1 sibling, 1 reply; 9+ messages in thread
From: Huang Rui @ 2016-03-03  8:04 UTC (permalink / raw)
  To: Borislav Petkov, Thomas Gleixner, Peter Zijlstra, Ingo Molnar,
	Andy Lutomirski, Robert Richter, Jacob Shin,
	Arnaldo Carvalho de Melo, Kan Liang
  Cc: linux-kernel, spg_linux_kernel, x86, Suravee Suthikulpanit,
	Aravind Gopalakrishnan, Borislav Petkov, Fengguang Wu, Huang Rui,
	Guenter Roeck

Introduce an AMD accumlated power reporting mechanism for the Family
15h, Model 60h processor that can be used to calculate the average
power consumed by a processor during a measurement interval. The
feature support is indicated by CPUID Fn8000_0007_EDX[12].

This feature will be implemented both in hwmon and perf. The current
design provides one event to report per package/processor power
consumption by counting each compute unit power value.

Here the gory details of how the computation is done:

---------------------------------------------------------------------
* Tsample: compute unit power accumulator sample period
* Tref: the PTSC counter period (PTSC: performance timestamp counter)
* N: the ratio of compute unit power accumulator sample period to the
  PTSC period

* Jmax: max compute unit accumulated power which is indicated by
  MSR_C001007b[MaxCpuSwPwrAcc]

* Jx/Jy: compute unit accumulated power which is indicated by
  MSR_C001007a[CpuSwPwrAcc]

* Tx/Ty: the value of performance timestamp counter which is indicated
  by CU_PTSC MSR_C0010280[PTSC]
* PwrCPUave: CPU average power

i. Determine the ratio of Tsample to Tref by executing CPUID Fn8000_0007.
	N = value of CPUID Fn8000_0007_ECX[CpuPwrSampleTimeRatio[15:0]].

ii. Read the full range of the cumulative energy value from the new
    MSR MaxCpuSwPwrAcc.
	Jmax = value returned.

iii. At time x, software reads CpuSwPwrAcc and samples the PTSC.
	Jx = value read from CpuSwPwrAcc and Tx = value read from PTSC.

iv. At time y, software reads CpuSwPwrAcc and samples the PTSC.
	Jy = value read from CpuSwPwrAcc and Ty = value read from PTSC.

v. Calculate the average power consumption for a compute unit over
time period (y-x). Unit of result is uWatt:

	if (Jy < Jx) // Rollover has occurred
		Jdelta = (Jy + Jmax) - Jx
	else
		Jdelta = Jy - Jx
	PwrCPUave = N * Jdelta * 1000 / (Ty - Tx)
----------------------------------------------------------------------

Simple example:

  root@hr-zp:/home/ray/tip# ./tools/perf/perf stat -a -e 'power/power-pkg/' make -j4
    CHK     include/config/kernel.release
    CHK     include/generated/uapi/linux/version.h
    CHK     include/generated/utsrelease.h
    CHK     include/generated/timeconst.h
    CHK     include/generated/bounds.h
    CHK     include/generated/asm-offsets.h
    CALL    scripts/checksyscalls.sh
    CHK     include/generated/compile.h
    SKIPPED include/generated/compile.h
    Building modules, stage 2.
  Kernel: arch/x86/boot/bzImage is ready  (#40)
    MODPOST 4225 modules

   Performance counter stats for 'system wide':

              183.44 mWatts power/power-pkg/

       341.837270111 seconds time elapsed

  root@hr-zp:/home/ray/tip# ./tools/perf/perf stat -a -e 'power/power-pkg/' sleep 10

   Performance counter stats for 'system wide':

                0.18 mWatts power/power-pkg/

        10.012551815 seconds time elapsed

Suggested-by: Peter Zijlstra <peterz@infradead.org>
Suggested-by: Ingo Molnar <mingo@kernel.org>
Suggested-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Huang Rui <ray.huang@amd.com>
Cc: Guenter Roeck <linux@roeck-us.net>
---

Hi Thomas,

Thanks to suggest the updates for power_cpu_init(), but there are some
minor issues with below codes.


target = cpumask_any_and(&cpu_mask, topology_sibling_cpumask(cpu));
if (target < nr_cpu_ids)
	cpumask_set_cpu(cpu, &cpu_mask);


For example: cores number is 4, and compute unit number is 2 (2 cores
per compute units). 

When amd_power_pmu completes initialization, the cpumask will be set
as 1111. Actually, I just would like to choose one core per compute
unit. So the expected value should be 0101.

when core 2 and core 3 are both online (they are in same compute
unit) and cpu_mask is 1111,
set core 2 offline, then 1111 -> 1011,
set core 2 online again, then 1011 -> 1111.
Actually, we don't expect two cores both set at cpu_mask in the same
compute unit.

So as inspired by you, I do below change for power_cpu_init and tested
in my platform, please see my codes. :-)

Thanks,
Rui

---
 arch/x86/Kconfig                           |   9 +
 arch/x86/kernel/cpu/Makefile               |   1 +
 arch/x86/kernel/cpu/perf_event_amd_power.c | 360 +++++++++++++++++++++++++++++
 include/linux/perf_event.h                 |   4 +
 4 files changed, 374 insertions(+)
 create mode 100644 arch/x86/kernel/cpu/perf_event_amd_power.c

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 330e738..a0d3fb0 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1202,6 +1202,15 @@ config MICROCODE_OLD_INTERFACE
 	def_bool y
 	depends on MICROCODE
 
+config PERF_EVENTS_AMD_POWER
+	depends on PERF_EVENTS && CPU_SUP_AMD
+	tristate "AMD Processor Power Reporting Mechanism"
+	---help---
+	  Provide power reporting mechanism support for AMD processors.
+	  Currently, it leverages X86_FEATURE_ACC_POWER
+	  (CPUID Fn8000_0007_EDX[12]) interface to calculate the
+	  average power consumption on Family 15h processors.
+
 config X86_MSR
 	tristate "/dev/cpu/*/msr - Model-specific register support"
 	---help---
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index faa7b52..95d8419 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_PERF_EVENTS)		+= perf_event.o
 
 ifdef CONFIG_PERF_EVENTS
 obj-$(CONFIG_CPU_SUP_AMD)		+= perf_event_amd.o perf_event_amd_uncore.o
+obj-$(CONFIG_PERF_EVENTS_AMD_POWER)	+= perf_event_amd_power.o
 ifdef CONFIG_AMD_IOMMU
 obj-$(CONFIG_CPU_SUP_AMD)		+= perf_event_amd_iommu.o
 endif
diff --git a/arch/x86/kernel/cpu/perf_event_amd_power.c b/arch/x86/kernel/cpu/perf_event_amd_power.c
new file mode 100644
index 0000000..42d5072
--- /dev/null
+++ b/arch/x86/kernel/cpu/perf_event_amd_power.c
@@ -0,0 +1,360 @@
+/*
+ * Performance events - AMD Processor Power Reporting Mechanism
+ *
+ * Copyright (C) 2016 Advanced Micro Devices, Inc.
+ *
+ * Author: Huang Rui <ray.huang@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/perf_event.h>
+#include <asm/cpu_device_id.h>
+#include "perf_event.h"
+
+#define MSR_F15H_CU_PWR_ACCUMULATOR     0xc001007a
+#define MSR_F15H_CU_MAX_PWR_ACCUMULATOR 0xc001007b
+#define MSR_F15H_PTSC			0xc0010280
+
+/* Event code: LSB 8 bits, passed in attr->config any other bit is reserved. */
+#define AMD_POWER_EVENT_MASK	0xFFULL
+
+/*
+ * Accumulated power status counters.
+ */
+#define AMD_POWER_EVENTSEL_PKG		1
+
+/*
+ * The ratio of compute unit power accumulator sample period to the
+ * PTSC period.
+ */
+static unsigned int cpu_pwr_sample_ratio;
+static unsigned int cu_num;
+
+/* Maximum accumulated power of a compute unit. */
+static u64 max_cu_acc_power;
+
+static struct pmu pmu_class;
+
+/*
+ * Accumulated power represents the sum of each compute unit's (CU) power
+ * consumption. On any core of each CU we read the total accumulated power from
+ * MSR_F15H_CU_PWR_ACCUMULATOR. cpu_mask represents CPU bit map of all cores
+ * which are picked to measure the power for the CUs they belong to.
+ */
+static cpumask_t cpu_mask;
+
+static void event_update(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	u64 prev_pwr_acc, new_pwr_acc, prev_ptsc, new_ptsc;
+	u64 delta, tdelta;
+
+	prev_pwr_acc = hwc->pwr_acc;
+	prev_ptsc = hwc->ptsc;
+	rdmsrl(MSR_F15H_CU_PWR_ACCUMULATOR, new_pwr_acc);
+	rdmsrl(MSR_F15H_PTSC, new_ptsc);
+
+	/*
+	 * Calculate the CU power consumption over a time period, the unit of
+	 * final value (delta) is micro-Watts. Then add it to the event count.
+	 */
+	if (new_pwr_acc < prev_pwr_acc) {
+		delta = max_cu_acc_power + new_pwr_acc;
+		delta -= prev_pwr_acc;
+	} else
+		delta = new_pwr_acc - prev_pwr_acc;
+
+	delta *= cpu_pwr_sample_ratio * 1000;
+	tdelta = new_ptsc - prev_ptsc;
+
+	do_div(delta, tdelta);
+	local64_add(delta, &event->count);
+}
+
+static void __pmu_event_start(struct perf_event *event)
+{
+	if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+		return;
+
+	event->hw.state = 0;
+
+	rdmsrl(MSR_F15H_PTSC, event->hw.ptsc);
+	rdmsrl(MSR_F15H_CU_PWR_ACCUMULATOR, event->hw.pwr_acc);
+}
+
+static void pmu_event_start(struct perf_event *event, int mode)
+{
+	__pmu_event_start(event);
+}
+
+static void pmu_event_stop(struct perf_event *event, int mode)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	/* Mark event as deactivated and stopped. */
+	if (!(hwc->state & PERF_HES_STOPPED))
+		hwc->state |= PERF_HES_STOPPED;
+
+	/* Check if software counter update is necessary. */
+	if ((mode & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+		/*
+		 * Drain the remaining delta count out of an event
+		 * that we are disabling:
+		 */
+		event_update(event);
+		hwc->state |= PERF_HES_UPTODATE;
+	}
+}
+
+static int pmu_event_add(struct perf_event *event, int mode)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+	if (mode & PERF_EF_START)
+		__pmu_event_start(event);
+
+	return 0;
+}
+
+static void pmu_event_del(struct perf_event *event, int flags)
+{
+	pmu_event_stop(event, PERF_EF_UPDATE);
+}
+
+static int pmu_event_init(struct perf_event *event)
+{
+	u64 cfg = event->attr.config & AMD_POWER_EVENT_MASK;
+
+	/* Only look at AMD power events. */
+	if (event->attr.type != pmu_class.type)
+		return -ENOENT;
+
+	/* Unsupported modes and filters. */
+	if (event->attr.exclude_user   ||
+	    event->attr.exclude_kernel ||
+	    event->attr.exclude_hv     ||
+	    event->attr.exclude_idle   ||
+	    event->attr.exclude_host   ||
+	    event->attr.exclude_guest  ||
+	    /* no sampling */
+	    event->attr.sample_period)
+		return -EINVAL;
+
+	if (cfg != AMD_POWER_EVENTSEL_PKG)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void pmu_event_read(struct perf_event *event)
+{
+	event_update(event);
+}
+
+static ssize_t
+get_attr_cpumask(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return cpumap_print_to_pagebuf(true, buf, &cpu_mask);
+}
+
+static DEVICE_ATTR(cpumask, S_IRUGO, get_attr_cpumask, NULL);
+
+static struct attribute *pmu_attrs[] = {
+	&dev_attr_cpumask.attr,
+	NULL,
+};
+
+static struct attribute_group pmu_attr_group = {
+	.attrs = pmu_attrs,
+};
+
+/*
+ * Currently it only supports to report the power of each
+ * processor/package.
+ */
+EVENT_ATTR_STR(power-pkg, power_pkg, "event=0x01");
+
+EVENT_ATTR_STR(power-pkg.unit, power_pkg_unit, "mWatts");
+
+/* Convert the count from micro-Watts to milli-Watts. */
+EVENT_ATTR_STR(power-pkg.scale, power_pkg_scale, "1.000000e-3");
+
+static struct attribute *events_attr[] = {
+	EVENT_PTR(power_pkg),
+	EVENT_PTR(power_pkg_unit),
+	EVENT_PTR(power_pkg_scale),
+	NULL,
+};
+
+static struct attribute_group pmu_events_group = {
+	.name	= "events",
+	.attrs	= events_attr,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-7");
+
+static struct attribute *formats_attr[] = {
+	&format_attr_event.attr,
+	NULL,
+};
+
+static struct attribute_group pmu_format_group = {
+	.name	= "format",
+	.attrs	= formats_attr,
+};
+
+static const struct attribute_group *attr_groups[] = {
+	&pmu_attr_group,
+	&pmu_format_group,
+	&pmu_events_group,
+	NULL,
+};
+
+static struct pmu pmu_class = {
+	.attr_groups	= attr_groups,
+	/* system-wide only */
+	.task_ctx_nr	= perf_invalid_context,
+	.event_init	= pmu_event_init,
+	.add		= pmu_event_add,
+	.del		= pmu_event_del,
+	.start		= pmu_event_start,
+	.stop		= pmu_event_stop,
+	.read		= pmu_event_read,
+};
+
+static void power_cpu_exit(int cpu)
+{
+	int target = nr_cpumask_bits;
+
+	if (!cpumask_test_and_clear_cpu(cpu, &cpu_mask))
+		return;
+
+	/*
+	 * Find a new CPU on the same compute unit, if was set in cpumask
+	 * and still some CPUs on compute unit. Then migrate event and
+	 * context to new CPU.
+	 */
+	target = cpumask_any_but(topology_sibling_cpumask(cpu), cpu);
+	if (target < nr_cpumask_bits) {
+		cpumask_set_cpu(target, &cpu_mask);
+		perf_pmu_migrate_context(&pmu_class, cpu, target);
+	}
+}
+
+static void power_cpu_init(int cpu)
+{
+	/*
+	 * 1) If any CPU is set at cpu_mask in the same compute unit, do
+	 * nothing.
+	 * 2) If no CPU is set at cpu_mask in the same compute unit,
+	 * set current STARTING CPU.
+	 *
+	 * If cpu_mask and topology_sibling_cpumask has intersected
+	 * bits, that means any CPU is set in the same compute unit.
+	 * But cpumask_weight(topology_sibling_cpumask(cpu)) == 1
+	 * means no CPU is set on cpu_mask in the same compute unit
+	 * before init current STARTING CPU.
+	 */
+	if (!cpumask_intersects(&cpu_mask, topology_sibling_cpumask(cpu)) &&
+	    cpumask_weight(topology_sibling_cpumask(cpu)) == 1)
+			cpumask_set_cpu(cpu, &cpu_mask);
+}
+
+static int
+power_cpu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (long)hcpu;
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		power_cpu_init(cpu);
+		break;
+	case CPU_DOWN_PREPARE:
+		power_cpu_exit(cpu);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block power_cpu_notifier_nb = {
+	.notifier_call = power_cpu_notifier,
+	.priority = CPU_PRI_PERF,
+};
+
+static const struct x86_cpu_id cpu_match[] = {
+	{ .vendor = X86_VENDOR_AMD, .family = 0x15 },
+	{},
+};
+
+static int __init amd_power_pmu_init(void)
+{
+	int i, ret;
+	u64 tmp;
+
+	if (!x86_match_cpu(cpu_match))
+		return 0;
+
+	if (!boot_cpu_has(X86_FEATURE_ACC_POWER))
+		return -ENODEV;
+
+	cu_num = boot_cpu_data.x86_max_cores / smp_num_siblings;
+
+	cpu_pwr_sample_ratio = cpuid_ecx(0x80000007);
+
+	if (rdmsrl_safe(MSR_F15H_CU_MAX_PWR_ACCUMULATOR, &tmp)) {
+		pr_err("Failed to read max compute unit power accumulator MSR\n");
+		return -ENODEV;
+	}
+	max_cu_acc_power = tmp;
+
+	cpu_notifier_register_begin();
+
+	/* Choose one online core of each compute unit. */
+	for (i = 0; i < boot_cpu_data.x86_max_cores; i += smp_num_siblings) {
+		WARN_ON(cpumask_empty(topology_sibling_cpumask(i)));
+		cpumask_set_cpu(cpumask_any(topology_sibling_cpumask(i)), &cpu_mask);
+	}
+
+	for_each_online_cpu(i)
+		power_cpu_init(i);
+
+	__register_cpu_notifier(&power_cpu_notifier_nb);
+
+	ret = perf_pmu_register(&pmu_class, "power", -1);
+	if (WARN_ON(ret)) {
+		pr_warn("AMD Power PMU registration failed\n");
+		goto out;
+	}
+
+	pr_info("AMD Power PMU detected, %d compute units\n", cu_num);
+
+out:
+	cpu_notifier_register_done();
+
+	return ret;
+}
+module_init(amd_power_pmu_init);
+
+static void __exit amd_power_pmu_exit(void)
+{
+	cpu_notifier_register_begin();
+	__unregister_cpu_notifier(&power_cpu_notifier_nb);
+	cpu_notifier_register_done();
+
+	perf_pmu_unregister(&pmu_class);
+}
+module_exit(amd_power_pmu_exit);
+
+MODULE_AUTHOR("Huang Rui <ray.huang@amd.com>");
+MODULE_DESCRIPTION("AMD Processor Power Reporting Mechanism");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index f9828a4..01ea21c 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -128,6 +128,10 @@ struct hw_perf_event {
 		struct { /* itrace */
 			int			itrace_started;
 		};
+		struct { /* amd_power */
+			u64	pwr_acc;
+			u64	ptsc;
+		};
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 		struct { /* breakpoint */
 			/*
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v6 2/2] perf/x86/amd/power: Add AMD accumulated power reporting mechanism
  2016-03-03  8:04 ` [PATCH v6 2/2] perf/x86/amd/power: Add AMD accumulated power reporting mechanism Huang Rui
@ 2016-03-03  8:50   ` Thomas Gleixner
  2016-03-03 15:13     ` Huang Rui
  0 siblings, 1 reply; 9+ messages in thread
From: Thomas Gleixner @ 2016-03-03  8:50 UTC (permalink / raw)
  To: Huang Rui
  Cc: Borislav Petkov, Peter Zijlstra, Ingo Molnar, Andy Lutomirski,
	Robert Richter, Jacob Shin, Arnaldo Carvalho de Melo, Kan Liang,
	linux-kernel, spg_linux_kernel, x86, Suravee Suthikulpanit,
	Aravind Gopalakrishnan, Borislav Petkov, Fengguang Wu,
	Guenter Roeck

On Thu, 3 Mar 2016, Huang Rui wrote:
> +/*
> + * The ratio of compute unit power accumulator sample period to the
> + * PTSC period.
> + */
> +static unsigned int cpu_pwr_sample_ratio;
> +static unsigned int cu_num;

Why do you need static storage for that information when the only purpose is
to printk it in init?

> +static void power_cpu_exit(int cpu)
> +{
> +	int target = nr_cpumask_bits;

What's that initialization for?

> +
> +	if (!cpumask_test_and_clear_cpu(cpu, &cpu_mask))
> +		return;
> +
> +	/*
> +	 * Find a new CPU on the same compute unit, if was set in cpumask
> +	 * and still some CPUs on compute unit. Then migrate event and
> +	 * context to new CPU.
> +	 */
> +	target = cpumask_any_but(topology_sibling_cpumask(cpu), cpu);
> +	if (target < nr_cpumask_bits) {
> +		cpumask_set_cpu(target, &cpu_mask);
> +		perf_pmu_migrate_context(&pmu_class, cpu, target);
> +	}
> +}
> +
> +static void power_cpu_init(int cpu)
> +{
> +	/*
> +	 * 1) If any CPU is set at cpu_mask in the same compute unit, do
> +	 * nothing.
> +	 * 2) If no CPU is set at cpu_mask in the same compute unit,
> +	 * set current STARTING CPU.
> +	 *
> +	 * If cpu_mask and topology_sibling_cpumask has intersected
> +	 * bits, that means any CPU is set in the same compute unit.
> +	 * But cpumask_weight(topology_sibling_cpumask(cpu)) == 1
> +	 * means no CPU is set on cpu_mask in the same compute unit
> +	 * before init current STARTING CPU.
> +	 */
> +	if (!cpumask_intersects(&cpu_mask, topology_sibling_cpumask(cpu)) &&
> +	    cpumask_weight(topology_sibling_cpumask(cpu)) == 1)
> +			cpumask_set_cpu(cpu, &cpu_mask);

I don't think you need that complexity.

	target = cpumask_any_but(topology_sibling_cpumask(cpu), cpu);
	if (target >= nr_cpumask_bits)
		cpumask_set_cpu(cpu, &cpu_mask);
	   
Simply because if there is a cpu aside of the new one already in the sibling
mask, then it is also in cpu_mask. Hmm?

> +static int
> +power_cpu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
> +{
> +	unsigned int cpu = (long)hcpu;
> +
> +	switch (action & ~CPU_TASKS_FROZEN) {
> +	case CPU_STARTING:
> +		power_cpu_init(cpu);
> +		break;
> +	case CPU_DOWN_PREPARE:
> +		power_cpu_exit(cpu);
> +		break;

And of course if CPU_DOWN_PREPARE fails and this is the last cpu in the
compute unit, nothing takes over the duty for this compute unit. So you need
to handle CPU_DOWN_FAILED ....

> +static int __init amd_power_pmu_init(void)
> +{
> +	int i, ret;
> +	u64 tmp;
> +
> +	if (!x86_match_cpu(cpu_match))
> +		return 0;
> +
> +	if (!boot_cpu_has(X86_FEATURE_ACC_POWER))
> +		return -ENODEV;
> +
> +	cu_num = boot_cpu_data.x86_max_cores / smp_num_siblings;
> +
> +	cpu_pwr_sample_ratio = cpuid_ecx(0x80000007);
> +
> +	if (rdmsrl_safe(MSR_F15H_CU_MAX_PWR_ACCUMULATOR, &tmp)) {
> +		pr_err("Failed to read max compute unit power accumulator MSR\n");
> +		return -ENODEV;
> +	}
> +	max_cu_acc_power = tmp;

Why do you need an intermediate 'tmp' for this?

> +	cpu_notifier_register_begin();
> +
> +	/* Choose one online core of each compute unit. */
> +	for (i = 0; i < boot_cpu_data.x86_max_cores; i += smp_num_siblings) {
> +		WARN_ON(cpumask_empty(topology_sibling_cpumask(i)));

Err. What guarantees that in each compute unit is one sibling online? And what
value has that WARN_ON? We don't care about the stack trace here, because it's
known already.

> +		cpumask_set_cpu(cpumask_any(topology_sibling_cpumask(i)), &cpu_mask);

Of course you just continue in that case and end up with:

       	      cpumask_set_cpu(nr_cpu_ids, &cpu_mask);

i.e. you try to do that on an invalid bit, which will trigger a justified
warning in cpumask_set_cpu() if CONFIG_DEBUG_PER_CPU_MAPS is enabled.

Aside of that this only handles a single socket. And why do you do the above
if you handle the same thing in the loop below?

> +	}
> +
> +	for_each_online_cpu(i)
> +		power_cpu_init(i);
> +
> +	__register_cpu_notifier(&power_cpu_notifier_nb);
> +
> +	ret = perf_pmu_register(&pmu_class, "power", -1);
> +	if (WARN_ON(ret)) {
> +		pr_warn("AMD Power PMU registration failed\n");

This still leaks the cpu notifier. .....

> +		goto out;
> +	}
> +
> +	pr_info("AMD Power PMU detected, %d compute units\n", cu_num);

Why is the number of compute units interesting at all?

Thanks,

	tglx

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v6 2/2] perf/x86/amd/power: Add AMD accumulated power reporting mechanism
  2016-03-03  8:50   ` Thomas Gleixner
@ 2016-03-03 15:13     ` Huang Rui
  2016-03-03 15:26       ` Thomas Gleixner
  0 siblings, 1 reply; 9+ messages in thread
From: Huang Rui @ 2016-03-03 15:13 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Borislav Petkov, Peter Zijlstra, Ingo Molnar, Andy Lutomirski,
	Robert Richter, Jacob Shin, Arnaldo Carvalho de Melo, Kan Liang,
	linux-kernel, spg_linux_kernel, x86, Suravee Suthikulpanit,
	Aravind Gopalakrishnan, Borislav Petkov, Fengguang Wu,
	Guenter Roeck

On Thu, Mar 03, 2016 at 09:50:11AM +0100, Thomas Gleixner wrote:
> On Thu, 3 Mar 2016, Huang Rui wrote:
> > +
> > +static void power_cpu_init(int cpu)
> > +{
> > +	/*
> > +	 * 1) If any CPU is set at cpu_mask in the same compute unit, do
> > +	 * nothing.
> > +	 * 2) If no CPU is set at cpu_mask in the same compute unit,
> > +	 * set current STARTING CPU.
> > +	 *
> > +	 * If cpu_mask and topology_sibling_cpumask has intersected
> > +	 * bits, that means any CPU is set in the same compute unit.
> > +	 * But cpumask_weight(topology_sibling_cpumask(cpu)) == 1
> > +	 * means no CPU is set on cpu_mask in the same compute unit
> > +	 * before init current STARTING CPU.
> > +	 */
> > +	if (!cpumask_intersects(&cpu_mask, topology_sibling_cpumask(cpu)) &&
> > +	    cpumask_weight(topology_sibling_cpumask(cpu)) == 1)
> > +			cpumask_set_cpu(cpu, &cpu_mask);
> 
> I don't think you need that complexity.
> 
> 	target = cpumask_any_but(topology_sibling_cpumask(cpu), cpu);
> 	if (target >= nr_cpumask_bits)
> 		cpumask_set_cpu(cpu, &cpu_mask);
> 	   
> Simply because if there is a cpu aside of the new one already in the sibling
> mask, then it is also in cpu_mask. Hmm?
> 

Make sense. Thanks. Will update.

> > +static int
> > +power_cpu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
> > +{
> > +	unsigned int cpu = (long)hcpu;
> > +
> > +	switch (action & ~CPU_TASKS_FROZEN) {
> > +	case CPU_STARTING:
> > +		power_cpu_init(cpu);
> > +		break;
> > +	case CPU_DOWN_PREPARE:
> > +		power_cpu_exit(cpu);
> > +		break;
> 
> And of course if CPU_DOWN_PREPARE fails and this is the last cpu in the
> compute unit, nothing takes over the duty for this compute unit. So you need
> to handle CPU_DOWN_FAILED ....
> 

OK, so I need to do power_cpu_init when notified CPU_DOWN_FAILED, am I
right?

> > +static int __init amd_power_pmu_init(void)
> > +{
> > +	int i, ret;
> > +	u64 tmp;
> > +
> > +	if (!x86_match_cpu(cpu_match))
> > +		return 0;
> > +
> > +	if (!boot_cpu_has(X86_FEATURE_ACC_POWER))
> > +		return -ENODEV;
> > +
> > +	cu_num = boot_cpu_data.x86_max_cores / smp_num_siblings;
> > +
> > +	cpu_pwr_sample_ratio = cpuid_ecx(0x80000007);
> > +
> > +	if (rdmsrl_safe(MSR_F15H_CU_MAX_PWR_ACCUMULATOR, &tmp)) {
> > +		pr_err("Failed to read max compute unit power accumulator MSR\n");
> > +		return -ENODEV;
> > +	}
> > +	max_cu_acc_power = tmp;
> 
> Why do you need an intermediate 'tmp' for this?
> 

Will use max_cu_acc_power directly.

> > +	cpu_notifier_register_begin();
> > +
> > +	/* Choose one online core of each compute unit. */
> > +	for (i = 0; i < boot_cpu_data.x86_max_cores; i += smp_num_siblings) {
> > +		WARN_ON(cpumask_empty(topology_sibling_cpumask(i)));
> 
> Err. What guarantees that in each compute unit is one sibling online? And what
> value has that WARN_ON? We don't care about the stack trace here, because it's
> known already.
> 

When this driver is not as module before, I think there should be one
sibling online at least at initialization phase. But now, you're
right, we cannot guarantee it.

> > +		cpumask_set_cpu(cpumask_any(topology_sibling_cpumask(i)), &cpu_mask);
> 
> Of course you just continue in that case and end up with:
> 
>        	      cpumask_set_cpu(nr_cpu_ids, &cpu_mask);
> 
> i.e. you try to do that on an invalid bit, which will trigger a justified
> warning in cpumask_set_cpu() if CONFIG_DEBUG_PER_CPU_MAPS is enabled.
> 
> Aside of that this only handles a single socket. And why do you do the above
> if you handle the same thing in the loop below?
> 

Because the sibling online shouldn't be empty at initialization phase
if the driver is not module before. So...

Thanks to catch it.

How about below update:

for (i = 0; i < boot_cpu_data.x86_max_cores; i += smp_num_siblings) {
        if (!cpumask_empty(topology_sibling_cpumask(i)))
                cpumask_set_cpu(cpumask_any(topology_sibling_cpumask(i)), &cpu_mask);
}

> > +	}
> > +
> > +	for_each_online_cpu(i)
> > +		power_cpu_init(i);
> > +
> > +	__register_cpu_notifier(&power_cpu_notifier_nb);
> > +
> > +	ret = perf_pmu_register(&pmu_class, "power", -1);
> > +	if (WARN_ON(ret)) {
> > +		pr_warn("AMD Power PMU registration failed\n");
> 
> This still leaks the cpu notifier. .....
> 

OK, so I should do __unregister_cpu_notifier(&power_cpu_notifier_nb)
here.

> > +		goto out;
> > +	}
> > +
> > +	pr_info("AMD Power PMU detected, %d compute units\n", cu_num);
> 
> Why is the number of compute units interesting at all?
> 

Because the accumulated power bases on compute units.
We can see the mask from /sys/devices/power/cpumask and number of
compute units to know if all compute units are set at cpumask.
So I add a printk here, does it make sense?

Thanks,
Rui

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v6 2/2] perf/x86/amd/power: Add AMD accumulated power reporting mechanism
  2016-03-03 15:13     ` Huang Rui
@ 2016-03-03 15:26       ` Thomas Gleixner
  2016-03-03 16:18         ` Huang Rui
  0 siblings, 1 reply; 9+ messages in thread
From: Thomas Gleixner @ 2016-03-03 15:26 UTC (permalink / raw)
  To: Huang Rui
  Cc: Borislav Petkov, Peter Zijlstra, Ingo Molnar, Andy Lutomirski,
	Robert Richter, Jacob Shin, Arnaldo Carvalho de Melo, Kan Liang,
	linux-kernel, spg_linux_kernel, x86, Suravee Suthikulpanit,
	Aravind Gopalakrishnan, Borislav Petkov, Fengguang Wu,
	Guenter Roeck

On Thu, 3 Mar 2016, Huang Rui wrote:
> On Thu, Mar 03, 2016 at 09:50:11AM +0100, Thomas Gleixner wrote:
> > On Thu, 3 Mar 2016, Huang Rui wrote:
> > And of course if CPU_DOWN_PREPARE fails and this is the last cpu in the
> > compute unit, nothing takes over the duty for this compute unit. So you need
> > to handle CPU_DOWN_FAILED ....
> > 
> 
> OK, so I need to do power_cpu_init when notified CPU_DOWN_FAILED, am I
> right?

Yes.
 
> > > +	cpu_notifier_register_begin();
> > > +
> > > +	/* Choose one online core of each compute unit. */
> > > +	for (i = 0; i < boot_cpu_data.x86_max_cores; i += smp_num_siblings) {
> > > +		WARN_ON(cpumask_empty(topology_sibling_cpumask(i)));
> > 
> > Err. What guarantees that in each compute unit is one sibling online? And what
> > value has that WARN_ON? We don't care about the stack trace here, because it's
> > known already.
> > 
> 
> When this driver is not as module before, I think there should be one
> sibling online at least at initialization phase. But now, you're
> right, we cannot guarantee it.
> 
> > > +		cpumask_set_cpu(cpumask_any(topology_sibling_cpumask(i)), &cpu_mask);
> > 
> > Of course you just continue in that case and end up with:
> > 
> >        	      cpumask_set_cpu(nr_cpu_ids, &cpu_mask);
> > 
> > i.e. you try to do that on an invalid bit, which will trigger a justified
> > warning in cpumask_set_cpu() if CONFIG_DEBUG_PER_CPU_MAPS is enabled.
> > 
> > Aside of that this only handles a single socket. And why do you do the above
> > if you handle the same thing in the loop below?
> > 
> 
> Because the sibling online shouldn't be empty at initialization phase
> if the driver is not module before. So...
> 
> Thanks to catch it.
> 
> How about below update:
> 
> for (i = 0; i < boot_cpu_data.x86_max_cores; i += smp_num_siblings) {
>         if (!cpumask_empty(topology_sibling_cpumask(i)))
>                 cpumask_set_cpu(cpumask_any(topology_sibling_cpumask(i)), &cpu_mask);
> }

Why? You do a full for_each_online_cpu(i) loop after that, which does
exactly the same thing, right?
 
> > > +	}
> > > +
> > > +	for_each_online_cpu(i)
> > > +		power_cpu_init(i);
> > > +
> > > +	__register_cpu_notifier(&power_cpu_notifier_nb);
> > > +
> > > +	ret = perf_pmu_register(&pmu_class, "power", -1);
> > > +	if (WARN_ON(ret)) {
> > > +		pr_warn("AMD Power PMU registration failed\n");
> > 
> > This still leaks the cpu notifier. .....
> > 
> 
> OK, so I should do __unregister_cpu_notifier(&power_cpu_notifier_nb)
> here.

You can register the notifier after perf_pmu_register succeeded, right?
 
> > > +	pr_info("AMD Power PMU detected, %d compute units\n", cu_num);
> > 
> > Why is the number of compute units interesting at all?
> > 
> 
> Because the accumulated power bases on compute units.
> We can see the mask from /sys/devices/power/cpumask and number of
> compute units to know if all compute units are set at cpumask.
> So I add a printk here, does it make sense?

No, because it's completely non intuitive. How on earth am I supposed to get
the connection between /sys/devices/power/cpumask and number of compute units
without staring at the code? So this is only interesting for a developer who
can deduce that number from /proc/cpuinfo or dmesg as well.

Thanks,

	tglx

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v6 2/2] perf/x86/amd/power: Add AMD accumulated power reporting mechanism
  2016-03-03 15:26       ` Thomas Gleixner
@ 2016-03-03 16:18         ` Huang Rui
  2016-03-03 17:57           ` Thomas Gleixner
  0 siblings, 1 reply; 9+ messages in thread
From: Huang Rui @ 2016-03-03 16:18 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Borislav Petkov, Peter Zijlstra, Ingo Molnar, Andy Lutomirski,
	Robert Richter, Jacob Shin, Arnaldo Carvalho de Melo, Kan Liang,
	linux-kernel, spg_linux_kernel, x86, Suravee Suthikulpanit,
	Aravind Gopalakrishnan, Borislav Petkov, Fengguang Wu,
	Guenter Roeck

On Thu, Mar 03, 2016 at 04:26:46PM +0100, Thomas Gleixner wrote:
> On Thu, 3 Mar 2016, Huang Rui wrote:
> > On Thu, Mar 03, 2016 at 09:50:11AM +0100, Thomas Gleixner wrote:
> > > On Thu, 3 Mar 2016, Huang Rui wrote:
> > > And of course if CPU_DOWN_PREPARE fails and this is the last cpu in the
> > > compute unit, nothing takes over the duty for this compute unit. So you need
> > > to handle CPU_DOWN_FAILED ....
> > > 
> > 
> > OK, so I need to do power_cpu_init when notified CPU_DOWN_FAILED, am I
> > right?
> 
> Yes.
>  
> > > > +	cpu_notifier_register_begin();
> > > > +
> > > > +	/* Choose one online core of each compute unit. */
> > > > +	for (i = 0; i < boot_cpu_data.x86_max_cores; i += smp_num_siblings) {
> > > > +		WARN_ON(cpumask_empty(topology_sibling_cpumask(i)));
> > > 
> > > Err. What guarantees that in each compute unit is one sibling online? And what
> > > value has that WARN_ON? We don't care about the stack trace here, because it's
> > > known already.
> > > 
> > 
> > When this driver is not as module before, I think there should be one
> > sibling online at least at initialization phase. But now, you're
> > right, we cannot guarantee it.
> > 
> > > > +		cpumask_set_cpu(cpumask_any(topology_sibling_cpumask(i)), &cpu_mask);
> > > 
> > > Of course you just continue in that case and end up with:
> > > 
> > >        	      cpumask_set_cpu(nr_cpu_ids, &cpu_mask);
> > > 
> > > i.e. you try to do that on an invalid bit, which will trigger a justified
> > > warning in cpumask_set_cpu() if CONFIG_DEBUG_PER_CPU_MAPS is enabled.
> > > 
> > > Aside of that this only handles a single socket. And why do you do the above
> > > if you handle the same thing in the loop below?
> > > 
> > 
> > Because the sibling online shouldn't be empty at initialization phase
> > if the driver is not module before. So...
> > 
> > Thanks to catch it.
> > 
> > How about below update:
> > 
> > for (i = 0; i < boot_cpu_data.x86_max_cores; i += smp_num_siblings) {
> >         if (!cpumask_empty(topology_sibling_cpumask(i)))
> >                 cpumask_set_cpu(cpumask_any(topology_sibling_cpumask(i)), &cpu_mask);
> > }
> 
> Why? You do a full for_each_online_cpu(i) loop after that, which does
> exactly the same thing, right?
>  

But looks like power_cpu_init cannot handle it if we don't take any
action here.

e. g. 
cpu_mask: 0000 and online mask: 1111 -> power_cpu_init(0) -> cpu_mask is still: 0000

topology_sibling_cpumask(0): 0011
target: 1 (i. e. we cannot do cpumask_set_cpu(0, &cpu_mask))

Maybe, we need to think out a stronger power_cpu_init if you want to
only do init thing at for_each_online_cpu.

> > > > +	}
> > > > +
> > > > +	for_each_online_cpu(i)
> > > > +		power_cpu_init(i);
> > > > +
> > > > +	__register_cpu_notifier(&power_cpu_notifier_nb);
> > > > +
> > > > +	ret = perf_pmu_register(&pmu_class, "power", -1);
> > > > +	if (WARN_ON(ret)) {
> > > > +		pr_warn("AMD Power PMU registration failed\n");
> > > 
> > > This still leaks the cpu notifier. .....
> > > 
> > 
> > OK, so I should do __unregister_cpu_notifier(&power_cpu_notifier_nb)
> > here.
> 
> You can register the notifier after perf_pmu_register succeeded, right?
>  

Yep.

> > > > +	pr_info("AMD Power PMU detected, %d compute units\n", cu_num);
> > > 
> > > Why is the number of compute units interesting at all?
> > > 
> > 
> > Because the accumulated power bases on compute units.
> > We can see the mask from /sys/devices/power/cpumask and number of
> > compute units to know if all compute units are set at cpumask.
> > So I add a printk here, does it make sense?
> 
> No, because it's completely non intuitive. How on earth am I supposed to get
> the connection between /sys/devices/power/cpumask and number of compute units
> without staring at the code? So this is only interesting for a developer who
> can deduce that number from /proc/cpuinfo or dmesg as well.
> 

OK, I will remove unnecessary cu_num next version. 

Thanks,
Rui

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v6 2/2] perf/x86/amd/power: Add AMD accumulated power reporting mechanism
  2016-03-03 16:18         ` Huang Rui
@ 2016-03-03 17:57           ` Thomas Gleixner
  2016-03-04  3:11             ` Huang Rui
  0 siblings, 1 reply; 9+ messages in thread
From: Thomas Gleixner @ 2016-03-03 17:57 UTC (permalink / raw)
  To: Huang Rui
  Cc: Borislav Petkov, Peter Zijlstra, Ingo Molnar, Andy Lutomirski,
	Robert Richter, Jacob Shin, Arnaldo Carvalho de Melo, Kan Liang,
	linux-kernel, spg_linux_kernel, x86, Suravee Suthikulpanit,
	Aravind Gopalakrishnan, Borislav Petkov, Fengguang Wu,
	Guenter Roeck

On Fri, 4 Mar 2016, Huang Rui wrote:
> On Thu, Mar 03, 2016 at 04:26:46PM +0100, Thomas Gleixner wrote:
> > Why? You do a full for_each_online_cpu(i) loop after that, which does
> > exactly the same thing, right?
> >  
> 
> But looks like power_cpu_init cannot handle it if we don't take any
> action here.
> 
> e. g. 
> cpu_mask: 0000 and online mask: 1111 -> power_cpu_init(0) -> cpu_mask is still: 0000
> 
> topology_sibling_cpumask(0): 0011
> target: 1 (i. e. we cannot do cpumask_set_cpu(0, &cpu_mask))

Fair enough, but then you don't need the power_cpu_init() call at all.

But your loop does not cover anything beyond the first socket. So you need a
separate init function which does:

   for_each_online_cpu(cpu) {
   	target = cpumask_first(topology_sibling_cpumask(cpu));
	if (!cpumask_test_cpu(target, cpumask))
	   	cpumask_set_cpu(target, cpumask);
   }	      
	   	
Thanks,

	tglx

   

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v6 2/2] perf/x86/amd/power: Add AMD accumulated power reporting mechanism
  2016-03-03 17:57           ` Thomas Gleixner
@ 2016-03-04  3:11             ` Huang Rui
  0 siblings, 0 replies; 9+ messages in thread
From: Huang Rui @ 2016-03-04  3:11 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Borislav Petkov, Peter Zijlstra, Ingo Molnar, Andy Lutomirski,
	Robert Richter, Jacob Shin, Arnaldo Carvalho de Melo, Kan Liang,
	linux-kernel, spg_linux_kernel, x86, Suravee Suthikulpanit,
	Aravind Gopalakrishnan, Borislav Petkov, Fengguang Wu,
	Guenter Roeck

On Thu, Mar 03, 2016 at 06:57:53PM +0100, Thomas Gleixner wrote:
> On Fri, 4 Mar 2016, Huang Rui wrote:
> > On Thu, Mar 03, 2016 at 04:26:46PM +0100, Thomas Gleixner wrote:
> > > Why? You do a full for_each_online_cpu(i) loop after that, which does
> > > exactly the same thing, right?
> > >  
> > 
> > But looks like power_cpu_init cannot handle it if we don't take any
> > action here.
> > 
> > e. g. 
> > cpu_mask: 0000 and online mask: 1111 -> power_cpu_init(0) -> cpu_mask is still: 0000
> > 
> > topology_sibling_cpumask(0): 0011
> > target: 1 (i. e. we cannot do cpumask_set_cpu(0, &cpu_mask))
> 
> Fair enough, but then you don't need the power_cpu_init() call at all.
> 
> But your loop does not cover anything beyond the first socket. So you need a
> separate init function which does:
> 
>    for_each_online_cpu(cpu) {
>    	target = cpumask_first(topology_sibling_cpumask(cpu));
> 	if (!cpumask_test_cpu(target, cpumask))
> 	   	cpumask_set_cpu(target, cpumask);
>    }	      
> 	   	

Looks good. Thanks Thomas. Will update it.

Rui

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2016-03-04  3:12 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-03-03  8:04 [PATCH v6 0/2] perf/x86/power: Introduce AMD accumlated power reporting mechanism Huang Rui
2016-03-03  8:04 ` [PATCH v6 1/2] perf/x86: Export events_sysfs_show() Huang Rui
2016-03-03  8:04 ` [PATCH v6 2/2] perf/x86/amd/power: Add AMD accumulated power reporting mechanism Huang Rui
2016-03-03  8:50   ` Thomas Gleixner
2016-03-03 15:13     ` Huang Rui
2016-03-03 15:26       ` Thomas Gleixner
2016-03-03 16:18         ` Huang Rui
2016-03-03 17:57           ` Thomas Gleixner
2016-03-04  3:11             ` Huang Rui

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox