Skip to contentSkip to conversation

x86 SMP: enables core-pair topology detection for AMD CPUs

RFC PATCH In review Wei Huang 4 participants 6 messages Jun 23, 2011 – Oct 21, 2011

lore
Share & tools
lore

Wei Huang

author
#0 lore raw

cover x86 SMP: enables core-pair topology detection for AMD CPUs

Hi,

The following two patches enable core-pair topology detection for AMD CPUs. The main idea is to record compute unit information into cpuinfo_x86 and use it when building sibling map. The sibling map will be used by Xen credit scheduler to coordinate VCPU scheduling in a fashion similar to SMT. This code is very similar to upstream Linux kernel.

Regarding the performance improvement, I saw ~8% improvement running kernel compilation on Dom0 with this patch. Anrea Przywara ran a POVRay benchmark using this patch and he saw ~5% improvement. No perf degradation was seen so far.

Please review.

Thanks,
-Wei

#1 lore raw
Quoted 9 lines
Quoted 1 line
Quoted 1 line · Wei Huang

Hi,

The following two patches enable core-pair topology detection for AMD CPUs. The main idea is to record compute unit information into cpuinfo_x86 and use it when building sibling map. The sibling map will be used by Xen credit scheduler to coordinate VCPU scheduling in a fashion similar to SMT. This code is very similar to upstream Linux kernel.

Quoted 6 lines

Regarding the performance improvement, I saw ~8% improvement running kernel compilation on Dom0 with this patch. Anrea Przywara ran a POVRay benchmark using this patch and he saw ~5% improvement. No perf degradation was seen so far.

Please review.

Apart from some indentation issues these look fine to me.

Jan

Quoted 2 lines

Thanks,
-Wei

author
#2 lore raw

Thanks, Jan and George. I attach the latest version which fixes the indentation issues.

-Wei

Quoted 14 lines · Jan Beulich
Quoted 14 lines
Quoted 1 line
Quoted 1 line · Wei Huang

Hi,

The following two patches enable core-pair topology detection for AMD CPUs. The main idea is to record compute unit information into cpuinfo_x86 and use it when building sibling map. The sibling map will be used by Xen credit scheduler to coordinate VCPU scheduling in a fashion similar to SMT. This code is very similar to upstream Linux kernel.

Regarding the performance improvement, I saw ~8% improvement running kernel compilation on Dom0 with this patch. Anrea Przywara ran a POVRay benchmark using this patch and he saw ~5% improvement. No perf degradation was seen so far.

Quoted 10 lines
Quoted 1 line

Please review.

Apart from some indentation issues these look fine to me.

Jan

Quoted 2 lines

Thanks,
-Wei

# HG changeset patch
# User Wei Huang <[email protected]>
# Date 1309193579 18000
# Node ID e6c4ff6fcb9fcbf1899463e5ec6c425bcbd683e3
# Parent d3027374a8c0d548c6ff468c4d747300e858904b
SMP: consolidate cpu_core_id and phys_proc_id into cpuinfo_x86 struct

This patch moves cpu_core_id and phys_proc_id into cpuinfo_x86 structure. This is similar to upstream Linux kernel's approach.

xen/arch/x86/cpu/amd.c +3 -3
diff -r d3027374a8c0 -r e6c4ff6fcb9f xen/arch/x86/cpu/amd.c
@@ -446,11 +446,11 @@
 			while ((1 << bits) < c->x86_max_cores)
 				bits++;
 		}
-		cpu_core_id[cpu] = phys_proc_id[cpu] & ((1<<bits)-1);
-		phys_proc_id[cpu] >>= bits;
+		c->cpu_core_id = c->phys_proc_id & ((1<<bits)-1);
+		c->phys_proc_id >>= bits;
 		if (opt_cpu_info)
 			printk("CPU %d(%d) -> Core %d\n",
-			       cpu, c->x86_max_cores, cpu_core_id[cpu]);
+			       cpu, c->x86_max_cores, c->cpu_core_id);
 	}
 #endif
 
