Commit d16ff97e authored by Andrew Eikum's avatar Andrew Eikum Committed by Michael Stefaniuc

ntdll: Implement SystemLogicalProcessorInformationEx.

Signed-off-by: 's avatarAndrew Eikum <aeikum@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org> (cherry picked from commit a124064c) Signed-off-by: 's avatarMichael Stefaniuc <mstefani@winehq.org>
parent ebcc9c52
...@@ -3850,6 +3850,11 @@ BOOL WINAPI GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP rela ...@@ -3850,6 +3850,11 @@ BOOL WINAPI GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP rela
status = NtQuerySystemInformationEx( SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship), status = NtQuerySystemInformationEx( SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship),
buffer, *len, len ); buffer, *len, len );
if (status == STATUS_INFO_LENGTH_MISMATCH)
{
SetLastError( ERROR_INSUFFICIENT_BUFFER );
return FALSE;
}
if (status != STATUS_SUCCESS) if (status != STATUS_SUCCESS)
{ {
SetLastError( RtlNtStatusToDosError( status ) ); SetLastError( RtlNtStatusToDosError( status ) );
......
...@@ -2986,25 +2986,20 @@ static void test_GetLogicalProcessorInformationEx(void) ...@@ -2986,25 +2986,20 @@ static void test_GetLogicalProcessorInformationEx(void)
len = 0; len = 0;
ret = pGetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &len); ret = pGetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &len);
todo_wine {
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError()); ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
ok(len > 0, "got %u\n", len); ok(len > 0, "got %u\n", len);
}
len = 0; len = 0;
ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len); ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len);
todo_wine {
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError()); ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
ok(len > 0, "got %u\n", len); ok(len > 0, "got %u\n", len);
}
if (len) {
info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
ret = pGetLogicalProcessorInformationEx(RelationAll, info, &len); ret = pGetLogicalProcessorInformationEx(RelationAll, info, &len);
ok(ret, "got %d, error %d\n", ret, GetLastError()); ok(ret, "got %d, error %d\n", ret, GetLastError());
ok(info->Size > 0, "got %u\n", info->Size); ok(info->Size > 0, "got %u\n", info->Size);
HeapFree(GetProcessHeap(), 0, info); HeapFree(GetProcessHeap(), 0, info);
} }
}
START_TEST(process) START_TEST(process)
{ {
......
...@@ -1243,77 +1243,255 @@ void fill_cpu_info(void) ...@@ -1243,77 +1243,255 @@ void fill_cpu_info(void)
cached_sci.Architecture, cached_sci.Level, cached_sci.Revision, cached_sci.FeatureSet); cached_sci.Architecture, cached_sci.Level, cached_sci.Revision, cached_sci.FeatureSet);
} }
#ifdef linux static BOOL grow_logical_proc_buf(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
static inline BOOL logical_proc_info_add_by_id(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *data, SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *max_len)
DWORD *len, DWORD max_len, LOGICAL_PROCESSOR_RELATIONSHIP rel, DWORD id, DWORD proc)
{ {
DWORD i; if (pdata)
{
SYSTEM_LOGICAL_PROCESSOR_INFORMATION *new_data;
for(i=0; i<*len; i++) *max_len *= 2;
new_data = RtlReAllocateHeap(GetProcessHeap(), 0, *pdata, *max_len*sizeof(*new_data));
if (!new_data)
return FALSE;
*pdata = new_data;
}
else
{ {
if(data[i].Relationship!=rel || data[i].u.Reserved[1]!=id) SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *new_dataex;
continue;
data[i].ProcessorMask |= (ULONG_PTR)1<<proc; *max_len *= 2;
return TRUE; new_dataex = RtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, *pdataex, *max_len*sizeof(*new_dataex));
if (!new_dataex)
return FALSE;
*pdataex = new_dataex;
} }
if(*len == max_len) return TRUE;
return FALSE; }
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;
}
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; return TRUE;
} }
static inline BOOL logical_proc_info_add_cache(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *data, static inline BOOL logical_proc_info_add_cache(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
DWORD *len, DWORD max_len, ULONG_PTR mask, CACHE_DESCRIPTOR *cache) SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len,
DWORD *pmax_len, ULONG_PTR mask, CACHE_DESCRIPTOR *cache)
{ {
DWORD i; if (pdata)
{
DWORD i;
for(i=0; i<*len; 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
{ {
if(data[i].Relationship==RelationCache && data[i].ProcessorMask==mask SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex = *pdataex;
&& data[i].u.Cache.Level==cache->Level && data[i].u.Cache.Type==cache->Type) DWORD ofs;
return TRUE;
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;
} }
if(*len == max_len) return TRUE;
return FALSE; }
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;
}
data[i].Relationship = RelationCache;
data[i].ProcessorMask = mask;
data[i].u.Cache = *cache;
*len = i+1;
return TRUE; return TRUE;
} }
static inline BOOL logical_proc_info_add_numa_node(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *data, static inline BOOL logical_proc_info_add_group(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex,
DWORD *len, DWORD max_len, ULONG_PTR mask, DWORD node_id) DWORD *len, DWORD *pmax_len, DWORD num_cpus, ULONG_PTR mask)
{ {
if(*len == max_len) SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
return FALSE;
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;
data[*len].Relationship = RelationNumaNode;
data[*len].ProcessorMask = mask;
data[*len].u.NumaNode.NodeNumber = node_id;
(*len)++;
return TRUE; return TRUE;
} }
static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data, DWORD *max_len) #ifdef linux
/* 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 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 cache_info[] = "/sys/devices/system/cpu/cpu%u/cache/index%u/%s";
static const char numa_info[] = "/sys/devices/system/node/node%u/cpumap"; static const char numa_info[] = "/sys/devices/system/node/node%u/cpumap";
FILE *fcpu_list, *fnuma_list, *f; 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]; char op, name[MAX_PATH];
ULONG_PTR all_cpus_mask = 0;
fcpu_list = fopen("/sys/devices/system/cpu/online", "r"); fcpu_list = fopen("/sys/devices/system/cpu/online", "r");
if(!fcpu_list) if(!fcpu_list)
...@@ -1334,52 +1512,32 @@ static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION ** ...@@ -1334,52 +1512,32 @@ static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **
continue; continue;
} }
sprintf(name, core_info, i, "core_id"); sprintf(name, core_info, i, "physical_package_id");
f = fopen(name, "r"); f = fopen(name, "r");
if(f) if(f)
{ {
fscanf(f, "%u", &r); fscanf(f, "%u", &r);
fclose(f); fclose(f);
} }
else r = i; else r = 0;
if(!logical_proc_info_add_by_id(*data, &len, *max_len, RelationProcessorCore, 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, RelationProcessorCore, r, i);
} }
sprintf(name, core_info, i, "physical_package_id"); sprintf(name, core_info, i, "core_id");
f = fopen(name, "r"); f = fopen(name, "r");
if(f) if(f)
{ {
fscanf(f, "%u", &r); fscanf(f, "%u", &r);
fclose(f); fclose(f);
} }
else r = 0; else r = i;
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, RelationProcessorCore, 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);
} }
for(j=0; j<4; j++) for(j=0; j<4; j++)
...@@ -1440,47 +1598,39 @@ static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION ** ...@@ -1440,47 +1598,39 @@ static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **
else else
cache.Type = CacheUnified; 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; 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_cache(*data, &len, *max_len, mask, &cache);
} }
} }
} }
} }
fclose(fcpu_list); 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"); fnuma_list = fopen("/sys/devices/system/node/online", "r");
if(!fnuma_list) if(!fnuma_list)
{ {
ULONG_PTR mask = 0; if(!logical_proc_info_add_numa_node(data, dataex, &len, max_len, all_cpus_mask, 0))
return STATUS_NO_MEMORY;
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);
} }
else else
{ {
...@@ -1506,151 +1656,163 @@ static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION ** ...@@ -1506,151 +1656,163 @@ static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **
} }
fclose(f); 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; fclose(fnuma_list);
return STATUS_NO_MEMORY;
*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;
} }
logical_proc_info_add_numa_node(*data, &len, *max_len, mask, i);
} }
} }
fclose(fnuma_list); 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; return STATUS_SUCCESS;
} }
#elif defined(__APPLE__) #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 pkgs_no, cores_no, lcpu_no, lcpu_per_core, cores_per_package, assoc, len = 0;
DWORD cores_no, lcpu_no, lcpu_per_core, cores_per_package, assoc; DWORD cache_ctrs[10] = {0};
size_t size; ULONG_PTR all_cpus_mask = 0;
ULONG_PTR mask; CACHE_DESCRIPTOR cache[10];
LONGLONG cache_size, cache_line_size, cache_sharing[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; 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); 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; cores_no = lcpu_no;
lcpu_per_core = lcpu_no/cores_no; TRACE("%u logical CPUs from %u physical cores across %u packages\n",
for(i=0; i<cores_no; i++) lcpu_no, cores_no, pkgs_no);
{
mask = 0;
for(j=lcpu_per_core*i; j<lcpu_per_core*(i+1); j++)
mask |= (ULONG_PTR)1<<j;
(*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; lcpu_per_core = lcpu_no / cores_no;
(*data)[len].ProcessorMask = mask; cores_per_package = cores_no / pkgs_no;
len++;
}
memset(cache, 0, sizeof(cache)); memset(cache, 0, sizeof(cache));
cache[0].Level = 1;
cache[0].Type = CacheInstruction;
cache[1].Level = 1; cache[1].Level = 1;
cache[1].Type = CacheData; cache[1].Type = CacheInstruction;
cache[2].Level = 2; cache[1].Associativity = 8; /* reasonable default */
cache[2].Type = CacheUnified; cache[1].LineSize = 0x40; /* reasonable default */
cache[3].Level = 3; 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].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); size = sizeof(cache_line_size);
if(!sysctlbyname("hw.cachelinesize", &cache_line_size, &size, NULL, 0)) 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; cache[i].LineSize = cache_line_size;
} }
/* TODO: set associativity for all caches */ /* TODO: set actual associativity for all caches */
size = sizeof(assoc); size = sizeof(assoc);
if(!sysctlbyname("machdep.cpu.cache.L2_associativity", &assoc, &size, NULL, 0)) if(!sysctlbyname("machdep.cpu.cache.L2_associativity", &assoc, &size, NULL, 0))
cache[2].Associativity = assoc; cache[3].Associativity = assoc;
size = sizeof(cache_size); size = sizeof(cache_size);
if(!sysctlbyname("hw.l1icachesize", &cache_size, &size, NULL, 0)) if(!sysctlbyname("hw.l1icachesize", &cache_size, &size, NULL, 0))
cache[0].Size = cache_size; cache[1].Size = cache_size;
size = sizeof(cache_size); size = sizeof(cache_size);
if(!sysctlbyname("hw.l1dcachesize", &cache_size, &size, NULL, 0)) if(!sysctlbyname("hw.l1dcachesize", &cache_size, &size, NULL, 0))
cache[1].Size = cache_size; cache[2].Size = cache_size;
size = sizeof(cache_size); size = sizeof(cache_size);
if(!sysctlbyname("hw.l2cachesize", &cache_size, &size, NULL, 0)) if(!sysctlbyname("hw.l2cachesize", &cache_size, &size, NULL, 0))
cache[2].Size = cache_size; cache[3].Size = cache_size;
size = sizeof(cache_size); size = sizeof(cache_size);
if(!sysctlbyname("hw.l3cachesize", &cache_size, &size, NULL, 0)) if(!sysctlbyname("hw.l3cachesize", &cache_size, &size, NULL, 0))
cache[3].Size = cache_size; cache[4].Size = cache_size;
size = sizeof(cache_sharing); size = sizeof(cache_sharing);
if(!sysctlbyname("hw.cacheconfig", cache_sharing, &size, NULL, 0)) if(sysctlbyname("hw.cacheconfig", cache_sharing, &size, NULL, 0) < 0){
{ cache_sharing[1] = lcpu_per_core;
for(i=1; i<4 && i<size/sizeof(*cache_sharing); i++) cache_sharing[2] = lcpu_per_core;
{ cache_sharing[3] = lcpu_per_core;
if(!cache_sharing[i] || !cache[i].Size) cache_sharing[4] = lcpu_no;
continue; }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++) for(p = 0; p < pkgs_no; ++p){
{ for(j = 0; j < cores_per_package && p * cores_per_package + j < cores_no; ++j){
mask = 0; ULONG_PTR mask = 0;
for(k=j*cache_sharing[i]; k<lcpu_no && k<(j+1)*cache_sharing[i]; k++)
mask |= (ULONG_PTR)1<<k;
if(i==1 && cache[0].Size) for(k = 0; k < lcpu_per_core; ++k)
{ mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
(*data)[len].Relationship = RelationCache;
(*data)[len].ProcessorMask = mask; all_cpus_mask |= mask;
(*data)[len].u.Cache = cache[0];
len++; /* 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; cache_ctrs[i] += lcpu_per_core;
(*data)[len].ProcessorMask = mask;
(*data)[len].u.Cache = cache[i]; if(cache_ctrs[i] == cache_sharing[i])
len++; cache_ctrs[i] = 0;
} }
} }
} }
mask = 0; /* OSX doesn't support NUMA, so just make one NUMA node for all CPUs */
for(i=0; i<lcpu_no; i++) if(!logical_proc_info_add_numa_node(data, dataex, &len, max_len, all_cpus_mask, 0))
mask |= (ULONG_PTR)1<<i; return STATUS_NO_MEMORY;
(*data)[len].Relationship = RelationNumaNode;
(*data)[len].ProcessorMask = mask; if(dataex)
(*data)[len].u.NumaNode.NodeNumber = 0; logical_proc_info_add_group(dataex, &len, max_len, lcpu_no, all_cpus_mask);
len++;
if(data)
*max_len = len * sizeof(**data);
else
*max_len = len;
*max_len = len * sizeof(**data);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
#else #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"); FIXME("stub\n");
return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED;
...@@ -2106,7 +2268,7 @@ NTSTATUS WINAPI NtQuerySystemInformation( ...@@ -2106,7 +2268,7 @@ NTSTATUS WINAPI NtQuerySystemInformation(
break; break;
} }
ret = create_logical_proc_info(&buf, &len); ret = create_logical_proc_info(&buf, NULL, &len);
if( ret != STATUS_SUCCESS ) if( ret != STATUS_SUCCESS )
{ {
RtlFreeHeap(GetProcessHeap(), 0, buf); RtlFreeHeap(GetProcessHeap(), 0, buf);
...@@ -2145,9 +2307,65 @@ NTSTATUS WINAPI NtQuerySystemInformation( ...@@ -2145,9 +2307,65 @@ NTSTATUS WINAPI NtQuerySystemInformation(
NTSTATUS WINAPI NtQuerySystemInformationEx(SYSTEM_INFORMATION_CLASS SystemInformationClass, NTSTATUS WINAPI NtQuerySystemInformationEx(SYSTEM_INFORMATION_CLASS SystemInformationClass,
void *Query, ULONG QueryLength, void *SystemInformation, ULONG Length, ULONG *ResultLength) 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); 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;
} }
/****************************************************************************** /******************************************************************************
......
...@@ -689,24 +689,23 @@ static void test_query_logicalprocex(void) ...@@ -689,24 +689,23 @@ static void test_query_logicalprocex(void)
len = 0; len = 0;
relationship = RelationProcessorCore; relationship = RelationProcessorCore;
status = pNtQuerySystemInformationEx(SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship), NULL, 0, &len); status = pNtQuerySystemInformationEx(SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship), NULL, 0, &len);
todo_wine {
ok(status == STATUS_INFO_LENGTH_MISMATCH, "got 0x%08x\n", status); ok(status == STATUS_INFO_LENGTH_MISMATCH, "got 0x%08x\n", status);
ok(len > 0, "got %u\n", len); ok(len > 0, "got %u\n", len);
}
len = 0; len = 0;
relationship = RelationAll; relationship = RelationAll;
status = pNtQuerySystemInformationEx(SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship), NULL, 0, &len); status = pNtQuerySystemInformationEx(SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship), NULL, 0, &len);
todo_wine {
ok(status == STATUS_INFO_LENGTH_MISMATCH, "got 0x%08x\n", status); ok(status == STATUS_INFO_LENGTH_MISMATCH, "got 0x%08x\n", status);
ok(len > 0, "got %u\n", len); ok(len > 0, "got %u\n", len);
}
len2 = 0; len2 = 0;
ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len2); ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len2);
todo_wine
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError()); ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
ok(len == len2, "got %u, expected %u\n", len2, len); ok(len == len2, "got %u, expected %u\n", len2, len);
if (len && len == len2) { if (len && len == len2) {
int j, i;
infoex = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); infoex = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
infoex2 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); infoex2 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
...@@ -718,6 +717,58 @@ todo_wine ...@@ -718,6 +717,58 @@ todo_wine
ok(ret, "got %d, error %d\n", ret, GetLastError()); ok(ret, "got %d, error %d\n", ret, GetLastError());
ok(!memcmp(infoex, infoex2, len), "returned info data mismatch\n"); 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\n", i, ex->Size);
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, infoex);
HeapFree(GetProcessHeap(), 0, infoex2); HeapFree(GetProcessHeap(), 0, infoex2);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment