Improve CPU feature check

Damn exit on SSSE3 failure
Check AVX for Intel processors
This commit is contained in:
Nekotekina 2017-07-18 15:21:29 +03:00
parent 3f6b24d33a
commit 0fa148e65e
10 changed files with 121 additions and 97 deletions

View File

@ -12,6 +12,7 @@
#include "File.h"
#include "Log.h"
#include "mutex.h"
#include "sysinfo.h"
#include "VirtualMemory.h"
#ifdef _MSC_VER
@ -377,6 +378,20 @@ jit_compiler::jit_compiler(const std::unordered_map<std::string, std::uintptr_t>
if (m_cpu.empty())
{
m_cpu = llvm::sys::getHostCPUName();
if (m_cpu == "sandybridge" ||
m_cpu == "ivybridge" ||
m_cpu == "haswell" ||
m_cpu == "broadwell" ||
m_cpu == "skylake" ||
m_cpu == "skylake-avx512" ||
m_cpu == "cannonlake")
{
if (!utils::has_avx())
{
m_cpu = "nehalem";
}
}
}
std::string result;

50
Utilities/sysinfo.cpp Normal file
View File

@ -0,0 +1,50 @@
#include "sysinfo.h"
#include "StrFmt.h"
#ifdef _WIN32
#include "windows.h"
#else
#include <unistd.h>
#endif
std::string utils::get_system_info()
{
std::string result;
std::string brand;
if (get_cpuid(0x80000000, 0)[0] >= 0x80000004)
{
for (u32 i = 0; i < 3; i++)
{
brand.append(reinterpret_cast<const char*>(get_cpuid(0x80000002 + i, 0).data()), 16);
}
}
else
{
brand = "Unknown CPU";
}
brand.erase(0, brand.find_first_not_of(' '));
brand.erase(brand.find_last_not_of(' ') + 1);
while (auto found = brand.find(" ") + 1)
{
brand.erase(brand.begin() + found);
}
#ifdef _WIN32
::SYSTEM_INFO sysInfo;
::GetNativeSystemInfo(&sysInfo);
::MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(memInfo);
::GlobalMemoryStatusEx(&memInfo);
const u32 num_proc = sysInfo.dwNumberOfProcessors;
const u64 mem_total = memInfo.ullTotalPhys;
#else
const u32 num_proc = ::sysconf(_SC_NPROCESSORS_ONLN);
const u64 mem_total = ::sysconf(_SC_PHYS_PAGES) * ::sysconf(_SC_PAGE_SIZE);
#endif
fmt::append(result, "%s | %d Threads | %.2f GiB RAM", brand, num_proc, mem_total / (1024.0f * 1024 * 1024));
return result;
}

35
Utilities/sysinfo.h Normal file
View File

@ -0,0 +1,35 @@
#pragma once
#include "types.h"
#include <string>
namespace utils
{
inline std::array<u32, 4> get_cpuid(u32 func, u32 subfunc)
{
int regs[4];
#ifdef _MSC_VER
__cpuidex(regs, func, subfunc);
#else
__asm__ volatile("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3]) : "a" (func), "c" (subfunc));
#endif
return {0u+regs[0], 0u+regs[1], 0u+regs[2], 0u+regs[3]};
}
inline bool has_ssse3()
{
return get_cpuid(0, 0)[0] >= 0x1 && get_cpuid(1, 0)[2] & 0x200;
}
inline bool has_avx()
{
return get_cpuid(0, 0)[0] >= 0x1 && get_cpuid(1, 0)[2] & 0x10000000;
}
inline bool has_rtm()
{
return get_cpuid(0, 0)[0] >= 0x7 && get_cpuid(7, 0)[1] & 0x800;
}
std::string get_system_info();
}

View File

@ -102,6 +102,13 @@
<ClCompile Include="..\Utilities\StrFmt.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\Utilities\sysinfo.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug - MemLeak|x64'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\Utilities\Thread.cpp" />
<ClCompile Include="..\Utilities\version.cpp" />
<ClCompile Include="..\Utilities\VirtualMemory.cpp" />
@ -426,6 +433,7 @@
<ClInclude Include="..\Utilities\rXml.h" />
<ClInclude Include="..\Utilities\StrFmt.h" />
<ClInclude Include="..\Utilities\StrUtil.h" />
<ClInclude Include="..\Utilities\sysinfo.h" />
<ClInclude Include="..\Utilities\Thread.h" />
<ClInclude Include="..\Utilities\Timer.h" />
<ClInclude Include="..\Utilities\types.h" />

View File

@ -923,6 +923,9 @@
<ClCompile Include="Emu\Cell\lv2\sys_ss.cpp">
<Filter>Emu\Cell\lv2</Filter>
</ClCompile>
<ClCompile Include="..\Utilities\sysinfo.cpp">
<Filter>Utilities</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Crypto\aes.h">
@ -1777,5 +1780,8 @@
<ClInclude Include="..\Utilities\CRC.h">
<Filter>Utilities</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\sysinfo.h">
<Filter>Utilities</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -1201,7 +1201,6 @@
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DLLVM_AVAILABLE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE "-I.\..\Vulkan\Vulkan-LoaderAndValidationLayers\include" "-I.\.." "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras"</Command>
</CustomBuild>
<ClInclude Include="rpcs3qt\system_info.h" />
<ClInclude Include="rpcs3qt\game_list.h" />
<ClInclude Include="rpcs3qt\game_list_grid_delegate.h" />
<ClInclude Include="resource.h" />

View File

@ -514,9 +514,6 @@
<ClInclude Include="QTGeneratedFiles\ui_welcome_dialog.h">
<Filter>Generated Files</Filter>
</ClInclude>
<ClInclude Include="rpcs3qt\system_info.h">
<Filter>Gui</Filter>
</ClInclude>
<ClInclude Include="rpcs3qt\game_list.h">
<Filter>Gui</Filter>
</ClInclude>

View File

@ -2,7 +2,7 @@
#include <stdafx.h>
#include "rpcs3_version.h"
#include "system_info.h"
#include "Utilities/sysinfo.h"
#include <QMenu>
#include <QActionGroup>
@ -40,7 +40,7 @@ struct gui_listener : logs::listener
read = new packet;
last = new packet;
read->next = last.load();
last->msg = fmt::format("RPCS3 v%s\n%s\n", rpcs3::version.to_string(), System_Info::getCPU().first);
last->msg = fmt::format("RPCS3 v%s\n%s\n", rpcs3::version.to_string(), utils::get_system_info());
// Self-registration
logs::listener::add(this);

View File

@ -41,7 +41,7 @@
#include "Utilities/StrUtil.h"
#include "rpcs3_version.h"
#include "system_info.h"
#include "Utilities/sysinfo.h"
#include "ui_main_window.h"
@ -112,13 +112,13 @@ void main_window::Init()
RequestGlobalStylesheetChange(guiSettings->GetCurrentStylesheetPath());
ConfigureGuiFromSettings(true);
if (!System_Info::getCPU().second)
if (!utils::has_ssse3())
{
QMessageBox::critical(this, "SSSE3 Error (with three S, not two)",
"Your system does not meet the minimum requirements needed to run RPCS3.\n"
"Your CPU does not support SSSE3 (with three S, not two).\n"
"\n"
"No games will run and RPCS3 will crash if you try.");
"Your CPU does not support SSSE3 (with three S, not two).\n");
std::exit(EXIT_FAILURE);
}
}