xen/arch/x86/cpu/common.c +11 -11
diff -r d3027374a8c0 -r e6c4ff6fcb9f xen/arch/x86/cpu/common.c
@@ -271,7 +271,7 @@
 	early_intel_workaround(c);
 
 #ifdef CONFIG_X86_HT
-	phys_proc_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff;
+	c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff;
 #endif
 }
 
@@ -316,6 +316,8 @@
 	c->x86_max_cores = 1;
 	c->x86_num_siblings = 1;
 	c->x86_clflush_size = 0;
+	c->phys_proc_id = BAD_APICID;
+	c->cpu_core_id = BAD_APICID;
 	memset(&c->x86_capability, 0, sizeof c->x86_capability);
 
 	generic_identify(c);
@@ -453,7 +455,6 @@
 	unsigned int ht_mask_width, core_plus_mask_width;
 	unsigned int core_select_mask, core_level_siblings;
 	unsigned int initial_apicid;
-	int cpu = smp_processor_id();
 
 	if ( c->cpuid_level < 0xb )
 		return;
@@ -488,9 +489,9 @@
 
 	core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
 
-	cpu_core_id[cpu] = phys_pkg_id(initial_apicid, ht_mask_width)
+	c->cpu_core_id = phys_pkg_id(initial_apicid, ht_mask_width)
 		& core_select_mask;
-	phys_proc_id[cpu] = phys_pkg_id(initial_apicid, core_plus_mask_width);
+	c->phys_proc_id = phys_pkg_id(initial_apicid, core_plus_mask_width);
 
 	c->apicid = phys_pkg_id(initial_apicid, 0);
 	c->x86_max_cores = (core_level_siblings / c->x86_num_siblings);
@@ -498,10 +499,10 @@
 	if ( opt_cpu_info )
 	{
 		printk("CPU: Physical Processor ID: %d\n",
-		       phys_proc_id[cpu]);
+		       c->phys_proc_id);
 		if ( c->x86_max_cores > 1 )
 			printk("CPU: Processor Core ID: %d\n",
-			       cpu_core_id[cpu]);
+			       c->cpu_core_id);
 	}
 }
 
@@ -510,7 +511,6 @@
 {
 	u32 	eax, ebx, ecx, edx;
 	int 	index_msb, core_bits;
-	int 	cpu = smp_processor_id();
 
 	cpuid(1, &eax, &ebx, &ecx, &edx);
 
@@ -533,11 +533,11 @@
 		}
 
 		index_msb = get_count_order(c->x86_num_siblings);
-		phys_proc_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
+		c->phys_proc_id = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
 
 		if (opt_cpu_info)
 			printk("CPU: Physical Processor ID: %d\n",
-			       phys_proc_id[cpu]);
+			       c->phys_proc_id);
 
 		c->x86_num_siblings = c->x86_num_siblings / c->x86_max_cores;
 
@@ -545,12 +545,12 @@
 
 		core_bits = get_count_order(c->x86_max_cores);
 
-		cpu_core_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb) &
+		c->cpu_core_id = phys_pkg_id((ebx >> 24) & 0xFF, index_msb) &
 					       ((1 << core_bits) - 1);
 
 		if (opt_cpu_info && c->x86_max_cores > 1)
 			printk("CPU: Processor Core ID: %d\n",
-			       cpu_core_id[cpu]);
+			       c->cpu_core_id);
 	}
 }
 #endif
