Commit a124064c authored by Andrew Eikum's avatar Andrew Eikum Committed by Alexandre Julliard

ntdll: Implement SystemLogicalProcessorInformationEx.

parent 3cffe923
......@@ -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 ) );
......
......@@ -3125,25 +3125,20 @@ static void test_GetLogicalProcessorInformationEx(void)
len = 0;
ret = pGetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &len);
todo_wine {
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
ok(len > 0, "got %u\n", len);
}
len = 0;
ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len);
todo_wine {
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
ok(len > 0, "got %u\n", len);
}
if (len) {
info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
ret = pGetLogicalProcessorInformationEx(RelationAll, info, &len);
ok(ret, "got %d, error %d\n", ret, GetLastError());
ok(info->Size > 0, "got %u\n", info->Size);
HeapFree(GetProcessHeap(), 0, info);
}
}
START_TEST(process)
{
......
......@@ -1243,77 +1243,255 @@ void fill_cpu_info(void)
cached_sci.Architecture, cached_sci.Level, cached_sci.Revision, cached_sci.FeatureSet);
}
#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)
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(data[i].Relationship!=rel || data[i].u.Reserved[1]!=id)
if ((*pdata)[i].Relationship!=rel || (*pdata)[i].u.Reserved[1]!=id)
continue;
data[i].ProcessorMask |= (ULONG_PTR)1<<proc;
(*pdata)[i].ProcessorMask |= mask;
return TRUE;
}
}else
i = *len;
if(*len == max_len)
while(*len == *pmax_len)
{
if (!grow_logical_proc_buf(pdata, NULL, pmax_len))
return FALSE;
}
data[i].Relationship = rel;
data[i].ProcessorMask = (ULONG_PTR)1<<proc;
(*pdata)[i].Relationship = rel;
(*pdata)[i].ProcessorMask = mask;
/* TODO: set processor core flags */
data[i].u.Reserved[0] = 0;
data[i].u.Reserved[1] = id;
(*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 *data,
DWORD *len, DWORD max_len, ULONG_PTR mask, CACHE_DESCRIPTOR *cache)
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++)
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)
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;
}
if(*len == max_len)
while (*len == *pmax_len)
if (!grow_logical_proc_buf(pdata, NULL, pmax_len))
return FALSE;
data[i].Relationship = RelationCache;
data[i].ProcessorMask = mask;
data[i].u.Cache = *cache;
(*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 *data,
DWORD *len, DWORD max_len, ULONG_PTR mask, DWORD node_id)
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(*len == max_len)
if (pdata)
{
while (*len == *pmax_len)
if (!grow_logical_proc_buf(pdata, NULL, pmax_len))
return FALSE;
data[*len].Relationship = RelationNumaNode;
data[*len].ProcessorMask = mask;
data[*len].u.NumaNode.NodeNumber = node_id;
(*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 NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data, DWORD *max_len)
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
/* 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,54 +1512,34 @@ static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **
continue;
}
sprintf(name, core_info, i, "core_id");
sprintf(name, core_info, i, "physical_package_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)
else r = 0;
if(!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorPackage, r, 1 << i))
{
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");
if(f)
{
fscanf(f, "%u", &r);
fclose(f);
}
else r = 0;
if(!logical_proc_info_add_by_id(*data, &len, *max_len, RelationProcessorPackage, 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)
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;
}
*data = new_data;
logical_proc_info_add_by_id(*data, &len, *max_len, RelationProcessorPackage, r, i);
}
for(j=0; j<4; j++)
{
CACHE_DESCRIPTOR cache;
......@@ -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))
{
SYSTEM_LOGICAL_PROCESSOR_INFORMATION *new_data;
*max_len *= 2;
new_data = RtlReAllocateHeap(GetProcessHeap(), 0, *data, *max_len*sizeof(*new_data));
if(!new_data)
if(!logical_proc_info_add_cache(data, dataex, &len, max_len, mask, &cache))
{
fclose(fcpu_list);
return STATUS_NO_MEMORY;
}
}
}
}
fclose(fcpu_list);
*data = new_data;
logical_proc_info_add_cache(*data, &len, *max_len, mask, &cache);
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;
}
}
fclose(fcpu_list);
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)
if(!logical_proc_info_add_numa_node(data, dataex, &len, max_len, all_cpus_mask, 0))
return STATUS_NO_MEMORY;
*data = new_data;
}
logical_proc_info_add_numa_node(*data, &len, *max_len, mask, 0);
}
else
{
......@@ -1506,151 +1656,163 @@ static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **
}
fclose(f);
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)
if(!logical_proc_info_add_numa_node(data, dataex, &len, max_len, mask, i))
{
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);
}
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;
(*data)[len].Relationship = RelationProcessorCore;
(*data)[len].ProcessorMask = mask;
(*data)[len].u.ProcessorCore.Flags = 0; /* TODO */
len++;
}
TRACE("%u logical CPUs from %u physical cores across %u packages\n",
lcpu_no, cores_no, pkgs_no);
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;
cache[1].Size = cache_size;
size = sizeof(cache_size);
if(!sysctlbyname("hw.l1dcachesize", &cache_size, &size, NULL, 0))
cache[1].Size = cache_size;
cache[2].Size = cache_size;
size = sizeof(cache_size);
if(!sysctlbyname("hw.l2cachesize", &cache_size, &size, NULL, 0))
cache[2].Size = cache_size;
cache[3].Size = cache_size;
size = sizeof(cache_size);
if(!sysctlbyname("hw.l3cachesize", &cache_size, &size, NULL, 0))
cache[3].Size = cache_size;
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(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;
for(j=0; j<lcpu_no/cache_sharing[i]; j++)
{
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=j*cache_sharing[i]; k<lcpu_no && k<(j+1)*cache_sharing[i]; k++)
mask |= (ULONG_PTR)1<<k;
for(k = 0; k < cache_sharing[i]; ++k)
mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
if(i==1 && cache[0].Size)
{
(*data)[len].Relationship = RelationCache;
(*data)[len].ProcessorMask = mask;
(*data)[len].u.Cache = cache[0];
len++;
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;
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)
{
ULONG len;
NTSTATUS ret = STATUS_NOT_IMPLEMENTED;
TRACE("(0x%08x,%p,%u,%p,%u,%p) stub\n", SystemInformationClass, Query, QueryLength, SystemInformation,
Length, ResultLength);
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);
return STATUS_NOT_IMPLEMENTED;
break;
}
if (ResultLength)
*ResultLength = len;
return ret;
}
/******************************************************************************
......
......@@ -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\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, 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