You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1623 lines
45 KiB
C++
1623 lines
45 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
#include "CrySystem_precompiled.h"
|
|
#include "System.h"
|
|
#include "AutoDetectSpec.h"
|
|
|
|
|
|
#if defined(AZ_RESTRICTED_PLATFORM)
|
|
#undef AZ_RESTRICTED_SECTION
|
|
#define CPUDETECT_CPP_SECTION_1 1
|
|
#define CPUDETECT_CPP_SECTION_2 2
|
|
#endif
|
|
|
|
#if defined(WIN32)
|
|
#include <intrin.h>
|
|
#elif defined(LINUX) || defined(APPLE)
|
|
#include <sys/resource.h> // setrlimit, getrlimit
|
|
#endif
|
|
|
|
#if defined(APPLE)
|
|
#include <mach/mach.h>
|
|
#include <mach/mach_init.h> // mach_thread_self
|
|
#include <mach/thread_policy.h> // Mac OS Thread affinity API
|
|
#include <sys/sysctl.h>
|
|
#endif
|
|
|
|
#if defined(LINUX)
|
|
#ifndef __GNU_SOURCE
|
|
#define __GNU_SOURCE
|
|
#endif
|
|
#include <pthread.h> //already includes sched.h
|
|
#endif
|
|
|
|
/* features */
|
|
#define FPU_FLAG 0x0001
|
|
#define SERIAL_FLAG 0x40000
|
|
#define MMX_FLAG 0x800000
|
|
#define ISSE_FLAG 0x2000000
|
|
|
|
#ifdef __GNUC__
|
|
# define cpuid(op, eax, ebx, ecx, edx) __asm__("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (op) : "cc");
|
|
#endif
|
|
|
|
int g_CpuFlags;
|
|
|
|
struct SAutoMaxPriority
|
|
{
|
|
SAutoMaxPriority()
|
|
{
|
|
/* get a copy of the current thread and process priorities */
|
|
#if defined(WIN32)
|
|
priority_class = GetPriorityClass(GetCurrentProcess());
|
|
thread_priority = GetThreadPriority(GetCurrentThread());
|
|
#elif defined(LINUX) || defined(APPLE)
|
|
nice_priority = getpriority(PRIO_PROCESS, 0);
|
|
success = nice_priority >= 0 &&
|
|
pthread_getschedparam(pthread_self(), &thread_policy, &thread_sched_param) == 0;
|
|
#endif
|
|
|
|
/* make this thread the highest possible priority */
|
|
#if defined(WIN32)
|
|
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
|
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
|
|
#elif defined(LINUX) || defined(APPLE)
|
|
if (success)
|
|
{
|
|
setpriority(PRIO_PROCESS, 0, MAX_NICE_PRIORITY);
|
|
|
|
sched_param new_sched_param = thread_sched_param;
|
|
new_sched_param.sched_priority = sched_get_priority_max(thread_policy);
|
|
pthread_setschedparam(pthread_self(), thread_policy, &new_sched_param);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
~SAutoMaxPriority()
|
|
{
|
|
/* restore the thread priority */
|
|
#if defined(WIN32)
|
|
SetPriorityClass(GetCurrentProcess(), priority_class);
|
|
SetThreadPriority(GetCurrentThread(), thread_priority);
|
|
#elif defined(LINUX) || defined(APPLE)
|
|
if (success)
|
|
{
|
|
pthread_setschedparam(pthread_self(), thread_policy, &thread_sched_param);
|
|
setpriority(PRIO_PROCESS, 0, nice_priority);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if defined(WIN32)
|
|
uint32 priority_class;
|
|
int thread_priority;
|
|
#elif defined(LINUX) || defined(APPLE)
|
|
rlimit nice_limit;
|
|
int nice_priority;
|
|
int thread_policy;
|
|
sched_param thread_sched_param;
|
|
bool success;
|
|
enum
|
|
{
|
|
MAX_NICE_PRIORITY = 40
|
|
};
|
|
#endif
|
|
};
|
|
|
|
#if AZ_LEGACY_CRYSYSTEM_TRAIT_ASM_VOLATILE_CPUID
|
|
static inline void __cpuid(int CPUInfo[4], int InfoType)
|
|
{
|
|
asm volatile("cpuid" : "=a" (*CPUInfo), "=b" (*(CPUInfo + 1)), "=c" (*(CPUInfo + 2)), "=d" (*(CPUInfo + 3)) : "a" (InfoType));
|
|
}
|
|
#endif
|
|
|
|
bool IsAMD()
|
|
{
|
|
// Broken out for validation support.
|
|
#if defined(WIN32) || (defined(LINUX) && !defined(ANDROID)) || defined(MAC)
|
|
#define AZ_SUPPORTS_AMD
|
|
#elif defined(AZ_RESTRICTED_PLATFORM)
|
|
#define AZ_RESTRICTED_SECTION CPUDETECT_CPP_SECTION_1
|
|
#include AZ_RESTRICTED_FILE(CPUDetect_cpp)
|
|
#endif
|
|
|
|
#if defined(AZ_SUPPORTS_AMD)
|
|
int CPUInfo[4];
|
|
__cpuid(CPUInfo, 0x00000000);
|
|
|
|
char szCPU[13];
|
|
memset(szCPU, 0, sizeof(szCPU));
|
|
*(int*)&szCPU[0] = CPUInfo[1];
|
|
*(int*)&szCPU[4] = CPUInfo[3];
|
|
*(int*)&szCPU[8] = CPUInfo[2];
|
|
|
|
return (strcmp(szCPU, "AuthenticAMD") == 0);
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool IsIntel()
|
|
{
|
|
#if defined(WIN32) || (defined(LINUX) && !defined(ANDROID)) || defined(MAC)
|
|
int CPUInfo[4];
|
|
__cpuid(CPUInfo, 0x00000000);
|
|
|
|
char szCPU[13];
|
|
memset(szCPU, 0, sizeof(szCPU));
|
|
*(int*)&szCPU[0] = CPUInfo[1];
|
|
*(int*)&szCPU[4] = CPUInfo[3];
|
|
*(int*)&szCPU[8] = CPUInfo[2];
|
|
|
|
return (strcmp(szCPU, "GenuineIntel") == 0);
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool Has64bitExtension()
|
|
{
|
|
#if AZ_LEGACY_CRYSYSTEM_TRAIT_HAS64BITEXT
|
|
int CPUInfo[4];
|
|
__cpuid(CPUInfo, 0x80000001); // Argument "Processor Signature and AMD Features"
|
|
if (CPUInfo[3] & 0x20000000) // Bit 29 in edx is set if 64-bit address extension is supported
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
#elif defined(WIN64) || defined(LINUX64) || defined(MAC)
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool HTSupported()
|
|
{
|
|
#if AZ_LEGACY_CRYSYSTEM_TRAIT_HTSUPPORTED
|
|
int CPUInfo[4];
|
|
__cpuid(CPUInfo, 0x00000001);
|
|
if (CPUInfo[3] & 0x10000000) // Bit 28 in edx is set if HT is supported
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
uint8 LogicalProcPerPhysicalProc()
|
|
{
|
|
#if AZ_LEGACY_CRYSYSTEM_TRAIT_HASCPUID
|
|
int CPUInfo[4];
|
|
__cpuid(CPUInfo, 0x00000001);
|
|
// Bits 16-23 in ebx contain the number of logical processors per physical processor when execute cpuid with eax set to 1
|
|
return (uint8) ((CPUInfo[1] & 0x00FF0000) >> 16);
|
|
#else
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
uint8 GetAPIC_ID()
|
|
{
|
|
#if AZ_LEGACY_CRYSYSTEM_TRAIT_HASCPUID
|
|
int CPUInfo[4];
|
|
__cpuid(CPUInfo, 0x00000001);
|
|
// Bits 24-31 in ebx contain the unique initial APIC ID for the processor this code is running on. Default value = 0xff if HT is not supported.
|
|
return (uint8) ((CPUInfo[1] & 0xFF000000) >> 24);
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
void GetCPUName(char* pName)
|
|
{
|
|
#if AZ_LEGACY_CRYSYSTEM_TRAIT_HASCPUID
|
|
if (pName)
|
|
{
|
|
int CPUInfo[4];
|
|
__cpuid(CPUInfo, 0x80000000);
|
|
if (CPUInfo[0] >= 0x80000004)
|
|
{
|
|
__cpuid(CPUInfo, 0x80000002);
|
|
((int*)pName)[0] = CPUInfo[0];
|
|
((int*)pName)[1] = CPUInfo[1];
|
|
((int*)pName)[2] = CPUInfo[2];
|
|
((int*)pName)[3] = CPUInfo[3];
|
|
|
|
__cpuid(CPUInfo, 0x80000003);
|
|
((int*)pName)[4] = CPUInfo[0];
|
|
((int*)pName)[5] = CPUInfo[1];
|
|
((int*)pName)[6] = CPUInfo[2];
|
|
((int*)pName)[7] = CPUInfo[3];
|
|
|
|
__cpuid(CPUInfo, 0x80000004);
|
|
((int*)pName)[8] = CPUInfo[0];
|
|
((int*)pName)[9] = CPUInfo[1];
|
|
((int*)pName)[10] = CPUInfo[2];
|
|
((int*)pName)[11] = CPUInfo[3];
|
|
}
|
|
else
|
|
{
|
|
pName[0] = '\0';
|
|
}
|
|
}
|
|
#else
|
|
if (pName)
|
|
{
|
|
pName[0] = '\0';
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool HasFPUOnChip()
|
|
{
|
|
#if AZ_LEGACY_CRYSYSTEM_TRAIT_HASCPUID
|
|
int CPUInfo[4];
|
|
__cpuid(CPUInfo, 0x00000001);
|
|
// Bit 0 in edx indicates presents of on chip FPU
|
|
return (CPUInfo[3] & 0x00000001) != 0;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
void GetCPUSteppingModelFamily(int& stepping, int& model, int& family)
|
|
{
|
|
#if AZ_LEGACY_CRYSYSTEM_TRAIT_HASCPUID
|
|
int CPUInfo[4];
|
|
__cpuid(CPUInfo, 0x00000001);
|
|
stepping = CPUInfo[0] & 0xF; // Bit 0-3 in eax specifies stepping
|
|
model = (CPUInfo[0] >> 4) & 0xF; // Bit 4-7 in eax specifies model
|
|
family = (CPUInfo[0] >> 8) & 0xF; // Bit 8-11 in eax specifies family
|
|
#else
|
|
stepping = 0;
|
|
model = 0;
|
|
family = 0;
|
|
#endif
|
|
}
|
|
|
|
#if AZ_LEGACY_CRYSYSTEM_TRAIT_HASCPUID
|
|
unsigned long GetCPUFeatureSet()
|
|
{
|
|
unsigned long features = 0;
|
|
|
|
int CPUInfo[4];
|
|
|
|
__cpuid(CPUInfo, 0);
|
|
const int nIds = CPUInfo[0];
|
|
|
|
__cpuid(CPUInfo, 0x80000000);
|
|
const unsigned int nExIds = CPUInfo[0];
|
|
|
|
if (nIds > 0)
|
|
{
|
|
__cpuid(CPUInfo, 0x00000001);
|
|
|
|
if (CPUInfo[3] & (1 << 26))
|
|
{
|
|
features |= CFI_SSE2;
|
|
}
|
|
if (CPUInfo[3] & (1 << 25))
|
|
{
|
|
features |= CFI_SSE;
|
|
}
|
|
if (CPUInfo[2] & (1 << 0))
|
|
{
|
|
features |= CFI_SSE3;
|
|
}
|
|
if (CPUInfo[2] & (1 << 29))
|
|
{
|
|
features |= CFI_F16C;
|
|
}
|
|
if (CPUInfo[2] & (1 << 19))
|
|
{
|
|
features |= CFI_SSE41;
|
|
}
|
|
}
|
|
|
|
if (nExIds > 0x80000000)
|
|
{
|
|
__cpuid(CPUInfo, 0x80000001);
|
|
if (CPUInfo[3] & (1 << 31))
|
|
{
|
|
features |= CFI_3DNOW;
|
|
}
|
|
}
|
|
|
|
return features;
|
|
}
|
|
#endif
|
|
|
|
#if AZ_LEGACY_CRYSYSTEM_TRAIT_DEFINE_DETECT_PROCESSOR
|
|
static unsigned long __stdcall DetectProcessor(void* arg)
|
|
{
|
|
const char hex_chars[16] =
|
|
{
|
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
|
};
|
|
unsigned long signature = 0;
|
|
unsigned long cache_temp;
|
|
unsigned long cache_eax = 0;
|
|
unsigned long cache_ebx = 0;
|
|
unsigned long cache_ecx = 0;
|
|
unsigned long cache_edx = 0;
|
|
unsigned long features_edx = 0;
|
|
unsigned long serial_number[3];
|
|
unsigned char cpu_type;
|
|
unsigned char fpu_type;
|
|
unsigned char CPUID_flag = 0;
|
|
unsigned char celeron_flag = 0;
|
|
unsigned char pentiumxeon_flag = 0;
|
|
unsigned char amd3d_flag = 0;
|
|
unsigned char name_flag = 0;
|
|
char vendor[13];
|
|
vendor[0] = '\0';
|
|
char name[49];
|
|
name[0] = '\0';
|
|
char* serial;
|
|
const char* cpu_string;
|
|
const char* cpu_extra_string;
|
|
const char* fpu_string;
|
|
const char* vendor_string;
|
|
SCpu* p = (SCpu*) arg;
|
|
|
|
memset(p, 0, sizeof(*p));
|
|
|
|
if (IsAMD() && Has64bitExtension())
|
|
{
|
|
p->meVendor = eCVendor_AMD;
|
|
p->mFeatures |= GetCPUFeatureSet();
|
|
p->mbSerialPresent = false;
|
|
azstrcpy(p->mSerialNumber, AZ_ARRAY_SIZE(p->mSerialNumber), "");
|
|
GetCPUSteppingModelFamily(p->mStepping, p->mModel, p->mFamily);
|
|
azstrcpy(p->mVendor, AZ_ARRAY_SIZE(p->mVendor), "AMD");
|
|
GetCPUName(p->mCpuType);
|
|
azstrcpy(p->mFpuType, AZ_ARRAY_SIZE(p->mFpuType), HasFPUOnChip() ? "On-Chip" : "Unknown");
|
|
p->mbPhysical = true;
|
|
|
|
return 1;
|
|
}
|
|
else if (IsIntel() && Has64bitExtension())
|
|
{
|
|
p->meVendor = eCVendor_Intel;
|
|
p->mFeatures |= GetCPUFeatureSet();
|
|
p->mbSerialPresent = false;
|
|
azstrcpy(p->mSerialNumber, AZ_ARRAY_SIZE(p->mSerialNumber), "");
|
|
GetCPUSteppingModelFamily(p->mStepping, p->mModel, p->mFamily);
|
|
azstrcpy(p->mVendor, AZ_ARRAY_SIZE(p->mVendor), "Intel");
|
|
GetCPUName(p->mCpuType);
|
|
azstrcpy(p->mFpuType, AZ_ARRAY_SIZE(p->mFpuType), HasFPUOnChip() ? "On-Chip" : "Unknown");
|
|
|
|
p->mbPhysical = true;
|
|
|
|
return 1;
|
|
}
|
|
|
|
cpu_type = 0xF;
|
|
fpu_type = 3;
|
|
signature = 0;
|
|
|
|
p->mFamily = cpu_type;
|
|
p->mModel = (signature >> 4) & 0xf;
|
|
p->mStepping = signature & 0xf;
|
|
|
|
p->mFeatures = 0;
|
|
|
|
p->mFeatures |= amd3d_flag ? CFI_3DNOW : 0;
|
|
p->mFeatures |= (features_edx & MMX_FLAG) ? CFI_MMX : 0;
|
|
p->mFeatures |= (features_edx & ISSE_FLAG) ? CFI_SSE : 0;
|
|
p->mbSerialPresent = ((features_edx & SERIAL_FLAG) != 0);
|
|
|
|
if (features_edx & SERIAL_FLAG)
|
|
{
|
|
serial_number[0] = serial_number[1] = serial_number[2] = 0;
|
|
|
|
/* format number */
|
|
serial = p->mSerialNumber;
|
|
|
|
serial[0] = hex_chars[(serial_number[2] >> 28) & 0x0f];
|
|
serial[1] = hex_chars[(serial_number[2] >> 24) & 0x0f];
|
|
serial[2] = hex_chars[(serial_number[2] >> 20) & 0x0f];
|
|
serial[3] = hex_chars[(serial_number[2] >> 16) & 0x0f];
|
|
|
|
serial[4] = '-';
|
|
|
|
serial[5] = hex_chars[(serial_number[2] >> 12) & 0x0f];
|
|
serial[6] = hex_chars[(serial_number[2] >> 8) & 0x0f];
|
|
serial[7] = hex_chars[(serial_number[2] >> 4) & 0x0f];
|
|
serial[8] = hex_chars[(serial_number[2] >> 0) & 0x0f];
|
|
|
|
serial[9] = '-';
|
|
|
|
serial[10] = hex_chars[(serial_number[1] >> 28) & 0x0f];
|
|
serial[11] = hex_chars[(serial_number[1] >> 24) & 0x0f];
|
|
serial[12] = hex_chars[(serial_number[1] >> 20) & 0x0f];
|
|
serial[13] = hex_chars[(serial_number[1] >> 16) & 0x0f];
|
|
|
|
serial[14] = '-';
|
|
|
|
serial[15] = hex_chars[(serial_number[1] >> 12) & 0x0f];
|
|
serial[16] = hex_chars[(serial_number[1] >> 8) & 0x0f];
|
|
serial[17] = hex_chars[(serial_number[1] >> 4) & 0x0f];
|
|
serial[18] = hex_chars[(serial_number[1] >> 0) & 0x0f];
|
|
|
|
serial[19] = '-';
|
|
|
|
serial[20] = hex_chars[(serial_number[0] >> 28) & 0x0f];
|
|
serial[21] = hex_chars[(serial_number[0] >> 24) & 0x0f];
|
|
serial[22] = hex_chars[(serial_number[0] >> 20) & 0x0f];
|
|
serial[23] = hex_chars[(serial_number[0] >> 16) & 0x0f];
|
|
|
|
serial[24] = '-';
|
|
|
|
serial[25] = hex_chars[(serial_number[0] >> 12) & 0x0f];
|
|
serial[26] = hex_chars[(serial_number[0] >> 8) & 0x0f];
|
|
serial[27] = hex_chars[(serial_number[0] >> 4) & 0x0f];
|
|
serial[28] = hex_chars[(serial_number[0] >> 0) & 0x0f];
|
|
|
|
serial[29] = 0;
|
|
}
|
|
|
|
vendor_string = "Unknown";
|
|
cpu_string = "Unknown";
|
|
cpu_extra_string = "";
|
|
fpu_string = "Unknown";
|
|
|
|
if (!CPUID_flag)
|
|
{
|
|
switch (cpu_type)
|
|
{
|
|
case 0:
|
|
cpu_string = "8086";
|
|
break;
|
|
|
|
case 2:
|
|
cpu_string = "80286";
|
|
break;
|
|
|
|
case 3:
|
|
cpu_string = "80386";
|
|
switch (fpu_type)
|
|
{
|
|
case 2:
|
|
fpu_string = "80287";
|
|
break;
|
|
|
|
case 1:
|
|
fpu_string = "80387";
|
|
break;
|
|
|
|
default:
|
|
fpu_string = "None";
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
if (fpu_type)
|
|
{
|
|
cpu_string = "80486DX, 80486DX2 or 80487SX";
|
|
fpu_string = "on-chip";
|
|
}
|
|
else
|
|
{
|
|
cpu_string = "80486SX";
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{ /* using CPUID instruction */
|
|
if (!name_flag)
|
|
{
|
|
if (!strcmp(vendor, "GenuineIntel"))
|
|
{
|
|
vendor_string = "Intel";
|
|
switch (cpu_type)
|
|
{
|
|
case 4:
|
|
switch (p->mModel)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
cpu_string = "80486DX";
|
|
break;
|
|
|
|
case 2:
|
|
cpu_string = "80486SX";
|
|
break;
|
|
|
|
case 3:
|
|
cpu_string = "80486DX2";
|
|
break;
|
|
|
|
case 4:
|
|
cpu_string = "80486SL";
|
|
break;
|
|
|
|
case 5:
|
|
cpu_string = "80486SX2";
|
|
break;
|
|
|
|
case 7:
|
|
cpu_string = "Write-Back Enhanced 80486DX2";
|
|
break;
|
|
|
|
case 8:
|
|
cpu_string = "80486DX4";
|
|
break;
|
|
|
|
default:
|
|
cpu_string = "80486";
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
switch (p->mModel)
|
|
{
|
|
default:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
cpu_string = "Pentium";
|
|
break;
|
|
|
|
case 4:
|
|
cpu_string = "Pentium MMX";
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 6:
|
|
switch (p->mModel)
|
|
{
|
|
case 1:
|
|
cpu_string = "Pentium Pro";
|
|
break;
|
|
|
|
case 3:
|
|
cpu_string = "Pentium II";
|
|
break;
|
|
|
|
case 5:
|
|
case 7:
|
|
{
|
|
cache_temp = cache_eax & 0xFF000000;
|
|
if (cache_temp == 0x40000000)
|
|
{
|
|
celeron_flag = 1;
|
|
}
|
|
if ((cache_temp >= 0x44000000) && (cache_temp <= 0x45000000))
|
|
{
|
|
pentiumxeon_flag = 1;
|
|
}
|
|
cache_temp = cache_eax & 0xFF0000;
|
|
if (cache_temp == 0x400000)
|
|
{
|
|
celeron_flag = 1;
|
|
}
|
|
if ((cache_temp >= 0x440000) && (cache_temp <= 0x450000))
|
|
{
|
|
pentiumxeon_flag = 1;
|
|
}
|
|
cache_temp = cache_eax & 0xFF00;
|
|
if (cache_temp == 0x4000)
|
|
{
|
|
celeron_flag = 1;
|
|
}
|
|
if ((cache_temp >= 0x4400) && (cache_temp <= 0x4500))
|
|
{
|
|
pentiumxeon_flag = 1;
|
|
}
|
|
cache_temp = cache_ebx & 0xFF000000;
|
|
if (cache_temp == 0x40000000)
|
|
{
|
|
celeron_flag = 1;
|
|
}
|
|
if ((cache_temp >= 0x44000000) && (cache_temp <= 0x45000000))
|
|
{
|
|
pentiumxeon_flag = 1;
|
|
}
|
|
cache_temp = cache_ebx & 0xFF0000;
|
|
if (cache_temp == 0x400000)
|
|
{
|
|
celeron_flag = 1;
|
|
}
|
|
if ((cache_temp >= 0x440000) && (cache_temp <= 0x450000))
|
|
{
|
|
pentiumxeon_flag = 1;
|
|
}
|
|
cache_temp = cache_ebx & 0xFF00;
|
|
if (cache_temp == 0x4000)
|
|
{
|
|
celeron_flag = 1;
|
|
}
|
|
if ((cache_temp >= 0x4400) && (cache_temp <= 0x4500))
|
|
{
|
|
pentiumxeon_flag = 1;
|
|
}
|
|
cache_temp = cache_ebx & 0xFF;
|
|
if (cache_temp == 0x40)
|
|
{
|
|
celeron_flag = 1;
|
|
}
|
|
if ((cache_temp >= 0x44) && (cache_temp <= 0x45))
|
|
{
|
|
pentiumxeon_flag = 1;
|
|
}
|
|
cache_temp = cache_ecx & 0xFF000000;
|
|
if (cache_temp == 0x40000000)
|
|
{
|
|
celeron_flag = 1;
|
|
}
|
|
if ((cache_temp >= 0x44000000) && (cache_temp <= 0x45000000))
|
|
{
|
|
pentiumxeon_flag = 1;
|
|
}
|
|
cache_temp = cache_ecx & 0xFF0000;
|
|
if (cache_temp == 0x400000)
|
|
{
|
|
celeron_flag = 1;
|
|
}
|
|
if ((cache_temp >= 0x440000) && (cache_temp <= 0x450000))
|
|
{
|
|
pentiumxeon_flag = 1;
|
|
}
|
|
cache_temp = cache_ecx & 0xFF00;
|
|
if (cache_temp == 0x4000)
|
|
{
|
|
celeron_flag = 1;
|
|
}
|
|
if ((cache_temp >= 0x4400) && (cache_temp <= 0x4500))
|
|
{
|
|
pentiumxeon_flag = 1;
|
|
}
|
|
cache_temp = cache_ecx & 0xFF;
|
|
if (cache_temp == 0x40)
|
|
{
|
|
celeron_flag = 1;
|
|
}
|
|
if ((cache_temp >= 0x44) && (cache_temp <= 0x45))
|
|
{
|
|
pentiumxeon_flag = 1;
|
|
}
|
|
cache_temp = cache_edx & 0xFF000000;
|
|
if (cache_temp == 0x40000000)
|
|
{
|
|
celeron_flag = 1;
|
|
}
|
|
if ((cache_temp >= 0x44000000) && (cache_temp <= 0x45000000))
|
|
{
|
|
pentiumxeon_flag = 1;
|
|
}
|
|
cache_temp = cache_edx & 0xFF0000;
|
|
if (cache_temp == 0x400000)
|
|
{
|
|
celeron_flag = 1;
|
|
}
|
|
if ((cache_temp >= 0x440000) && (cache_temp <= 0x450000))
|
|
{
|
|
pentiumxeon_flag = 1;
|
|
}
|
|
cache_temp = cache_edx & 0xFF00;
|
|
if (cache_temp == 0x4000)
|
|
{
|
|
celeron_flag = 1;
|
|
}
|
|
if ((cache_temp >= 0x4400) && (cache_temp <= 0x4500))
|
|
{
|
|
pentiumxeon_flag = 1;
|
|
}
|
|
cache_temp = cache_edx & 0xFF;
|
|
if (cache_temp == 0x40)
|
|
{
|
|
celeron_flag = 1;
|
|
}
|
|
if ((cache_temp >= 0x44) && (cache_temp <= 0x45))
|
|
{
|
|
pentiumxeon_flag = 1;
|
|
}
|
|
|
|
if (celeron_flag)
|
|
{
|
|
cpu_string = "Celeron";
|
|
}
|
|
else
|
|
{
|
|
if (pentiumxeon_flag)
|
|
{
|
|
if (p->mModel == 5)
|
|
{
|
|
cpu_string = "Pentium II Xeon";
|
|
}
|
|
else
|
|
{
|
|
cpu_string = "Pentium III Xeon";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (p->mModel == 5)
|
|
{
|
|
cpu_string = "Pentium II";
|
|
}
|
|
else
|
|
{
|
|
cpu_string = "Pentium III";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 6:
|
|
cpu_string = "Celeron";
|
|
break;
|
|
|
|
case 8:
|
|
cpu_string = "Pentium III";
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (signature & 0x1000)
|
|
{
|
|
cpu_extra_string = " OverDrive";
|
|
}
|
|
else
|
|
if (signature & 0x2000)
|
|
{
|
|
cpu_extra_string = " dual upgrade";
|
|
}
|
|
}
|
|
else
|
|
if (!strcmp(vendor, "CyrixInstead"))
|
|
{
|
|
vendor_string = "Cyrix";
|
|
switch (p->mFamily)
|
|
{
|
|
case 4:
|
|
switch (p->mModel)
|
|
{
|
|
case 4:
|
|
cpu_string = "MediaGX";
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
switch (p->mModel)
|
|
{
|
|
case 2:
|
|
cpu_string = "6x86";
|
|
break;
|
|
|
|
case 4:
|
|
cpu_string = "GXm";
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 6:
|
|
switch (p->mModel)
|
|
{
|
|
case 0:
|
|
cpu_string = "6x86MX";
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
if (!strcmp(vendor, "AuthenticAMD"))
|
|
{
|
|
cry_strcpy(p->mVendor, "AMD");
|
|
switch (p->mFamily)
|
|
{
|
|
case 4:
|
|
cpu_string = "Am486 or Am5x86";
|
|
break;
|
|
|
|
case 5:
|
|
switch (p->mModel)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
cpu_string = "K5";
|
|
break;
|
|
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
cpu_string = "K6";
|
|
break;
|
|
|
|
case 8:
|
|
cpu_string = "K6-2";
|
|
break;
|
|
|
|
case 9:
|
|
cpu_string = "K6-III";
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 6:
|
|
cpu_string = "Athlon";
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
if (!strcmp(vendor, "CentaurHauls"))
|
|
{
|
|
vendor_string = "Centaur";
|
|
switch (cpu_type)
|
|
{
|
|
case 5:
|
|
switch (p->mModel)
|
|
{
|
|
case 4:
|
|
cpu_string = "WinChip";
|
|
break;
|
|
|
|
case 8:
|
|
cpu_string = "WinChip2";
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
if (!strcmp(vendor, "UMC UMC UMC "))
|
|
{
|
|
vendor_string = "UMC";
|
|
}
|
|
else
|
|
if (!strcmp(vendor, "NexGenDriven"))
|
|
{
|
|
vendor_string = "NexGen";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vendor_string = vendor;
|
|
cpu_string = name;
|
|
}
|
|
|
|
if (features_edx & FPU_FLAG)
|
|
{
|
|
fpu_string = "On-Chip";
|
|
}
|
|
else
|
|
{
|
|
fpu_string = "Unknown";
|
|
}
|
|
}
|
|
|
|
stack_string sCpuType = stack_string(cpu_string) + cpu_extra_string;
|
|
|
|
cry_strcpy(p->mCpuType, sCpuType.c_str());
|
|
cry_strcpy(p->mFpuType, fpu_string);
|
|
cry_strcpy(p->mVendor, vendor_string);
|
|
|
|
if (!azstricmp(vendor_string, "Intel"))
|
|
{
|
|
p->meVendor = eCVendor_Intel;
|
|
}
|
|
else
|
|
if (!azstricmp(vendor_string, "Cyrix"))
|
|
{
|
|
p->meVendor = eCVendor_Cyrix;
|
|
}
|
|
else
|
|
if (!azstricmp(vendor_string, "AMD"))
|
|
{
|
|
p->meVendor = eCVendor_AMD;
|
|
}
|
|
else
|
|
if (!azstricmp(vendor_string, "Centaur"))
|
|
{
|
|
p->meVendor = eCVendor_Centaur;
|
|
}
|
|
else
|
|
if (!azstricmp(vendor_string, "NexGen"))
|
|
{
|
|
p->meVendor = eCVendor_NexGen;
|
|
}
|
|
else
|
|
if (!azstricmp(vendor_string, "UMC"))
|
|
{
|
|
p->meVendor = eCVendor_UMC;
|
|
}
|
|
else
|
|
{
|
|
p->meVendor = eCVendor_Unknown;
|
|
}
|
|
|
|
if (strstr(cpu_string, "8086"))
|
|
{
|
|
p->meModel = eCpu_8086;
|
|
}
|
|
else
|
|
if (strstr(cpu_string, "80286"))
|
|
{
|
|
p->meModel = eCpu_80286;
|
|
}
|
|
else
|
|
if (strstr(cpu_string, "80386"))
|
|
{
|
|
p->meModel = eCpu_80386;
|
|
}
|
|
else
|
|
if (strstr(cpu_string, "80486"))
|
|
{
|
|
p->meModel = eCpu_80486;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "Pentium MMX") || !azstricmp(cpu_string, "Pentium"))
|
|
{
|
|
p->meModel = eCpu_Pentium;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "Pentium Pro"))
|
|
{
|
|
p->meModel = eCpu_PentiumPro;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "Pentium II"))
|
|
{
|
|
p->meModel = eCpu_Pentium2;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "Pentium III"))
|
|
{
|
|
p->meModel = eCpu_Pentium3;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "Pentium 4"))
|
|
{
|
|
p->meModel = eCpu_Pentium4;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "Celeron"))
|
|
{
|
|
p->meModel = eCpu_Celeron;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "Pentium II Xeon"))
|
|
{
|
|
p->meModel = eCpu_Pentium2Xeon;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "Pentium III Xeon"))
|
|
{
|
|
p->meModel = eCpu_Pentium3Xeon;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "MediaGX"))
|
|
{
|
|
p->meModel = eCpu_CyrixMediaGX;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "6x86"))
|
|
{
|
|
p->meModel = eCpu_Cyrix6x86;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "GXm"))
|
|
{
|
|
p->meModel = eCpu_CyrixGXm;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "6x86MX"))
|
|
{
|
|
p->meModel = eCpu_Cyrix6x86MX;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "Am486 or Am5x86"))
|
|
{
|
|
p->meModel = eCpu_Am5x86;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "K5"))
|
|
{
|
|
p->meModel = eCpu_AmK5;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "K6"))
|
|
{
|
|
p->meModel = eCpu_AmK6;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "K6-2"))
|
|
{
|
|
p->meModel = eCpu_AmK6_2;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "K6-III"))
|
|
{
|
|
p->meModel = eCpu_AmK6_3;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "Athlon"))
|
|
{
|
|
p->meModel = eCpu_AmAthlon;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "Duron"))
|
|
{
|
|
p->meModel = eCpu_AmDuron;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "WinChip"))
|
|
{
|
|
p->meModel = eCpu_CenWinChip;
|
|
}
|
|
else
|
|
if (!azstricmp(cpu_string, "WinChip2"))
|
|
{
|
|
p->meModel = eCpu_CenWinChip2;
|
|
}
|
|
else
|
|
{
|
|
p->meModel = eCpu_Unknown;
|
|
}
|
|
|
|
p->mbPhysical = true;
|
|
if (!strcmp(vendor_string, "GenuineIntel") && p->mStepping > 4 && HTSupported())
|
|
{
|
|
p->mbPhysical = (GetAPIC_ID() & LogicalProcPerPhysicalProc() - 1) == 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
#endif //AZ_LEGACY_CRYSYSTEM_TRAIT_DEFINE_DETECT_PROCESSOR
|
|
|
|
#if defined(MAC) || (defined(LINUX) && !defined(ANDROID))
|
|
static void* DetectProcessorThreadProc(void* pData)
|
|
{
|
|
DetectProcessor(pData);
|
|
return NULL;
|
|
}
|
|
#endif // MAC LINUX
|
|
|
|
// #define SQRT_TEST
|
|
#ifdef SQRT_TEST
|
|
/* ------------------------------------------------------------------------------ */
|
|
|
|
ILINE float CorrectInvSqrt(float fNum, float fInvSqrtEst)
|
|
{
|
|
// Newton-Rhapson method for improving estimated inv sqrt.
|
|
// f(x) = x^(-1/2)
|
|
// f(n) = f(a) + (n-a)f'(a)
|
|
// = a^(-1/2) + (n-a)(-1/2)a^(-3/2)
|
|
// = a^(-1/2)*3/2 - na^(-3/2)/2
|
|
// = e*3/2 - ne^3/2
|
|
return fInvSqrtEst * (1.5f - fNum * fInvSqrtEst * fInvSqrtEst * 0.5f);
|
|
}
|
|
|
|
|
|
float Null(float f) { return f; }
|
|
float Inv(float f) { return 1.f / f; }
|
|
|
|
float Square(float f) { return f * f; }
|
|
float InvSquare(float f) { return 1.f / (f * f); }
|
|
|
|
float Sqrt(float f) { return sqrtf(f); }
|
|
float SqrtT(float f) { return sqrt_tpl(f); }
|
|
float SqrtFT(float f) { return sqrt_fast_tpl(f); }
|
|
|
|
float InvSqrt(float f) { return 1.f / sqrtf(f); }
|
|
float ISqrtT(float f) { return isqrt_tpl(f); }
|
|
float ISqrtFT(float f) { return isqrt_fast_tpl(f); }
|
|
|
|
float SSEInv(float f)
|
|
{
|
|
__m128 s = _mm_rcp_ss(_mm_load_ss(&f));
|
|
float r;
|
|
_mm_store_ss(&r, s);
|
|
return r;
|
|
}
|
|
float SSESqrt(float f)
|
|
{
|
|
__m128 s = _mm_sqrt_ss(_mm_load_ss(&f));
|
|
float r;
|
|
_mm_store_ss(&r, s);
|
|
return r;
|
|
}
|
|
float SSEISqrt(float f)
|
|
{
|
|
__m128 s = _mm_sqrt_ss(_mm_load_ss(&f));
|
|
float r;
|
|
_mm_store_ss(&r, s);
|
|
return 1.f / r;
|
|
}
|
|
float SSERSqrt(float f)
|
|
{
|
|
__m128 s = _mm_rsqrt_ss(_mm_load_ss(&f));
|
|
float r;
|
|
_mm_store_ss(&r, s);
|
|
return r;
|
|
}
|
|
float SSERSqrtInv(float f)
|
|
{
|
|
__m128 s = _mm_rcp_ss(_mm_rsqrt_ss(_mm_load_ss(&f)));
|
|
float r;
|
|
_mm_store_ss(&r, s);
|
|
return r;
|
|
}
|
|
float SSERSqrtNR(float f)
|
|
{
|
|
__m128 s = _mm_rsqrt_ss(_mm_load_ss(&f));
|
|
float r;
|
|
_mm_store_ss(&r, s);
|
|
return CorrectInvSqrt(f, r);
|
|
}
|
|
float SSERISqrtNR(float f)
|
|
{
|
|
__m128 s = _mm_rsqrt_ss(_mm_load_ss(&f));
|
|
float r;
|
|
_mm_store_ss(&r, s);
|
|
return 1.f / CorrectInvSqrt(f, r);
|
|
}
|
|
|
|
inline float cryISqrtf(float fVal)
|
|
{
|
|
unsigned int* n1 = (unsigned int*)&fVal;
|
|
unsigned int n = 0x5f3759df - (*n1 >> 1);
|
|
float* n2 = (float*)&n;
|
|
fVal = (1.5f - (fVal * 0.5f) * *n2 * *n2) * *n2;
|
|
return fVal;
|
|
}
|
|
|
|
float cryISqrtNRf(float f)
|
|
{
|
|
return CorrectInvSqrt(f, cryISqrtf(f));
|
|
}
|
|
|
|
inline float crySqrtf(float fVal)
|
|
{
|
|
return 1.0f / cryISqrtf(fVal);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------ */
|
|
struct SMathTest
|
|
{
|
|
typedef int64 TTime;
|
|
static inline TTime GetTime()
|
|
{
|
|
return CryGetTicks();
|
|
}
|
|
|
|
static const int T = 100, N = 1000;
|
|
float fNullTime;
|
|
|
|
float aTestVals[T];
|
|
float aResVals[T];
|
|
|
|
typedef float (* FFloatFunc)(float f);
|
|
|
|
float Timer(const char* sName, FFloatFunc func, FFloatFunc finv)
|
|
{
|
|
for (int i = 0; i < T; i++)
|
|
{
|
|
aResVals[i] = func(aTestVals[i]);
|
|
}
|
|
TTime tStart = GetTime();
|
|
for (int r = 0; r < N; r++)
|
|
{
|
|
for (int i = 0; i < T; i++)
|
|
{
|
|
aResVals[i] = func(aTestVals[i]);
|
|
}
|
|
}
|
|
float fTime = (GetTime() - tStart) / float(N * T);
|
|
|
|
// Error computation.
|
|
float fAvgErr = 0.f, fMaxErr = 0.f;
|
|
for (int i = 0; i < T; i++)
|
|
{
|
|
float fErr = abs(finv(aResVals[i]) / aTestVals[i] - 1.f);
|
|
fAvgErr += fErr;
|
|
fMaxErr = max(fMaxErr, fErr);
|
|
}
|
|
fAvgErr /= float(T);
|
|
|
|
CryLogAlways("%-20s : %5.2f cycles, avg err %.2e, max err %.2e", sName, fTime - fNullTime, fAvgErr, fMaxErr);
|
|
|
|
return fTime;
|
|
};
|
|
|
|
SMathTest()
|
|
{
|
|
for (int i = 0; i < T; i++)
|
|
{
|
|
aTestVals[i] = powf(cry_random(1.f, 2.f), cry_random(-30.f, 30.f));
|
|
}
|
|
|
|
CryLogAlways("--- Math Test ---");
|
|
|
|
fNullTime = 0.f;
|
|
fNullTime = Timer("(null)", &Null, &Null);
|
|
|
|
CryLogAlways("-- Inverse methods");
|
|
Timer("1/f", &Inv, &Inv);
|
|
Timer("rcpss", &SSEInv, &Inv);
|
|
|
|
CryLogAlways("-- Sqrt methods");
|
|
Timer("sqrtf()", &Sqrt, &Square);
|
|
Timer("sqrt_tpl()", &SqrtT, &Square);
|
|
Timer("sqrt_fast_tpl()", &SqrtFT, &Square);
|
|
Timer("crySqrt()", &crySqrtf, &Square);
|
|
|
|
// Timer("sqrtss", &SSESqrt, &Square);
|
|
// Timer("rsqrtss,rcpss", &SSERSqrtInv, &Square);
|
|
Timer("1/rsqrtss,correction", &SSERISqrtNR, &Square);
|
|
|
|
CryLogAlways("-- InvSqrt methods");
|
|
Timer("1/sqrtf()", &InvSqrt, &InvSquare);
|
|
Timer("isqrt_tpl()", &ISqrtT, &InvSquare);
|
|
Timer("isqrt_fast_tpl()", &ISqrtFT, &InvSquare);
|
|
Timer("cryISqrt()", &cryISqrtf, &InvSquare);
|
|
|
|
Timer("1/sqrtss", &SSEISqrt, &InvSquare);
|
|
// Timer("rsqrtss", &SSERSqrt, &InvSquare);
|
|
// Timer("rsqrtss,correction", &SSERSqrtNR, &InvSquare);
|
|
Timer("cryISqrt,correction", &cryISqrtNRf, &InvSquare);
|
|
|
|
CryLogAlways("--------------------");
|
|
}
|
|
};
|
|
|
|
#endif // SQRT_TEST
|
|
|
|
#if defined(LINUX)
|
|
// collection of functions to read from /proc/cpuinfo
|
|
|
|
static bool proc_read_str(char* buffer, char* output, size_t output_length)
|
|
{
|
|
if (!buffer || !output || output_length <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
while (*buffer && *buffer != ':')
|
|
{
|
|
++buffer;
|
|
}
|
|
if (*buffer == ':')
|
|
{
|
|
buffer += 2;
|
|
cry_strcpy(output, output_length, buffer);
|
|
const int len = strlen(output);
|
|
if (len > 0 && output[len - 1] == '\n')
|
|
{
|
|
output[len - 1] = '\0';
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
static bool proc_read_int(char* buffer, int& output)
|
|
{
|
|
if (!buffer)
|
|
{
|
|
return false;
|
|
}
|
|
while (*buffer && *buffer != ':')
|
|
{
|
|
++buffer;
|
|
}
|
|
if (*buffer == ':')
|
|
{
|
|
buffer += 2;
|
|
output = atoi(buffer);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
/* ------------------------------------------------------------------------------ */
|
|
void CCpuFeatures::Detect(void)
|
|
{
|
|
m_NumSystemProcessors = 1;
|
|
m_NumAvailProcessors = 0;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
#if AZ_LEGACY_CRYSYSTEM_TRAIT_HASAFFINITYMASK
|
|
CryLogAlways("");
|
|
|
|
DWORD_PTR process_affinity_mask = 1;
|
|
|
|
/* get the system info to derive the number of processors within the system. */
|
|
|
|
SYSTEM_INFO sys_info;
|
|
DWORD_PTR system_affinity_mask;
|
|
GetSystemInfo(&sys_info);
|
|
m_NumLogicalProcessors = m_NumSystemProcessors = sys_info.dwNumberOfProcessors;
|
|
m_NumAvailProcessors = 0;
|
|
GetProcessAffinityMask(GetCurrentProcess(), &process_affinity_mask, &system_affinity_mask);
|
|
|
|
for (unsigned char c = 0; c < m_NumSystemProcessors; c++)
|
|
{
|
|
if (process_affinity_mask & ((DWORD_PTR)1 << c))
|
|
{
|
|
m_NumAvailProcessors++;
|
|
SetProcessAffinityMask(GetCurrentProcess(), DWORD_PTR(1) << c);
|
|
DetectProcessor(&m_Cpu[c]);
|
|
m_Cpu[c].mAffinityMask = ((DWORD_PTR)1 << c);
|
|
}
|
|
}
|
|
|
|
SetProcessAffinityMask(GetCurrentProcess(), process_affinity_mask);
|
|
|
|
m_bOS_ISSE = false;
|
|
m_bOS_ISSE_EXCEPTIONS = false;
|
|
#elif defined(LINUX)
|
|
// Retrieve information from /proc/cpuinfo
|
|
FILE* cpu_info = fopen("/proc/cpuinfo", "r");
|
|
if (!cpu_info)
|
|
{
|
|
m_NumLogicalProcessors = m_NumSystemProcessors = m_NumAvailProcessors = 1;
|
|
CryLogAlways("Could not open /proc/cpuinfo, defaulting values to 1.");
|
|
}
|
|
else
|
|
{
|
|
int nCores = 0;
|
|
int nCpu = -1;
|
|
int index = 0;
|
|
char buffer[512];
|
|
while (!feof(cpu_info))
|
|
{
|
|
if (nCpu >= MAX_CPU)
|
|
{
|
|
--nCpu; //Decrement so the sets after the while loop matches the number of CPUs examined
|
|
CryLogAlways("Found a higher than expected number of CPUs, defaulting to %d", MAX_CPU);
|
|
break;
|
|
}
|
|
|
|
fgets(buffer, sizeof(buffer), cpu_info);
|
|
|
|
if (buffer[0] == '\0' || buffer[0] == '\n')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (strncmp("processor", buffer, (index = strlen("processor"))) == 0)
|
|
{
|
|
++nCpu;
|
|
}
|
|
else if (strncmp("vendor_id", buffer, (index = strlen("vendor_id"))) == 0)
|
|
{
|
|
proc_read_str(&buffer[index], m_Cpu[nCpu].mVendor, sizeof(m_Cpu[nCpu].mVendor));
|
|
}
|
|
else if (strncmp("model name", buffer, (index = strlen("model name"))) == 0)
|
|
{
|
|
proc_read_str(&buffer[index], m_Cpu[nCpu].mCpuType, sizeof(m_Cpu[nCpu].mCpuType));
|
|
}
|
|
else if (strncmp("cpu cores", buffer, (index = strlen("cpu cores"))) == 0 && nCores == 0)
|
|
{
|
|
proc_read_int(&buffer[index], nCores);
|
|
}
|
|
else if (strncmp("fpu", buffer, (index = strlen("fpu"))) == 0)
|
|
{
|
|
while (buffer[index] != ':' && index < 512)
|
|
{
|
|
++index;
|
|
}
|
|
if (buffer[index] == ':')
|
|
{
|
|
if (strncmp(&buffer[index + 2], "yes", 3) == 0)
|
|
{
|
|
snprintf(m_Cpu[nCpu].mFpuType, sizeof(m_Cpu[nCpu].mFpuType), "On-Chip");
|
|
}
|
|
else
|
|
{
|
|
snprintf(m_Cpu[nCpu].mFpuType, sizeof(m_Cpu[nCpu].mFpuType), "Unkown");
|
|
}
|
|
}
|
|
}
|
|
else if (strncmp("cpu family", buffer, (index = strlen("cpu family"))) == 0)
|
|
{
|
|
proc_read_int(&buffer[index], m_Cpu[nCpu].mFamily);
|
|
}
|
|
else if (strncmp("model", buffer, (index = strlen("model"))) == 0)
|
|
{
|
|
proc_read_int(&buffer[index], m_Cpu[nCpu].mModel);
|
|
}
|
|
else if (strncmp("stepping", buffer, (index = strlen("stepping"))) == 0)
|
|
{
|
|
proc_read_int(&buffer[index], m_Cpu[nCpu].mStepping);
|
|
}
|
|
else if (strncmp("flags", buffer, (index = strlen("flags"))) == 0)
|
|
{
|
|
if (strstr(buffer + index, "mmx"))
|
|
{
|
|
m_Cpu[nCpu].mFeatures |= CFI_MMX;
|
|
}
|
|
|
|
if (strstr(buffer + index, "sse"))
|
|
{
|
|
m_Cpu[nCpu].mFeatures |= CFI_SSE;
|
|
}
|
|
|
|
if (strstr(buffer + index, "sse2"))
|
|
{
|
|
m_Cpu[nCpu].mFeatures |= CFI_SSE2;
|
|
}
|
|
}
|
|
}
|
|
m_NumLogicalProcessors = m_NumAvailProcessors = nCpu + 1;
|
|
m_NumSystemProcessors = nCores;
|
|
}
|
|
|
|
|
|
#elif defined(APPLE)
|
|
size_t len;
|
|
unsigned int ncpu;
|
|
|
|
len = sizeof(ncpu);
|
|
if (sysctlbyname ("hw.physicalcpu_max", &ncpu, &len, NULL, 0) == 0)
|
|
{
|
|
m_NumSystemProcessors = ncpu;
|
|
}
|
|
else
|
|
{
|
|
CryLogAlways("Failed to detect the number of available processors, defaulting to 1");
|
|
m_NumSystemProcessors = 1;
|
|
}
|
|
|
|
if (sysctlbyname ("hw.logicalcpu_max", &ncpu, &len, NULL, 0) == 0)
|
|
{
|
|
m_NumAvailProcessors = m_NumLogicalProcessors = ncpu;
|
|
}
|
|
else
|
|
{
|
|
CryLogAlways("Failed to detect the number of available logical processors, defaulting to 1");
|
|
m_NumAvailProcessors = m_NumLogicalProcessors = 1;
|
|
}
|
|
uint64_t cpu_freq;
|
|
len = sizeof(cpu_freq);
|
|
if (sysctlbyname ("hw.cpufrequency_max", &cpu_freq, &len, NULL, 0) != 0)
|
|
{
|
|
CryLogAlways("Failed to detect cpu frequency , defaulting to 0");
|
|
cpu_freq = 0;
|
|
}
|
|
|
|
// On macs, the processors are always the same model, so we can easily
|
|
// calculate once and apply the settings for all.
|
|
SCpu cpuInfo;
|
|
#if !defined(IOS)
|
|
DetectProcessor(&cpuInfo);
|
|
#endif
|
|
for (int c = 0; c < m_NumAvailProcessors; c++)
|
|
{
|
|
m_Cpu[c] = cpuInfo;
|
|
}
|
|
|
|
#elif defined(AZ_RESTRICTED_PLATFORM)
|
|
#define AZ_RESTRICTED_SECTION CPUDETECT_CPP_SECTION_2
|
|
#include AZ_RESTRICTED_FILE(CPUDetect_cpp)
|
|
#endif
|
|
|
|
|
|
#if defined(WIN32) || defined(WIN64)
|
|
CryLogAlways("Total number of logical processors: %d", m_NumSystemProcessors);
|
|
CryLogAlways("Number of available logical processors: %d", m_NumAvailProcessors);
|
|
|
|
unsigned int numSysCores(1), numProcessCores(1);
|
|
Win32SysInspect::GetNumCPUCores(numSysCores, numProcessCores);
|
|
m_NumSystemProcessors = numSysCores;
|
|
m_NumAvailProcessors = numProcessCores;
|
|
CryLogAlways("Total number of system cores: %d", m_NumSystemProcessors);
|
|
CryLogAlways("Number of cores available to process: %d", m_NumAvailProcessors);
|
|
|
|
#else
|
|
CryLogAlways("Number of system processors: %d", m_NumSystemProcessors);
|
|
CryLogAlways("Number of available processors: %d", m_NumAvailProcessors);
|
|
#endif
|
|
|
|
if (m_NumAvailProcessors > MAX_CPU)
|
|
{
|
|
m_NumAvailProcessors = MAX_CPU;
|
|
}
|
|
|
|
for (int i = 0; i < m_NumAvailProcessors; i++)
|
|
{
|
|
SCpu* p = &m_Cpu[i];
|
|
|
|
CryLogAlways(" ");
|
|
CryLogAlways("Processor %d:", i);
|
|
CryLogAlways(" CPU: %s %s", p->mVendor, p->mCpuType);
|
|
CryLogAlways(" Family: %d, Model: %d, Stepping: %d", p->mFamily, p->mModel, p->mStepping);
|
|
CryLogAlways(" FPU: %s", p->mFpuType);
|
|
CryLogAlways(" 3DNow!: %s", (p->mFeatures & CFI_3DNOW) ? "present" : "not present");
|
|
CryLogAlways(" MMX: %s", (p->mFeatures & CFI_MMX) ? "present" : "not present");
|
|
CryLogAlways(" SSE: %s", (p->mFeatures & CFI_SSE) ? "present" : "not present");
|
|
CryLogAlways(" SSE2: %s", (p->mFeatures & CFI_SSE2) ? "present" : "not present");
|
|
CryLogAlways(" SSE3: %s", (p->mFeatures & CFI_SSE3) ? "present" : "not present");
|
|
CryLogAlways(" SSE4.1: %s", (p->mFeatures& CFI_SSE41) ? "present" : "not present");
|
|
if (p->mbSerialPresent)
|
|
{
|
|
CryLogAlways(" Serial number: %s", p->mSerialNumber);
|
|
}
|
|
else
|
|
{
|
|
CryLogAlways(" Serial number not present or disabled");
|
|
}
|
|
}
|
|
|
|
#ifdef SQRT_TEST
|
|
SMathTest test;
|
|
#endif
|
|
|
|
CryLogAlways(" ");
|
|
|
|
//m_NumPhysicsProcessors = m_NumSystemProcessors;
|
|
for (int i = m_NumPhysicsProcessors = 0; i < m_NumAvailProcessors; i++)
|
|
{
|
|
if (m_Cpu[i].mbPhysical)
|
|
{
|
|
++m_NumPhysicsProcessors;
|
|
}
|
|
}
|
|
|
|
// Set the cpu flags global variable
|
|
g_CpuFlags = 0;
|
|
if (hasMMX())
|
|
{
|
|
g_CpuFlags |= CPUF_MMX;
|
|
}
|
|
if (hasSSE())
|
|
{
|
|
g_CpuFlags |= CPUF_SSE;
|
|
}
|
|
if (hasSSE2())
|
|
{
|
|
g_CpuFlags |= CPUF_SSE2;
|
|
}
|
|
if (hasSSE3())
|
|
{
|
|
g_CpuFlags |= CPUF_SSE3;
|
|
}
|
|
if (hasSSE41())
|
|
{
|
|
g_CpuFlags |= CPUF_SSE41;
|
|
}
|
|
if (has3DNow())
|
|
{
|
|
g_CpuFlags |= CPUF_3DNOW;
|
|
}
|
|
if (hasF16C())
|
|
{
|
|
g_CpuFlags |= CPUF_F16C;
|
|
}
|
|
}
|
|
|