[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