xen/arch/x86/cpu/mcheck/mce.c +2 -2
diff -r d3027374a8c0 -r e6c4ff6fcb9f xen/arch/x86/cpu/mcheck/mce.c
@@ -1046,9 +1046,9 @@
         if (nthreads != NULL)
             *nthreads = 1;
     } else {
-        *chipid = phys_proc_id[cpu];
+        *chipid = c->phys_proc_id;
         if (c->x86_max_cores > 1)
-            *coreid = cpu_core_id[cpu];
+            *coreid = c->cpu_core_id;
         else
             *coreid = 0;
         *threadid = c->apicid & ((1 << (c->x86_num_siblings - 1)) - 1);
xen/arch/x86/smpboot.c +5 -11
diff -r d3027374a8c0 -r e6c4ff6fcb9f xen/arch/x86/smpboot.c
@@ -49,12 +49,6 @@
 
 #define setup_trampoline()    (bootsym_phys(trampoline_realmode_entry))
 
-/* Package ID of each logical CPU */
-int phys_proc_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
-
-/* Core ID of each logical CPU */
-int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
-
 /* representing HT siblings of each logical CPU */
 DEFINE_PER_CPU_READ_MOSTLY(cpumask_t, cpu_sibling_map);
 /* representing HT and core siblings of each logical CPU */
@@ -247,8 +241,8 @@
     {
         for_each_cpu_mask ( i, cpu_sibling_setup_map )
         {
-            if ( (phys_proc_id[cpu] == phys_proc_id[i]) &&
-                 (cpu_core_id[cpu] == cpu_core_id[i]) )
+            if ( (c[cpu].phys_proc_id == c[i].phys_proc_id) &&
+                 (c[cpu].cpu_core_id == c[i].cpu_core_id) )
             {
                 cpu_set(i, per_cpu(cpu_sibling_map, cpu));
                 cpu_set(cpu, per_cpu(cpu_sibling_map, i));
@@ -271,7 +265,7 @@
 
     for_each_cpu_mask ( i, cpu_sibling_setup_map )
     {
-        if ( phys_proc_id[cpu] == phys_proc_id[i] )
+        if ( c[cpu].phys_proc_id == c[i].phys_proc_id )
         {
             cpu_set(i, per_cpu(cpu_core_map, cpu));
             cpu_set(cpu, per_cpu(cpu_core_map, i));
@@ -832,8 +826,8 @@
         cpu_clear(cpu, per_cpu(cpu_sibling_map, sibling));
     cpus_clear(per_cpu(cpu_sibling_map, cpu));
     cpus_clear(per_cpu(cpu_core_map, cpu));
-    phys_proc_id[cpu] = BAD_APICID;
-    cpu_core_id[cpu] = BAD_APICID;
+    c[cpu].phys_proc_id = BAD_APICID;
+    c[cpu].cpu_core_id = BAD_APICID;
     cpu_clear(cpu, cpu_sibling_setup_map);
 }
 
xen/include/asm-x86/processor.h +4 -4
diff -r d3027374a8c0 -r e6c4ff6fcb9f xen/include/asm-x86/processor.h
@@ -175,6 +175,8 @@
     __u32 x86_max_cores; /* cpuid returned max cores value */
     __u32 booted_cores;  /* number of cores as seen by OS */
     __u32 x86_num_siblings; /* cpuid logical cpus per chip value */
+    int   phys_proc_id; /* package ID of each logical CPU */
+    int   cpu_core_id; /* core ID of each logical CPU*/
     __u32 apicid;
     unsigned short x86_clflush_size;
 } __cacheline_aligned;
@@ -194,8 +196,6 @@
 #endif
 
 extern u64 host_pat;
-extern int phys_proc_id[NR_CPUS];
-extern int cpu_core_id[NR_CPUS];
 extern bool_t opt_cpu_info;
 
 /* Maximum width of physical addresses supported by the hardware */
@@ -215,8 +215,8 @@
 static always_inline void detect_ht(struct cpuinfo_x86 *c) {}
 #endif
 
-#define cpu_to_core(_cpu)   (cpu_core_id[_cpu])
-#define cpu_to_socket(_cpu) (phys_proc_id[_cpu])
+#define cpu_to_core(_cpu)   (cpu_data[_cpu].cpu_core_id)
+#define cpu_to_socket(_cpu) (cpu_data[_cpu].phys_proc_id)
 
 /*
  * Generic CPUID function

# HG changeset patch
# User Wei Huang <[email protected]>
# Date 1309193845 18000
# Node ID 4d928bdd56769eb8b09eefd5db80400e1c6c818a # Parent e6c4ff6fcb9fcbf1899463e5ec6c425bcbd683e3
x86: AMD core-pair topology detection code

This patch is to support core-pair topology introduced by AMD CPUs, which introduces a new concept of [core, compute unit]. There is a new feature bit for topology extension in CPUID:0x80000001. Also a new CPUID 0x8000001E is introduced for CPU topology enumeration. This patch collects the sibling information from the new CPUID and will be stored in the sibling map in Xen hypervisor.

xen/arch/x86/cpu/amd.c +44 -20

76 lines not on this page · raw message

xen/arch/x86/cpu/common.c +1 -0
diff -r e6c4ff6fcb9f -r 4d928bdd5676 xen/arch/x86/cpu/common.c
@@ -318,6 +318,7 @@
 	c->x86_clflush_size = 0;
 	c->phys_proc_id = BAD_APICID;
 	c->cpu_core_id = BAD_APICID;
+	c->compute_unit_id = BAD_APICID;
 	memset(&c->x86_capability, 0, sizeof c->x86_capability);
 
 	generic_identify(c);
xen/arch/x86/smpboot.c +16 -7
diff -r e6c4ff6fcb9f -r 4d928bdd5676 xen/arch/x86/smpboot.c
@@ -230,6 +230,14 @@
 /* CPUs for which sibling maps can be computed. */
 static cpumask_t cpu_sibling_setup_map;
 
+static void link_thread_siblings(int cpu1, int cpu2)
+{
+    cpu_set(cpu1, per_cpu(cpu_sibling_map, cpu2));
+    cpu_set(cpu2, per_cpu(cpu_sibling_map, cpu1));
+    cpu_set(cpu1, per_cpu(cpu_core_map, cpu2));
+    cpu_set(cpu2, per_cpu(cpu_core_map, cpu1));
+}
+
 static void set_cpu_sibling_map(int cpu)
 {
     int i;
@@ -241,13 +249,13 @@
     {
         for_each_cpu_mask ( i, cpu_sibling_setup_map )
         {
-            if ( (c[cpu].phys_proc_id == c[i].phys_proc_id) &&
-                 (c[cpu].cpu_core_id == c[i].cpu_core_id) )
-            {
-                cpu_set(i, per_cpu(cpu_sibling_map, cpu));
-                cpu_set(cpu, per_cpu(cpu_sibling_map, i));
-                cpu_set(i, per_cpu(cpu_core_map, cpu));
-                cpu_set(cpu, per_cpu(cpu_core_map, i));
+            if ( cpu_has(c, X86_FEATURE_TOPOEXT) ) {
+                if ( (c[cpu].phys_proc_id == c[i].phys_proc_id) &&
+                     (c[cpu].compute_unit_id == c[i].compute_unit_id) )
+                    link_thread_siblings(cpu, i);
+            } else if ( (c[cpu].phys_proc_id == c[i].phys_proc_id) &&
+                        (c[cpu].cpu_core_id == c[i].cpu_core_id) ) {
+                link_thread_siblings(cpu, i);
             }
         }
     }
@@ -828,6 +836,7 @@
     cpus_clear(per_cpu(cpu_core_map, cpu));
     c[cpu].phys_proc_id = BAD_APICID;
     c[cpu].cpu_core_id = BAD_APICID;
+    c[cpu].compute_unit_id = BAD_APICID;
     cpu_clear(cpu, cpu_sibling_setup_map);
 }
 
xen/include/asm-x86/processor.h +2 -1
diff -r e6c4ff6fcb9f -r 4d928bdd5676 xen/include/asm-x86/processor.h
@@ -175,9 +175,10 @@
     __u32 x86_max_cores; /* cpuid returned max cores value */
     __u32 booted_cores;  /* number of cores as seen by OS */
     __u32 x86_num_siblings; /* cpuid logical cpus per chip value */
+    __u32 apicid;
     int   phys_proc_id; /* package ID of each logical CPU */
     int   cpu_core_id; /* core ID of each logical CPU*/
-    __u32 apicid;
+    int   compute_unit_id; /* AMD compute unit ID of each logical CPU */
     unsigned short x86_clflush_size;
 } __cacheline_aligned;
 

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

Acked-by
#3 lore raw
Quoted 3 lines
Quoted 1 line
Quoted 1 line · Wei Huang

Thanks, Jan and George. I attach the latest version which fixes the indentation issues.

Quoted 29 lines

-Wei

Quoted 24 lines · Jan Beulich
Quoted 9 lines
Quoted 1 line
Quoted 1 line · Wei Huang

Hi,

The following two patches enable core-pair topology detection for AMD CPUs. The main idea is to record compute unit information into cpuinfo_x86 and use it when building sibling map. The sibling map will be used by Xen credit scheduler to coordinate VCPU scheduling in a fashion similar to SMT. This code is very similar to upstream Linux kernel.

Quoted 6 lines

Regarding the performance improvement, I saw ~8% improvement running kernel compilation on Dom0 with this patch. Anrea Przywara ran a POVRay benchmark using this patch and he saw ~5% improvement. No perf degradation was seen so far.

Please review.

Apart from some indentation issues these look fine to me.

Jan

Quoted 2 lines

Thanks,
-Wei

Acked-by
#4 lore raw
In reply to Wei Huang
Quoted 2 lines · Wei Huang

Thanks, Jan and George. I attach the latest version which fixes the indentation issues.

Assuming the patch has the same effect on the scheduling, my previous ack-effects-on-the-schedulers stands:

Quoted 30 lines

-Wei

Quoted 24 lines · Jan Beulich
Quoted 9 lines
Quoted 1 line
Quoted 1 line · Wei Huang

Hi,

The following two patches enable core-pair topology detection for AMD CPUs. The main idea is to record compute unit information into cpuinfo_x86 and use it when building sibling map. The sibling map will be used by Xen credit scheduler to coordinate VCPU scheduling in a fashion similar to SMT. This code is very similar to upstream Linux kernel.

Quoted 6 lines

Regarding the performance improvement, I saw ~8% improvement running kernel compilation on Dom0 with this patch. Anrea Przywara ran a POVRay benchmark using this patch and he saw ~5% improvement. No perf degradation was seen so far.

Please review.

Apart from some indentation issues these look fine to me.

Jan

Quoted 2 lines

Thanks,
-Wei

#5 lore raw
In reply to Wei Huang

Sorry for the late request -- should these patches be back-ported to 4.1.2? Otherwise anyone using AMD Magny-cours may have a significant performance hit when using 4.1.

-George

Quoted 43 lines · Wei Huang

Thanks, Jan and George. I attach the latest version which fixes the indentation issues.

-Wei

Quoted 17 lines · Jan Beulich
Quoted 17 lines
Quoted 2 lines
Quoted 2 lines · Wei Huang

Hi,

The following two patches enable core-pair topology detection for AMD CPUs. The main idea is to record compute unit information into cpuinfo_x86 and use it when building sibling map. The sibling map will be used by Xen credit scheduler to coordinate VCPU scheduling in a fashion similar to SMT. This code is very similar to upstream Linux kernel.

Regarding the performance improvement, I saw ~8% improvement running kernel compilation on Dom0 with this patch. Anrea Przywara ran a POVRay benchmark using this patch and he saw ~5% improvement. No perf degradation was seen so far.

Quoted 11 lines
Quoted 1 line

Please review.

Apart from some indentation issues these look fine to me.

Jan

Quoted 2 lines

Thanks,
-Wei

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel