[PATCH] ntdll: Implement SystemLogicalProcessorInformationEx
Andrew Eikum
aeikum at codeweavers.com
Mon Jan 25 08:47:10 CST 2016
Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
---
dlls/kernel32/process.c | 5 +
dlls/ntdll/nt.c | 666 ++++++++++++++++++++++++++++++++----------------
dlls/ntdll/tests/info.c | 61 ++++-
3 files changed, 503 insertions(+), 229 deletions(-)
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c
index 7795b47..1d306a7 100644
--- a/dlls/kernel32/process.c
+++ b/dlls/kernel32/process.c
@@ -3850,6 +3850,11 @@ BOOL WINAPI GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP rela
status = NtQuerySystemInformationEx( SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship),
buffer, *len, len );
+ if (status == STATUS_INFO_LENGTH_MISMATCH)
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ return FALSE;
+ }
if (status != STATUS_SUCCESS)
{
SetLastError( RtlNtStatusToDosError( status ) );
diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
index 9ee1923..9b750e4 100644
--- a/dlls/ntdll/nt.c
+++ b/dlls/ntdll/nt.c
@@ -1243,77 +1243,255 @@ void fill_cpu_info(void)
cached_sci.Architecture, cached_sci.Level, cached_sci.Revision, cached_sci.FeatureSet);
}
+static BOOL grow_logical_proc_buf(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *max_len)
+{
+ if (pdata)
+ {
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION *new_data;
+
+ *max_len *= 2;
+ new_data = RtlReAllocateHeap(GetProcessHeap(), 0, *pdata, *max_len*sizeof(*new_data));
+ if (!new_data)
+ return FALSE;
+
+ *pdata = new_data;
+ }
+ else
+ {
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *new_dataex;
+
+ *max_len *= 2;
+ new_dataex = RtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, *pdataex, *max_len*sizeof(*new_dataex));
+ if (!new_dataex)
+ return FALSE;
+
+ *pdataex = new_dataex;
+ }
+
+ return TRUE;
+}
+
+static DWORD log_proc_ex_size_plus(DWORD size)
+{
+ /* add SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX.Relationship and .Size */
+ return sizeof(LOGICAL_PROCESSOR_RELATIONSHIP) + sizeof(DWORD) + size;
+}
+
+static inline BOOL logical_proc_info_add_by_id(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len, DWORD *pmax_len,
+ LOGICAL_PROCESSOR_RELATIONSHIP rel, DWORD id, ULONG_PTR mask)
+{
+ if (pdata) {
+ DWORD i;
+
+ if(rel == RelationProcessorPackage){
+ for(i=0; i<*len; i++)
+ {
+ if ((*pdata)[i].Relationship!=rel || (*pdata)[i].u.Reserved[1]!=id)
+ continue;
+
+ (*pdata)[i].ProcessorMask |= mask;
+ return TRUE;
+ }
+ }else
+ i = *len;
+
+ while(*len == *pmax_len)
+ {
+ if (!grow_logical_proc_buf(pdata, NULL, pmax_len))
+ return FALSE;
+ }
+
+ (*pdata)[i].Relationship = rel;
+ (*pdata)[i].ProcessorMask = mask;
+ /* TODO: set processor core flags */
+ (*pdata)[i].u.Reserved[0] = 0;
+ (*pdata)[i].u.Reserved[1] = id;
+ *len = i+1;
+ }else{
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex = *pdataex;
+ DWORD ofs = 0;
+
+ while(ofs < *len)
+ {
+ dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
+ if (rel == RelationProcessorPackage && dataex->Relationship == rel && dataex->u.Processor.Reserved[1] == id)
+ {
+ dataex->u.Processor.GroupMask[0].Mask |= mask;
+ return TRUE;
+ }
+ ofs += dataex->Size;
+ }
+
+ /* TODO: For now, just one group. If more than 64 processors, then we
+ * need another group. */
+
+ while (ofs + log_proc_ex_size_plus(sizeof(PROCESSOR_RELATIONSHIP)) > *pmax_len)
+ {
+ if (!grow_logical_proc_buf(NULL, pdataex, pmax_len))
+ return FALSE;
+ }
+
+ dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
+
+ dataex->Relationship = rel;
+ dataex->Size = log_proc_ex_size_plus(sizeof(PROCESSOR_RELATIONSHIP));
+ dataex->u.Processor.Flags = 0; /* TODO */
+ dataex->u.Processor.EfficiencyClass = 0;
+ dataex->u.Processor.GroupCount = 1;
+ dataex->u.Processor.GroupMask[0].Mask = mask;
+ dataex->u.Processor.GroupMask[0].Group = 0;
+ /* mark for future lookup */
+ dataex->u.Processor.Reserved[0] = 0;
+ dataex->u.Processor.Reserved[1] = id;
+
+ *len += dataex->Size;
+ }
+
+ return TRUE;
+}
+
+static inline BOOL logical_proc_info_add_cache(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len,
+ DWORD *pmax_len, ULONG_PTR mask, CACHE_DESCRIPTOR *cache)
+{
+ if (pdata)
+ {
+ DWORD i;
+
+ for (i=0; i<*len; i++)
+ {
+ if ((*pdata)[i].Relationship==RelationCache && (*pdata)[i].ProcessorMask==mask
+ && (*pdata)[i].u.Cache.Level==cache->Level && (*pdata)[i].u.Cache.Type==cache->Type)
+ return TRUE;
+ }
+
+ while (*len == *pmax_len)
+ if (!grow_logical_proc_buf(pdata, NULL, pmax_len))
+ return FALSE;
+
+ (*pdata)[i].Relationship = RelationCache;
+ (*pdata)[i].ProcessorMask = mask;
+ (*pdata)[i].u.Cache = *cache;
+ *len = i+1;
+ }
+ else
+ {
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex = *pdataex;
+ DWORD ofs;
+
+ for (ofs = 0; ofs < *len; )
+ {
+ dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
+ if (dataex->Relationship == RelationCache && dataex->u.Cache.GroupMask.Mask == mask &&
+ dataex->u.Cache.Level == cache->Level && dataex->u.Cache.Type == cache->Type)
+ return TRUE;
+ ofs += dataex->Size;
+ }
+
+ while (ofs + log_proc_ex_size_plus(sizeof(CACHE_RELATIONSHIP)) > *pmax_len)
+ {
+ if (!grow_logical_proc_buf(NULL, pdataex, pmax_len))
+ return FALSE;
+ }
+
+ dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
+
+ dataex->Relationship = RelationCache;
+ dataex->Size = log_proc_ex_size_plus(sizeof(CACHE_RELATIONSHIP));
+ dataex->u.Cache.Level = cache->Level;
+ dataex->u.Cache.Associativity = cache->Associativity;
+ dataex->u.Cache.LineSize = cache->LineSize;
+ dataex->u.Cache.CacheSize = cache->Size;
+ dataex->u.Cache.Type = cache->Type;
+ dataex->u.Cache.GroupMask.Mask = mask;
+ dataex->u.Cache.GroupMask.Group = 0;
+
+ *len += dataex->Size;
+ }
+
+ return TRUE;
+}
+
+static inline BOOL logical_proc_info_add_numa_node(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len, DWORD *pmax_len, ULONG_PTR mask,
+ DWORD node_id)
+{
+ if (pdata)
+ {
+ while (*len == *pmax_len)
+ if (!grow_logical_proc_buf(pdata, NULL, pmax_len))
+ return FALSE;
+
+ (*pdata)[*len].Relationship = RelationNumaNode;
+ (*pdata)[*len].ProcessorMask = mask;
+ (*pdata)[*len].u.NumaNode.NodeNumber = node_id;
+ (*len)++;
+ }
+ else
+ {
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
+
+ while (*len + log_proc_ex_size_plus(sizeof(NUMA_NODE_RELATIONSHIP)) > *pmax_len)
+ {
+ if (!grow_logical_proc_buf(NULL, pdataex, pmax_len))
+ return FALSE;
+ }
+
+ dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + *len);
+
+ dataex->Relationship = RelationNumaNode;
+ dataex->Size = log_proc_ex_size_plus(sizeof(NUMA_NODE_RELATIONSHIP));
+ dataex->u.NumaNode.NodeNumber = node_id;
+ dataex->u.NumaNode.GroupMask.Mask = mask;
+ dataex->u.NumaNode.GroupMask.Group = 0;
+
+ *len += dataex->Size;
+ }
+
+ return TRUE;
+}
+
+static inline BOOL logical_proc_info_add_group(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex,
+ DWORD *len, DWORD *pmax_len, DWORD num_cpus, ULONG_PTR mask)
+{
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
+
+ while (*len + log_proc_ex_size_plus(sizeof(GROUP_RELATIONSHIP)) > *pmax_len)
+ {
+ if (!grow_logical_proc_buf(NULL, pdataex, pmax_len))
+ return FALSE;
+ }
+
+ dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + *len);
+
+ dataex->Relationship = RelationGroup;
+ dataex->Size = log_proc_ex_size_plus(sizeof(GROUP_RELATIONSHIP));
+ dataex->u.Group.MaximumGroupCount = 1;
+ dataex->u.Group.ActiveGroupCount = 1;
+ dataex->u.Group.GroupInfo[0].MaximumProcessorCount = num_cpus;
+ dataex->u.Group.GroupInfo[0].ActiveProcessorCount = num_cpus;
+ dataex->u.Group.GroupInfo[0].ActiveProcessorMask = mask;
+
+ *len += dataex->Size;
+
+ return TRUE;
+}
+
#ifdef linux
-static inline BOOL logical_proc_info_add_by_id(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *data,
- DWORD *len, DWORD max_len, LOGICAL_PROCESSOR_RELATIONSHIP rel, DWORD id, DWORD proc)
-{
- DWORD i;
-
- for(i=0; i<*len; i++)
- {
- if(data[i].Relationship!=rel || data[i].u.Reserved[1]!=id)
- continue;
-
- data[i].ProcessorMask |= (ULONG_PTR)1<<proc;
- return TRUE;
- }
-
- if(*len == max_len)
- return FALSE;
-
- data[i].Relationship = rel;
- data[i].ProcessorMask = (ULONG_PTR)1<<proc;
- /* TODO: set processor core flags */
- data[i].u.Reserved[0] = 0;
- data[i].u.Reserved[1] = id;
- *len = i+1;
- return TRUE;
-}
-
-static inline BOOL logical_proc_info_add_cache(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *data,
- DWORD *len, DWORD max_len, ULONG_PTR mask, CACHE_DESCRIPTOR *cache)
-{
- DWORD i;
-
- for(i=0; i<*len; i++)
- {
- if(data[i].Relationship==RelationCache && data[i].ProcessorMask==mask
- && data[i].u.Cache.Level==cache->Level && data[i].u.Cache.Type==cache->Type)
- return TRUE;
- }
-
- if(*len == max_len)
- return FALSE;
-
- data[i].Relationship = RelationCache;
- data[i].ProcessorMask = mask;
- data[i].u.Cache = *cache;
- *len = i+1;
- return TRUE;
-}
-
-static inline BOOL logical_proc_info_add_numa_node(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *data,
- DWORD *len, DWORD max_len, ULONG_PTR mask, DWORD node_id)
-{
- if(*len == max_len)
- return FALSE;
-
- data[*len].Relationship = RelationNumaNode;
- data[*len].ProcessorMask = mask;
- data[*len].u.NumaNode.NodeNumber = node_id;
- (*len)++;
- return TRUE;
-}
-
-static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data, DWORD *max_len)
+/* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
+static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data,
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **dataex, DWORD *max_len)
{
static const char core_info[] = "/sys/devices/system/cpu/cpu%u/%s";
static const char cache_info[] = "/sys/devices/system/cpu/cpu%u/cache/index%u/%s";
static const char numa_info[] = "/sys/devices/system/node/node%u/cpumap";
FILE *fcpu_list, *fnuma_list, *f;
- DWORD len = 0, beg, end, i, j, r;
+ DWORD len = 0, beg, end, i, j, r, num_cpus = 0;
char op, name[MAX_PATH];
+ ULONG_PTR all_cpus_mask = 0;
fcpu_list = fopen("/sys/devices/system/cpu/online", "r");
if(!fcpu_list)
@@ -1334,30 +1512,6 @@ static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **
continue;
}
- sprintf(name, core_info, i, "core_id");
- f = fopen(name, "r");
- if(f)
- {
- fscanf(f, "%u", &r);
- fclose(f);
- }
- else r = i;
- if(!logical_proc_info_add_by_id(*data, &len, *max_len, RelationProcessorCore, r, i))
- {
- SYSTEM_LOGICAL_PROCESSOR_INFORMATION *new_data;
-
- *max_len *= 2;
- new_data = RtlReAllocateHeap(GetProcessHeap(), 0, *data, *max_len*sizeof(*new_data));
- if(!new_data)
- {
- fclose(fcpu_list);
- return STATUS_NO_MEMORY;
- }
-
- *data = new_data;
- logical_proc_info_add_by_id(*data, &len, *max_len, RelationProcessorCore, r, i);
- }
-
sprintf(name, core_info, i, "physical_package_id");
f = fopen(name, "r");
if(f)
@@ -1366,20 +1520,24 @@ static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **
fclose(f);
}
else r = 0;
- if(!logical_proc_info_add_by_id(*data, &len, *max_len, RelationProcessorPackage, r, i))
+ if(!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorPackage, r, 1 << i))
{
- SYSTEM_LOGICAL_PROCESSOR_INFORMATION *new_data;
+ fclose(fcpu_list);
+ return STATUS_NO_MEMORY;
+ }
- *max_len *= 2;
- new_data = RtlReAllocateHeap(GetProcessHeap(), 0, *data, *max_len*sizeof(*new_data));
- if(!new_data)
- {
- fclose(fcpu_list);
- return STATUS_NO_MEMORY;
- }
-
- *data = new_data;
- logical_proc_info_add_by_id(*data, &len, *max_len, RelationProcessorPackage, r, i);
+ sprintf(name, core_info, i, "core_id");
+ f = fopen(name, "r");
+ if(f)
+ {
+ fscanf(f, "%u", &r);
+ fclose(f);
+ }
+ else r = i;
+ if(!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorCore, r, 1 << i))
+ {
+ fclose(fcpu_list);
+ return STATUS_NO_MEMORY;
}
for(j=0; j<4; j++)
@@ -1440,47 +1598,39 @@ static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **
else
cache.Type = CacheUnified;
- if(!logical_proc_info_add_cache(*data, &len, *max_len, mask, &cache))
+ if(!logical_proc_info_add_cache(data, dataex, &len, max_len, mask, &cache))
{
- SYSTEM_LOGICAL_PROCESSOR_INFORMATION *new_data;
-
- *max_len *= 2;
- new_data = RtlReAllocateHeap(GetProcessHeap(), 0, *data, *max_len*sizeof(*new_data));
- if(!new_data)
- {
- fclose(fcpu_list);
- return STATUS_NO_MEMORY;
- }
-
- *data = new_data;
- logical_proc_info_add_cache(*data, &len, *max_len, mask, &cache);
+ fclose(fcpu_list);
+ return STATUS_NO_MEMORY;
}
}
}
}
fclose(fcpu_list);
+ if(data){
+ for(i=0; i<len; i++){
+ if((*data)[i].Relationship == RelationProcessorCore){
+ all_cpus_mask |= (*data)[i].ProcessorMask;
+ ++num_cpus;
+ }
+ }
+ }else{
+ for(i = 0; i < len; ){
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *infoex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*dataex) + i);
+ if(infoex->Relationship == RelationProcessorCore){
+ all_cpus_mask |= infoex->u.Processor.GroupMask[0].Mask;
+ ++num_cpus;
+ }
+ i += infoex->Size;
+ }
+ }
+
fnuma_list = fopen("/sys/devices/system/node/online", "r");
if(!fnuma_list)
{
- ULONG_PTR mask = 0;
-
- for(i=0; i<len; i++)
- if((*data)[i].Relationship == RelationProcessorCore)
- mask |= (*data)[i].ProcessorMask;
-
- if(len == *max_len)
- {
- SYSTEM_LOGICAL_PROCESSOR_INFORMATION *new_data;
-
- *max_len *= 2;
- new_data = RtlReAllocateHeap(GetProcessHeap(), 0, *data, *max_len*sizeof(*new_data));
- if(!new_data)
- return STATUS_NO_MEMORY;
-
- *data = new_data;
- }
- logical_proc_info_add_numa_node(*data, &len, *max_len, mask, 0);
+ if(!logical_proc_info_add_numa_node(data, dataex, &len, max_len, all_cpus_mask, 0))
+ return STATUS_NO_MEMORY;
}
else
{
@@ -1506,151 +1656,163 @@ static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **
}
fclose(f);
- if(len == *max_len)
+ if(!logical_proc_info_add_numa_node(data, dataex, &len, max_len, mask, i))
{
- SYSTEM_LOGICAL_PROCESSOR_INFORMATION *new_data;
-
- *max_len *= 2;
- new_data = RtlReAllocateHeap(GetProcessHeap(), 0, *data, *max_len*sizeof(*new_data));
- if(!new_data)
- {
- fclose(fnuma_list);
- return STATUS_NO_MEMORY;
- }
-
- *data = new_data;
+ fclose(fnuma_list);
+ return STATUS_NO_MEMORY;
}
- logical_proc_info_add_numa_node(*data, &len, *max_len, mask, i);
}
}
fclose(fnuma_list);
}
- *max_len = len * sizeof(**data);
+ if(dataex)
+ logical_proc_info_add_group(dataex, &len, max_len, num_cpus, all_cpus_mask);
+
+ if(data)
+ *max_len = len * sizeof(**data);
+ else
+ *max_len = len;
+
return STATUS_SUCCESS;
}
#elif defined(__APPLE__)
-static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data, DWORD *max_len)
+/* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
+static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data,
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **dataex, DWORD *max_len)
{
- DWORD len = 0, i, j, k;
- DWORD cores_no, lcpu_no, lcpu_per_core, cores_per_package, assoc;
- size_t size;
- ULONG_PTR mask;
+ DWORD pkgs_no, cores_no, lcpu_no, lcpu_per_core, cores_per_package, assoc, len = 0;
+ DWORD cache_ctrs[10] = {0};
+ ULONG_PTR all_cpus_mask = 0;
+ CACHE_DESCRIPTOR cache[10];
LONGLONG cache_size, cache_line_size, cache_sharing[10];
- CACHE_DESCRIPTOR cache[4];
+ size_t size;
+ DWORD p,i,j,k;
lcpu_no = NtCurrentTeb()->Peb->NumberOfProcessors;
+ size = sizeof(pkgs_no);
+ if(sysctlbyname("hw.packages", &pkgs_no, &size, NULL, 0))
+ pkgs_no = 1;
+
size = sizeof(cores_no);
- if(sysctlbyname("machdep.cpu.core_count", &cores_no, &size, NULL, 0))
+ if(sysctlbyname("hw.physicalcpu", &cores_no, &size, NULL, 0))
cores_no = lcpu_no;
- lcpu_per_core = lcpu_no/cores_no;
- for(i=0; i<cores_no; i++)
- {
- mask = 0;
- for(j=lcpu_per_core*i; j<lcpu_per_core*(i+1); j++)
- mask |= (ULONG_PTR)1<<j;
+ TRACE("%u logical CPUs from %u physical cores across %u packages\n",
+ lcpu_no, cores_no, pkgs_no);
- (*data)[len].Relationship = RelationProcessorCore;
- (*data)[len].ProcessorMask = mask;
- (*data)[len].u.ProcessorCore.Flags = 0; /* TODO */
- len++;
- }
-
- size = sizeof(cores_per_package);
- if(sysctlbyname("machdep.cpu.cores_per_package", &cores_per_package, &size, NULL, 0))
- cores_per_package = lcpu_no;
-
- for(i=0; i<(lcpu_no+cores_per_package-1)/cores_per_package; i++)
- {
- mask = 0;
- for(j=cores_per_package*i; j<cores_per_package*(i+1) && j<lcpu_no; j++)
- mask |= (ULONG_PTR)1<<j;
-
- (*data)[len].Relationship = RelationProcessorPackage;
- (*data)[len].ProcessorMask = mask;
- len++;
- }
+ lcpu_per_core = lcpu_no / cores_no;
+ cores_per_package = cores_no / pkgs_no;
memset(cache, 0, sizeof(cache));
- cache[0].Level = 1;
- cache[0].Type = CacheInstruction;
cache[1].Level = 1;
- cache[1].Type = CacheData;
- cache[2].Level = 2;
- cache[2].Type = CacheUnified;
- cache[3].Level = 3;
+ cache[1].Type = CacheInstruction;
+ cache[1].Associativity = 8; /* reasonable default */
+ cache[1].LineSize = 0x40; /* reasonable default */
+ cache[2].Level = 1;
+ cache[2].Type = CacheData;
+ cache[2].Associativity = 8;
+ cache[2].LineSize = 0x40;
+ cache[3].Level = 2;
cache[3].Type = CacheUnified;
+ cache[3].Associativity = 8;
+ cache[3].LineSize = 0x40;
+ cache[4].Level = 3;
+ cache[4].Type = CacheUnified;
+ cache[4].Associativity = 12;
+ cache[4].LineSize = 0x40;
size = sizeof(cache_line_size);
if(!sysctlbyname("hw.cachelinesize", &cache_line_size, &size, NULL, 0))
{
- for(i=0; i<4; i++)
+ for(i=1; i<5; i++)
cache[i].LineSize = cache_line_size;
}
- /* TODO: set associativity for all caches */
+ /* TODO: set actual associativity for all caches */
size = sizeof(assoc);
if(!sysctlbyname("machdep.cpu.cache.L2_associativity", &assoc, &size, NULL, 0))
- cache[2].Associativity = assoc;
+ cache[3].Associativity = assoc;
size = sizeof(cache_size);
if(!sysctlbyname("hw.l1icachesize", &cache_size, &size, NULL, 0))
- cache[0].Size = cache_size;
- size = sizeof(cache_size);
- if(!sysctlbyname("hw.l1dcachesize", &cache_size, &size, NULL, 0))
cache[1].Size = cache_size;
size = sizeof(cache_size);
- if(!sysctlbyname("hw.l2cachesize", &cache_size, &size, NULL, 0))
+ if(!sysctlbyname("hw.l1dcachesize", &cache_size, &size, NULL, 0))
cache[2].Size = cache_size;
size = sizeof(cache_size);
- if(!sysctlbyname("hw.l3cachesize", &cache_size, &size, NULL, 0))
+ if(!sysctlbyname("hw.l2cachesize", &cache_size, &size, NULL, 0))
cache[3].Size = cache_size;
+ size = sizeof(cache_size);
+ if(!sysctlbyname("hw.l3cachesize", &cache_size, &size, NULL, 0))
+ cache[4].Size = cache_size;
size = sizeof(cache_sharing);
- if(!sysctlbyname("hw.cacheconfig", cache_sharing, &size, NULL, 0))
- {
- for(i=1; i<4 && i<size/sizeof(*cache_sharing); i++)
- {
- if(!cache_sharing[i] || !cache[i].Size)
- continue;
+ if(sysctlbyname("hw.cacheconfig", cache_sharing, &size, NULL, 0) < 0){
+ cache_sharing[1] = lcpu_per_core;
+ cache_sharing[2] = lcpu_per_core;
+ cache_sharing[3] = lcpu_per_core;
+ cache_sharing[4] = lcpu_no;
+ }else{
+ /* in cache[], indexes 1 and 2 are l1 caches */
+ cache_sharing[4] = cache_sharing[3];
+ cache_sharing[3] = cache_sharing[2];
+ cache_sharing[2] = cache_sharing[1];
+ }
- for(j=0; j<lcpu_no/cache_sharing[i]; j++)
- {
- mask = 0;
- for(k=j*cache_sharing[i]; k<lcpu_no && k<(j+1)*cache_sharing[i]; k++)
- mask |= (ULONG_PTR)1<<k;
+ for(p = 0; p < pkgs_no; ++p){
+ for(j = 0; j < cores_per_package && p * cores_per_package + j < cores_no; ++j){
+ ULONG_PTR mask = 0;
- if(i==1 && cache[0].Size)
- {
- (*data)[len].Relationship = RelationCache;
- (*data)[len].ProcessorMask = mask;
- (*data)[len].u.Cache = cache[0];
- len++;
+ for(k = 0; k < lcpu_per_core; ++k)
+ mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
+
+ all_cpus_mask |= mask;
+
+ /* add to package */
+ if(!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorPackage, p, mask))
+ return STATUS_NO_MEMORY;
+
+ /* add new core */
+ if(!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorCore, p, mask))
+ return STATUS_NO_MEMORY;
+
+ for(i = 1; i < 5; ++i){
+ if(cache_ctrs[i] == 0 && cache[i].Size > 0){
+ mask = 0;
+ for(k = 0; k < cache_sharing[i]; ++k)
+ mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
+
+ if(!logical_proc_info_add_cache(data, dataex, &len, max_len, mask, &cache[i]))
+ return STATUS_NO_MEMORY;
}
- (*data)[len].Relationship = RelationCache;
- (*data)[len].ProcessorMask = mask;
- (*data)[len].u.Cache = cache[i];
- len++;
+ cache_ctrs[i] += lcpu_per_core;
+
+ if(cache_ctrs[i] == cache_sharing[i])
+ cache_ctrs[i] = 0;
}
}
}
- mask = 0;
- for(i=0; i<lcpu_no; i++)
- mask |= (ULONG_PTR)1<<i;
- (*data)[len].Relationship = RelationNumaNode;
- (*data)[len].ProcessorMask = mask;
- (*data)[len].u.NumaNode.NodeNumber = 0;
- len++;
+ /* OSX doesn't support NUMA, so just make one NUMA node for all CPUs */
+ if(!logical_proc_info_add_numa_node(data, dataex, &len, max_len, all_cpus_mask, 0))
+ return STATUS_NO_MEMORY;
+
+ if(dataex)
+ logical_proc_info_add_group(dataex, &len, max_len, lcpu_no, all_cpus_mask);
+
+ if(data)
+ *max_len = len * sizeof(**data);
+ else
+ *max_len = len;
- *max_len = len * sizeof(**data);
return STATUS_SUCCESS;
}
#else
-static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data, DWORD *max_len)
+static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data,
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **dataex, DWORD *max_len)
{
FIXME("stub\n");
return STATUS_NOT_IMPLEMENTED;
@@ -2139,7 +2301,7 @@ NTSTATUS WINAPI NtQuerySystemInformation(
break;
}
- ret = create_logical_proc_info(&buf, &len);
+ ret = create_logical_proc_info(&buf, NULL, &len);
if( ret != STATUS_SUCCESS )
{
RtlFreeHeap(GetProcessHeap(), 0, buf);
@@ -2178,9 +2340,65 @@ NTSTATUS WINAPI NtQuerySystemInformation(
NTSTATUS WINAPI NtQuerySystemInformationEx(SYSTEM_INFORMATION_CLASS SystemInformationClass,
void *Query, ULONG QueryLength, void *SystemInformation, ULONG Length, ULONG *ResultLength)
{
- FIXME("(0x%08x,%p,%u,%p,%u,%p) stub\n", SystemInformationClass, Query, QueryLength, SystemInformation,
+ ULONG len;
+ NTSTATUS ret = STATUS_NOT_IMPLEMENTED;
+
+ TRACE("(0x%08x,%p,%u,%p,%u,%p) stub\n", SystemInformationClass, Query, QueryLength, SystemInformation,
Length, ResultLength);
- return STATUS_NOT_IMPLEMENTED;
+
+ switch (SystemInformationClass) {
+ case SystemLogicalProcessorInformationEx:
+ {
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buf;
+
+ if (!Query || QueryLength < sizeof(DWORD))
+ {
+ ret = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ if (*(DWORD*)Query != RelationAll)
+ FIXME("Relationship filtering not implemented: 0x%x\n", *(DWORD*)Query);
+
+ len = 3 * sizeof(*buf);
+ buf = RtlAllocateHeap(GetProcessHeap(), 0, len);
+ if (!buf)
+ {
+ ret = STATUS_NO_MEMORY;
+ break;
+ }
+
+ ret = create_logical_proc_info(NULL, &buf, &len);
+ if (ret != STATUS_SUCCESS)
+ {
+ RtlFreeHeap(GetProcessHeap(), 0, buf);
+ break;
+ }
+
+ if (Length >= len)
+ {
+ if (!SystemInformation)
+ ret = STATUS_ACCESS_VIOLATION;
+ else
+ memcpy( SystemInformation, buf, len);
+ }
+ else
+ ret = STATUS_INFO_LENGTH_MISMATCH;
+
+ RtlFreeHeap(GetProcessHeap(), 0, buf);
+
+ break;
+ }
+ default:
+ FIXME("(0x%08x,%p,%u,%p,%u,%p) stub\n", SystemInformationClass, Query, QueryLength, SystemInformation,
+ Length, ResultLength);
+ break;
+ }
+
+ if (ResultLength)
+ *ResultLength = len;
+
+ return ret;
}
/******************************************************************************
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index 252736e..c32650f 100644
--- a/dlls/ntdll/tests/info.c
+++ b/dlls/ntdll/tests/info.c
@@ -721,24 +721,23 @@ static void test_query_logicalprocex(void)
len = 0;
relationship = RelationProcessorCore;
status = pNtQuerySystemInformationEx(SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship), NULL, 0, &len);
-todo_wine {
ok(status == STATUS_INFO_LENGTH_MISMATCH, "got 0x%08x\n", status);
ok(len > 0, "got %u\n", len);
-}
+
len = 0;
relationship = RelationAll;
status = pNtQuerySystemInformationEx(SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship), NULL, 0, &len);
-todo_wine {
ok(status == STATUS_INFO_LENGTH_MISMATCH, "got 0x%08x\n", status);
ok(len > 0, "got %u\n", len);
-}
+
len2 = 0;
ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len2);
-todo_wine
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
ok(len == len2, "got %u, expected %u\n", len2, len);
if (len && len == len2) {
+ int j, i;
+
infoex = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
infoex2 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
@@ -750,6 +749,58 @@ todo_wine
ok(ret, "got %d, error %d\n", ret, GetLastError());
ok(!memcmp(infoex, infoex2, len), "returned info data mismatch\n");
+ for(i = 0; i < len; ){
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *ex = (void*)(((char *)infoex) + i);
+
+ ok(ex->Relationship >= RelationProcessorCore && ex->Relationship <= RelationGroup,
+ "Got invalid relationship value: 0x%x\n", ex->Relationship);
+
+ trace("infoex[%u].Size: %u (vs whole %u)\n", i, ex->Size, sizeof(*ex));
+ switch(ex->Relationship){
+ case RelationProcessorCore:
+ case RelationProcessorPackage:
+ trace("infoex[%u].Relationship: 0x%x (Core == 0x0 or Package == 0x3)\n", i, ex->Relationship);
+ trace("infoex[%u].Processor.Flags: 0x%x\n", i, ex->Processor.Flags);
+ trace("infoex[%u].Processor.EfficiencyClass: 0x%x\n", i, ex->Processor.EfficiencyClass);
+ trace("infoex[%u].Processor.GroupCount: 0x%x\n", i, ex->Processor.GroupCount);
+ for(j = 0; j < ex->Processor.GroupCount; ++j){
+ trace("infoex[%u].Processor.GroupMask[%u].Mask: 0x%lx\n", i, j, ex->Processor.GroupMask[j].Mask);
+ trace("infoex[%u].Processor.GroupMask[%u].Group: 0x%x\n", i, j, ex->Processor.GroupMask[j].Group);
+ }
+ break;
+ case RelationNumaNode:
+ trace("infoex[%u].Relationship: 0x%x (NumaNode)\n", i, ex->Relationship);
+ trace("infoex[%u].NumaNode.NodeNumber: 0x%x\n", i, ex->NumaNode.NodeNumber);
+ trace("infoex[%u].NumaNode.GroupMask.Mask: 0x%lx\n", i, ex->NumaNode.GroupMask.Mask);
+ trace("infoex[%u].NumaNode.GroupMask.Group: 0x%x\n", i, ex->NumaNode.GroupMask.Group);
+ break;
+ case RelationCache:
+ trace("infoex[%u].Relationship: 0x%x (Cache)\n", i, ex->Relationship);
+ trace("infoex[%u].Cache.Level: 0x%x\n", i, ex->Cache.Level);
+ trace("infoex[%u].Cache.Associativity: 0x%x\n", i, ex->Cache.Associativity);
+ trace("infoex[%u].Cache.LineSize: 0x%x\n", i, ex->Cache.LineSize);
+ trace("infoex[%u].Cache.CacheSize: 0x%x\n", i, ex->Cache.CacheSize);
+ trace("infoex[%u].Cache.Type: 0x%x\n", i, ex->Cache.Type);
+ trace("infoex[%u].Cache.GroupMask.Mask: 0x%lx\n", i, ex->Cache.GroupMask.Mask);
+ trace("infoex[%u].Cache.GroupMask.Group: 0x%x\n", i, ex->Cache.GroupMask.Group);
+ break;
+ case RelationGroup:
+ trace("infoex[%u].Relationship: 0x%x (Group)\n", i, ex->Relationship);
+ trace("infoex[%u].Group.MaximumGroupCount: 0x%x\n", i, ex->Group.MaximumGroupCount);
+ trace("infoex[%u].Group.ActiveGroupCount: 0x%x\n", i, ex->Group.ActiveGroupCount);
+ for(j = 0; j < ex->Group.ActiveGroupCount; ++j){
+ trace("infoex[%u].Group.GroupInfo[%u].MaximumProcessorCount: 0x%x\n", i, j, ex->Group.GroupInfo[j].MaximumProcessorCount);
+ trace("infoex[%u].Group.GroupInfo[%u].ActiveProcessorCount: 0x%x\n", i, j, ex->Group.GroupInfo[j].ActiveProcessorCount);
+ trace("infoex[%u].Group.GroupInfo[%u].ActiveProcessorMask: 0x%lx\n", i, j, ex->Group.GroupInfo[j].ActiveProcessorMask);
+ }
+ break;
+ default:
+ break;
+ }
+
+ i += ex->Size;
+ }
+
HeapFree(GetProcessHeap(), 0, infoex);
HeapFree(GetProcessHeap(), 0, infoex2);
}
--
2.7.0
More information about the wine-patches
mailing list