1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/base/internal/sysinfo.h"
16
17 #include "absl/base/attributes.h"
18
19 #ifdef _WIN32
20 #include <windows.h>
21 #else
22 #include <fcntl.h>
23 #include <pthread.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #endif
28
29 #ifdef __linux__
30 #include <sys/syscall.h>
31 #endif
32
33 #if defined(__APPLE__) || defined(__FreeBSD__)
34 #include <sys/sysctl.h>
35 #endif
36
37 #if defined(__myriad2__)
38 #include <rtems.h>
39 #endif
40
41 #include <string.h>
42
43 #include <cassert>
44 #include <cstdint>
45 #include <cstdio>
46 #include <cstdlib>
47 #include <ctime>
48 #include <limits>
49 #include <thread> // NOLINT(build/c++11)
50 #include <utility>
51 #include <vector>
52
53 #include "absl/base/call_once.h"
54 #include "absl/base/config.h"
55 #include "absl/base/internal/raw_logging.h"
56 #include "absl/base/internal/spinlock.h"
57 #include "absl/base/internal/unscaledcycleclock.h"
58 #include "absl/base/thread_annotations.h"
59
60 namespace absl {
61 ABSL_NAMESPACE_BEGIN
62 namespace base_internal {
63
64 namespace {
65
66 #if defined(_WIN32)
67
68 // Returns number of bits set in `bitMask`
Win32CountSetBits(ULONG_PTR bitMask)69 DWORD Win32CountSetBits(ULONG_PTR bitMask) {
70 for (DWORD bitSetCount = 0; ; ++bitSetCount) {
71 if (bitMask == 0) return bitSetCount;
72 bitMask &= bitMask - 1;
73 }
74 }
75
76 // Returns the number of logical CPUs using GetLogicalProcessorInformation(), or
77 // 0 if the number of processors is not available or can not be computed.
78 // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformation
Win32NumCPUs()79 int Win32NumCPUs() {
80 #pragma comment(lib, "kernel32.lib")
81 using Info = SYSTEM_LOGICAL_PROCESSOR_INFORMATION;
82
83 DWORD info_size = sizeof(Info);
84 Info* info(static_cast<Info*>(malloc(info_size)));
85 if (info == nullptr) return 0;
86
87 bool success = GetLogicalProcessorInformation(info, &info_size);
88 if (!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
89 free(info);
90 info = static_cast<Info*>(malloc(info_size));
91 if (info == nullptr) return 0;
92 success = GetLogicalProcessorInformation(info, &info_size);
93 }
94
95 DWORD logicalProcessorCount = 0;
96 if (success) {
97 Info* ptr = info;
98 DWORD byteOffset = 0;
99 while (byteOffset + sizeof(Info) <= info_size) {
100 switch (ptr->Relationship) {
101 case RelationProcessorCore:
102 logicalProcessorCount += Win32CountSetBits(ptr->ProcessorMask);
103 break;
104
105 case RelationNumaNode:
106 case RelationCache:
107 case RelationProcessorPackage:
108 // Ignore other entries
109 break;
110
111 default:
112 // Ignore unknown entries
113 break;
114 }
115 byteOffset += sizeof(Info);
116 ptr++;
117 }
118 }
119 free(info);
120 return logicalProcessorCount;
121 }
122
123 #endif
124
125 } // namespace
126
127
GetNumCPUs()128 static int GetNumCPUs() {
129 #if defined(__myriad2__)
130 return 1;
131 #elif defined(_WIN32)
132 const unsigned hardware_concurrency = Win32NumCPUs();
133 return hardware_concurrency ? hardware_concurrency : 1;
134 #elif defined(_AIX)
135 return sysconf(_SC_NPROCESSORS_ONLN);
136 #else
137 // Other possibilities:
138 // - Read /sys/devices/system/cpu/online and use cpumask_parse()
139 // - sysconf(_SC_NPROCESSORS_ONLN)
140 return std::thread::hardware_concurrency();
141 #endif
142 }
143
144 #if defined(_WIN32)
145
GetNominalCPUFrequency()146 static double GetNominalCPUFrequency() {
147 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
148 !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
149 // UWP apps don't have access to the registry and currently don't provide an
150 // API informing about CPU nominal frequency.
151 return 1.0;
152 #else
153 #pragma comment(lib, "advapi32.lib") // For Reg* functions.
154 HKEY key;
155 // Use the Reg* functions rather than the SH functions because shlwapi.dll
156 // pulls in gdi32.dll which makes process destruction much more costly.
157 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
158 "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0,
159 KEY_READ, &key) == ERROR_SUCCESS) {
160 DWORD type = 0;
161 DWORD data = 0;
162 DWORD data_size = sizeof(data);
163 auto result = RegQueryValueExA(key, "~MHz", 0, &type,
164 reinterpret_cast<LPBYTE>(&data), &data_size);
165 RegCloseKey(key);
166 if (result == ERROR_SUCCESS && type == REG_DWORD &&
167 data_size == sizeof(data)) {
168 return data * 1e6; // Value is MHz.
169 }
170 }
171 return 1.0;
172 #endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
173 }
174
175 #elif defined(CTL_HW) && defined(HW_CPU_FREQ)
176
GetNominalCPUFrequency()177 static double GetNominalCPUFrequency() {
178 unsigned freq;
179 size_t size = sizeof(freq);
180 int mib[2] = {CTL_HW, HW_CPU_FREQ};
181 if (sysctl(mib, 2, &freq, &size, nullptr, 0) == 0) {
182 return static_cast<double>(freq);
183 }
184 return 1.0;
185 }
186
187 #else
188
189 // Helper function for reading a long from a file. Returns true if successful
190 // and the memory location pointed to by value is set to the value read.
ReadLongFromFile(const char * file,long * value)191 static bool ReadLongFromFile(const char *file, long *value) {
192 bool ret = false;
193 int fd = open(file, O_RDONLY);
194 if (fd != -1) {
195 char line[1024];
196 char *err;
197 memset(line, '\0', sizeof(line));
198 int len = read(fd, line, sizeof(line) - 1);
199 if (len <= 0) {
200 ret = false;
201 } else {
202 const long temp_value = strtol(line, &err, 10);
203 if (line[0] != '\0' && (*err == '\n' || *err == '\0')) {
204 *value = temp_value;
205 ret = true;
206 }
207 }
208 close(fd);
209 }
210 return ret;
211 }
212
213 #if defined(ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY)
214
215 // Reads a monotonic time source and returns a value in
216 // nanoseconds. The returned value uses an arbitrary epoch, not the
217 // Unix epoch.
ReadMonotonicClockNanos()218 static int64_t ReadMonotonicClockNanos() {
219 struct timespec t;
220 #ifdef CLOCK_MONOTONIC_RAW
221 int rc = clock_gettime(CLOCK_MONOTONIC_RAW, &t);
222 #else
223 int rc = clock_gettime(CLOCK_MONOTONIC, &t);
224 #endif
225 if (rc != 0) {
226 perror("clock_gettime() failed");
227 abort();
228 }
229 return int64_t{t.tv_sec} * 1000000000 + t.tv_nsec;
230 }
231
232 class UnscaledCycleClockWrapperForInitializeFrequency {
233 public:
Now()234 static int64_t Now() { return base_internal::UnscaledCycleClock::Now(); }
235 };
236
237 struct TimeTscPair {
238 int64_t time; // From ReadMonotonicClockNanos().
239 int64_t tsc; // From UnscaledCycleClock::Now().
240 };
241
242 // Returns a pair of values (monotonic kernel time, TSC ticks) that
243 // approximately correspond to each other. This is accomplished by
244 // doing several reads and picking the reading with the lowest
245 // latency. This approach is used to minimize the probability that
246 // our thread was preempted between clock reads.
GetTimeTscPair()247 static TimeTscPair GetTimeTscPair() {
248 int64_t best_latency = std::numeric_limits<int64_t>::max();
249 TimeTscPair best;
250 for (int i = 0; i < 10; ++i) {
251 int64_t t0 = ReadMonotonicClockNanos();
252 int64_t tsc = UnscaledCycleClockWrapperForInitializeFrequency::Now();
253 int64_t t1 = ReadMonotonicClockNanos();
254 int64_t latency = t1 - t0;
255 if (latency < best_latency) {
256 best_latency = latency;
257 best.time = t0;
258 best.tsc = tsc;
259 }
260 }
261 return best;
262 }
263
264 // Measures and returns the TSC frequency by taking a pair of
265 // measurements approximately `sleep_nanoseconds` apart.
MeasureTscFrequencyWithSleep(int sleep_nanoseconds)266 static double MeasureTscFrequencyWithSleep(int sleep_nanoseconds) {
267 auto t0 = GetTimeTscPair();
268 struct timespec ts;
269 ts.tv_sec = 0;
270 ts.tv_nsec = sleep_nanoseconds;
271 while (nanosleep(&ts, &ts) != 0 && errno == EINTR) {}
272 auto t1 = GetTimeTscPair();
273 double elapsed_ticks = t1.tsc - t0.tsc;
274 double elapsed_time = (t1.time - t0.time) * 1e-9;
275 return elapsed_ticks / elapsed_time;
276 }
277
278 // Measures and returns the TSC frequency by calling
279 // MeasureTscFrequencyWithSleep(), doubling the sleep interval until the
280 // frequency measurement stabilizes.
MeasureTscFrequency()281 static double MeasureTscFrequency() {
282 double last_measurement = -1.0;
283 int sleep_nanoseconds = 1000000; // 1 millisecond.
284 for (int i = 0; i < 8; ++i) {
285 double measurement = MeasureTscFrequencyWithSleep(sleep_nanoseconds);
286 if (measurement * 0.99 < last_measurement &&
287 last_measurement < measurement * 1.01) {
288 // Use the current measurement if it is within 1% of the
289 // previous measurement.
290 return measurement;
291 }
292 last_measurement = measurement;
293 sleep_nanoseconds *= 2;
294 }
295 return last_measurement;
296 }
297
298 #endif // ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
299
GetNominalCPUFrequency()300 static double GetNominalCPUFrequency() {
301 long freq = 0;
302
303 // Google's production kernel has a patch to export the TSC
304 // frequency through sysfs. If the kernel is exporting the TSC
305 // frequency use that. There are issues where cpuinfo_max_freq
306 // cannot be relied on because the BIOS may be exporting an invalid
307 // p-state (on x86) or p-states may be used to put the processor in
308 // a new mode (turbo mode). Essentially, those frequencies cannot
309 // always be relied upon. The same reasons apply to /proc/cpuinfo as
310 // well.
311 if (ReadLongFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)) {
312 return freq * 1e3; // Value is kHz.
313 }
314
315 #if defined(ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY)
316 // On these platforms, the TSC frequency is the nominal CPU
317 // frequency. But without having the kernel export it directly
318 // though /sys/devices/system/cpu/cpu0/tsc_freq_khz, there is no
319 // other way to reliably get the TSC frequency, so we have to
320 // measure it ourselves. Some CPUs abuse cpuinfo_max_freq by
321 // exporting "fake" frequencies for implementing new features. For
322 // example, Intel's turbo mode is enabled by exposing a p-state
323 // value with a higher frequency than that of the real TSC
324 // rate. Because of this, we prefer to measure the TSC rate
325 // ourselves on i386 and x86-64.
326 return MeasureTscFrequency();
327 #else
328
329 // If CPU scaling is in effect, we want to use the *maximum*
330 // frequency, not whatever CPU speed some random processor happens
331 // to be using now.
332 if (ReadLongFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
333 &freq)) {
334 return freq * 1e3; // Value is kHz.
335 }
336
337 return 1.0;
338 #endif // !ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
339 }
340
341 #endif
342
343 ABSL_CONST_INIT static once_flag init_num_cpus_once;
344 ABSL_CONST_INIT static int num_cpus = 0;
345
346 // NumCPUs() may be called before main() and before malloc is properly
347 // initialized, therefore this must not allocate memory.
NumCPUs()348 int NumCPUs() {
349 base_internal::LowLevelCallOnce(
350 &init_num_cpus_once, []() { num_cpus = GetNumCPUs(); });
351 return num_cpus;
352 }
353
354 // A default frequency of 0.0 might be dangerous if it is used in division.
355 ABSL_CONST_INIT static once_flag init_nominal_cpu_frequency_once;
356 ABSL_CONST_INIT static double nominal_cpu_frequency = 1.0;
357
358 // NominalCPUFrequency() may be called before main() and before malloc is
359 // properly initialized, therefore this must not allocate memory.
NominalCPUFrequency()360 double NominalCPUFrequency() {
361 base_internal::LowLevelCallOnce(
362 &init_nominal_cpu_frequency_once,
363 []() { nominal_cpu_frequency = GetNominalCPUFrequency(); });
364 return nominal_cpu_frequency;
365 }
366
367 #if defined(_WIN32)
368
GetTID()369 pid_t GetTID() {
370 return pid_t{GetCurrentThreadId()};
371 }
372
373 #elif defined(__linux__)
374
375 #ifndef SYS_gettid
376 #define SYS_gettid __NR_gettid
377 #endif
378
GetTID()379 pid_t GetTID() {
380 return syscall(SYS_gettid);
381 }
382
383 #elif defined(__akaros__)
384
GetTID()385 pid_t GetTID() {
386 // Akaros has a concept of "vcore context", which is the state the program
387 // is forced into when we need to make a user-level scheduling decision, or
388 // run a signal handler. This is analogous to the interrupt context that a
389 // CPU might enter if it encounters some kind of exception.
390 //
391 // There is no current thread context in vcore context, but we need to give
392 // a reasonable answer if asked for a thread ID (e.g., in a signal handler).
393 // Thread 0 always exists, so if we are in vcore context, we return that.
394 //
395 // Otherwise, we know (since we are using pthreads) that the uthread struct
396 // current_uthread is pointing to is the first element of a
397 // struct pthread_tcb, so we extract and return the thread ID from that.
398 //
399 // TODO(dcross): Akaros anticipates moving the thread ID to the uthread
400 // structure at some point. We should modify this code to remove the cast
401 // when that happens.
402 if (in_vcore_context())
403 return 0;
404 return reinterpret_cast<struct pthread_tcb *>(current_uthread)->id;
405 }
406
407 #elif defined(__myriad2__)
408
GetTID()409 pid_t GetTID() {
410 uint32_t tid;
411 rtems_task_ident(RTEMS_SELF, 0, &tid);
412 return tid;
413 }
414
415 #else
416
417 // Fallback implementation of GetTID using pthread_getspecific.
418 ABSL_CONST_INIT static once_flag tid_once;
419 ABSL_CONST_INIT static pthread_key_t tid_key;
420 ABSL_CONST_INIT static absl::base_internal::SpinLock tid_lock(
421 absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
422
423 // We set a bit per thread in this array to indicate that an ID is in
424 // use. ID 0 is unused because it is the default value returned by
425 // pthread_getspecific().
426 ABSL_CONST_INIT static std::vector<uint32_t> *tid_array
427 ABSL_GUARDED_BY(tid_lock) = nullptr;
428 static constexpr int kBitsPerWord = 32; // tid_array is uint32_t.
429
430 // Returns the TID to tid_array.
FreeTID(void * v)431 static void FreeTID(void *v) {
432 intptr_t tid = reinterpret_cast<intptr_t>(v);
433 int word = tid / kBitsPerWord;
434 uint32_t mask = ~(1u << (tid % kBitsPerWord));
435 absl::base_internal::SpinLockHolder lock(&tid_lock);
436 assert(0 <= word && static_cast<size_t>(word) < tid_array->size());
437 (*tid_array)[word] &= mask;
438 }
439
InitGetTID()440 static void InitGetTID() {
441 if (pthread_key_create(&tid_key, FreeTID) != 0) {
442 // The logging system calls GetTID() so it can't be used here.
443 perror("pthread_key_create failed");
444 abort();
445 }
446
447 // Initialize tid_array.
448 absl::base_internal::SpinLockHolder lock(&tid_lock);
449 tid_array = new std::vector<uint32_t>(1);
450 (*tid_array)[0] = 1; // ID 0 is never-allocated.
451 }
452
453 // Return a per-thread small integer ID from pthread's thread-specific data.
GetTID()454 pid_t GetTID() {
455 absl::call_once(tid_once, InitGetTID);
456
457 intptr_t tid = reinterpret_cast<intptr_t>(pthread_getspecific(tid_key));
458 if (tid != 0) {
459 return tid;
460 }
461
462 int bit; // tid_array[word] = 1u << bit;
463 size_t word;
464 {
465 // Search for the first unused ID.
466 absl::base_internal::SpinLockHolder lock(&tid_lock);
467 // First search for a word in the array that is not all ones.
468 word = 0;
469 while (word < tid_array->size() && ~(*tid_array)[word] == 0) {
470 ++word;
471 }
472 if (word == tid_array->size()) {
473 tid_array->push_back(0); // No space left, add kBitsPerWord more IDs.
474 }
475 // Search for a zero bit in the word.
476 bit = 0;
477 while (bit < kBitsPerWord && (((*tid_array)[word] >> bit) & 1) != 0) {
478 ++bit;
479 }
480 tid = (word * kBitsPerWord) + bit;
481 (*tid_array)[word] |= 1u << bit; // Mark the TID as allocated.
482 }
483
484 if (pthread_setspecific(tid_key, reinterpret_cast<void *>(tid)) != 0) {
485 perror("pthread_setspecific failed");
486 abort();
487 }
488
489 return static_cast<pid_t>(tid);
490 }
491
492 #endif
493
494 // GetCachedTID() caches the thread ID in thread-local storage (which is a
495 // userspace construct) to avoid unnecessary system calls. Without this caching,
496 // it can take roughly 98ns, while it takes roughly 1ns with this caching.
GetCachedTID()497 pid_t GetCachedTID() {
498 #ifdef ABSL_HAVE_THREAD_LOCAL
499 static thread_local pid_t thread_id = GetTID();
500 return thread_id;
501 #else
502 return GetTID();
503 #endif // ABSL_HAVE_THREAD_LOCAL
504 }
505
506 } // namespace base_internal
507 ABSL_NAMESPACE_END
508 } // namespace absl
509