diff --git a/source/lib/sysdep/os/linux/lcpu.cpp b/source/lib/sysdep/os/linux/lcpu.cpp index eb6655ce41..f4af9e3c46 100644 --- a/source/lib/sysdep/os/linux/lcpu.cpp +++ b/source/lib/sysdep/os/linux/lcpu.cpp @@ -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); } diff --git a/source/lib/sysdep/os/osx/ocpu.cpp b/source/lib/sysdep/os/osx/ocpu.cpp index 80f11b3267..a8cb43c40a 100644 --- a/source/lib/sysdep/os/osx/ocpu.cpp +++ b/source/lib/sysdep/os/osx/ocpu.cpp @@ -27,13 +27,6 @@ #include - -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; } diff --git a/source/lib/sysdep/os/win/wcpu.cpp b/source/lib/sysdep/os/win/wcpu.cpp index 4f78ecd4e8..2c4770900c 100644 --- a/source/lib/sysdep/os/win/wcpu.cpp +++ b/source/lib/sysdep/os/win/wcpu.cpp @@ -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() diff --git a/source/lib/sysdep/os/win/wcpu.h b/source/lib/sysdep/os/win/wcpu.h index 7f8fba6a67..c6e717a8b7 100644 --- a/source/lib/sysdep/os/win/wcpu.h +++ b/source/lib/sysdep/os/win/wcpu.h @@ -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 diff --git a/source/lib/sysdep/os_cpu.cpp b/source/lib/sysdep/os_cpu.cpp index 99816da26d..00f4fa318d 100644 --- a/source/lib/sysdep/os_cpu.cpp +++ b/source/lib/sysdep/os_cpu.cpp @@ -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; +} diff --git a/source/lib/sysdep/os_cpu.h b/source/lib/sysdep/os_cpu.h index b25a1b70f6..a724987a10 100644 --- a/source/lib/sysdep/os_cpu.h +++ b/source/lib/sysdep/os_cpu.h @@ -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(); diff --git a/source/lib/sysdep/smbios.cpp b/source/lib/sysdep/smbios.cpp index c03f920abe..aaa7755327 100644 --- a/source/lib/sysdep/smbios.cpp +++ b/source/lib/sysdep/smbios.cpp @@ -577,10 +577,10 @@ private: template 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::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::min() || field == std::numeric_limits::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; } diff --git a/source/lib/sysdep/smbios.h b/source/lib/sysdep/smbios.h index d850f07d34..f4769b4b6f 100644 --- a/source/lib/sysdep/smbios.h +++ b/source/lib/sysdep/smbios.h @@ -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 diff --git a/source/ps/Util.cpp b/source/ps/Util.cpp index fd4fc5470b..e52df583ca 100644 --- a/source/ps/Util.cpp +++ b/source/ps/Util.cpp @@ -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; }