• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/system/sys_info.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <windows.h>
10 
11 #include <algorithm>
12 #include <bit>
13 #include <limits>
14 #include <type_traits>
15 #include <vector>
16 
17 #include "base/check.h"
18 #include "base/files/file_path.h"
19 #include "base/notreached.h"
20 #include "base/numerics/safe_conversions.h"
21 #include "base/process/process_metrics.h"
22 #include "base/strings/string_util.h"
23 #include "base/strings/stringprintf.h"
24 #include "base/strings/sys_string_conversions.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "base/threading/scoped_blocking_call.h"
27 #include "base/win/registry.h"
28 #include "base/win/windows_version.h"
29 #include "third_party/abseil-cpp/absl/container/inlined_vector.h"
30 
31 namespace {
32 
33 // Returns the power efficiency levels of physical cores or empty vector on
34 // failure. The BYTE value of the element is the relative efficiency rank among
35 // all physical cores, where 0 is the most efficient, 1 is the second most
36 // efficient, and so on.
GetCoreEfficiencyClasses()37 std::vector<BYTE> GetCoreEfficiencyClasses() {
38   const DWORD kReservedSize =
39       sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) * 64;
40   absl::InlinedVector<BYTE, kReservedSize> buffer;
41   buffer.resize(kReservedSize);
42   DWORD byte_length = kReservedSize;
43   if (!GetLogicalProcessorInformationEx(
44           RelationProcessorCore,
45           reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*>(
46               buffer.data()),
47           &byte_length)) {
48     DPCHECK(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
49     buffer.resize(byte_length);
50     if (!GetLogicalProcessorInformationEx(
51             RelationProcessorCore,
52             reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*>(
53                 buffer.data()),
54             &byte_length)) {
55       return {};
56     }
57   }
58 
59   std::vector<BYTE> efficiency_classes;
60   BYTE* byte_ptr = buffer.data();
61   while (byte_ptr < buffer.data() + byte_length) {
62     const auto* structure_ptr =
63         reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*>(byte_ptr);
64     DCHECK_EQ(structure_ptr->Relationship, RelationProcessorCore);
65     DCHECK_LE(&structure_ptr->Processor.EfficiencyClass +
66                   sizeof(structure_ptr->Processor.EfficiencyClass),
67               buffer.data() + byte_length);
68     efficiency_classes.push_back(structure_ptr->Processor.EfficiencyClass);
69     DCHECK_GE(
70         structure_ptr->Size,
71         offsetof(std::remove_pointer_t<decltype(structure_ptr)>, Processor) +
72             sizeof(structure_ptr->Processor));
73     byte_ptr = byte_ptr + structure_ptr->Size;
74   }
75 
76   return efficiency_classes;
77 }
78 
79 // Returns the physical cores to logical processor mapping masks by using the
80 // Windows API GetLogicalProcessorInformation(), or an empty vector on failure.
81 // When succeeded, the vector would be of same size to the number of physical
82 // cores, while each element is the bitmask of the logical processors that the
83 // physical core has.
GetCoreProcessorMasks()84 std::vector<uint64_t> GetCoreProcessorMasks() {
85   const DWORD kReservedSize = 64;
86   absl::InlinedVector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION, kReservedSize>
87       buffer;
88   buffer.resize(kReservedSize);
89   DWORD byte_length = sizeof(buffer[0]) * kReservedSize;
90   const BOOL result =
91       GetLogicalProcessorInformation(buffer.data(), &byte_length);
92   DWORD element_count = byte_length / sizeof(buffer[0]);
93   DCHECK_EQ(byte_length % sizeof(buffer[0]), 0u);
94   if (!result) {
95     DPCHECK(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
96     buffer.resize(element_count);
97     if (!GetLogicalProcessorInformation(buffer.data(), &byte_length)) {
98       return {};
99     }
100   }
101 
102   std::vector<uint64_t> processor_masks;
103   for (DWORD i = 0; i < element_count; i++) {
104     if (buffer[i].Relationship == RelationProcessorCore) {
105       processor_masks.push_back(buffer[i].ProcessorMask);
106     }
107   }
108 
109   return processor_masks;
110 }
111 
AmountOfMemory(DWORDLONG MEMORYSTATUSEX::* memory_field)112 uint64_t AmountOfMemory(DWORDLONG MEMORYSTATUSEX::*memory_field) {
113   MEMORYSTATUSEX memory_info;
114   memory_info.dwLength = sizeof(memory_info);
115   if (!GlobalMemoryStatusEx(&memory_info)) {
116     NOTREACHED();
117     return 0;
118   }
119 
120   return memory_info.*memory_field;
121 }
122 
GetDiskSpaceInfo(const base::FilePath & path,int64_t * available_bytes,int64_t * total_bytes)123 bool GetDiskSpaceInfo(const base::FilePath& path,
124                       int64_t* available_bytes,
125                       int64_t* total_bytes) {
126   ULARGE_INTEGER available;
127   ULARGE_INTEGER total;
128   ULARGE_INTEGER free;
129   if (!GetDiskFreeSpaceExW(path.value().c_str(), &available, &total, &free))
130     return false;
131 
132   if (available_bytes) {
133     *available_bytes = static_cast<int64_t>(available.QuadPart);
134     if (*available_bytes < 0)
135       *available_bytes = std::numeric_limits<int64_t>::max();
136   }
137   if (total_bytes) {
138     *total_bytes = static_cast<int64_t>(total.QuadPart);
139     if (*total_bytes < 0)
140       *total_bytes = std::numeric_limits<int64_t>::max();
141   }
142   return true;
143 }
144 
145 }  // namespace
146 
147 namespace base {
148 
149 // static
NumberOfProcessors()150 int SysInfo::NumberOfProcessors() {
151   return win::OSInfo::GetInstance()->processors();
152 }
153 
154 // static
NumberOfEfficientProcessorsImpl()155 int SysInfo::NumberOfEfficientProcessorsImpl() {
156   std::vector<BYTE> efficiency_classes = GetCoreEfficiencyClasses();
157   if (efficiency_classes.empty())
158     return 0;
159 
160   auto [min_efficiency_class_it, max_efficiency_class_it] =
161       std::minmax_element(efficiency_classes.begin(), efficiency_classes.end());
162   if (*min_efficiency_class_it == *max_efficiency_class_it)
163     return 0;
164 
165   std::vector<uint64_t> processor_masks = GetCoreProcessorMasks();
166   if (processor_masks.empty())
167     return 0;
168 
169   DCHECK_EQ(efficiency_classes.size(), processor_masks.size());
170   int num_of_efficient_processors = 0;
171   for (size_t i = 0; i < efficiency_classes.size(); i++) {
172     if (efficiency_classes[i] == *min_efficiency_class_it) {
173       num_of_efficient_processors += std::popcount(processor_masks[i]);
174     }
175   }
176 
177   return num_of_efficient_processors;
178 }
179 
180 // static
AmountOfPhysicalMemoryImpl()181 uint64_t SysInfo::AmountOfPhysicalMemoryImpl() {
182   return AmountOfMemory(&MEMORYSTATUSEX::ullTotalPhys);
183 }
184 
185 // static
AmountOfAvailablePhysicalMemoryImpl()186 uint64_t SysInfo::AmountOfAvailablePhysicalMemoryImpl() {
187   SystemMemoryInfoKB info;
188   if (!GetSystemMemoryInfo(&info))
189     return 0;
190   return checked_cast<uint64_t>(info.avail_phys) * 1024;
191 }
192 
193 // static
AmountOfVirtualMemory()194 uint64_t SysInfo::AmountOfVirtualMemory() {
195   return AmountOfMemory(&MEMORYSTATUSEX::ullTotalVirtual);
196 }
197 
198 // static
AmountOfFreeDiskSpace(const FilePath & path)199 int64_t SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
200   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
201                                                 base::BlockingType::MAY_BLOCK);
202 
203   int64_t available;
204   if (!GetDiskSpaceInfo(path, &available, nullptr))
205     return -1;
206   return available;
207 }
208 
209 // static
AmountOfTotalDiskSpace(const FilePath & path)210 int64_t SysInfo::AmountOfTotalDiskSpace(const FilePath& path) {
211   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
212                                                 base::BlockingType::MAY_BLOCK);
213 
214   int64_t total;
215   if (!GetDiskSpaceInfo(path, nullptr, &total))
216     return -1;
217   return total;
218 }
219 
OperatingSystemName()220 std::string SysInfo::OperatingSystemName() {
221   return "Windows NT";
222 }
223 
224 // static
OperatingSystemVersion()225 std::string SysInfo::OperatingSystemVersion() {
226   win::OSInfo* os_info = win::OSInfo::GetInstance();
227   win::OSInfo::VersionNumber version_number = os_info->version_number();
228   std::string version(StringPrintf("%d.%d.%d", version_number.major,
229                                    version_number.minor, version_number.build));
230   win::OSInfo::ServicePack service_pack = os_info->service_pack();
231   if (service_pack.major != 0) {
232     version += StringPrintf(" SP%d", service_pack.major);
233     if (service_pack.minor != 0)
234       version += StringPrintf(".%d", service_pack.minor);
235   }
236   return version;
237 }
238 
239 // TODO: Implement OperatingSystemVersionComplete, which would include
240 // patchlevel/service pack number.
241 // See chrome/browser/feedback/feedback_util.h, FeedbackUtil::SetOSVersion.
242 
243 // static
OperatingSystemArchitecture()244 std::string SysInfo::OperatingSystemArchitecture() {
245   win::OSInfo::WindowsArchitecture arch = win::OSInfo::GetArchitecture();
246   switch (arch) {
247     case win::OSInfo::X86_ARCHITECTURE:
248       return "x86";
249     case win::OSInfo::X64_ARCHITECTURE:
250       return "x86_64";
251     case win::OSInfo::IA64_ARCHITECTURE:
252       return "ia64";
253     case win::OSInfo::ARM64_ARCHITECTURE:
254       return "arm64";
255     default:
256       return "";
257   }
258 }
259 
260 // static
CPUModelName()261 std::string SysInfo::CPUModelName() {
262   return win::OSInfo::GetInstance()->processor_model_name();
263 }
264 
265 // static
VMAllocationGranularity()266 size_t SysInfo::VMAllocationGranularity() {
267   return win::OSInfo::GetInstance()->allocation_granularity();
268 }
269 
270 // static
OperatingSystemVersionNumbers(int32_t * major_version,int32_t * minor_version,int32_t * bugfix_version)271 void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
272                                             int32_t* minor_version,
273                                             int32_t* bugfix_version) {
274   win::OSInfo* os_info = win::OSInfo::GetInstance();
275   *major_version = static_cast<int32_t>(os_info->version_number().major);
276   *minor_version = static_cast<int32_t>(os_info->version_number().minor);
277   *bugfix_version = 0;
278 }
279 
280 // static
ReadHardwareInfoFromRegistry(const wchar_t * reg_value_name)281 std::string ReadHardwareInfoFromRegistry(const wchar_t* reg_value_name) {
282   // On some systems or VMs, the system information and some of the below
283   // locations may be missing info. Attempt to find the info from the below
284   // registry keys in the order provided.
285   static const wchar_t* const kSystemInfoRegKeyPaths[] = {
286       L"HARDWARE\\DESCRIPTION\\System\\BIOS",
287       L"SYSTEM\\CurrentControlSet\\Control\\SystemInformation",
288       L"SYSTEM\\HardwareConfig\\Current",
289   };
290 
291   std::wstring value;
292   for (const wchar_t* system_info_reg_key_path : kSystemInfoRegKeyPaths) {
293     base::win::RegKey system_information_key;
294     if (system_information_key.Open(HKEY_LOCAL_MACHINE,
295                                     system_info_reg_key_path,
296                                     KEY_READ) == ERROR_SUCCESS) {
297       if ((system_information_key.ReadValue(reg_value_name, &value) ==
298            ERROR_SUCCESS) &&
299           !value.empty()) {
300         break;
301       }
302     }
303   }
304 
305   return base::SysWideToUTF8(value);
306 }
307 
308 // static
GetHardwareInfoSync()309 SysInfo::HardwareInfo SysInfo::GetHardwareInfoSync() {
310   HardwareInfo info = {ReadHardwareInfoFromRegistry(L"SystemManufacturer"),
311                        SysInfo::HardwareModelName()};
312   return info;
313 }
314 
315 // static
HardwareModelName()316 std::string SysInfo::HardwareModelName() {
317   return ReadHardwareInfoFromRegistry(L"SystemProductName");
318 }
319 
320 }  // namespace base
321