SystemInfo.cpp (10971B)
1 // 2 // Copyright 2013 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // SystemInfo.cpp: implementation of the system-agnostic parts of SystemInfo.h 8 9 #include "gpu_info_util/SystemInfo.h" 10 11 #include <cstring> 12 #include <iostream> 13 #include <sstream> 14 15 #include "anglebase/no_destructor.h" 16 #include "common/debug.h" 17 #include "common/string_utils.h" 18 #include "common/system_utils.h" 19 20 namespace angle 21 { 22 namespace 23 { 24 constexpr char kANGLEPreferredDeviceEnv[] = "ANGLE_PREFERRED_DEVICE"; 25 } 26 27 std::string VendorName(VendorID vendor) 28 { 29 switch (vendor) 30 { 31 case kVendorID_AMD: 32 return "AMD"; 33 case kVendorID_ARM: 34 return "ARM"; 35 case kVendorID_Broadcom: 36 return "Broadcom"; 37 case kVendorID_GOOGLE: 38 return "Google"; 39 case kVendorID_ImgTec: 40 return "ImgTec"; 41 case kVendorID_Intel: 42 return "Intel"; 43 case kVendorID_Kazan: 44 return "Kazan"; 45 case kVendorID_NVIDIA: 46 return "NVIDIA"; 47 case kVendorID_Qualcomm: 48 return "Qualcomm"; 49 case kVendorID_VeriSilicon: 50 return "VeriSilicon"; 51 case kVendorID_Vivante: 52 return "Vivante"; 53 case kVendorID_VMWare: 54 return "VMWare"; 55 case kVendorID_Apple: 56 return "Apple"; 57 case kVendorID_Microsoft: 58 return "Microsoft"; 59 default: 60 return "Unknown (" + std::to_string(vendor) + ")"; 61 } 62 } 63 64 GPUDeviceInfo::GPUDeviceInfo() = default; 65 66 GPUDeviceInfo::~GPUDeviceInfo() = default; 67 68 GPUDeviceInfo::GPUDeviceInfo(const GPUDeviceInfo &other) = default; 69 70 SystemInfo::SystemInfo() = default; 71 72 SystemInfo::~SystemInfo() = default; 73 74 SystemInfo::SystemInfo(const SystemInfo &other) = default; 75 76 bool SystemInfo::hasNVIDIAGPU() const 77 { 78 for (const GPUDeviceInfo &gpu : gpus) 79 { 80 if (IsNVIDIA(gpu.vendorId)) 81 { 82 return true; 83 } 84 } 85 return false; 86 } 87 88 bool SystemInfo::hasIntelGPU() const 89 { 90 for (const GPUDeviceInfo &gpu : gpus) 91 { 92 if (IsIntel(gpu.vendorId)) 93 { 94 return true; 95 } 96 } 97 return false; 98 } 99 100 bool SystemInfo::hasAMDGPU() const 101 { 102 for (const GPUDeviceInfo &gpu : gpus) 103 { 104 if (IsAMD(gpu.vendorId)) 105 { 106 return true; 107 } 108 } 109 return false; 110 } 111 112 std::optional<size_t> SystemInfo::getPreferredGPUIndex() const 113 { 114 std::string device = GetPreferredDeviceString(); 115 if (!device.empty()) 116 { 117 for (size_t i = 0; i < gpus.size(); ++i) 118 { 119 std::string vendor = VendorName(gpus[i].vendorId); 120 ToLower(&vendor); 121 if (vendor == device) 122 return i; 123 } 124 } 125 return std::nullopt; 126 } 127 128 bool IsAMD(VendorID vendorId) 129 { 130 return vendorId == kVendorID_AMD; 131 } 132 133 bool IsARM(VendorID vendorId) 134 { 135 return vendorId == kVendorID_ARM; 136 } 137 138 bool IsBroadcom(VendorID vendorId) 139 { 140 return vendorId == kVendorID_Broadcom; 141 } 142 143 bool IsImgTec(VendorID vendorId) 144 { 145 return vendorId == kVendorID_ImgTec; 146 } 147 148 bool IsKazan(VendorID vendorId) 149 { 150 return vendorId == kVendorID_Kazan; 151 } 152 153 bool IsIntel(VendorID vendorId) 154 { 155 return vendorId == kVendorID_Intel; 156 } 157 158 bool IsNVIDIA(VendorID vendorId) 159 { 160 return vendorId == kVendorID_NVIDIA; 161 } 162 163 bool IsQualcomm(VendorID vendorId) 164 { 165 return vendorId == kVendorID_Qualcomm; 166 } 167 168 bool IsGoogle(VendorID vendorId) 169 { 170 return vendorId == kVendorID_GOOGLE; 171 } 172 173 bool IsVeriSilicon(VendorID vendorId) 174 { 175 return vendorId == kVendorID_VeriSilicon; 176 } 177 178 bool IsVMWare(VendorID vendorId) 179 { 180 return vendorId == kVendorID_VMWare; 181 } 182 183 bool IsVivante(VendorID vendorId) 184 { 185 return vendorId == kVendorID_Vivante; 186 } 187 188 bool IsApple(VendorID vendorId) 189 { 190 return vendorId == kVendorID_Apple; 191 } 192 193 bool IsMicrosoft(VendorID vendorId) 194 { 195 return vendorId == kVendorID_Microsoft; 196 } 197 198 bool ParseAMDBrahmaDriverVersion(const std::string &content, std::string *version) 199 { 200 const size_t begin = content.find_first_of("0123456789"); 201 if (begin == std::string::npos) 202 { 203 return false; 204 } 205 206 const size_t end = content.find_first_not_of("0123456789.", begin); 207 if (end == std::string::npos) 208 { 209 *version = content.substr(begin); 210 } 211 else 212 { 213 *version = content.substr(begin, end - begin); 214 } 215 return true; 216 } 217 218 bool ParseAMDCatalystDriverVersion(const std::string &content, std::string *version) 219 { 220 std::istringstream stream(content); 221 222 std::string line; 223 while (std::getline(stream, line)) 224 { 225 static const char kReleaseVersion[] = "ReleaseVersion="; 226 if (line.compare(0, std::strlen(kReleaseVersion), kReleaseVersion) != 0) 227 { 228 continue; 229 } 230 231 if (ParseAMDBrahmaDriverVersion(line, version)) 232 { 233 return true; 234 } 235 } 236 return false; 237 } 238 239 bool ParseMacMachineModel(const std::string &identifier, 240 std::string *type, 241 int32_t *major, 242 int32_t *minor) 243 { 244 size_t numberLoc = identifier.find_first_of("0123456789"); 245 if (numberLoc == std::string::npos) 246 { 247 return false; 248 } 249 250 size_t commaLoc = identifier.find(',', numberLoc); 251 if (commaLoc == std::string::npos || commaLoc >= identifier.size()) 252 { 253 return false; 254 } 255 256 const char *numberPtr = &identifier[numberLoc]; 257 const char *commaPtr = &identifier[commaLoc + 1]; 258 char *endPtr = nullptr; 259 260 int32_t majorTmp = static_cast<int32_t>(std::strtol(numberPtr, &endPtr, 10)); 261 if (endPtr == numberPtr) 262 { 263 return false; 264 } 265 266 int32_t minorTmp = static_cast<int32_t>(std::strtol(commaPtr, &endPtr, 10)); 267 if (endPtr == commaPtr) 268 { 269 return false; 270 } 271 272 *major = majorTmp; 273 *minor = minorTmp; 274 *type = identifier.substr(0, numberLoc); 275 276 return true; 277 } 278 279 bool CMDeviceIDToDeviceAndVendorID(const std::string &id, uint32_t *vendorId, uint32_t *deviceId) 280 { 281 unsigned int vendor = 0; 282 unsigned int device = 0; 283 284 bool success = id.length() >= 21 && HexStringToUInt(id.substr(8, 4), &vendor) && 285 HexStringToUInt(id.substr(17, 4), &device); 286 287 *vendorId = vendor; 288 *deviceId = device; 289 return success; 290 } 291 292 void GetDualGPUInfo(SystemInfo *info) 293 { 294 ASSERT(!info->gpus.empty()); 295 296 // On dual-GPU systems we assume the non-Intel GPU is the graphics one. 297 // TODO: this is incorrect and problematic. activeGPUIndex must be removed if it cannot be 298 // determined correctly. A potential solution is to create an OpenGL context and parse 299 // GL_VENDOR. Currently, our test infrastructure is relying on this information and incorrectly 300 // applies test expectations on dual-GPU systems when the Intel GPU is active. 301 // http://anglebug.com/6174. 302 int active = 0; 303 bool hasIntel = false; 304 for (size_t i = 0; i < info->gpus.size(); ++i) 305 { 306 if (IsIntel(info->gpus[i].vendorId)) 307 { 308 hasIntel = true; 309 } 310 if (IsIntel(info->gpus[active].vendorId)) 311 { 312 active = static_cast<int>(i); 313 } 314 } 315 316 // Assume that a combination of NVIDIA or AMD with Intel means Optimus or AMD Switchable 317 info->activeGPUIndex = active; 318 info->isOptimus = hasIntel && IsNVIDIA(info->gpus[active].vendorId); 319 info->isAMDSwitchable = hasIntel && IsAMD(info->gpus[active].vendorId); 320 } 321 322 void PrintSystemInfo(const SystemInfo &info) 323 { 324 std::cout << info.gpus.size() << " GPUs:\n"; 325 326 for (size_t i = 0; i < info.gpus.size(); i++) 327 { 328 const auto &gpu = info.gpus[i]; 329 330 std::cout << " " << i << " - " << VendorName(gpu.vendorId) << " device id: 0x" << std::hex 331 << std::uppercase << gpu.deviceId << std::dec << ", revision id: 0x" << std::hex 332 << std::uppercase << gpu.revisionId << std::dec << ", system device id: 0x" 333 << std::hex << std::uppercase << gpu.systemDeviceId << std::dec << "\n"; 334 if (!gpu.driverVendor.empty()) 335 { 336 std::cout << " Driver Vendor: " << gpu.driverVendor << "\n"; 337 } 338 if (!gpu.driverVersion.empty()) 339 { 340 std::cout << " Driver Version: " << gpu.driverVersion << "\n"; 341 } 342 if (!gpu.driverDate.empty()) 343 { 344 std::cout << " Driver Date: " << gpu.driverDate << "\n"; 345 } 346 if (gpu.detailedDriverVersion.major != 0 || gpu.detailedDriverVersion.minor != 0 || 347 gpu.detailedDriverVersion.subMinor != 0 || gpu.detailedDriverVersion.patch != 0) 348 { 349 std::cout << " Detailed Driver Version:\n" 350 << " major: " << gpu.detailedDriverVersion.major 351 << " minor: " << gpu.detailedDriverVersion.minor 352 << " subMinor: " << gpu.detailedDriverVersion.subMinor 353 << " patch: " << gpu.detailedDriverVersion.patch << "\n"; 354 } 355 } 356 357 std::cout << "\n"; 358 std::cout << "Active GPU: " << info.activeGPUIndex << "\n"; 359 360 std::cout << "\n"; 361 std::cout << "Optimus: " << (info.isOptimus ? "true" : "false") << "\n"; 362 std::cout << "AMD Switchable: " << (info.isAMDSwitchable ? "true" : "false") << "\n"; 363 std::cout << "Mac Switchable: " << (info.isMacSwitchable ? "true" : "false") << "\n"; 364 std::cout << "Needs EAGL on Mac: " << (info.needsEAGLOnMac ? "true" : "false") << "\n"; 365 366 std::cout << "\n"; 367 if (!info.machineManufacturer.empty()) 368 { 369 std::cout << "Machine Manufacturer: " << info.machineManufacturer << "\n"; 370 } 371 if (info.androidSdkLevel != 0) 372 { 373 std::cout << "Android SDK Level: " << info.androidSdkLevel << "\n"; 374 } 375 if (!info.machineModelName.empty()) 376 { 377 std::cout << "Machine Model: " << info.machineModelName << "\n"; 378 } 379 if (!info.machineModelVersion.empty()) 380 { 381 std::cout << "Machine Model Version: " << info.machineModelVersion << "\n"; 382 } 383 std::cout << std::endl; 384 } 385 386 VersionInfo ParseNvidiaDriverVersion(uint32_t version) 387 { 388 return { 389 version >> 22, // major 390 version >> 14 & 0xff, // minor 391 version >> 6 & 0xff, // subMinor 392 version & 0x3f // patch 393 }; 394 } 395 396 uint64_t GetSystemDeviceIdFromParts(uint32_t highPart, uint32_t lowPart) 397 { 398 return (static_cast<uint64_t>(highPart) << 32) | lowPart; 399 } 400 401 uint32_t GetSystemDeviceIdHighPart(uint64_t systemDeviceId) 402 { 403 return (systemDeviceId >> 32) & 0xffffffff; 404 } 405 406 uint32_t GetSystemDeviceIdLowPart(uint64_t systemDeviceId) 407 { 408 return systemDeviceId & 0xffffffff; 409 } 410 411 std::string GetPreferredDeviceString() 412 { 413 std::string device = angle::GetEnvironmentVar(kANGLEPreferredDeviceEnv); 414 ToLower(&device); 415 return device; 416 } 417 418 } // namespace angle