CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Common/ArmCPUDetect.cpp
Views: 1401
// Copyright (C) 2003 Dolphin Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official SVN repository and contact information can be found at15// http://code.google.com/p/dolphin-emu/1617#include "ppsspp_config.h"1819#include <sstream>2021#if PPSSPP_PLATFORM(IOS) || PPSSPP_PLATFORM(MAC)22#include <sys/sysctl.h>23#endif242526#if PPSSPP_ARCH(ARM) || PPSSPP_ARCH(ARM64)2728#if PPSSPP_ARCH(ARM)29#include "ext/cpu_features/include/cpuinfo_arm.h"3031#if defined(CPU_FEATURES_OS_LINUX)32#define USE_CPU_FEATURES 133#endif34#elif PPSSPP_ARCH(ARM64)35#include "ext/cpu_features/include/cpuinfo_aarch64.h"3637#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) || defined(CPU_FEATURES_OS_WINDOWS)38#define USE_CPU_FEATURES 139#endif40#endif4142#include <cstring>43#include <ctype.h>4445#include "Common/CommonTypes.h"46#include "Common/CPUDetect.h"47#include "Common/StringUtils.h"48#include "Common/File/FileUtil.h"49#include "Common/Data/Encoding/Utf8.h"5051#if PPSSPP_PLATFORM(WINDOWS)52#if PPSSPP_PLATFORM(UWP)53// TODO: Maybe we can move the implementation here?54std::string GetCPUBrandString();55#else56// No CPUID on ARM, so we'll have to read the registry57#include "Common/CommonWindows.h"58std::string GetCPUBrandString() {59std::string cpu_string;6061HKEY key;62LSTATUS result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &key);63if (result == ERROR_SUCCESS) {64DWORD size = 0;65DWORD type = REG_SZ;66RegQueryValueEx(key, L"ProcessorNameString", NULL, &type, NULL, &size);67LPBYTE buff = (LPBYTE)malloc(size);68if (buff != NULL) {69RegQueryValueEx(key, L"ProcessorNameString", NULL, &type, buff, &size);70cpu_string = ConvertWStringToUTF8((wchar_t*)buff);71free(buff);72}73RegCloseKey(key);74}7576if (cpu_string.empty())77return "Unknown";78else79return cpu_string;80}81#endif82#endif8384// Only Linux platforms have /proc/cpuinfo85#if PPSSPP_PLATFORM(LINUX)86const char procfile[] = "/proc/cpuinfo";87// https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu88const char syscpupresentfile[] = "/sys/devices/system/cpu/present";8990std::string GetCPUString() {91std::string procdata;92bool readSuccess = File::ReadSysTextFileToString(Path(procfile), &procdata);93std::istringstream file(procdata);94std::string cpu_string;9596if (readSuccess) {97std::string line, marker = "Hardware\t: ";98while (std::getline(file, line)) {99if (line.find(marker) != std::string::npos) {100cpu_string = line.substr(marker.length());101}102}103}104105if (cpu_string.empty())106cpu_string = "Unknown";107else if (cpu_string.back() == '\n')108cpu_string.pop_back(); // Drop the new-line character109110return cpu_string;111}112113std::string GetCPUBrandString() {114std::string procdata;115bool readSuccess = File::ReadSysTextFileToString(Path(procfile), &procdata);116std::istringstream file(procdata);117std::string brand_string;118119if (readSuccess) {120std::string line, marker = "Processor\t: ";121while (std::getline(file, line)) {122if (line.find(marker) != std::string::npos) {123brand_string = line.substr(marker.length());124if (brand_string.length() != 0 && !isdigit(brand_string[0])) {125break;126}127}128}129}130131if (brand_string.empty())132brand_string = "Unknown";133else if (brand_string.back() == '\n')134brand_string.pop_back(); // Drop the new-line character135136return brand_string;137}138139unsigned char GetCPUImplementer()140{141std::string line, marker = "CPU implementer\t: ";142unsigned char implementer = 0;143144std::string procdata;145if (!File::ReadSysTextFileToString(Path(procfile), &procdata))146return 0;147std::istringstream file(procdata);148149while (std::getline(file, line))150{151if (line.find(marker) != std::string::npos)152{153line = line.substr(marker.length());154sscanf(line.c_str(), "0x%02hhx", &implementer);155break;156}157}158159return implementer;160}161162unsigned short GetCPUPart()163{164std::string line, marker = "CPU part\t: ";165unsigned short part = 0;166167std::string procdata;168if (!File::ReadSysTextFileToString(Path(procfile), &procdata))169return 0;170std::istringstream file(procdata);171172while (std::getline(file, line))173{174if (line.find(marker) != std::string::npos)175{176line = line.substr(marker.length());177sscanf(line.c_str(), "0x%03hx", &part);178break;179}180}181182return part;183}184185bool CheckCPUFeature(const std::string& feature)186{187std::string line, marker = "Features\t: ";188189std::string procdata;190if (!File::ReadSysTextFileToString(Path(procfile), &procdata))191return false;192std::istringstream file(procdata);193while (std::getline(file, line))194{195if (line.find(marker) != std::string::npos)196{197std::stringstream line_stream(line);198std::string token;199while (std::getline(line_stream, token, ' '))200{201if (token == feature)202return true;203}204}205}206207return false;208}209210int GetCoreCount()211{212std::string line, marker = "processor\t: ";213int cores = 1;214215std::string presentData;216bool presentSuccess = File::ReadSysTextFileToString(Path(syscpupresentfile), &presentData);217std::istringstream presentFile(presentData);218219if (presentSuccess) {220int low, high, found;221std::getline(presentFile, line);222found = sscanf(line.c_str(), "%d-%d", &low, &high);223if (found == 1)224return 1;225if (found == 2)226return high - low + 1;227}228229std::string procdata;230if (!File::ReadSysTextFileToString(Path(procfile), &procdata))231return 1;232std::istringstream file(procdata);233234while (std::getline(file, line))235{236if (line.find(marker) != std::string::npos)237++cores;238}239240return cores;241}242#endif243244CPUInfo cpu_info;245246CPUInfo::CPUInfo() {247Detect();248}249250// Detects the various cpu features251void CPUInfo::Detect()252{253// Set some defaults here254HTT = false;255#if PPSSPP_ARCH(ARM64)256OS64bit = true;257CPU64bit = true;258Mode64bit = true;259#else260OS64bit = false;261CPU64bit = false;262Mode64bit = false;263#endif264vendor = VENDOR_ARM;265logical_cpu_count = 1;266267// Get the information about the CPU268#if !PPSSPP_PLATFORM(LINUX)269bool isVFP3 = false;270bool isVFP4 = false;271#if PPSSPP_PLATFORM(IOS) || PPSSPP_PLATFORM(MAC)272#if PPSSPP_PLATFORM(IOS)273isVFP3 = true;274// Check for swift arch (VFP4)275#ifdef __ARM_ARCH_7S__276isVFP4 = true;277#endif278#endif // PPSSPP_PLATFORM(IOS)279size_t sz = 0x41; // char brand_string[0x41]280if (sysctlbyname("machdep.cpu.brand_string", brand_string, &sz, nullptr, 0) != 0) {281strcpy(brand_string, "Unknown");282}283int num = 0;284sz = sizeof(num);285if (sysctlbyname("hw.physicalcpu_max", &num, &sz, nullptr, 0) == 0) {286num_cores = num;287sz = sizeof(num);288if (sysctlbyname("hw.logicalcpu_max", &num, &sz, nullptr, 0) == 0) {289logical_cpu_count = num / num_cores;290}291}292#elif PPSSPP_PLATFORM(WINDOWS)293truncate_cpy(brand_string, GetCPUBrandString().c_str());294isVFP3 = true;295isVFP4 = false;296SYSTEM_INFO sysInfo;297GetSystemInfo(&sysInfo);298num_cores = sysInfo.dwNumberOfProcessors;299#else // !PPSSPP_PLATFORM(IOS) && !PPSSPP_PLATFORM(MAC) && !PPSSPP_PLATFORM(WINDOWS)300strcpy(brand_string, "Unknown");301num_cores = 1;302#endif303truncate_cpy(cpu_string, brand_string);304// Hardcode this for now305bSwp = true;306bHalf = true;307bThumb = false;308bFastMult = true;309bVFP = true;310bEDSP = true;311bThumbEE = isVFP3;312bNEON = isVFP3;313bVFPv3 = isVFP3;314bTLS = true;315bVFPv4 = isVFP4;316bIDIVa = isVFP4;317bIDIVt = isVFP4;318bFP = false;319bASIMD = false;320#else // PPSSPP_PLATFORM(LINUX)321truncate_cpy(cpu_string, GetCPUString().c_str());322truncate_cpy(brand_string, GetCPUBrandString().c_str());323324bSwp = CheckCPUFeature("swp");325bHalf = CheckCPUFeature("half");326bThumb = CheckCPUFeature("thumb");327bFastMult = CheckCPUFeature("fastmult");328bVFP = CheckCPUFeature("vfp");329bEDSP = CheckCPUFeature("edsp");330bThumbEE = CheckCPUFeature("thumbee");331bNEON = CheckCPUFeature("neon");332bVFPv3 = CheckCPUFeature("vfpv3");333bTLS = CheckCPUFeature("tls");334bVFPv4 = CheckCPUFeature("vfpv4");335bIDIVa = CheckCPUFeature("idiva");336bIDIVt = CheckCPUFeature("idivt");337// Qualcomm Krait supports IDIVA but it doesn't report it. Check for krait (0x4D = Plus, 0x6F = Pro).338unsigned short CPUPart = GetCPUPart();339if (GetCPUImplementer() == 0x51 && (CPUPart == 0x4D || CPUPart == 0x6F))340bIDIVa = bIDIVt = true;341// Vero4k supports NEON but doesn't report it. Check for Arm Cortex-A53.342if (GetCPUImplementer() == 0x41 && CPUPart == 0xd03)343bNEON = true;344// These two require ARMv8 or higher345bFP = CheckCPUFeature("fp");346bASIMD = CheckCPUFeature("asimd");347num_cores = GetCoreCount();348#endif349#if PPSSPP_ARCH(ARM64)350// Whether the above detection failed or not, on ARM64 we do have ASIMD/NEON.351bNEON = true;352bASIMD = true;353#endif354355#if PPSSPP_ARCH(ARM) && defined(USE_CPU_FEATURES)356cpu_features::ArmInfo info = cpu_features::GetArmInfo();357bSwp = info.features.swp;358bHalf = info.features.half;359bThumb = info.features.thumb;360bFastMult = info.features.fastmult;361bEDSP = info.features.edsp;362bThumbEE = info.features.thumbee;363bNEON = info.features.neon;364bTLS = info.features.tls;365bVFP = info.features.vfp;366bVFPv3 = info.features.vfpv3;367bVFPv4 = info.features.vfpv4;368bIDIVa = info.features.idiva;369bIDIVt = info.features.idivt;370#endif371#if PPSSPP_ARCH(ARM64) && defined(USE_CPU_FEATURES)372cpu_features::Aarch64Info info = cpu_features::GetAarch64Info();373bFP = info.features.fp;374bASIMD = info.features.asimd;375bSVE = info.features.sve;376bSVE2 = info.features.sve2;377bFRINT = info.features.frint;378#endif379}380381std::vector<std::string> CPUInfo::Features() {382std::vector<std::string> features;383384struct Flag {385bool &flag;386const char *str;387};388const Flag list[] = {389{ bSwp, "SWP" },390{ bHalf, "Half" },391{ bThumb, "Thumb" },392{ bFastMult, "FastMult" },393{ bEDSP, "EDSP" },394{ bThumbEE, "ThumbEE" },395{ bTLS, "TLS" },396{ bVFP, "VFP" },397{ bVFPv3, "VFPv3" },398{ bVFPv4, "VFPv4" },399{ bNEON, "NEON" },400{ bIDIVa, "IDIVa" },401{ bIDIVt, "IDIVt" },402{ bFRINT, "FRINT" },403{ bSVE, "SVE" },404{ bSVE2, "SVE2" },405{ CPU64bit, "64-bit" },406};407408for (auto &item : list) {409if (item.flag) {410features.push_back(item.str);411}412}413414return features;415}416417// Turn the cpu info into a string we can show418std::string CPUInfo::Summarize() {419std::string sum;420if (num_cores == 1)421sum = StringFromFormat("%s, %d core", cpu_string, num_cores);422else423sum = StringFromFormat("%s, %d cores", cpu_string, num_cores);424425auto features = Features();426for (std::string &feature : features) {427sum += ", " + feature;428}429return sum;430}431432#endif // PPSSPP_ARCH(ARM) || PPSSPP_ARCH(ARM64)433434435