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