Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/winsup
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2015-08-29 10:16:47 +0300
committerCorinna Vinschen <corinna@vinschen.de>2015-08-29 10:16:47 +0300
commit38fd7ddb790609db3e91540d183fb8b62250d969 (patch)
treed4e89397a7d1f80da69e79bbf7752633ae2f9507 /winsup
parent35d5d87540c3262c341c35e974d0d3a53ce30684 (diff)
Allow sysconf to return CPU cache information
* include/sys/unistd.h (_SC_LEVEL*): Add cache-related variables as on Linux. * fhandler_proc.cc (format_proc_cpuinfo): Fetch cache information from new cache functions in sysconf.cc, get_cpu_cache_intel and get_cpu_cache_amd. * sysconf.cc (__nt_query_system): New local helper. (get_nproc_values): Utilize __nt_query_system on pre-Windows 7 systems. Use GetLogicalProcessorInformationEx otherwise to handle more than 64 CPUs. Only handle _SC_NPROCESSORS_CONF and _SC_NPROCESSORS_ONLN. (get_phys_pages): New helper to handle _SC_PHYS_PAGES. (cpuid2_cache_descriptor): New array to map Intel CPUID 2 descriptor values to cache type, cache size, associativity and linesize. (cpuid2_cache_desc_compar): Comparision function for bsearch over cpuid2_cache_descriptor. (get_cpu_cache_intel_cpuid2): New function to fetch cache info from Intel CPUID 2. (get_cpu_cache_intel_cpuid4): Ditto from Intel CPUID 4. (get_cpu_cache_intel): New function as CPU-specific entry point. (assoc): New array to map associativity values from AMD CPUID 0x80000006. (get_cpu_cache_amd): New function to fetch cache info from AMD CPUIDs 0x80000005 and 0x80000006. (get_cpu_cache): New function to fetch cache info. (sca): Call get_phys_pages if _SC_PHYS_PAGES is requested. Call get_cpu_cache for new _SC_* cache requests. (SC_MAX): Set to _SC_LEVEL4_CACHE_LINESIZE. (get_phys_pages(void)): Call get_phys_pages(int). * include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump. * new-features.xml (ov-new2.3): Document sysconf cache addition. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diffstat (limited to 'winsup')
-rw-r--r--winsup/cygwin/ChangeLog29
-rw-r--r--winsup/cygwin/fhandler_proc.cc65
-rw-r--r--winsup/cygwin/include/cygwin/version.h3
-rw-r--r--winsup/cygwin/release/2.3.010
-rw-r--r--winsup/cygwin/sysconf.cc480
-rw-r--r--winsup/doc/ChangeLog4
-rw-r--r--winsup/doc/new-features.xml11
7 files changed, 539 insertions, 63 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index c76eb7a5f..d9ab9753a 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,32 @@
+2015-08-29 Corinna Vinschen <corinna@vinschen.de>
+
+ * fhandler_proc.cc (format_proc_cpuinfo): Fetch cache information
+ from new cache functions in sysconf.cc, get_cpu_cache_intel and
+ get_cpu_cache_amd.
+ * sysconf.cc (__nt_query_system): New local helper.
+ (get_nproc_values): Utilize __nt_query_system on pre-Windows 7 systems.
+ Use GetLogicalProcessorInformationEx otherwise to handle more than
+ 64 CPUs. Only handle _SC_NPROCESSORS_CONF and _SC_NPROCESSORS_ONLN.
+ (get_phys_pages): New helper to handle _SC_PHYS_PAGES.
+ (cpuid2_cache_descriptor): New array to map Intel CPUID 2 descriptor
+ values to cache type, cache size, associativity and linesize.
+ (cpuid2_cache_desc_compar): Comparision function for bsearch over
+ cpuid2_cache_descriptor.
+ (get_cpu_cache_intel_cpuid2): New function to fetch cache info from
+ Intel CPUID 2.
+ (get_cpu_cache_intel_cpuid4): Ditto from Intel CPUID 4.
+ (get_cpu_cache_intel): New function as CPU-specific entry point.
+ (assoc): New array to map associativity values from AMD CPUID
+ 0x80000006.
+ (get_cpu_cache_amd): New function to fetch cache info from AMD CPUIDs
+ 0x80000005 and 0x80000006.
+ (get_cpu_cache): New function to fetch cache info.
+ (sca): Call get_phys_pages if _SC_PHYS_PAGES is requested. Call
+ get_cpu_cache for new _SC_* cache requests.
+ (SC_MAX): Set to _SC_LEVEL4_CACHE_LINESIZE.
+ (get_phys_pages(void)): Call get_phys_pages(int).
+ * include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
+
2015-08-27 Corinna Vinschen <corinna@vinschen.de>
* autoload.cc (DiscardVirtualMemory): Import.
diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc
index fca8265fe..d34bf3135 100644
--- a/winsup/cygwin/fhandler_proc.cc
+++ b/winsup/cygwin/fhandler_proc.cc
@@ -758,47 +758,46 @@ format_proc_cpuinfo (void *, char *&destbuf)
cache_alignment = clflush * 2;
if (is_intel)
{
- uint32_t cache_level = 0;
- uint32_t info, layout, sets;
+ extern long get_cpu_cache_intel (int sysc, uint32_t maxf);
+ long cs;
- for (int idx = 0; ; ++idx)
+ /* As on Linux, don't check for L3 cache. */
+ cs = get_cpu_cache_intel (_SC_LEVEL2_CACHE_SIZE, maxf);
+ if (cs == -1)
{
- cpuid (&info, &layout, &sets, &unused, 0x00000004, idx);
- uint32_t cache_type = (info & 0x1f);
- if (cache_type == 0)
- break;
- uint32_t cur_level = ((info >> 5) & 0x7);
- uint32_t ways = ((layout >> 22) & 0x3ff) + 1;
- uint32_t part = ((layout >> 12) & 0x3ff) + 1;
- uint32_t line = (layout & 0xfff) + 1;
- sets++;
- if (cur_level == cache_level)
- cache_size += ways * part * line * sets;
- else if (cur_level > cache_level)
- {
- cache_size = ways * part * line * sets;
- cache_level = cur_level;
- }
+ cs = get_cpu_cache_intel (_SC_LEVEL1_ICACHE_SIZE, maxf);
+ if (cs != -1)
+ cache_size = cs;
+ cs = get_cpu_cache_intel (_SC_LEVEL1_DCACHE_SIZE, maxf);
+ if (cs != -1)
+ cache_size += cs;
}
+ else
+ cache_size = cs;
if (cache_size != -1)
cache_size >>= 10;
}
- /* L2 Cache and L2 TLB Identifiers. */
- if (cache_size == -1 && maxe >= 0x80000006)
- {
- uint32_t l2;
- cpuid (&unused, &unused, &l2, &unused, 0x80000006);
-
- cache_size = l2 >> 16;
- }
- /* L1 Cache and TLB Identifiers. */
- if (cache_size == -1 && maxe >= 0x80000005)
+ else if (is_amd)
{
- uint32_t data_cache, inst_cache;
- cpuid (&unused, &unused, &data_cache, &inst_cache,
- 0x80000005);
+ extern long get_cpu_cache_amd (int sysc, uint32_t maxe);
+ long cs;
- cache_size = (inst_cache >> 24) + (data_cache >> 24);
+ cs = get_cpu_cache_amd (_SC_LEVEL3_CACHE_SIZE, maxe);
+ if (cs == -1)
+ cs = get_cpu_cache_amd (_SC_LEVEL2_CACHE_SIZE, maxe);
+ if (cs == -1)
+ {
+ cs = get_cpu_cache_amd (_SC_LEVEL1_ICACHE_SIZE, maxe);
+ if (cs != -1)
+ cache_size = cs;
+ cs = get_cpu_cache_amd (_SC_LEVEL1_DCACHE_SIZE, maxe);
+ if (cs != -1)
+ cache_size += cs;
+ }
+ else
+ cache_size = cs;
+ if (cache_size != -1)
+ cache_size >>= 10;
}
bufptr += __small_sprintf (bufptr, "cpu family\t: %d\n"
"model\t\t: %d\n"
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index 53842efb8..3b14ff40d 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -471,13 +471,14 @@ details. */
287: Export issetugid.
288: Export getcontext, makecontext, setcontext, swapcontext.
289: Export sigsetjmp, siglongjmp.
+ 290: Add sysconf cache handling.
*/
/* Note that we forgot to bump the api for ualarm, strtoll, strtoull,
sigaltstack, sethostname. */
#define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 289
+#define CYGWIN_VERSION_API_MINOR 290
/* There is also a compatibity version number associated with the
shared memory regions. It is incremented when incompatible
diff --git a/winsup/cygwin/release/2.3.0 b/winsup/cygwin/release/2.3.0
index 88b67487f..0ce6dc7ba 100644
--- a/winsup/cygwin/release/2.3.0
+++ b/winsup/cygwin/release/2.3.0
@@ -7,6 +7,13 @@ What's new:
- posix_madvise(POSIX_MADV_DONTNEED) now utilizes OS functionality available
starting with Windows 8.1/Server 2012R2. Still a no-op on older systems.
+- sysconf() now supports returning CPU cache information:
+ _SC_LEVEL1_ICACHE_SIZE, _SC_LEVEL1_ICACHE_ASSOC, _SC_LEVEL1_ICACHE_LINESIZE,
+ _SC_LEVEL1_DCACHE_SIZE, _SC_LEVEL1_DCACHE_ASSOC, _SC_LEVEL1_DCACHE_LINESIZE,
+ _SC_LEVEL2_CACHE_SIZE, _SC_LEVEL2_CACHE_ASSOC, _SC_LEVEL2_CACHE_LINESIZE,
+ _SC_LEVEL3_CACHE_SIZE, _SC_LEVEL3_CACHE_ASSOC, _SC_LEVEL3_CACHE_LINESIZE,
+ _SC_LEVEL4_CACHE_SIZE, _SC_LEVEL4_CACHE_ASSOC, _SC_LEVEL4_CACHE_LINESIZE
+
What changed:
-------------
@@ -22,3 +29,6 @@ Bug Fixes
- Fix long-standing potential SEGV on 32 bit Cygwin when the dynamic loader
for OS functions fails to load a function on Windows 7 or later.
Addresses: No actual bug report known.
+
+- sysconf _SC_NPROCESSORS_CONF and _SC_NPROCESSORS_ONLN now handle more than
+ 64 CPUs on Windows 7 and later.
diff --git a/winsup/cygwin/sysconf.cc b/winsup/cygwin/sysconf.cc
index 7d09f53d0..b9bcb2b6c 100644
--- a/winsup/cygwin/sysconf.cc
+++ b/winsup/cygwin/sysconf.cc
@@ -1,7 +1,7 @@
/* sysconf.cc
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- 2007, 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc.
+ 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2015 Red Hat, Inc.
This file is part of Cygwin.
@@ -20,6 +20,8 @@ details. */
#include "dtable.h"
#include "pinfo.h"
#include "ntdll.h"
+#include "tls_pbuf.h"
+#include "cpuid.h"
static long
get_open_max (int in)
@@ -36,38 +38,79 @@ get_page_size (int in)
return wincap.allocation_granularity ();
}
-static long
-get_nproc_values (int in)
+static bool
+__nt_query_system (PSYSTEM_BASIC_INFORMATION psbi)
{
NTSTATUS status;
- SYSTEM_BASIC_INFORMATION sbi;
- status = NtQuerySystemInformation (SystemBasicInformation, (PVOID) &sbi,
- sizeof sbi, NULL);
- if (!NT_SUCCESS (status))
+ status = NtQuerySystemInformation (SystemBasicInformation, (PVOID) psbi,
+ sizeof *psbi, NULL);
+ return NT_SUCCESS (status);
+}
+
+#define add_size(p,s) ((p) = ((__typeof__(p))((PBYTE)(p)+(s))))
+
+static long
+get_nproc_values (int in)
+{
+ if (!wincap.has_processor_groups ()) /* Pre Windows 7 */
{
- __seterrno_from_nt_status (status);
- debug_printf ("NtQuerySystemInformation: status %y, %E", status);
- return -1;
+ SYSTEM_BASIC_INFORMATION sbi;
+
+ if (!__nt_query_system (&sbi))
+ return -1;
+ switch (in)
+ {
+ case _SC_NPROCESSORS_CONF:
+ return sbi.NumberProcessors;
+ case _SC_NPROCESSORS_ONLN:
+ {
+ int i = 0;
+ do
+ if (sbi.ActiveProcessors & 1)
+ i++;
+ while (sbi.ActiveProcessors >>= 1);
+ return i;
+ }
+ }
}
- switch (in)
- {
- case _SC_NPROCESSORS_CONF:
- return sbi.NumberProcessors;
- case _SC_NPROCESSORS_ONLN:
+
+ tmp_pathbuf tp;
+ PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX lpi, plpi;
+ DWORD lpi_size = NT_MAX_PATH;
+ long cnt = 0;
+
+ lpi = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) tp.c_get ();
+ if (!GetLogicalProcessorInformationEx (RelationGroup, lpi, &lpi_size))
+ return -1;
+ plpi = lpi;
+ for (DWORD size = lpi_size; size > 0;
+ size -= plpi->Size, add_size (plpi, plpi->Size))
+ if (plpi->Relationship == RelationGroup)
{
- int i = 0;
- do
- if (sbi.ActiveProcessors & 1)
- i++;
- while (sbi.ActiveProcessors >>= 1);
- return i;
+ for (WORD i = 0; i < plpi->Group.MaximumGroupCount; ++i)
+ switch (in)
+ {
+ case _SC_NPROCESSORS_CONF:
+ cnt += plpi->Group.GroupInfo[0].MaximumProcessorCount;
+ break;
+ case _SC_NPROCESSORS_ONLN:
+ cnt += plpi->Group.GroupInfo[0].ActiveProcessorCount;
+ break;
+ }
}
- case _SC_PHYS_PAGES:
- return sbi.NumberOfPhysicalPages
- / (wincap.allocation_granularity () / wincap.page_size ());
- }
- return -1;
+ return cnt;
+}
+
+static long
+get_phys_pages (int in)
+{
+ SYSTEM_BASIC_INFORMATION sbi;
+
+ if (!__nt_query_system (&sbi))
+ return -1;
+ return sbi.NumberOfPhysicalPages
+ / (wincap.allocation_granularity () / wincap.page_size ());
}
static long
@@ -88,6 +131,370 @@ get_avphys (int in)
/ (wincap.allocation_granularity () / wincap.page_size ());
}
+enum cache_level
+{
+ LevelNone,
+ Level1I,
+ Level1D,
+ Level2,
+ Level3,
+ Level4
+};
+
+struct cpuid2_cache_desc
+{
+ uint8_t desc;
+ cache_level level;
+ uint32_t size;
+ uint32_t assoc;
+ uint32_t linesize;
+};
+
+static const cpuid2_cache_desc cpuid2_cache_descriptor[] =
+{
+ { 0x06, Level1I, 8, 4, 32 },
+ { 0x08, Level1I, 16, 4, 32 },
+ { 0x09, Level1I, 32, 4, 64 },
+ { 0x0a, Level1D, 8, 2, 32 },
+ { 0x0c, Level1D, 16, 4, 32 },
+ { 0x0d, Level1D, 16, 4, 64 },
+ { 0x0e, Level1D, 24, 6, 64 },
+ { 0x21, Level2, 256, 8, 64 },
+ { 0x22, Level3, 512, 4, 64 },
+ { 0x23, Level3, 1024, 8, 64 },
+ { 0x25, Level3, 2048, 8, 64 },
+ { 0x29, Level3, 4096, 8, 64 },
+ { 0x2c, Level1D, 32, 8, 64 },
+ { 0x30, Level1I, 32, 8, 64 },
+ { 0x39, Level2, 128, 4, 64 },
+ { 0x3a, Level2, 192, 6, 64 },
+ { 0x3b, Level2, 128, 2, 64 },
+ { 0x3c, Level2, 256, 4, 64 },
+ { 0x3d, Level2, 384, 6, 64 },
+ { 0x3e, Level2, 512, 4, 64 },
+ { 0x3f, Level2, 256, 2, 64 },
+ { 0x41, Level2, 128, 4, 32 },
+ { 0x42, Level2, 256, 4, 32 },
+ { 0x43, Level2, 512, 4, 32 },
+ { 0x44, Level2, 1024, 4, 32 },
+ { 0x45, Level2, 2048, 4, 32 },
+ { 0x46, Level3, 4096, 4, 64 },
+ { 0x47, Level3, 8192, 8, 64 },
+ { 0x48, Level2, 3072, 12, 64 },
+ { 0x49, Level3, 4096, 16, 64 },
+ { 0x4a, Level3, 6144, 12, 64 },
+ { 0x4b, Level3, 8192, 16, 64 },
+ { 0x4c, Level3, 12288, 12, 64 },
+ { 0x4d, Level3, 16384, 16, 64 },
+ { 0x4e, Level2, 6144, 24, 64 },
+ { 0x60, Level1D, 16, 8, 64 },
+ { 0x66, Level1D, 8, 4, 64 },
+ { 0x67, Level1D, 16, 4, 64 },
+ { 0x68, Level1D, 32, 4, 64 },
+ { 0x78, Level2, 1024, 4, 64 },
+ { 0x79, Level2, 128, 8, 64 },
+ { 0x7a, Level2, 256, 8, 64 },
+ { 0x7b, Level2, 512, 8, 64 },
+ { 0x7c, Level2, 1024, 8, 64 },
+ { 0x7d, Level2, 2048, 8, 64 },
+ { 0x7f, Level2, 512, 2, 64 },
+ { 0x80, Level2, 512, 8, 64 },
+ { 0x82, Level2, 256, 8, 32 },
+ { 0x83, Level2, 512, 8, 32 },
+ { 0x84, Level2, 1024, 8, 32 },
+ { 0x85, Level2, 2048, 8, 32 },
+ { 0x86, Level2, 512, 4, 64 },
+ { 0x87, Level2, 1024, 8, 64 },
+ { 0xd0, Level3, 512, 4, 64 },
+ { 0xd1, Level3, 1024, 4, 64 },
+ { 0xd2, Level3, 2048, 4, 64 },
+ { 0xd6, Level3, 1024, 8, 64 },
+ { 0xd7, Level3, 2048, 8, 64 },
+ { 0xd8, Level3, 4096, 12, 64 },
+ { 0xdc, Level3, 2048, 12, 64 },
+ { 0xdd, Level3, 4096, 12, 64 },
+ { 0xde, Level3, 8192, 12, 64 },
+ { 0xe2, Level3, 2048, 16, 64 },
+ { 0xe3, Level3, 4096, 16, 64 },
+ { 0xe4, Level3, 8192, 16, 64 },
+ { 0xea, Level3, 12288, 24, 64 },
+ { 0xeb, Level3, 18432, 24, 64 },
+ { 0xec, Level3, 24576, 24, 64 },
+};
+
+static int
+cpuid2_cache_desc_compar (const void *key, const void *memb)
+{
+ cpuid2_cache_desc *ckey = (cpuid2_cache_desc *) key;
+ cpuid2_cache_desc *cmemb = (cpuid2_cache_desc *) memb;
+ return ckey->desc - cmemb->desc;
+}
+
+static long
+get_cpu_cache_intel_cpuid2 (int in)
+{
+ uint32_t reg[4];
+ long ret = 0;
+ int num;
+
+ cpuid (reg, reg + 1, reg + 2, reg + 3, 0x00000002);
+ num = reg[0] & 0xff;
+ for (int i = 0; i < num; ++i)
+ {
+ cpuid (reg, reg + 1, reg + 2, reg + 3, 0x00000002);
+ for (int r = 0; r < 4; ++r)
+ {
+ if (reg[r] & 0x80000000)
+ continue;
+ for (int b = (r == 0) ? 1 : 0; b < 4; ++b)
+ {
+ cpuid2_cache_desc key, *cdp;
+
+ key.desc = ((uint8_t *) &reg[r])[b];
+ cdp = (cpuid2_cache_desc *)
+ bsearch (&key, cpuid2_cache_descriptor,
+ sizeof cpuid2_cache_descriptor
+ / sizeof *cpuid2_cache_descriptor,
+ sizeof *cpuid2_cache_descriptor,
+ cpuid2_cache_desc_compar);
+ if (!cdp)
+ continue;
+ switch (in)
+ {
+ case _SC_LEVEL1_ICACHE_SIZE:
+ if (cdp->level == Level1I)
+ ret += cdp->size * 1024;
+ break;
+ case _SC_LEVEL1_ICACHE_ASSOC:
+ if (cdp->level == Level1I)
+ return cdp->assoc;
+ break;
+ case _SC_LEVEL1_ICACHE_LINESIZE:
+ if (cdp->level == Level1I)
+ return cdp->linesize;
+ break;
+ case _SC_LEVEL1_DCACHE_SIZE:
+ if (cdp->level == Level1D)
+ ret += cdp->size * 1024;
+ break;
+ case _SC_LEVEL1_DCACHE_ASSOC:
+ if (cdp->level == Level1D)
+ return cdp->assoc;
+ break;
+ case _SC_LEVEL1_DCACHE_LINESIZE:
+ if (cdp->level == Level1D)
+ return cdp->linesize;
+ break;
+ case _SC_LEVEL2_CACHE_SIZE:
+ if (cdp->level == Level2)
+ ret += cdp->size * 1024;
+ break;
+ case _SC_LEVEL2_CACHE_ASSOC:
+ if (cdp->level == Level2)
+ return cdp->assoc;
+ break;
+ case _SC_LEVEL2_CACHE_LINESIZE:
+ if (cdp->level == Level2)
+ return cdp->linesize;
+ break;
+ case _SC_LEVEL3_CACHE_SIZE:
+ if (cdp->level == Level3)
+ ret += cdp->size * 1024;
+ break;
+ case _SC_LEVEL3_CACHE_ASSOC:
+ if (cdp->level == Level3)
+ return cdp->assoc;
+ break;
+ case _SC_LEVEL3_CACHE_LINESIZE:
+ if (cdp->level == Level3)
+ return cdp->linesize;
+ break;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+static long
+get_cpu_cache_intel_cpuid4 (int in)
+{
+ uint32_t eax, ebx, ecx, edx;
+ long ret = 0;
+
+ for (int idx = 0; ; ++idx)
+ {
+ uint32_t cache_type, cur_level, assoc, part, linesize, sets;
+
+ cpuid (&eax, &ebx, &ecx, &edx, 0x00000004, idx);
+ if ((cache_type = (eax & 0x1f))== 0)
+ break;
+ cur_level = ((eax >> 5) & 0x7);
+ assoc = ((ebx >> 22) & 0x3ff) + 1;
+ part = ((ebx >> 12) & 0x3ff) + 1;
+ linesize = (ebx & 0xfff) + 1;
+ sets = ecx + 1;
+ switch (in)
+ {
+ case _SC_LEVEL1_ICACHE_SIZE:
+ if (cur_level == 1 && cache_type == 2)
+ ret += assoc * part * linesize * sets;
+ break;
+ case _SC_LEVEL1_ICACHE_ASSOC:
+ if (cur_level == 1 && cache_type == 2)
+ return assoc;
+ case _SC_LEVEL1_ICACHE_LINESIZE:
+ if (cur_level == 1 && cache_type == 2)
+ return linesize;
+ case _SC_LEVEL1_DCACHE_SIZE:
+ if (cur_level == 1 && cache_type == 1)
+ ret += assoc * part * linesize * sets;
+ break;
+ case _SC_LEVEL1_DCACHE_ASSOC:
+ if (cur_level == 1 && cache_type == 1)
+ return assoc;
+ case _SC_LEVEL1_DCACHE_LINESIZE:
+ if (cur_level == 1 && cache_type == 1)
+ return linesize;
+ case _SC_LEVEL2_CACHE_SIZE:
+ if (cur_level == 2)
+ ret += assoc * part * linesize * sets;
+ break;
+ case _SC_LEVEL2_CACHE_ASSOC:
+ if (cur_level == 2)
+ return assoc;
+ case _SC_LEVEL2_CACHE_LINESIZE:
+ if (cur_level == 2)
+ return linesize;
+ case _SC_LEVEL3_CACHE_SIZE:
+ if (cur_level == 3)
+ ret += assoc * part * linesize * sets;
+ break;
+ case _SC_LEVEL3_CACHE_ASSOC:
+ if (cur_level == 3)
+ return assoc;
+ case _SC_LEVEL3_CACHE_LINESIZE:
+ if (cur_level == 3)
+ return linesize;
+ }
+ }
+ return ret;
+}
+
+/* Also called from format_proc_cpuinfo */
+long
+get_cpu_cache_intel (int in, uint32_t maxf)
+{
+ long ret = 0;
+
+ switch (in)
+ {
+ case _SC_LEVEL1_ICACHE_SIZE:
+ case _SC_LEVEL1_ICACHE_ASSOC:
+ case _SC_LEVEL1_ICACHE_LINESIZE:
+ case _SC_LEVEL1_DCACHE_SIZE:
+ case _SC_LEVEL1_DCACHE_ASSOC:
+ case _SC_LEVEL1_DCACHE_LINESIZE:
+ case _SC_LEVEL2_CACHE_SIZE:
+ case _SC_LEVEL2_CACHE_ASSOC:
+ case _SC_LEVEL2_CACHE_LINESIZE:
+ case _SC_LEVEL3_CACHE_SIZE:
+ case _SC_LEVEL3_CACHE_ASSOC:
+ case _SC_LEVEL3_CACHE_LINESIZE:
+ if (maxf >= 4)
+ ret = get_cpu_cache_intel_cpuid4 (in);
+ else if (maxf >= 2)
+ ret = get_cpu_cache_intel_cpuid2 (in);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+static const long assoc[16] = { 0, 1, 2, 2, 4, 4, 8, 8,
+ 16, 16, 32, 48, 64, 96, 128, 0x8000 };
+
+/* Also called from format_proc_cpuinfo */
+long
+get_cpu_cache_amd (int in, uint32_t maxe)
+{
+ uint32_t eax, ebx, ecx, edx;
+ long ret = 0;
+
+ if (in >= _SC_LEVEL1_ICACHE_SIZE && in <= _SC_LEVEL1_DCACHE_LINESIZE
+ && maxe >= 0x80000005)
+ cpuid (&eax, &ebx, &ecx, &edx, 0x80000005);
+ else if (in >= _SC_LEVEL2_CACHE_SIZE && in <= _SC_LEVEL3_CACHE_LINESIZE
+ && maxe >= 0x80000006)
+ cpuid (&eax, &ebx, &ecx, &edx, 0x80000006);
+
+ switch (in)
+ {
+ case _SC_LEVEL1_ICACHE_SIZE:
+ ret = (edx & 0xff000000) >> 14;
+ break;
+ case _SC_LEVEL1_ICACHE_ASSOC:
+ ret = (edx & 0xff0000) >> 16;
+ if (ret == 0xff)
+ ret = 0x8000;
+ break;
+ case _SC_LEVEL1_ICACHE_LINESIZE:
+ ret = (edx & 0xff);
+ break;
+ case _SC_LEVEL1_DCACHE_SIZE:
+ ret = (ecx & 0xff000000) >> 14;
+ break;
+ case _SC_LEVEL1_DCACHE_ASSOC:
+ ret = (ecx & 0xff0000) >> 16;
+ if (ret == 0xff)
+ ret = 0x8000;
+ break;
+ case _SC_LEVEL1_DCACHE_LINESIZE:
+ ret = (ecx & 0xff);
+ break;
+ case _SC_LEVEL2_CACHE_SIZE:
+ ret = (ecx & 0xffff0000) >> 6;
+ break;
+ case _SC_LEVEL2_CACHE_ASSOC:
+ ret = assoc[(ecx & 0xf000) >> 12];
+ break;
+ case _SC_LEVEL2_CACHE_LINESIZE:
+ ret = (ecx & 0xff);
+ break;
+ case _SC_LEVEL3_CACHE_SIZE:
+ ret = (long) ((edx & 0xfffc0000) >> 18) * 512 * 1024;
+ break;
+ case _SC_LEVEL3_CACHE_ASSOC:
+ ret = assoc[(edx & 0xf000) >> 12];
+ break;
+ case _SC_LEVEL3_CACHE_LINESIZE:
+ ret = (edx & 0xff);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+static long
+get_cpu_cache (int in)
+{
+ uint32_t maxf, vendor_id[4];
+ cpuid (&maxf, &vendor_id[0], &vendor_id[2], &vendor_id[1], 0x00000000);
+
+ vendor_id[3] = 0;
+ if (!strcmp ((char*) vendor_id, "GenuineIntel"))
+ return get_cpu_cache_intel (in, maxf & 0xffff);
+ else if (!strcmp ((char*)vendor_id, "AuthenticAMD"))
+ {
+ uint32_t maxe = 0, unused;
+ cpuid (&maxe, &unused, &unused, &unused, 0x80000000);
+ return get_cpu_cache_amd (in, maxe);
+ }
+ return 0;
+}
+
enum sc_type { nsup, cons, func };
static struct
@@ -111,7 +518,7 @@ static struct
{func, {f:get_page_size}}, /* 8, _SC_PAGESIZE */
{func, {f:get_nproc_values}}, /* 9, _SC_NPROCESSORS_CONF */
{func, {f:get_nproc_values}}, /* 10, _SC_NPROCESSORS_ONLN */
- {func, {f:get_nproc_values}}, /* 11, _SC_PHYS_PAGES */
+ {func, {f:get_phys_pages}}, /* 11, _SC_PHYS_PAGES */
{func, {f:get_avphys}}, /* 12, _SC_AVPHYS_PAGES */
{cons, {c:MQ_OPEN_MAX}}, /* 13, _SC_MQ_OPEN_MAX */
{cons, {c:MQ_PRIO_MAX}}, /* 14, _SC_MQ_PRIO_MAX */
@@ -225,10 +632,25 @@ static struct
{cons, {c:-1L}}, /* 122, _SC_THREAD_ROBUST_PRIO_INHERIT */
{cons, {c:-1L}}, /* 123, _SC_THREAD_ROBUST_PRIO_PROTECT */
{cons, {c:-1L}}, /* 124, _SC_XOPEN_UUCP */
+ {func, {f:get_cpu_cache}}, /* 125, _SC_LEVEL1_ICACHE_SIZE */
+ {func, {f:get_cpu_cache}}, /* 126, _SC_LEVEL1_ICACHE_ASSOC */
+ {func, {f:get_cpu_cache}}, /* 127, _SC_LEVEL1_ICACHE_LINESIZE */
+ {func, {f:get_cpu_cache}}, /* 128, _SC_LEVEL1_DCACHE_SIZE */
+ {func, {f:get_cpu_cache}}, /* 129, _SC_LEVEL1_DCACHE_ASSOC */
+ {func, {f:get_cpu_cache}}, /* 130, _SC_LEVEL1_DCACHE_LINESIZE */
+ {func, {f:get_cpu_cache}}, /* 131, _SC_LEVEL2_CACHE_SIZE */
+ {func, {f:get_cpu_cache}}, /* 132, _SC_LEVEL2_CACHE_ASSOC */
+ {func, {f:get_cpu_cache}}, /* 133, _SC_LEVEL2_CACHE_LINESIZE */
+ {func, {f:get_cpu_cache}}, /* 134, _SC_LEVEL3_CACHE_SIZE */
+ {func, {f:get_cpu_cache}}, /* 135, _SC_LEVEL3_CACHE_ASSOC */
+ {func, {f:get_cpu_cache}}, /* 136, _SC_LEVEL3_CACHE_LINESIZE */
+ {func, {f:get_cpu_cache}}, /* 137, _SC_LEVEL4_CACHE_SIZE */
+ {func, {f:get_cpu_cache}}, /* 138, _SC_LEVEL4_CACHE_ASSOC */
+ {func, {f:get_cpu_cache}}, /* 139, _SC_LEVEL4_CACHE_LINESIZE */
};
#define SC_MIN _SC_ARG_MAX
-#define SC_MAX _SC_XOPEN_UUCP
+#define SC_MAX _SC_LEVEL4_CACHE_LINESIZE
/* sysconf: POSIX 4.8.1.1 */
/* Allows a portable app to determine quantities of resources or
@@ -335,7 +757,7 @@ get_nprocs (void)
extern "C" long
get_phys_pages (void)
{
- return get_nproc_values (_SC_PHYS_PAGES);
+ return get_phys_pages (_SC_PHYS_PAGES);
}
extern "C" long
diff --git a/winsup/doc/ChangeLog b/winsup/doc/ChangeLog
index c645c670d..7587d683e 100644
--- a/winsup/doc/ChangeLog
+++ b/winsup/doc/ChangeLog
@@ -1,3 +1,7 @@
+2015-08-29 Corinna Vinschen <corinna@vinschen.de>
+
+ * new-features.xml (ov-new2.3): Document sysconf cache addition.
+
2015-08-27 Corinna Vinschen <corinna@vinschen.de>
* new-features.xml (ov-new2.3): New section, document posix_madvise
diff --git a/winsup/doc/new-features.xml b/winsup/doc/new-features.xml
index edd19633f..fc53b0138 100644
--- a/winsup/doc/new-features.xml
+++ b/winsup/doc/new-features.xml
@@ -16,6 +16,17 @@ posix_madvise(POSIX_MADV_DONTNEED) now utilizes OS functionality available
starting with Windows 8.1/Server 2012R2.
</para></listitem>
+<listitem><para>
+sysconf() now supports returning CPU cache information:
+ <screen>
+ _SC_LEVEL1_ICACHE_SIZE, _SC_LEVEL1_ICACHE_ASSOC, _SC_LEVEL1_ICACHE_LINESIZE,
+ _SC_LEVEL1_DCACHE_SIZE, _SC_LEVEL1_DCACHE_ASSOC, _SC_LEVEL1_DCACHE_LINESIZE,
+ _SC_LEVEL2_CACHE_SIZE, _SC_LEVEL2_CACHE_ASSOC, _SC_LEVEL2_CACHE_LINESIZE,
+ _SC_LEVEL3_CACHE_SIZE, _SC_LEVEL3_CACHE_ASSOC, _SC_LEVEL3_CACHE_LINESIZE,
+ _SC_LEVEL4_CACHE_SIZE, _SC_LEVEL4_CACHE_ASSOC, _SC_LEVEL4_CACHE_LINESIZE
+ </screen>
+</para></listitem>
+
</itemizedlist>
</sect2>