sysinfo.cc 15 KB

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