|
|
//////////////////////////////////////////////////////////////////// |
|
|
// Util.cpp |
|
|
// |
|
|
// Copyright 2007 cDc@seacave |
|
|
// Distributed under the Boost Software License, Version 1.0 |
|
|
// (See http://www.boost.org/LICENSE_1_0.txt) |
|
|
|
|
|
#include "Common.h" |
|
|
#include "Util.h" |
|
|
#ifdef _MSC_VER |
|
|
#include <Shlobj.h> |
|
|
#ifndef _USE_WINSDKOS |
|
|
#define _USE_WINSDKOS |
|
|
#include <VersionHelpers.h> |
|
|
#endif |
|
|
#else |
|
|
#include <sys/utsname.h> |
|
|
#ifdef __APPLE__ |
|
|
#include <sys/sysctl.h> |
|
|
#else |
|
|
#include <sys/sysinfo.h> |
|
|
#endif |
|
|
#include <pwd.h> |
|
|
#endif |
|
|
|
|
|
using namespace SEACAVE; |
|
|
|
|
|
|
|
|
// D E F I N E S /////////////////////////////////////////////////// |
|
|
|
|
|
|
|
|
// S T R U C T S /////////////////////////////////////////////////// |
|
|
|
|
|
typedef struct CPUINFO_TYP { |
|
|
bool bSSE; // Streaming SIMD Extensions |
|
|
bool bSSE2; // Streaming SIMD Extensions 2 |
|
|
bool bSSE3; // Streaming SIMD Extensions 3 |
|
|
bool bSSE41; // Streaming SIMD Extensions 4.1 |
|
|
bool bSSE42; // Streaming SIMD Extensions 4.2 |
|
|
bool bAVX; // Advanced Vector Extensions |
|
|
bool bFMA; // Fused Multiply<EFBFBD>Add |
|
|
bool b3DNOW; // 3DNow! (vendor independent) |
|
|
bool b3DNOWEX; // 3DNow! (AMD specific extensions) |
|
|
bool bMMX; // MMX support |
|
|
bool bMMXEX; // MMX (AMD specific extensions) |
|
|
bool bEXT; // extended features available |
|
|
char vendor[13]; // vendor name |
|
|
char name[49]; // CPU name |
|
|
} CPUINFO; |
|
|
|
|
|
|
|
|
// F U N C T I O N S /////////////////////////////////////////////// |
|
|
|
|
|
Flags InitCPU(); |
|
|
CPUINFO GetCPUInfo(); |
|
|
bool OSSupportsSSE(); |
|
|
bool OSSupportsAVX(); |
|
|
|
|
|
|
|
|
// G L O B A L S /////////////////////////////////////////////////// |
|
|
|
|
|
const Flags Util::ms_CPUFNC(InitCPU()); |
|
|
|
|
|
/** |
|
|
* Lookup table (precomputed CRC64 values for each 8 bit string) computation |
|
|
* takes into account the fact that the reverse polynom has zeros in lower 8 bits: |
|
|
* |
|
|
* @code |
|
|
* for (i = 0; i < 256; i++) |
|
|
* { |
|
|
* shiftRegister = i; |
|
|
* for (j = 0; j < 8; j++) |
|
|
* { |
|
|
* if (shiftRegister & 1) |
|
|
* shiftRegister = (shiftRegister >> 1) ^ Reverse_polynom; |
|
|
* else |
|
|
* shiftRegister >>= 1; |
|
|
* } |
|
|
* CRCTable[i] = shiftRegister; |
|
|
* } |
|
|
* @endcode |
|
|
* |
|
|
* Generic code would look as follows: |
|
|
* |
|
|
* @code |
|
|
* for (i = 0; i < 256; i++) |
|
|
* { |
|
|
* shiftRegister = 0; |
|
|
* bitString = i; |
|
|
* for (j = 0; j < 8; j++) |
|
|
* { |
|
|
* if ((shiftRegister ^ (bitString >> j)) & 1) |
|
|
* shiftRegister = (shiftRegister >> 1) ^ Reverse_polynom; |
|
|
* else |
|
|
* shiftRegister >>= 1; |
|
|
* } |
|
|
* CRCTable[i] = shiftRegister; |
|
|
* } |
|
|
* @endcode |
|
|
* |
|
|
* @remark Since the lookup table elements have 0 in the lower 32 bit word, |
|
|
* the 32 bit assembler implementation of CRC64Process can be optimized, |
|
|
* avoiding at least one 'xor' operation. |
|
|
*/ |
|
|
static const uint64_t gs_au64CRC64[256] = |
|
|
{ |
|
|
0x0000000000000000ULL, 0x01B0000000000000ULL, 0x0360000000000000ULL, 0x02D0000000000000ULL, |
|
|
0x06C0000000000000ULL, 0x0770000000000000ULL, 0x05A0000000000000ULL, 0x0410000000000000ULL, |
|
|
0x0D80000000000000ULL, 0x0C30000000000000ULL, 0x0EE0000000000000ULL, 0x0F50000000000000ULL, |
|
|
0x0B40000000000000ULL, 0x0AF0000000000000ULL, 0x0820000000000000ULL, 0x0990000000000000ULL, |
|
|
0x1B00000000000000ULL, 0x1AB0000000000000ULL, 0x1860000000000000ULL, 0x19D0000000000000ULL, |
|
|
0x1DC0000000000000ULL, 0x1C70000000000000ULL, 0x1EA0000000000000ULL, 0x1F10000000000000ULL, |
|
|
0x1680000000000000ULL, 0x1730000000000000ULL, 0x15E0000000000000ULL, 0x1450000000000000ULL, |
|
|
0x1040000000000000ULL, 0x11F0000000000000ULL, 0x1320000000000000ULL, 0x1290000000000000ULL, |
|
|
0x3600000000000000ULL, 0x37B0000000000000ULL, 0x3560000000000000ULL, 0x34D0000000000000ULL, |
|
|
0x30C0000000000000ULL, 0x3170000000000000ULL, 0x33A0000000000000ULL, 0x3210000000000000ULL, |
|
|
0x3B80000000000000ULL, 0x3A30000000000000ULL, 0x38E0000000000000ULL, 0x3950000000000000ULL, |
|
|
0x3D40000000000000ULL, 0x3CF0000000000000ULL, 0x3E20000000000000ULL, 0x3F90000000000000ULL, |
|
|
0x2D00000000000000ULL, 0x2CB0000000000000ULL, 0x2E60000000000000ULL, 0x2FD0000000000000ULL, |
|
|
0x2BC0000000000000ULL, 0x2A70000000000000ULL, 0x28A0000000000000ULL, 0x2910000000000000ULL, |
|
|
0x2080000000000000ULL, 0x2130000000000000ULL, 0x23E0000000000000ULL, 0x2250000000000000ULL, |
|
|
0x2640000000000000ULL, 0x27F0000000000000ULL, 0x2520000000000000ULL, 0x2490000000000000ULL, |
|
|
0x6C00000000000000ULL, 0x6DB0000000000000ULL, 0x6F60000000000000ULL, 0x6ED0000000000000ULL, |
|
|
0x6AC0000000000000ULL, 0x6B70000000000000ULL, 0x69A0000000000000ULL, 0x6810000000000000ULL, |
|
|
0x6180000000000000ULL, 0x6030000000000000ULL, 0x62E0000000000000ULL, 0x6350000000000000ULL, |
|
|
0x6740000000000000ULL, 0x66F0000000000000ULL, 0x6420000000000000ULL, 0x6590000000000000ULL, |
|
|
0x7700000000000000ULL, 0x76B0000000000000ULL, 0x7460000000000000ULL, 0x75D0000000000000ULL, |
|
|
0x71C0000000000000ULL, 0x7070000000000000ULL, 0x72A0000000000000ULL, 0x7310000000000000ULL, |
|
|
0x7A80000000000000ULL, 0x7B30000000000000ULL, 0x79E0000000000000ULL, 0x7850000000000000ULL, |
|
|
0x7C40000000000000ULL, 0x7DF0000000000000ULL, 0x7F20000000000000ULL, 0x7E90000000000000ULL, |
|
|
0x5A00000000000000ULL, 0x5BB0000000000000ULL, 0x5960000000000000ULL, 0x58D0000000000000ULL, |
|
|
0x5CC0000000000000ULL, 0x5D70000000000000ULL, 0x5FA0000000000000ULL, 0x5E10000000000000ULL, |
|
|
0x5780000000000000ULL, 0x5630000000000000ULL, 0x54E0000000000000ULL, 0x5550000000000000ULL, |
|
|
0x5140000000000000ULL, 0x50F0000000000000ULL, 0x5220000000000000ULL, 0x5390000000000000ULL, |
|
|
0x4100000000000000ULL, 0x40B0000000000000ULL, 0x4260000000000000ULL, 0x43D0000000000000ULL, |
|
|
0x47C0000000000000ULL, 0x4670000000000000ULL, 0x44A0000000000000ULL, 0x4510000000000000ULL, |
|
|
0x4C80000000000000ULL, 0x4D30000000000000ULL, 0x4FE0000000000000ULL, 0x4E50000000000000ULL, |
|
|
0x4A40000000000000ULL, 0x4BF0000000000000ULL, 0x4920000000000000ULL, 0x4890000000000000ULL, |
|
|
0xD800000000000000ULL, 0xD9B0000000000000ULL, 0xDB60000000000000ULL, 0xDAD0000000000000ULL, |
|
|
0xDEC0000000000000ULL, 0xDF70000000000000ULL, 0xDDA0000000000000ULL, 0xDC10000000000000ULL, |
|
|
0xD580000000000000ULL, 0xD430000000000000ULL, 0xD6E0000000000000ULL, 0xD750000000000000ULL, |
|
|
0xD340000000000000ULL, 0xD2F0000000000000ULL, 0xD020000000000000ULL, 0xD190000000000000ULL, |
|
|
0xC300000000000000ULL, 0xC2B0000000000000ULL, 0xC060000000000000ULL, 0xC1D0000000000000ULL, |
|
|
0xC5C0000000000000ULL, 0xC470000000000000ULL, 0xC6A0000000000000ULL, 0xC710000000000000ULL, |
|
|
0xCE80000000000000ULL, 0xCF30000000000000ULL, 0xCDE0000000000000ULL, 0xCC50000000000000ULL, |
|
|
0xC840000000000000ULL, 0xC9F0000000000000ULL, 0xCB20000000000000ULL, 0xCA90000000000000ULL, |
|
|
0xEE00000000000000ULL, 0xEFB0000000000000ULL, 0xED60000000000000ULL, 0xECD0000000000000ULL, |
|
|
0xE8C0000000000000ULL, 0xE970000000000000ULL, 0xEBA0000000000000ULL, 0xEA10000000000000ULL, |
|
|
0xE380000000000000ULL, 0xE230000000000000ULL, 0xE0E0000000000000ULL, 0xE150000000000000ULL, |
|
|
0xE540000000000000ULL, 0xE4F0000000000000ULL, 0xE620000000000000ULL, 0xE790000000000000ULL, |
|
|
0xF500000000000000ULL, 0xF4B0000000000000ULL, 0xF660000000000000ULL, 0xF7D0000000000000ULL, |
|
|
0xF3C0000000000000ULL, 0xF270000000000000ULL, 0xF0A0000000000000ULL, 0xF110000000000000ULL, |
|
|
0xF880000000000000ULL, 0xF930000000000000ULL, 0xFBE0000000000000ULL, 0xFA50000000000000ULL, |
|
|
0xFE40000000000000ULL, 0xFFF0000000000000ULL, 0xFD20000000000000ULL, 0xFC90000000000000ULL, |
|
|
0xB400000000000000ULL, 0xB5B0000000000000ULL, 0xB760000000000000ULL, 0xB6D0000000000000ULL, |
|
|
0xB2C0000000000000ULL, 0xB370000000000000ULL, 0xB1A0000000000000ULL, 0xB010000000000000ULL, |
|
|
0xB980000000000000ULL, 0xB830000000000000ULL, 0xBAE0000000000000ULL, 0xBB50000000000000ULL, |
|
|
0xBF40000000000000ULL, 0xBEF0000000000000ULL, 0xBC20000000000000ULL, 0xBD90000000000000ULL, |
|
|
0xAF00000000000000ULL, 0xAEB0000000000000ULL, 0xAC60000000000000ULL, 0xADD0000000000000ULL, |
|
|
0xA9C0000000000000ULL, 0xA870000000000000ULL, 0xAAA0000000000000ULL, 0xAB10000000000000ULL, |
|
|
0xA280000000000000ULL, 0xA330000000000000ULL, 0xA1E0000000000000ULL, 0xA050000000000000ULL, |
|
|
0xA440000000000000ULL, 0xA5F0000000000000ULL, 0xA720000000000000ULL, 0xA690000000000000ULL, |
|
|
0x8200000000000000ULL, 0x83B0000000000000ULL, 0x8160000000000000ULL, 0x80D0000000000000ULL, |
|
|
0x84C0000000000000ULL, 0x8570000000000000ULL, 0x87A0000000000000ULL, 0x8610000000000000ULL, |
|
|
0x8F80000000000000ULL, 0x8E30000000000000ULL, 0x8CE0000000000000ULL, 0x8D50000000000000ULL, |
|
|
0x8940000000000000ULL, 0x88F0000000000000ULL, 0x8A20000000000000ULL, 0x8B90000000000000ULL, |
|
|
0x9900000000000000ULL, 0x98B0000000000000ULL, 0x9A60000000000000ULL, 0x9BD0000000000000ULL, |
|
|
0x9FC0000000000000ULL, 0x9E70000000000000ULL, 0x9CA0000000000000ULL, 0x9D10000000000000ULL, |
|
|
0x9480000000000000ULL, 0x9530000000000000ULL, 0x97E0000000000000ULL, 0x9650000000000000ULL, |
|
|
0x9240000000000000ULL, 0x93F0000000000000ULL, 0x9120000000000000ULL, 0x9090000000000000ULL |
|
|
}; |
|
|
|
|
|
|
|
|
// F U N C T I O N S /////////////////////////////////////////////// |
|
|
|
|
|
String Util::getHomeFolder() |
|
|
{ |
|
|
#ifdef _MSC_VER |
|
|
TCHAR homedir[MAX_PATH]; |
|
|
if (SHGetSpecialFolderPath(0, homedir, CSIDL_PROFILE, TRUE) != TRUE) |
|
|
return String(); |
|
|
#else |
|
|
const char *homedir; |
|
|
if ((homedir = getenv("HOME")) == NULL) |
|
|
homedir = getpwuid(getuid())->pw_dir; |
|
|
#endif // _MSC_VER |
|
|
String dir(String(homedir) + PATH_SEPARATOR); |
|
|
return ensureUnifySlash(dir); |
|
|
} |
|
|
|
|
|
String Util::getApplicationFolder() |
|
|
{ |
|
|
#ifdef _MSC_VER |
|
|
TCHAR appdir[MAX_PATH]; |
|
|
if (SHGetSpecialFolderPath(0, appdir, CSIDL_APPDATA, TRUE) != TRUE) |
|
|
return String(); |
|
|
String dir(String(appdir) + PATH_SEPARATOR); |
|
|
#else |
|
|
const char *homedir; |
|
|
if ((homedir = getenv("HOME")) == NULL) |
|
|
homedir = getpwuid(getuid())->pw_dir; |
|
|
String dir(String(homedir) + PATH_SEPARATOR + String(_T(".config")) + PATH_SEPARATOR); |
|
|
#endif // _MSC_VER |
|
|
return ensureUnifySlash(dir); |
|
|
} |
|
|
|
|
|
String Util::getCurrentFolder() |
|
|
{ |
|
|
TCHAR pathname[MAX_PATH+1]; |
|
|
#ifdef _MSC_VER |
|
|
if (!GetCurrentDirectory(MAX_PATH, pathname)) |
|
|
#else // _MSC_VER |
|
|
if (!getcwd(pathname, MAX_PATH)) |
|
|
#endif // _MSC_VER |
|
|
return String(); |
|
|
String dir(String(pathname) + PATH_SEPARATOR); |
|
|
return ensureUnifySlash(dir); |
|
|
} |
|
|
/*----------------------------------------------------------------*/ |
|
|
|
|
|
|
|
|
uint64_t Util::CRC64(const void *pv, size_t cb) |
|
|
{ |
|
|
const uint8_t* pu8 = (const uint8_t *)pv; |
|
|
uint64_t uCRC64 = 0ULL; |
|
|
while (cb--) |
|
|
uCRC64 = gs_au64CRC64[(uCRC64 ^ *pu8++) & 0xff] ^ (uCRC64 >> 8); |
|
|
return uCRC64; |
|
|
} |
|
|
|
|
|
uint64_t Util::CRC64Process(uint64_t uCRC64, const void *pv, size_t cb) |
|
|
{ |
|
|
const uint8_t *pu8 = (const uint8_t *)pv; |
|
|
while (cb--) |
|
|
uCRC64 = gs_au64CRC64[(uCRC64 ^ *pu8++) & 0xff] ^ (uCRC64 >> 8); |
|
|
return uCRC64; |
|
|
} |
|
|
/*----------------------------------------------------------------*/ |
|
|
|
|
|
|
|
|
String Util::GetCPUInfo() |
|
|
{ |
|
|
const CPUINFO info(::GetCPUInfo()); |
|
|
String cpu(info.name[0] == 0 ? info.vendor : info.name); |
|
|
#if 0 |
|
|
if (info.bFMA) |
|
|
cpu += _T(" FMA"); |
|
|
else if (info.bAVX) |
|
|
cpu += _T(" AVX"); |
|
|
else if (info.bSSE42) |
|
|
cpu += _T(" SSE4.2"); |
|
|
else if (info.bSSE41) |
|
|
cpu += _T(" SSE4.1"); |
|
|
else if (info.bSSE3) |
|
|
cpu += _T(" SSE3"); |
|
|
else if (info.bSSE2) |
|
|
cpu += _T(" SSE2"); |
|
|
else if (info.bSSE) |
|
|
cpu += _T(" SSE"); |
|
|
if (info.b3DNOWEX) |
|
|
cpu += _T(" 3DNOWEX"); |
|
|
else if (info.b3DNOW) |
|
|
cpu += _T(" 3DNOW"); |
|
|
#endif |
|
|
return cpu; |
|
|
} |
|
|
/*----------------------------------------------------------------*/ |
|
|
|
|
|
String Util::GetRAMInfo() |
|
|
{ |
|
|
#if defined(_MSC_VER) |
|
|
|
|
|
#ifdef _WIN64 |
|
|
MEMORYSTATUSEX memoryStatus; |
|
|
memset(&memoryStatus, sizeof(MEMORYSTATUSEX), 0); |
|
|
memoryStatus.dwLength = sizeof(memoryStatus); |
|
|
::GlobalMemoryStatusEx(&memoryStatus); |
|
|
const size_t nTotalPhys((size_t)memoryStatus.ullTotalPhys); |
|
|
const size_t nTotalVirtual((size_t)memoryStatus.ullTotalVirtual); |
|
|
#else |
|
|
MEMORYSTATUS memoryStatus; |
|
|
memset(&memoryStatus, sizeof(MEMORYSTATUS), 0); |
|
|
memoryStatus.dwLength = sizeof(MEMORYSTATUS); |
|
|
::GlobalMemoryStatus(&memoryStatus); |
|
|
const size_t nTotalPhys((size_t)memoryStatus.dwTotalPhys); |
|
|
const size_t nTotalVirtual((size_t)memoryStatus.dwTotalVirtual); |
|
|
#endif |
|
|
|
|
|
#elif defined(__APPLE__) |
|
|
|
|
|
int mib[2] = {CTL_HW, HW_MEMSIZE}; |
|
|
const unsigned namelen = sizeof(mib) / sizeof(mib[0]); |
|
|
size_t len = sizeof(size_t); |
|
|
size_t nTotalPhys; |
|
|
sysctl(mib, namelen, &nTotalPhys, &len, NULL, 0); |
|
|
const size_t nTotalVirtual(nTotalPhys); |
|
|
|
|
|
#else // __GNUC__ |
|
|
|
|
|
struct sysinfo info; |
|
|
sysinfo(&info); |
|
|
const size_t nTotalPhys((size_t)info.totalram); |
|
|
const size_t nTotalVirtual((size_t)info.totalswap); |
|
|
|
|
|
#endif // _MSC_VER |
|
|
return formatBytes(nTotalPhys) + _T(" Physical Memory ") + formatBytes(nTotalVirtual) + _T(" Virtual Memory"); |
|
|
} |
|
|
/*----------------------------------------------------------------*/ |
|
|
|
|
|
String Util::GetOSInfo() |
|
|
{ |
|
|
#ifdef _MSC_VER |
|
|
|
|
|
String os; |
|
|
#ifdef _USE_WINSDKOS |
|
|
#ifndef _WIN32_WINNT_WIN10 |
|
|
#define _WIN32_WINNT_WIN10 0x0A00 |
|
|
if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN10), LOBYTE(_WIN32_WINNT_WIN10), 0)) |
|
|
#else |
|
|
if (IsWindows10OrGreater()) |
|
|
#endif |
|
|
os = _T("Windows 10+"); |
|
|
else if (IsWindows8Point1OrGreater()) |
|
|
os = _T("Windows 8.1"); |
|
|
else if (IsWindows8OrGreater()) |
|
|
os = _T("Windows 8"); |
|
|
else if (IsWindows7SP1OrGreater()) |
|
|
os = _T("Windows 7 (SP1)"); |
|
|
else if (IsWindows7OrGreater()) |
|
|
os = _T("Windows 7"); |
|
|
else if (IsWindowsVistaSP2OrGreater()) |
|
|
os = _T("Windows Vista (SP2)"); |
|
|
else if (IsWindowsVistaSP1OrGreater()) |
|
|
os = _T("Windows Vista (SP1)"); |
|
|
else if (IsWindowsVistaOrGreater()) |
|
|
os = _T("Windows Vista"); |
|
|
else if (IsWindowsXPSP3OrGreater()) |
|
|
os = _T("Windows XP (SP3)"); |
|
|
else if (IsWindowsXPSP2OrGreater()) |
|
|
os = _T("Windows XP (SP2)"); |
|
|
else if (IsWindowsXPSP1OrGreater()) |
|
|
os = _T("Windows XP (SP1)"); |
|
|
else if (IsWindowsXPOrGreater()) |
|
|
os = _T("Windows XP"); |
|
|
else |
|
|
os = _T("Windows (unknown version)"); |
|
|
#else |
|
|
OSVERSIONINFOEX ver; |
|
|
memset(&ver, 0, sizeof(OSVERSIONINFOEX)); |
|
|
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); |
|
|
|
|
|
if (!GetVersionEx((OSVERSIONINFO*)&ver)) { |
|
|
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); |
|
|
if (!GetVersionEx((OSVERSIONINFO*)&ver)) { |
|
|
return "Windows (unknown version)"; |
|
|
} |
|
|
} |
|
|
|
|
|
if (ver.dwPlatformId != VER_PLATFORM_WIN32_NT) { |
|
|
os = "Win9x/ME"; |
|
|
} else { |
|
|
switch (ver.dwMajorVersion) |
|
|
{ |
|
|
case 4: |
|
|
os = "WinNT4"; |
|
|
break; |
|
|
|
|
|
case 5: |
|
|
switch (ver.dwMinorVersion) |
|
|
{ |
|
|
case 0: os = "Win2000"; break; |
|
|
case 1: os = "WinXP"; break; |
|
|
case 2: os = "Win2003"; break; |
|
|
default:os = "Unknown WinNT5"; |
|
|
} |
|
|
break; |
|
|
|
|
|
case 6: |
|
|
switch (ver.dwMinorVersion) |
|
|
{ |
|
|
case 0: os = (ver.wProductType == VER_NT_WORKSTATION ? "WinVista" : "Win2008"); break; |
|
|
case 1: os = (ver.wProductType == VER_NT_WORKSTATION ? "Win7" : "Win2008R2"); break; |
|
|
case 2: os = (ver.wProductType == VER_NT_WORKSTATION ? "Win8" : "Win2012"); break; |
|
|
case 3: os = (ver.wProductType == VER_NT_WORKSTATION ? "Win8.1" : "Win2012R2"); break; |
|
|
case 4: os = "Win10"; break; |
|
|
default:os = "Unknown WinNT6"; |
|
|
} |
|
|
break; |
|
|
|
|
|
default: |
|
|
os = "Windows (version unknown)"; |
|
|
} |
|
|
if (ver.wProductType & VER_NT_WORKSTATION) |
|
|
os += " Pro"; |
|
|
else if (ver.wProductType & VER_NT_SERVER) |
|
|
os += " Server"; |
|
|
else if (ver.wProductType & VER_NT_DOMAIN_CONTROLLER) |
|
|
os += " DC"; |
|
|
} |
|
|
|
|
|
if (ver.wServicePackMajor != 0) { |
|
|
os += " (SP"; |
|
|
os += String::ToString(ver.wServicePackMajor); |
|
|
if (ver.wServicePackMinor != 0) { |
|
|
os += '.'; |
|
|
os += String::ToString(ver.wServicePackMinor); |
|
|
} |
|
|
os += ")"; |
|
|
} |
|
|
#endif |
|
|
|
|
|
#ifdef _WIN64 |
|
|
os += " x64"; |
|
|
#else |
|
|
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); |
|
|
const LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"),"IsWow64Process"); |
|
|
BOOL bIsWow64 = FALSE; |
|
|
if (fnIsWow64Process && fnIsWow64Process(GetCurrentProcess(),&bIsWow64) && bIsWow64) |
|
|
os += " x64"; |
|
|
#endif |
|
|
|
|
|
return os; |
|
|
|
|
|
#else // _MSC_VER |
|
|
|
|
|
utsname n; |
|
|
if (uname(&n) != 0) |
|
|
return "linux (unknown version)"; |
|
|
return String(n.sysname) + " " + String(n.release) + " (" + String(n.machine) + ")"; |
|
|
|
|
|
#endif // _MSC_VER |
|
|
} |
|
|
/*----------------------------------------------------------------*/ |
|
|
|
|
|
String Util::GetDiskInfo(const String& path) |
|
|
{ |
|
|
#if defined(_SUPPORT_CPP17) && (!defined(__GNUC__) || (__GNUC__ > 7)) |
|
|
|
|
|
const std::filesystem::space_info si = std::filesystem::space(path.c_str()); |
|
|
return String::FormatString("%s (%s) space", formatBytes(si.available).c_str(), formatBytes(si.capacity).c_str()); |
|
|
|
|
|
#else |
|
|
|
|
|
return String(); |
|
|
|
|
|
#endif // _SUPPORT_CPP17 |
|
|
} |
|
|
/*----------------------------------------------------------------*/ |
|
|
|
|
|
|
|
|
// Initialize various global variables (ex: random-number-generator state). |
|
|
void Util::Init() |
|
|
{ |
|
|
#ifdef _RELEASE |
|
|
const time_t t(Util::getTime()); |
|
|
std::srand((unsigned)t); |
|
|
#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_MINOR_VERSION >= 4) |
|
|
cv::setRNGSeed((int)t); |
|
|
#endif |
|
|
#else |
|
|
std::srand((unsigned)0); |
|
|
#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_MINOR_VERSION >= 4) |
|
|
cv::setRNGSeed((int)0); |
|
|
#endif |
|
|
#endif |
|
|
} |
|
|
/*----------------------------------------------------------------*/ |
|
|
|
|
|
|
|
|
/** |
|
|
* Set global variable for availability of SSE instructions. |
|
|
*/ |
|
|
Flags InitCPU() |
|
|
{ |
|
|
const CPUINFO info(GetCPUInfo()); |
|
|
Flags cpufncs(0); |
|
|
if (info.bSSE) { |
|
|
#if defined(_MSC_VER) && !defined(_WIN64) |
|
|
_set_SSE2_enable(1); |
|
|
#endif |
|
|
if (OSSupportsSSE()) |
|
|
cpufncs.set(Util::SSE); |
|
|
} |
|
|
if (info.bAVX && OSSupportsAVX()) |
|
|
cpufncs.set(Util::AVX); |
|
|
return (cpufncs); |
|
|
} |
|
|
/*----------------------------------------------------------------*/ |
|
|
|
|
|
|
|
|
#if _PLATFORM_X86 |
|
|
#ifdef _MSC_VER |
|
|
#include <intrin.h> |
|
|
inline void CPUID(int CPUInfo[4], int level) { |
|
|
__cpuid(CPUInfo, level); |
|
|
} |
|
|
#else |
|
|
#include <cpuid.h> |
|
|
inline void CPUID(int CPUInfo[4], int level) { |
|
|
unsigned* p((unsigned*)CPUInfo); |
|
|
__get_cpuid((unsigned&)level, p+0, p+1, p+2, p+3); |
|
|
} |
|
|
#endif |
|
|
#else // _PLATFORM_X86 |
|
|
inline void CPUID(int CPUInfo[4], int level) { |
|
|
memset(CPUInfo, 0, sizeof(int)*4); |
|
|
} |
|
|
#endif // _PLATFORM_X86 |
|
|
|
|
|
/** |
|
|
* Function to detect SSE availability in CPU. |
|
|
*/ |
|
|
CPUINFO GetCPUInfo() |
|
|
{ |
|
|
CPUINFO info; |
|
|
|
|
|
// set all values to 0 (false) |
|
|
memset(&info, 0, sizeof(CPUINFO)); |
|
|
|
|
|
int CPUInfo[4]; |
|
|
|
|
|
// CPUID with an InfoType argument of 0 returns the number of |
|
|
// valid Ids in CPUInfo[0] and the CPU identification string in |
|
|
// the other three array elements. The CPU identification string is |
|
|
// not in linear order. The code below arranges the information |
|
|
// in a human readable form. |
|
|
CPUID(CPUInfo, 0); |
|
|
*((int*)info.vendor) = CPUInfo[1]; |
|
|
*((int*)(info.vendor+4)) = CPUInfo[3]; |
|
|
*((int*)(info.vendor+8)) = CPUInfo[2]; |
|
|
|
|
|
// Interpret CPU feature information. |
|
|
CPUID(CPUInfo, 1); |
|
|
info.bMMX = (CPUInfo[3] & 0x800000) != 0; // test bit 23 for MMX |
|
|
info.bSSE = (CPUInfo[3] & 0x2000000) != 0; // test bit 25 for SSE |
|
|
info.bSSE2 = (CPUInfo[3] & 0x4000000) != 0; // test bit 26 for SSE2 |
|
|
info.bSSE3 = (CPUInfo[2] & 0x1) != 0; // test bit 0 for SSE3 |
|
|
info.bSSE41 = (CPUInfo[2] & 0x80000) != 0; // test bit 19 for SSE4.1 |
|
|
info.bSSE42 = (CPUInfo[2] & 0x100000) != 0; // test bit 20 for SSE4.2 |
|
|
info.bAVX = (CPUInfo[2] & 0x18000000) == 0x18000000; // test bits 28,27 for AVX |
|
|
info.bFMA = (CPUInfo[2] & 0x18001000) == 0x18001000; // test bits 28,27,12 for FMA |
|
|
|
|
|
// EAX=0x80000000 => CPUID returns extended features |
|
|
CPUID(CPUInfo, 0x80000000); |
|
|
const unsigned nExIds = CPUInfo[0]; |
|
|
info.bEXT = (nExIds >= 0x80000000); |
|
|
|
|
|
// must be greater than 0x80000004 to support CPU name |
|
|
if (nExIds > 0x80000004) { |
|
|
size_t idx(0); |
|
|
CPUID(CPUInfo, 0x80000002); // CPUID returns CPU name part1 |
|
|
while (((uint8_t*)CPUInfo)[idx] == ' ') |
|
|
++idx; |
|
|
memcpy(info.name, (uint8_t*)CPUInfo + idx, sizeof(CPUInfo) - idx); |
|
|
idx = sizeof(CPUInfo) - idx; |
|
|
|
|
|
CPUID(CPUInfo, 0x80000003); // CPUID returns CPU name part2 |
|
|
memcpy(info.name+idx, CPUInfo, sizeof(CPUInfo)); |
|
|
idx += 16; |
|
|
|
|
|
CPUID(CPUInfo, 0x80000004); // CPUID returns CPU name part3 |
|
|
memcpy(info.name+idx, CPUInfo, sizeof(CPUInfo)); |
|
|
} |
|
|
|
|
|
if ((strncmp(info.vendor, "AuthenticAMD", 12)==0) && info.bEXT) { // AMD |
|
|
CPUID(CPUInfo, 0x80000001); // CPUID will copy ext. feat. bits to EDX and cpu type to EAX |
|
|
info.b3DNOWEX = (CPUInfo[3] & 0x40000000) != 0; // indicates AMD extended 3DNow+! |
|
|
info.bMMXEX = (CPUInfo[3] & 0x400000) != 0; // indicates AMD extended MMX |
|
|
} |
|
|
|
|
|
return info; |
|
|
} |
|
|
/*----------------------------------------------------------------*/ |
|
|
|
|
|
#if _PLATFORM_X86 |
|
|
#ifdef _MSC_VER |
|
|
// Function to detect SSE availability in operating system. |
|
|
bool OSSupportsSSE() |
|
|
{ |
|
|
#ifndef _WIN64 |
|
|
// try SSE instruction and look for crash |
|
|
__try |
|
|
{ |
|
|
_asm xorps xmm0, xmm0 |
|
|
} |
|
|
__except(EXCEPTION_EXECUTE_HANDLER) { |
|
|
if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION) |
|
|
return false; // sse not supported by os |
|
|
return false; // unknown exception occurred |
|
|
} |
|
|
#endif // _WIN64 |
|
|
|
|
|
return true; |
|
|
} |
|
|
// Function to detect AVX availability in operating system. |
|
|
bool OSSupportsAVX() |
|
|
{ |
|
|
#ifndef _WIN64 |
|
|
// try AVX instruction |
|
|
unsigned flag; |
|
|
_asm { |
|
|
mov ecx, 0; //specify 0 for XFEATURE_ENABLED_MASK register |
|
|
XGETBV; //result in EDX:EAX |
|
|
and eax, 06H; |
|
|
cmp eax, 06H; // check OS has enabled both XMM and YMM state support |
|
|
jne not_supported |
|
|
mov eax, 1; // mark as supported |
|
|
jmp done |
|
|
not_supported: |
|
|
mov eax, 0; // mark as not supported |
|
|
done: |
|
|
mov esi, flag |
|
|
mov [esi], eax |
|
|
} |
|
|
return flag != 0; |
|
|
#else |
|
|
// check if the OS will save the YMM registers |
|
|
unsigned long long xcrFeatureMask(_xgetbv(_XCR_XFEATURE_ENABLED_MASK)); |
|
|
return (xcrFeatureMask & 0x6) == 0x6; |
|
|
#endif // _WIN64 |
|
|
} |
|
|
/*----------------------------------------------------------------*/ |
|
|
|
|
|
#else // _MSC_VER |
|
|
|
|
|
// Function to detect SSE availability in operating system. |
|
|
bool OSSupportsSSE() |
|
|
{ |
|
|
// try SSE instruction and look for crash |
|
|
try { |
|
|
asm("xorps %xmm0, %xmm0"); |
|
|
} |
|
|
catch(int e) { |
|
|
return false; // unknown exception occurred |
|
|
} |
|
|
return true; |
|
|
} |
|
|
// Function to detect AVX availability in operating system. |
|
|
bool OSSupportsAVX() |
|
|
{ |
|
|
// check if the OS will save the YMM registers |
|
|
unsigned int index(0); //specify 0 for XFEATURE_ENABLED_MASK register |
|
|
unsigned int eax, edx; |
|
|
__asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); |
|
|
unsigned long long xcrFeatureMask(((unsigned long long)edx << 32) | eax); |
|
|
return (xcrFeatureMask & 0x6) == 0x6; |
|
|
} |
|
|
/*----------------------------------------------------------------*/ |
|
|
#endif // _MSC_VER |
|
|
|
|
|
#else // _PLATFORM_X86 |
|
|
|
|
|
// Function to detect SSE availability in operating system. |
|
|
bool OSSupportsSSE() |
|
|
{ |
|
|
return false; |
|
|
} |
|
|
// Function to detect AVX availability in operating system. |
|
|
bool OSSupportsAVX() |
|
|
{ |
|
|
return false; |
|
|
} |
|
|
/*----------------------------------------------------------------*/ |
|
|
#endif // _PLATFORM_X86 |
|
|
|
|
|
|
|
|
// print details about the current build and PC |
|
|
void Util::LogBuild() |
|
|
{ |
|
|
LOG(_T("OpenMVS %s v%u.%u.%u"), |
|
|
#ifdef _ENVIRONMENT64 |
|
|
_T("x64"), |
|
|
#else |
|
|
_T("x32"), |
|
|
#endif |
|
|
OpenMVS_MAJOR_VERSION, OpenMVS_MINOR_VERSION, OpenMVS_PATCH_VERSION); |
|
|
#if TD_VERBOSE == TD_VERBOSE_OFF |
|
|
LOG(_T("Build date: ") __DATE__); |
|
|
#else |
|
|
LOG(_T("Build date: ") __DATE__ _T(", ") __TIME__); |
|
|
#endif |
|
|
LOG(_T("CPU: %s (%u cores)"), Util::GetCPUInfo().c_str(), Thread::hardwareConcurrency()); |
|
|
LOG((_T("RAM: ") + Util::GetRAMInfo()).c_str()); |
|
|
LOG((_T("OS: ") + Util::GetOSInfo()).c_str()); |
|
|
#ifdef _SUPPORT_CPP17 |
|
|
LOG((_T("Disk: ") + Util::GetDiskInfo(WORKING_FOLDER_FULL)).c_str()); |
|
|
#endif |
|
|
if (!SIMD_ENABLED.isSet(Util::SSE)) LOG(_T("warning: no SSE compatible CPU or OS detected")); |
|
|
else if (!SIMD_ENABLED.isSet(Util::AVX)) LOG(_T("warning: no AVX compatible CPU or OS detected")); |
|
|
else LOG(_T("SSE & AVX compatible CPU & OS detected")); |
|
|
} |
|
|
|
|
|
// print information about the memory usage |
|
|
#if _PLATFORM_X86 |
|
|
#ifdef _MSC_VER |
|
|
#include <Psapi.h> |
|
|
#pragma comment(lib, "Psapi.lib") |
|
|
void Util::LogMemoryInfo() |
|
|
{ |
|
|
PROCESS_MEMORY_COUNTERS pmc; |
|
|
if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) |
|
|
return; |
|
|
LOG(_T("MEMORYINFO: {")); |
|
|
LOG(_T("\tPageFaultCount %d"), pmc.PageFaultCount); |
|
|
LOG(_T("\tPeakWorkingSetSize %s"), SEACAVE::Util::formatBytes(pmc.PeakWorkingSetSize).c_str()); |
|
|
LOG(_T("\tWorkingSetSize %s"), SEACAVE::Util::formatBytes(pmc.WorkingSetSize).c_str()); |
|
|
LOG(_T("\tQuotaPeakPagedPoolUsage %s"), SEACAVE::Util::formatBytes(pmc.QuotaPeakPagedPoolUsage).c_str()); |
|
|
LOG(_T("\tQuotaPagedPoolUsage %s"), SEACAVE::Util::formatBytes(pmc.QuotaPagedPoolUsage).c_str()); |
|
|
LOG(_T("\tQuotaPeakNonPagedPoolUsage %s"), SEACAVE::Util::formatBytes(pmc.QuotaPeakNonPagedPoolUsage).c_str()); |
|
|
LOG(_T("\tQuotaNonPagedPoolUsage %s"), SEACAVE::Util::formatBytes(pmc.QuotaNonPagedPoolUsage).c_str()); |
|
|
LOG(_T("\tPagefileUsage %s"), SEACAVE::Util::formatBytes(pmc.PagefileUsage).c_str()); |
|
|
LOG(_T("\tPeakPagefileUsage %s"), SEACAVE::Util::formatBytes(pmc.PeakPagefileUsage).c_str()); |
|
|
LOG(_T("} ENDINFO")); |
|
|
} |
|
|
#else // _MSC_VER |
|
|
void Util::LogMemoryInfo() |
|
|
{ |
|
|
std::ifstream proc("/proc/self/status"); |
|
|
if (!proc.is_open()) |
|
|
return; |
|
|
String s; |
|
|
LOG(_T("MEMORYINFO: {")); |
|
|
while (std::getline(proc, s), !proc.fail()) { |
|
|
if (s.substr(0, 6) == "VmPeak" || s.substr(0, 6) == "VmSize") |
|
|
LOG(_T("\t%s"), s.c_str()); |
|
|
} |
|
|
LOG(_T("} ENDINFO")); |
|
|
} |
|
|
#endif // _MSC_VER |
|
|
#else // _PLATFORM_X86 |
|
|
void Util::LogMemoryInfo() |
|
|
{ |
|
|
} |
|
|
#endif // _PLATFORM_X86 |
|
|
|
|
|
|
|
|
// Parses a ASCII command line string and returns an array of pointers to the command line arguments, |
|
|
// along with a count of such arguments, in a way that is similar to the standard C run-time |
|
|
// argv and argc values. |
|
|
LPSTR* Util::CommandLineToArgvA(LPCSTR CmdLine, size_t& _argc) |
|
|
{ |
|
|
bool in_QM(false); |
|
|
bool in_TEXT(false); |
|
|
bool in_SPACE(true); |
|
|
|
|
|
size_t argc(0); |
|
|
size_t len = strlen(CmdLine); |
|
|
size_t i = ((len+2)/2)*sizeof(void*) + sizeof(void*); |
|
|
LPSTR* argv = (LPSTR*)(new uint8_t[i + (len+2)*sizeof(CHAR)]); |
|
|
LPSTR _argv = (LPSTR)(((CHAR*)argv)+i); |
|
|
argv[argc] = _argv; |
|
|
size_t j(0); i = 0; |
|
|
|
|
|
CHAR a; |
|
|
while ((a = CmdLine[i]) != 0) { |
|
|
if (in_QM) { |
|
|
if (a == '\"') { |
|
|
in_QM = false; |
|
|
} else { |
|
|
_argv[j] = a; |
|
|
j++; |
|
|
} |
|
|
} else { |
|
|
switch (a) { |
|
|
case '\"': |
|
|
in_QM = true; |
|
|
in_TEXT = true; |
|
|
if (in_SPACE) { |
|
|
argv[argc] = _argv+j; |
|
|
argc++; |
|
|
} |
|
|
in_SPACE = false; |
|
|
break; |
|
|
case ' ': |
|
|
case '\t': |
|
|
case '\n': |
|
|
case '\r': |
|
|
if (in_TEXT) { |
|
|
_argv[j] = '\0'; |
|
|
j++; |
|
|
} |
|
|
in_TEXT = false; |
|
|
in_SPACE = true; |
|
|
break; |
|
|
default: |
|
|
in_TEXT = true; |
|
|
if (in_SPACE) { |
|
|
argv[argc] = _argv+j; |
|
|
argc++; |
|
|
} |
|
|
_argv[j] = a; |
|
|
j++; |
|
|
in_SPACE = false; |
|
|
break; |
|
|
} |
|
|
} |
|
|
i++; |
|
|
} |
|
|
_argv[j] = '\0'; |
|
|
argv[argc] = NULL; |
|
|
|
|
|
_argc = argc; |
|
|
return argv; |
|
|
} |
|
|
/*----------------------------------------------------------------*/
|
|
|
|