ultimatepp/uppsrc/Core/Cpu.cpp

188 lines
4 KiB
C++

#include "Core.h"
#if defined(CPU_X86) && !defined(COMPILER_MSC)
#include <cpuid.h>
#endif
#ifdef PLATFORM_FREEBSD
#include <sys/vmmeter.h>
#endif
#ifdef PLATFORM_MACOS
#include <mach/mach.h>
#include <mach/vm_statistics.h>
#endif
#ifdef PLATFORM_POSIX
#ifdef PLATFORM_BSD
#include <sys/param.h>
#include <sys/sysctl.h>
#else
#include <sys/sysinfo.h>
#endif
#endif
namespace Upp {
#ifdef CPU_X86
static bool sHasMMX;
static bool sHasSSE;
static bool sHasSSE2;
static bool sHasSSE3;
static bool sHasAVX;
static bool sHypervisor;
static void sCheckCPU()
{
static bool done;
if(done) return;
done = true;
ONCELOCK {
unsigned int eax, ebx, ecx, edx;
#ifdef COMPILER_MSC
int cpuInfo[4];
__cpuid(cpuInfo, 1);
eax = cpuInfo[0];
ebx = cpuInfo[1];
ecx = cpuInfo[2];
edx = cpuInfo[3];
#else
if(__get_cpuid(1, &eax, &ebx, &ecx, &edx))
#endif
// https://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits
{
sHasMMX = edx & (1 << 23);
sHasSSE = edx & (1 << 25);
sHasSSE2 = edx & (1 << 26);
sHasSSE3 = ecx & 1;
sHasAVX = ecx & (1 << 28);
sHypervisor = ecx & (1 << 31);
}
}
}
INITBLOCK {
// sCheckCPU();
}
bool CpuMMX() { sCheckCPU(); return sHasMMX; }
bool CpuSSE() { sCheckCPU(); return sHasSSE; }
bool CpuSSE2() { sCheckCPU(); return sHasSSE2; }
bool CpuSSE3() { sCheckCPU(); return sHasSSE3; }
bool CpuAVX() { sCheckCPU(); return sHasAVX; }
bool CpuHypervisor() { sCheckCPU(); return sHypervisor; }
#endif
#ifdef PLATFORM_ANDROID
#include <cpu-features.h>
int CPU_Cores()
{
return android_getCpuCount();
}
#else
int CPU_Cores()
{
static int n;
ONCELOCK {
#ifdef PLATFORM_WIN32
SYSTEM_INFO info;
GetSystemInfo(&info);
n = info.dwNumberOfProcessors;
#elif defined(PLATFORM_POSIX)
#ifdef PLATFORM_BSD
int mib[2];
size_t len = sizeof(n);
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
sysctl(mib, 2, &n, &len, NULL, 0);
#elif defined(PLATFORM_SOLARIS)
n = minmax((int)sysconf(_SC_NPROCESSORS_ONLN), 1, 256);
#else
n = get_nprocs();
#endif
#else
n = 1;
#endif
n = max(n, 1); // sanity
}
return n;
}
#endif
void GetSystemMemoryStatus(uint64& total, uint64& available)
{
#ifdef PLATFORM_WIN32
MEMORYSTATUSEX m;
m.dwLength = sizeof(m);
if(GlobalMemoryStatusEx(&m)) {
total = m.ullTotalPhys;
available = m.ullAvailPhys;
return;
}
#endif
#ifdef PLATFORM_LINUX
int pgsz = getpagesize();
total = sysconf(_SC_PHYS_PAGES);
available = sysconf(_SC_AVPHYS_PAGES);
if(total >= 0 && available >= 0) {
total *= pgsz;
available *= pgsz;
return;
}
#endif
#ifdef PLATFORM_MACOS
mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
vm_statistics_data_t vmstat;
int mib[2];
int64 physical_memory;
size_t length;
// Get the Physical memory size
mib[0] = CTL_HW;
mib[1] = HW_MEMSIZE;
length = sizeof(int64);
if(host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmstat, &count) == KERN_SUCCESS &&
sysctl(mib, 2, &physical_memory, &length, NULL, 0) >= 0) {
int pgsz = getpagesize();
available = (vmstat.free_count + vmstat.inactive_count) * pgsz;
// available = physical_memory - (vmstat.wire_count + vmstat.inactive_count) * pgsz;
total = physical_memory;
return;
}
#endif
#ifdef PLATFORM_FREEBSD
u_int page_size;
struct vmtotal vmt;
size_t vmt_size, uint_size;
vmt_size = sizeof(vmt);
uint_size = sizeof(page_size);
if(sysctlbyname("vm.vmtotal", &vmt, &vmt_size, NULL, 0) >= 0 &&
sysctlbyname("vm.stats.vm.v_page_size", &page_size, &uint_size, NULL, 0) >= 0) {
available = vmt.t_free * (u_int64_t)page_size;
total = vmt.t_avm * (u_int64_t)page_size;
return;
}
#endif
total = 256*1024*1024;
available = 16*1024*1024;
}
#define ENDIAN_SWAP { while(count--) { EndianSwap(*v++); } }
void EndianSwap(word *v, size_t count) ENDIAN_SWAP
void EndianSwap(int16 *v, size_t count) ENDIAN_SWAP
void EndianSwap(dword *v, size_t count) ENDIAN_SWAP
void EndianSwap(int *v, size_t count) ENDIAN_SWAP
void EndianSwap(int64 *v, size_t count) ENDIAN_SWAP
void EndianSwap(uint64 *v, size_t count) ENDIAN_SWAP
}