ultimatepp/uppsrc/Core/Cpu.cpp
Mirek Fidler 34ff691308 sizeof(wchar) is changed to 4 (32 bits) to support non BMP unicode characters
This might bring some incompatibilities in the code that expects wchar to be 16 bit, which
  escpecially involves dealing with Win32 (and to lesser extend MacOS) APIs, so if your application
  is doing that, please check all instances of WCHAR (UniChar on MacOS) or even wchar
  especially type casts.

  To support host APIs, char16 is introduced (but there is no 16-bit String varian).

  Use ToSystemCharsetW, FromSystemCharsetW to convert texts to Win32 API.

- Support of drawing non-BMP characters in GUI
- Vastly improved character font replacement code (when drawing characters missing with requested font, replacement font is used)
- Last instances of Win32 ANSI calls (those ending with A) are removed
- UTF handling routines are refactored and their's naming is unified
- RTF is now being able to handle non-BMP characters (RTF is used as clipboard format for RichText)

Other minor changes:

- fixed TryRealloc issue
- improved MemoryCheck
- Removed MemoryAlloc48/MemoryFree48
- In theide Background parsing should less often cause delays in the main thread
2021-12-02 12:03:19 +01:00

209 lines
4.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
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; }
#ifdef PLATFORM_POSIX
#ifdef PLATFORM_BSD
#include <sys/param.h>
#include <sys/sysctl.h>
#else
#include <sys/sysinfo.h>
#endif
#endif
int CPU_Cores()
{
static int n;
ONCELOCK {
#ifdef PLATFORM_WIN32
#ifdef CPU_64
uint64 pa, sa;
GetProcessAffinityMask(GetCurrentProcess(), &pa, &sa);
for(int i = 0; i < 64; i++)
n += !!(sa & ((uint64)1 << i));
#else
DWORD pa, sa;
GetProcessAffinityMask(GetCurrentProcess(), &pa, &sa);
for(int i = 0; i < 32; i++)
n += !!(sa & (1 << i));
#endif
#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);
n = minmax(n, 1, 256);
#elif defined(PLATFORM_SOLARIS)
n = minmax((int)sysconf(_SC_NPROCESSORS_ONLN), 1, 256);
#else
n = minmax(get_nprocs(), 1, 256);
#endif
#else
n = 1;
#endif
}
return n;
}
#else
#ifdef PLATFORM_LINUX
#ifdef PLATFORM_ANDROID
#include <cpu-features.h>
int CPU_Cores()
{
return android_getCpuCount();
}
#else
#include <sys/sysinfo.h>
int CPU_Cores()
{
return minmax(get_nprocs(), 1, 256);
}
#endif
#else
int CPU_Cores()
{
return 1;
}
#endif
#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
}