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:
janwas 2011-04-07 17:06:00 +00:00
parent e5e9e38532
commit 99aa427ffa
9 changed files with 95 additions and 77 deletions

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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()

View File

@ -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

View File

@ -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;
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}