make use of SMBIOS information to detect CPU frequency and memory size
smbios fixes: also ignore max value (used by Dell BIOS to report invalid MemoryDevice bit width); fix incorrect error check that caused 0 to be returned on all but the first call; add implicit conversion operator to allow using size without appending .value This was SVN commit r9195.
This commit is contained in:
parent
e5e9e38532
commit
99aa427ffa
@ -30,12 +30,6 @@
|
||||
#endif
|
||||
|
||||
|
||||
double os_cpu_ClockFrequency()
|
||||
{
|
||||
return -1; // don't know
|
||||
}
|
||||
|
||||
|
||||
size_t os_cpu_NumProcessors()
|
||||
{
|
||||
static size_t numProcessors;
|
||||
@ -88,17 +82,10 @@ size_t os_cpu_LargePageSize()
|
||||
}
|
||||
|
||||
|
||||
size_t os_cpu_MemorySize()
|
||||
size_t os_cpu_QueryMemorySize()
|
||||
{
|
||||
static size_t memorySize;
|
||||
|
||||
if(!memorySize)
|
||||
{
|
||||
const uint64_t memorySizeBytes = (uint64_t)sysconf(_SC_PHYS_PAGES) * os_cpu_PageSize();
|
||||
memorySize = size_t(memorySizeBytes / MiB);
|
||||
}
|
||||
|
||||
return memorySize;
|
||||
const uint64_t memorySize = (uint64_t)sysconf(_SC_PHYS_PAGES) * os_cpu_PageSize();
|
||||
return size_t(memorySize / MiB);
|
||||
}
|
||||
|
||||
|
||||
|
@ -27,13 +27,6 @@
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
|
||||
double os_cpu_ClockFrequency()
|
||||
{
|
||||
return -1; // don't know
|
||||
}
|
||||
|
||||
|
||||
size_t os_cpu_NumProcessors()
|
||||
{
|
||||
static size_t numProcessors;
|
||||
@ -82,19 +75,13 @@ size_t os_cpu_LargePageSize()
|
||||
}
|
||||
|
||||
|
||||
size_t os_cpu_MemorySize()
|
||||
size_t os_cpu_QueryMemorySize()
|
||||
{
|
||||
static size_t memorySize;
|
||||
|
||||
if(!memorySize)
|
||||
{
|
||||
size_t len = sizeof(memorySize);
|
||||
// Argh, the API doesn't seem to be const-correct
|
||||
/*const*/ int mib[2] = { CTL_HW, HW_PHYSMEM };
|
||||
sysctl(mib, 2, &memorySize, &len, 0, 0);
|
||||
memorySize /= MiB;
|
||||
}
|
||||
|
||||
size_t len = sizeof(memorySize);
|
||||
// Argh, the API doesn't seem to be const-correct
|
||||
/*const*/ int mib[2] = { CTL_HW, HW_PHYSMEM };
|
||||
sysctl(mib, 2, &memorySize, &len, 0, 0);
|
||||
memorySize /= MiB;
|
||||
return memorySize;
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ size_t os_cpu_NumProcessors()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static LibError ReadFrequencyFromRegistry(DWORD& freqMhz)
|
||||
LibError wcpu_ReadFrequencyFromRegistry(u32& freqMhz)
|
||||
{
|
||||
HKEY hKey;
|
||||
if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
|
||||
@ -90,22 +90,6 @@ static LibError ReadFrequencyFromRegistry(DWORD& freqMhz)
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
double os_cpu_ClockFrequency()
|
||||
{
|
||||
static double clockFrequency;
|
||||
|
||||
if(clockFrequency == 0.0)
|
||||
{
|
||||
DWORD freqMhz;
|
||||
if(ReadFrequencyFromRegistry(freqMhz) == INFO::OK)
|
||||
clockFrequency = freqMhz * 1e6;
|
||||
else
|
||||
clockFrequency = -1.0;
|
||||
}
|
||||
|
||||
return clockFrequency;
|
||||
}
|
||||
|
||||
|
||||
size_t os_cpu_PageSize()
|
||||
{
|
||||
@ -155,27 +139,20 @@ static void GetMemoryStatus(MEMORYSTATUSEX& mse)
|
||||
WARN_IF_FALSE(ok);
|
||||
}
|
||||
|
||||
size_t os_cpu_MemorySize()
|
||||
size_t os_cpu_QueryMemorySize()
|
||||
{
|
||||
static size_t memorySizeMiB;
|
||||
MEMORYSTATUSEX mse;
|
||||
GetMemoryStatus(mse);
|
||||
DWORDLONG memorySize = mse.ullTotalPhys;
|
||||
|
||||
if(memorySizeMiB == 0)
|
||||
{
|
||||
MEMORYSTATUSEX mse;
|
||||
GetMemoryStatus(mse);
|
||||
DWORDLONG memorySize = 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.
|
||||
memorySize = round_up(memorySize, DWORDLONG(1*MiB));
|
||||
|
||||
// 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.
|
||||
memorySize = round_up(memorySize, DWORDLONG(1*MiB));
|
||||
|
||||
memorySizeMiB = size_t(memorySize / MiB);
|
||||
}
|
||||
|
||||
return memorySizeMiB;
|
||||
return size_t(memorySize / MiB);
|
||||
}
|
||||
|
||||
size_t os_cpu_MemoryAvailable()
|
||||
|
@ -29,6 +29,8 @@
|
||||
|
||||
#include "lib/sysdep/os/win/win.h"
|
||||
|
||||
extern LibError wcpu_ReadFrequencyFromRegistry(u32& freqMhz);
|
||||
|
||||
// "affinity" and "processorNumber" are what Windows sees.
|
||||
// "processorMask" and "processor" are the idealized representation we expose
|
||||
// to users. the latter insulates them from process affinity restrictions by
|
||||
|
@ -27,4 +27,55 @@
|
||||
#include "precompiled.h"
|
||||
#include "lib/sysdep/os_cpu.h"
|
||||
|
||||
#include "lib/sysdep/smbios.h"
|
||||
|
||||
#if OS_WIN
|
||||
# include "lib/sysdep/os/win/wcpu.h"
|
||||
#endif
|
||||
|
||||
|
||||
ERROR_ASSOCIATE(ERR::OS_CPU_RESTRICTED_AFFINITY, L"Cannot set desired CPU affinity", -1);
|
||||
|
||||
|
||||
double os_cpu_ClockFrequency()
|
||||
{
|
||||
static double clockFrequency;
|
||||
if(clockFrequency != 0.0) // already initialized
|
||||
return clockFrequency;
|
||||
|
||||
#if OS_WIN
|
||||
u32 freqMhz;
|
||||
if(wcpu_ReadFrequencyFromRegistry(freqMhz) == INFO::OK)
|
||||
return clockFrequency = freqMhz * 1e6;
|
||||
#endif
|
||||
|
||||
const SMBIOS::Structures* structures = SMBIOS::GetStructures();
|
||||
if(structures->Processor_)
|
||||
return clockFrequency = structures->Processor_->maxFrequency * 1e6;
|
||||
|
||||
return clockFrequency = -1.0; // unknown
|
||||
}
|
||||
|
||||
|
||||
size_t os_cpu_MemorySize()
|
||||
{
|
||||
static size_t memorySize;
|
||||
if(memorySize != 0) // already initialized
|
||||
return memorySize;
|
||||
|
||||
memorySize = os_cpu_QueryMemorySize();
|
||||
|
||||
// replace with the sum of all memory devices reported by SMBIOS if
|
||||
// that's within 10% of what the OS reported
|
||||
{
|
||||
const SMBIOS::Structures* structures = SMBIOS::GetStructures();
|
||||
u64 memorySizeBytes = 0;
|
||||
for(const SMBIOS::MemoryDevice* p = structures->MemoryDevice_; p; p = p->next)
|
||||
memorySizeBytes += p->size;
|
||||
const size_t memorySize2 = memorySizeBytes/MiB;
|
||||
if(9*memorySize/10 <= memorySize2 && memorySize2 <= 11*memorySize/10)
|
||||
memorySize = memorySize2;
|
||||
}
|
||||
|
||||
return memorySize;
|
||||
}
|
||||
|
@ -92,12 +92,20 @@ LIB_API size_t os_cpu_PageSize();
|
||||
LIB_API size_t os_cpu_LargePageSize();
|
||||
|
||||
/**
|
||||
* @return the size [MB] of physical memory.
|
||||
* @return the size [MB] of physical memory as reported by the OS;
|
||||
* no caching/validation is performed.
|
||||
**/
|
||||
LIB_API size_t os_cpu_QueryMemorySize();
|
||||
|
||||
/**
|
||||
* @return the size [MB] of physical memory; caches the result of
|
||||
* os_cpu_QueryMemorySize and overrides it with a more exact value
|
||||
* if SMBIOS information is available.
|
||||
**/
|
||||
LIB_API size_t os_cpu_MemorySize();
|
||||
|
||||
/**
|
||||
* @return the size [MB] of currently available memory.
|
||||
* @return the current amount [MB] of available memory.
|
||||
**/
|
||||
LIB_API size_t os_cpu_MemoryAvailable();
|
||||
|
||||
|
@ -577,10 +577,10 @@ private:
|
||||
template<typename Field>
|
||||
void Write(size_t flags, Field& field, const char* name, const char* units, ...)
|
||||
{
|
||||
// SMBIOS uses the smallest representable signed/unsigned value to
|
||||
// indicate `unknown' (except enumerators - but those are handled in
|
||||
// the other function overload), so skip those.
|
||||
if(field == std::numeric_limits<Field>::min())
|
||||
// SMBIOS uses the smallest and sometimes also largest representable
|
||||
// signed/unsigned value to indicate `unknown' (except enumerators -
|
||||
// but those are handled in the other function overload), so skip them.
|
||||
if(field == std::numeric_limits<Field>::min() || field == std::numeric_limits<Field>::max())
|
||||
return;
|
||||
|
||||
WriteName(name);
|
||||
@ -659,7 +659,7 @@ const Structures* GetStructures()
|
||||
{
|
||||
static ModuleInitState initState;
|
||||
LibError ret = ModuleInit(&initState, InitStructures);
|
||||
if(ret != INFO::OK)
|
||||
if(ret < 0) // failed (success is either INFO::OK or INFO::SKIPPED)
|
||||
return 0;
|
||||
return &structures;
|
||||
}
|
||||
|
@ -134,6 +134,7 @@ struct Size
|
||||
Size(): value(0) {}
|
||||
Size(T value): value(value) {}
|
||||
T value;
|
||||
operator T() const { return value; }
|
||||
};
|
||||
|
||||
// SMBIOS structure handle - only displayed if meaningful
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "lib/sysdep/cpu.h"
|
||||
#include "lib/sysdep/os_cpu.h"
|
||||
#include "lib/sysdep/arch/x86_x64/topology.h"
|
||||
#include "lib/sysdep/smbios.h"
|
||||
#include "lib/tex/tex.h"
|
||||
#include "lib/file/io/io_align.h" // BLOCK_SIZE
|
||||
|
||||
@ -167,6 +168,10 @@ no_ip:
|
||||
if (!exts) exts = "{unknown}";
|
||||
fprintf(f, "\nOpenGL Extensions: \n%s\n", SplitExts(exts).c_str());
|
||||
|
||||
// System Management BIOS (even more text than OpenGL extensions)
|
||||
std::string smbios = SMBIOS::StringizeStructures(SMBIOS::GetStructures());
|
||||
fprintf(f, "\nSMBIOS: \n%s\n", smbios.c_str());
|
||||
|
||||
fclose(f);
|
||||
f = 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user