sysinfo.cc 16 KB

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