1
0
forked from 0ad/0ad
0ad/source/lib/sysdep/win/wcpu.cpp

127 lines
3.1 KiB
C++

/**
* =========================================================================
* File : wcpu.cpp
* Project : 0 A.D.
* Description : Windows implementation of sysdep/cpu
* =========================================================================
*/
// license: GPL; see lib/license.txt
#include "precompiled.h"
#include "../cpu.h"
#include "win.h"
#include "lib/bits.h"
static LibError ReadFrequencyFromRegistry(DWORD* freqMhz)
{
HKEY hKey;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
return ERR::NO_SYS;
DWORD size = sizeof(*freqMhz);
LONG ret = RegQueryValueEx(hKey, "~MHz", 0, 0, (LPBYTE)freqMhz, &size);
RegCloseKey(hKey);
if(ret != ERROR_SUCCESS)
WARN_RETURN(ERR::FAIL);
return INFO::OK;
}
double cpu_ClockFrequency()
{
DWORD freqMhz;
if(ReadFrequencyFromRegistry(&freqMhz) < 0)
return -1.0;
const double clockFrequency = freqMhz * 1e6;
return clockFrequency;
}
uint cpu_NumProcessors()
{
SYSTEM_INFO si;
GetSystemInfo(&si); // can't fail
const uint numProcessors = (uint)si.dwNumberOfProcessors;
return numProcessors;
}
size_t cpu_PageSize()
{
SYSTEM_INFO si;
GetSystemInfo(&si); // can't fail
const size_t pageSize = (size_t)si.dwPageSize;
return pageSize;
}
size_t cpu_MemorySize(CpuMemoryIndicators mem_type)
{
// note: we no longer bother dynamically importing GlobalMemoryStatusEx -
// it's available on Win2k and above. this function safely handles
// systems with > 4 GB of memory.
MEMORYSTATUSEX mse = { sizeof(mse) };
BOOL ok = GlobalMemoryStatusEx(&mse);
WARN_IF_FALSE(ok);
if(mem_type == CPU_MEM_TOTAL)
{
size_t memoryTotal = (size_t)mse.ullTotalPhys;
// Richter, "Programming Applications for Windows": the reported
// value doesn't include non-paged pool reserved during boot;
// it's not considered available to the kernel. (the amount is
// 528 KiB on a 512 MiB WinXP/Win2k machine). we'll round up
// to the nearest megabyte to fix this.
memoryTotal = round_up(memoryTotal, 1*MiB);
return memoryTotal;
}
else
{
const size_t memoryAvailable = (size_t)mse.ullAvailPhys;
return memoryAvailable;
}
}
LibError cpu_CallByEachCPU(CpuCallback cb, void* param)
{
const HANDLE hProcess = GetCurrentProcess();
DWORD process_affinity, system_affinity;
if(!GetProcessAffinityMask(hProcess, &process_affinity, &system_affinity))
WARN_RETURN(ERR::FAIL);
// our affinity != system affinity: OS is limiting the CPUs that
// this process can run on. fail (cannot call back for each CPU).
if(process_affinity != system_affinity)
WARN_RETURN(ERR::CPU_RESTRICTED_AFFINITY);
for(DWORD_PTR cpu_bit = 1; cpu_bit != 0 && cpu_bit <= process_affinity; cpu_bit *= 2)
{
// check if we can switch to target CPU
if(!(process_affinity & cpu_bit))
continue;
// .. and do so.
if(!SetThreadAffinityMask(GetCurrentThread(), cpu_bit))
{
WARN_ERR(ERR::CPU_RESTRICTED_AFFINITY);
continue;
}
// reschedule to make sure we switch CPUs.
Sleep(1);
cb(param);
}
// restore to original value
SetThreadAffinityMask(hProcess, process_affinity);
return INFO::OK;
}