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 "common/debug.h"
16 #include "common/string_utils.h"
17
18 namespace angle
19 {
20 namespace
21 {
VendorName(VendorID vendor)22 std::string VendorName(VendorID vendor)
23 {
24 switch (vendor)
25 {
26 case kVendorID_AMD:
27 return "AMD";
28 case kVendorID_ARM:
29 return "ARM";
30 case kVendorID_Broadcom:
31 return "Broadcom";
32 case kVendorID_GOOGLE:
33 return "Google";
34 case kVendorID_ImgTec:
35 return "ImgTec";
36 case kVendorID_Intel:
37 return "Intel";
38 case kVendorID_Kazan:
39 return "Kazan";
40 case kVendorID_NVIDIA:
41 return "NVIDIA";
42 case kVendorID_Qualcomm:
43 return "Qualcomm";
44 case kVendorID_VeriSilicon:
45 return "VeriSilicon";
46 case kVendorID_Vivante:
47 return "Vivante";
48 case kVendorID_VMWare:
49 return "VMWare";
50 default:
51 return "Unknown (" + std::to_string(vendor) + ")";
52 }
53 }
54 } // anonymous namespace
55 GPUDeviceInfo::GPUDeviceInfo() = default;
56
57 GPUDeviceInfo::~GPUDeviceInfo() = default;
58
59 GPUDeviceInfo::GPUDeviceInfo(const GPUDeviceInfo &other) = default;
60
61 SystemInfo::SystemInfo() = default;
62
63 SystemInfo::~SystemInfo() = default;
64
65 SystemInfo::SystemInfo(const SystemInfo &other) = default;
66
hasNVIDIAGPU() const67 bool SystemInfo::hasNVIDIAGPU() const
68 {
69 for (const GPUDeviceInfo &gpu : gpus)
70 {
71 if (IsNVIDIA(gpu.vendorId))
72 {
73 return true;
74 }
75 }
76 return false;
77 }
78
hasIntelGPU() const79 bool SystemInfo::hasIntelGPU() const
80 {
81 for (const GPUDeviceInfo &gpu : gpus)
82 {
83 if (IsIntel(gpu.vendorId))
84 {
85 return true;
86 }
87 }
88 return false;
89 }
90
hasAMDGPU() const91 bool SystemInfo::hasAMDGPU() const
92 {
93 for (const GPUDeviceInfo &gpu : gpus)
94 {
95 if (IsAMD(gpu.vendorId))
96 {
97 return true;
98 }
99 }
100 return false;
101 }
102
IsAMD(VendorID vendorId)103 bool IsAMD(VendorID vendorId)
104 {
105 return vendorId == kVendorID_AMD;
106 }
107
IsARM(VendorID vendorId)108 bool IsARM(VendorID vendorId)
109 {
110 return vendorId == kVendorID_ARM;
111 }
112
IsBroadcom(VendorID vendorId)113 bool IsBroadcom(VendorID vendorId)
114 {
115 return vendorId == kVendorID_Broadcom;
116 }
117
IsImgTec(VendorID vendorId)118 bool IsImgTec(VendorID vendorId)
119 {
120 return vendorId == kVendorID_ImgTec;
121 }
122
IsKazan(VendorID vendorId)123 bool IsKazan(VendorID vendorId)
124 {
125 return vendorId == kVendorID_Kazan;
126 }
127
IsIntel(VendorID vendorId)128 bool IsIntel(VendorID vendorId)
129 {
130 return vendorId == kVendorID_Intel;
131 }
132
IsNVIDIA(VendorID vendorId)133 bool IsNVIDIA(VendorID vendorId)
134 {
135 return vendorId == kVendorID_NVIDIA;
136 }
137
IsQualcomm(VendorID vendorId)138 bool IsQualcomm(VendorID vendorId)
139 {
140 return vendorId == kVendorID_Qualcomm;
141 }
142
IsGoogle(VendorID vendorId)143 bool IsGoogle(VendorID vendorId)
144 {
145 return vendorId == kVendorID_GOOGLE;
146 }
147
IsVeriSilicon(VendorID vendorId)148 bool IsVeriSilicon(VendorID vendorId)
149 {
150 return vendorId == kVendorID_VeriSilicon;
151 }
152
IsVMWare(VendorID vendorId)153 bool IsVMWare(VendorID vendorId)
154 {
155 return vendorId == kVendorID_VMWare;
156 }
157
IsVivante(VendorID vendorId)158 bool IsVivante(VendorID vendorId)
159 {
160 return vendorId == kVendorID_Vivante;
161 }
162
ParseAMDBrahmaDriverVersion(const std::string & content,std::string * version)163 bool ParseAMDBrahmaDriverVersion(const std::string &content, std::string *version)
164 {
165 const size_t begin = content.find_first_of("0123456789");
166 if (begin == std::string::npos)
167 {
168 return false;
169 }
170
171 const size_t end = content.find_first_not_of("0123456789.", begin);
172 if (end == std::string::npos)
173 {
174 *version = content.substr(begin);
175 }
176 else
177 {
178 *version = content.substr(begin, end - begin);
179 }
180 return true;
181 }
182
ParseAMDCatalystDriverVersion(const std::string & content,std::string * version)183 bool ParseAMDCatalystDriverVersion(const std::string &content, std::string *version)
184 {
185 std::istringstream stream(content);
186
187 std::string line;
188 while (std::getline(stream, line))
189 {
190 static const char kReleaseVersion[] = "ReleaseVersion=";
191 if (line.compare(0, std::strlen(kReleaseVersion), kReleaseVersion) != 0)
192 {
193 continue;
194 }
195
196 if (ParseAMDBrahmaDriverVersion(line, version))
197 {
198 return true;
199 }
200 }
201 return false;
202 }
203
ParseMacMachineModel(const std::string & identifier,std::string * type,int32_t * major,int32_t * minor)204 bool ParseMacMachineModel(const std::string &identifier,
205 std::string *type,
206 int32_t *major,
207 int32_t *minor)
208 {
209 size_t numberLoc = identifier.find_first_of("0123456789");
210 if (numberLoc == std::string::npos)
211 {
212 return false;
213 }
214
215 size_t commaLoc = identifier.find(',', numberLoc);
216 if (commaLoc == std::string::npos || commaLoc >= identifier.size())
217 {
218 return false;
219 }
220
221 const char *numberPtr = &identifier[numberLoc];
222 const char *commaPtr = &identifier[commaLoc + 1];
223 char *endPtr = nullptr;
224
225 int32_t majorTmp = static_cast<int32_t>(std::strtol(numberPtr, &endPtr, 10));
226 if (endPtr == numberPtr)
227 {
228 return false;
229 }
230
231 int32_t minorTmp = static_cast<int32_t>(std::strtol(commaPtr, &endPtr, 10));
232 if (endPtr == commaPtr)
233 {
234 return false;
235 }
236
237 *major = majorTmp;
238 *minor = minorTmp;
239 *type = identifier.substr(0, numberLoc);
240
241 return true;
242 }
243
CMDeviceIDToDeviceAndVendorID(const std::string & id,uint32_t * vendorId,uint32_t * deviceId)244 bool CMDeviceIDToDeviceAndVendorID(const std::string &id, uint32_t *vendorId, uint32_t *deviceId)
245 {
246 unsigned int vendor = 0;
247 unsigned int device = 0;
248
249 bool success = id.length() >= 21 && HexStringToUInt(id.substr(8, 4), &vendor) &&
250 HexStringToUInt(id.substr(17, 4), &device);
251
252 *vendorId = vendor;
253 *deviceId = device;
254 return success;
255 }
256
GetDualGPUInfo(SystemInfo * info)257 void GetDualGPUInfo(SystemInfo *info)
258 {
259 ASSERT(!info->gpus.empty());
260
261 // On dual-GPU systems we assume the non-Intel GPU is the graphics one.
262 int active = 0;
263 bool hasIntel = false;
264 for (size_t i = 0; i < info->gpus.size(); ++i)
265 {
266 if (IsIntel(info->gpus[i].vendorId))
267 {
268 hasIntel = true;
269 }
270 if (IsIntel(info->gpus[active].vendorId))
271 {
272 active = static_cast<int>(i);
273 }
274 }
275
276 // Assume that a combination of NVIDIA or AMD with Intel means Optimus or AMD Switchable
277 info->activeGPUIndex = active;
278 info->isOptimus = hasIntel && IsNVIDIA(info->gpus[active].vendorId);
279 info->isAMDSwitchable = hasIntel && IsAMD(info->gpus[active].vendorId);
280 }
281
PrintSystemInfo(const SystemInfo & info)282 void PrintSystemInfo(const SystemInfo &info)
283 {
284 std::cout << info.gpus.size() << " GPUs:\n";
285
286 for (size_t i = 0; i < info.gpus.size(); i++)
287 {
288 const auto &gpu = info.gpus[i];
289
290 std::cout << " " << i << " - " << VendorName(gpu.vendorId) << " device id: 0x" << std::hex
291 << std::uppercase << gpu.deviceId << std::dec << "\n";
292 if (!gpu.driverVendor.empty())
293 {
294 std::cout << " Driver Vendor: " << gpu.driverVendor << "\n";
295 }
296 if (!gpu.driverVersion.empty())
297 {
298 std::cout << " Driver Version: " << gpu.driverVersion << "\n";
299 }
300 if (!gpu.driverDate.empty())
301 {
302 std::cout << " Driver Date: " << gpu.driverDate << "\n";
303 }
304 }
305
306 std::cout << "\n";
307 std::cout << "Active GPU: " << info.activeGPUIndex << "\n";
308
309 std::cout << "\n";
310 std::cout << "Optimus: " << (info.isOptimus ? "true" : "false") << "\n";
311 std::cout << "AMD Switchable: " << (info.isAMDSwitchable ? "true" : "false") << "\n";
312
313 std::cout << "\n";
314 if (!info.machineManufacturer.empty())
315 {
316 std::cout << "Machine Manufacturer: " << info.machineManufacturer << "\n";
317 }
318 if (!info.machineModelName.empty())
319 {
320 std::cout << "Machine Model: " << info.machineModelName << "\n";
321 }
322 if (!info.machineModelVersion.empty())
323 {
324 std::cout << "Machine Model Version: " << info.machineModelVersion << "\n";
325 }
326 std::cout << std::endl;
327 }
328
ParseNvidiaDriverVersion(uint32_t version)329 VersionInfo ParseNvidiaDriverVersion(uint32_t version)
330 {
331 return {
332 version >> 22, // major
333 version >> 14 & 0xff, // minor
334 version >> 6 & 0xff, // subMinor
335 version & 0x3f // patch
336 };
337 }
338 } // namespace angle
339