View File

@ -1,86 +0,0 @@
#pragma once
#include <regex>
#ifdef _WIN32
#include "windows.h"
#include <bitset>
typedef unsigned __int32 uint32_t;
#else
#include <stdint.h>
#include <unistd.h>
#include <cmath>
#endif
class System_Info
{
class CPUID {
uint32_t regs[4];
public:
explicit CPUID(uint32_t func, uint32_t subfunc) {
#ifdef _WIN32
__cpuidex((int *)regs, func, subfunc);
#else
asm volatile
("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
: "a" (func), "c" (subfunc));
// ECX is set to zero for CPUID function 4
#endif
}
const uint32_t &EAX() const { return regs[0]; }
const uint32_t &EBX() const { return regs[1]; }
const uint32_t &ECX() const { return regs[2]; }
const uint32_t &EDX() const { return regs[3]; }
const uint32_t *data() const { return &regs[0]; }
};
public:
/**
Retrieves various information about the system's hardware
@return a pair consisting of the compiled information as string value and a bool for SSSE3 compatibility
*/
static const std::pair<std::string, bool> getCPU()
{
int nIds_ = 0;
int nExIds_ = 0;
char brand[0x40];
std::bitset<32> cpu_capabilities = 0;
nIds_ = CPUID(0, 0).EAX();
// load bitset with flags for function 0x00000001
if (nIds_ >= 1)
{
cpu_capabilities = CPUID(1, 0).ECX();
}
nExIds_ = CPUID(0x80000000, 0).EAX();
memset(brand, 0, sizeof(brand));
if (nExIds_ >= 0x80000004)
{
memcpy(brand, CPUID(0x80000002, 0).data(), 16);
memcpy(brand + 16, CPUID(0x80000003, 0).data(), 16);
memcpy(brand + 32, CPUID(0x80000004, 0).data(), 16);
}
bool supports_ssse3 = cpu_capabilities[9];
std::string s_sysInfo = fmt::format("%s | SSSE3 %s", std::regex_replace(brand, std::regex("^ +"), ""), supports_ssse3 ? "Supported" : "Not Supported");
#ifdef _WIN32
SYSTEM_INFO sysInfo;
GetNativeSystemInfo(&sysInfo);
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(memInfo);
GlobalMemoryStatusEx(&memInfo);
s_sysInfo += fmt::format(" | %d Threads | %.2f GB RAM", sysInfo.dwNumberOfProcessors, (float)memInfo.ullTotalPhys / std::pow(1024.0f, 3));
#else
long mem_total = sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGE_SIZE);
s_sysInfo += fmt::format(" | %d Threads | %.2f GB RAM", sysconf(_SC_NPROCESSORS_ONLN), (float)mem_total / std::pow(1024.0f, 3));
#endif
return std::pair<std::string, bool>(s_sysInfo, supports_ssse3);
};
};