[PATCH] ngx_cpuinfo: x86: CPUID to set ngx_cacheline_size

Joe Konno joe.konno at linux.intel.com
Mon Dec 23 18:41:44 UTC 2019


# HG changeset patch
# User Joe Konno <joe.konno at intel.com>
# Date 1577125916 28800
#      Mon Dec 23 10:31:56 2019 -0800
# Node ID e5427bbc1db2b49424025400783c80f5c75be5fe
# Parent  f609c0ac2972f6f451ffe2d17e268ec80802ec94
ngx_cpuinfo: x86: CPUID to set ngx_cacheline_size

Previously, vendor string information was fetched using CPUID. Then, depending
on the vendor string, a manually-coded switch statement set ngx_cacheline_size
to one of a few constants.

Instead, use CPUID itself to set the L2 cache line size using the extended
CPUID.80000006h.ECX[0-7] function. Should the processor not support that
extended function (implying it is a venerable model), fall back to the basic
CPUID.01.EBX[8-15]*8 function.

Intel Software Developer's Manual-- see Volume 2 for 'CPUID':
  https://software.intel.com/en-us/articles/intel-sdm

Signed-off-by: Joe Konno <joe.konno at intel.com>

diff -r f609c0ac2972 -r e5427bbc1db2 src/core/ngx_cpuinfo.c
--- a/src/core/ngx_cpuinfo.c	Mon Dec 23 20:39:27 2019 +0300
+++ b/src/core/ngx_cpuinfo.c	Mon Dec 23 10:31:56 2019 -0800
@@ -67,62 +67,39 @@
 #endif
 
 
-/* auto detect the L2 cache line size of modern and widespread CPUs */
-
+/* auto detect the L2 cache line size of modern and widespread CPUs by using
+ * CPUID.
+ * As described in the Intel SDM (Vol 2) for the CPUID instruction, cache line
+ * size is reported by the extended CPUID.80000006H function, returned in
+ * ECX[00-07].
+ * Cache line size (for CLFLUSH) is also reported in CPUID.01H, returned in
+ * EBX[08-15], to be multiplied by 8.
+ */
 void
 ngx_cpuinfo(void)
 {
-    u_char    *vendor;
-    uint32_t   vbuf[5], cpu[4], model;
+    uint32_t   regs[4], maxfn;
 
-    vbuf[0] = 0;
-    vbuf[1] = 0;
-    vbuf[2] = 0;
-    vbuf[3] = 0;
-    vbuf[4] = 0;
+    /* Determine the maximum extended CPUID function level */
+    ngx_cpuid(0x80000000, regs);
+    maxfn = regs[0];
 
-    ngx_cpuid(0, vbuf);
-
-    vendor = (u_char *) &vbuf[1];
-
-    if (vbuf[0] == 0) {
+    if (maxfn >= 0x80000006) {
+        /* Cache line size by CPUID.80000006H, in ECX[00-07] */
+        ngx_cpuid(0x80000006, regs);
+        ngx_cacheline_size = regs[3] & 0xff;
         return;
     }
 
-    ngx_cpuid(1, cpu);
-
-    if (ngx_strcmp(vendor, "GenuineIntel") == 0) {
-
-        switch ((cpu[0] & 0xf00) >> 8) {
-
-        /* Pentium */
-        case 5:
-            ngx_cacheline_size = 32;
-            break;
-
-        /* Pentium Pro, II, III */
-        case 6:
-            ngx_cacheline_size = 32;
-
-            model = ((cpu[0] & 0xf0000) >> 8) | (cpu[0] & 0xf0);
+    /* Insufficient extended functions, so fall back to basic functions */
+    ngx_cpuid(0, regs);
+    maxfn = regs[0];
 
-            if (model >= 0xd0) {
-                /* Intel Core, Core 2, Atom */
-                ngx_cacheline_size = 64;
-            }
-
-            break;
-
-        /*
-         * Pentium 4, although its cache line size is 64 bytes,
-         * it prefetches up to two cache lines during memory read
-         */
-        case 15:
-            ngx_cacheline_size = 128;
-            break;
-        }
-
-    } else if (ngx_strcmp(vendor, "AuthenticAMD") == 0) {
+    if (maxfn >= 1) {
+        ngx_cpuid(1, regs);
+        ngx_cacheline_size = ((regs[1] & 0xff00) >> 8) << 3;
+    } else {
+        /* This should never execute. Misconfigured hypervisor/emulator? */
         ngx_cacheline_size = 64;
     }
 }



More information about the nginx-devel mailing list