[PATCH 4/7] perf: Check if HT is supported and enabled

Previous thread: [PATCH 3/7] perf-events: Fix LLC-* events on Intel Nehalem/Westmere v2 by Lin Ming on Monday, December 27, 2010 - 8:36 am. (1 message)

Next thread: [PATCH] Input: bu21013_ts: fix misuse of logical operation in place of bitop by David Sterba on Monday, December 27, 2010 - 8:36 am. (3 messages)
From: Lin Ming
Date: Monday, December 27, 2010 - 8:36 am

Avoid the percore allocations if HT is not supported or disabled.

Signed-off-by: Lin Ming <ming.m.lin@intel.com>
---
 arch/x86/kernel/cpu/perf_event_intel.c |   44 +++++++++++++++++++++++++++----
 1 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index bc4afb1..354d1de 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -1053,9 +1053,38 @@ static __initconst const struct x86_pmu core_pmu = {
 	.event_constraints	= intel_core_event_constraints,
 };
 
+/*
+ * Check if HT is capable and enabled
+ * TBD: move it to generic place, so it can be used by others
+ */
+
+static bool ht_enabled(int cpu)
+{
+	int total_logical_processors, total_cores;
+	unsigned int eax, ebx, ecx, edx;
+
+	cpuid(1, &eax, &ebx, &ecx, &edx);
+
+	/* Bit 28 in EDX indicates if it's HT capable */
+	if (!(edx & 0x10000000))
+		return false;
+
+	total_logical_processors = (ebx >> 16) & 0xff;
+
+	ecx = 0;
+	cpuid(4, &eax, &ebx, &ecx, &edx);
+	total_cores = ((eax >> 26) & 0x3f) + 1;
+
+	/* Thread nums per core */
+	return (total_logical_processors / total_cores) > 1;
+}
+
 static int intel_pmu_cpu_prepare(int cpu)
 {
 	struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
+
+	if (!ht_enabled(cpu))
+		return NOTIFY_OK;
 	
 	cpuc->per_core = kzalloc_node(sizeof(struct intel_percore), 
 				      GFP_KERNEL, cpu_to_node(cpu));
@@ -1073,6 +1102,15 @@ static void intel_pmu_cpu_starting(int cpu)
 	int core_id = topology_core_id(cpu);
 	int i;
 
+	init_debug_store_on_cpu(cpu);
+	/*
+	 * Deal with CPUs that don't clear their LBRs on power-up.
+	 */
+	intel_pmu_lbr_reset();
+
+	if (!ht_enabled(cpu))
+		return;
+
 	for_each_online_cpu(i) {
 		struct intel_percore *pc = per_cpu(cpu_hw_events, i).per_core;
 
@@ -1085,12 +1123,6 @@ static void intel_pmu_cpu_starting(int cpu)
 
 	cpuc->per_core->core_id = core_id;
 ...
From: Lin Ming
Date: Tuesday, December 28, 2010 - 1:51 am

This function can be simplified as below,

static bool ht_enabled()
{
        if (!cpu_has(&boot_cpu_data, X86_FEATURE_HT))
                return false;

        return smp_num_siblings > 1;
}

But this still can't detect if HT is on or off.
smp_num_siblings is always 2 even if HT is disabled in BIOS.

Any idea how to detect if HT is on or not?

Thanks,


--

From: Peter Zijlstra
Date: Monday, January 3, 2011 - 3:58 am

Not quite sure, the intel docs aren't really clear on how the HW
supports HT, has 2 siblings but BIOS disabled it thing works. I just
tried reading the arch/x86 code but that only got me more confused.

hpa, could you comment?
--

From: Andi Kleen
Date: Monday, January 3, 2011 - 8:21 am

... or you just keep the original code which works fine in any case
without this.

-Andi
--

From: H. Peter Anvin
Date: Monday, January 3, 2011 - 12:53 pm

Zeroeth of all: anyone who writes () in a function prototype in C needs
to get severely napalmed, maimed, hung and then really hurt.  It is
(void) in C, () means (...) which is literally NEVER what you want.

Now, *first* of all: smp_num_siblings as it sits is obviously broken;
the whole notion of a global variable for what is inherently a per-cpu
property is just braindead.  At least theoretically there could be cores
with and without HT or with different thread count in the same system.

Second, perf should get this from /proc/cpuinfo, not by grotting around
cpuid by itself.

Third, the code in the kernel is indeed pretty confusing, and it also
has the global variable braindamage... but either it works (in which
case getting the data from /proc/cpuinfo works) or it needs fixing in
addition to the global variable issue.

	-hpa
--

From: Peter Zijlstra
Date: Tuesday, January 4, 2011 - 4:10 am

Its the kernel space bit that wants to know if HT is enabled on CPU

So you failed to address the primary question, how do we tell if HT is
enabled for a particular CPU?

X86_FEATURE_HT tells us the CPU supports telling us about HT,
smp_num_siblings > 1 tells us the CPU is capable of HT. But Lin found
that if you disable HT in the BIOS both those are true but we still
don't have HT enabled.

The problem we have to address is that Intel has some MSRs shared
between threads and if HT is enabled we need to allocate some memory to
manage this shared resource.

The simple check outlined above X86_FEATURE_HT && smp_num_siblings > 1,
will get us most of the way and will I think be good enough (false
positives but no false negatives). But it did get us wondering about how
all this works.

So could you, irrespective of Linux implementation details tell us how
to detect if HT is available and enabled from a HW and BIOS perspective?
--

From: Stephane Eranian
Date: Tuesday, January 4, 2011 - 6:38 am

Hi,

I had to deal with this issue with perfmon back in 2.6.30 and earlier kernels.
I remember that I was surprised not to find any easy helper function to figure
this out back then. Being HT capable is different from having HT enabled.
Seems like the situation has not improved since then.

My solution at the time (2.6.30) was to do:
        ht_enabled = cpumask_weight(__get_cpu_var(cpu_sibling_map)) > 1;

Not too convinced the per-cpu variable is necessary because I don't
know of a BIOS that would allow you to turn on HT on only some of the
cores (AFAIK, this is an all or nothing feature).


--

From: Peter Zijlstra
Date: Tuesday, January 4, 2011 - 6:44 am

Won't that report a machine a HT disabled when you offline a sibling?
Which kinda defeats the purpose of our usage here, since we need to know
it before either sibling comes online.
--

From: Stephane Eranian
Date: Tuesday, January 4, 2011 - 6:52 am

Then, it seems the only hope is to peek at a MSR that reports the BIOS setting.
But I don't know which one it is.

Couldn't you simply over-provision, and then when the CPU is online, use my
ht_enabled statement to figure out whether or not you need to handle the sharing
issue?
--

From: Peter Zijlstra
Date: Tuesday, January 4, 2011 - 6:58 am

That's pretty much what Lin's latest does:

 X86_FEATURE_HT && smp_num_siblings > 1

shows the CPU is capable of HT and will allocate the needed resources.
--

From: Stephane Eranian
Date: Tuesday, January 4, 2011 - 8:35 am

Ok, but once the CPU is online, you can still check whether or not HT is
enabled. If not, then you don't need to bother with the MSR sharing code.
So you may allocate a data structure which you won't use and I think that's
fine given we don't have a good way of figuring out whether HT is enabled
or not.
--

From: H. Peter Anvin
Date: Tuesday, January 4, 2011 - 12:00 pm

From the sound of it, it doesn't seem like it's worth optimizing out the
fairly small memory allocation.

	-hpa

--

From: Valdis.Kletnieks
Date: Tuesday, January 4, 2011 - 11:55 am

A subtle but important distinction. Several laptops ago, I had a P4-M chip that
had FEATURE_HT, but num_siblings == 1.  ISTR trying to boot an SMP kernel on it
and it dying gloriously trying to bring up the non-existent other sibling.

Previous thread: [PATCH 3/7] perf-events: Fix LLC-* events on Intel Nehalem/Westmere v2 by Lin Ming on Monday, December 27, 2010 - 8:36 am. (1 message)

Next thread: [PATCH] Input: bu21013_ts: fix misuse of logical operation in place of bitop by David Sterba on Monday, December 27, 2010 - 8:36 am. (3 messages)