diff options
Diffstat (limited to 'abseil-cpp/absl/base/internal/sysinfo.cc')
-rw-r--r-- | abseil-cpp/absl/base/internal/sysinfo.cc | 182 |
1 files changed, 106 insertions, 76 deletions
diff --git a/abseil-cpp/absl/base/internal/sysinfo.cc b/abseil-cpp/absl/base/internal/sysinfo.cc index 349d926..8bcc4fa 100644 --- a/abseil-cpp/absl/base/internal/sysinfo.cc +++ b/abseil-cpp/absl/base/internal/sysinfo.cc @@ -41,6 +41,7 @@ #include <string.h> #include <cassert> +#include <cerrno> #include <cstdint> #include <cstdio> #include <cstdlib> @@ -61,14 +62,82 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace base_internal { +namespace { + +#if defined(_WIN32) + +// Returns number of bits set in `bitMask` +DWORD Win32CountSetBits(ULONG_PTR bitMask) { + for (DWORD bitSetCount = 0; ; ++bitSetCount) { + if (bitMask == 0) return bitSetCount; + bitMask &= bitMask - 1; + } +} + +// Returns the number of logical CPUs using GetLogicalProcessorInformation(), or +// 0 if the number of processors is not available or can not be computed. +// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformation +int Win32NumCPUs() { +#pragma comment(lib, "kernel32.lib") + using Info = SYSTEM_LOGICAL_PROCESSOR_INFORMATION; + + DWORD info_size = sizeof(Info); + Info* info(static_cast<Info*>(malloc(info_size))); + if (info == nullptr) return 0; + + bool success = GetLogicalProcessorInformation(info, &info_size); + if (!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + free(info); + info = static_cast<Info*>(malloc(info_size)); + if (info == nullptr) return 0; + success = GetLogicalProcessorInformation(info, &info_size); + } + + DWORD logicalProcessorCount = 0; + if (success) { + Info* ptr = info; + DWORD byteOffset = 0; + while (byteOffset + sizeof(Info) <= info_size) { + switch (ptr->Relationship) { + case RelationProcessorCore: + logicalProcessorCount += Win32CountSetBits(ptr->ProcessorMask); + break; + + case RelationNumaNode: + case RelationCache: + case RelationProcessorPackage: + // Ignore other entries + break; + + default: + // Ignore unknown entries + break; + } + byteOffset += sizeof(Info); + ptr++; + } + } + free(info); + return static_cast<int>(logicalProcessorCount); +} + +#endif + +} // namespace + static int GetNumCPUs() { #if defined(__myriad2__) return 1; +#elif defined(_WIN32) + const int hardware_concurrency = Win32NumCPUs(); + return hardware_concurrency ? hardware_concurrency : 1; +#elif defined(_AIX) + return sysconf(_SC_NPROCESSORS_ONLN); #else // Other possibilities: // - Read /sys/devices/system/cpu/online and use cpumask_parse() // - sysconf(_SC_NPROCESSORS_ONLN) - return std::thread::hardware_concurrency(); + return static_cast<int>(std::thread::hardware_concurrency()); #endif } @@ -91,7 +160,7 @@ static double GetNominalCPUFrequency() { DWORD type = 0; DWORD data = 0; DWORD data_size = sizeof(data); - auto result = RegQueryValueExA(key, "~MHz", 0, &type, + auto result = RegQueryValueExA(key, "~MHz", nullptr, &type, reinterpret_cast<LPBYTE>(&data), &data_size); RegCloseKey(key); if (result == ERROR_SUCCESS && type == REG_DWORD && @@ -121,12 +190,21 @@ static double GetNominalCPUFrequency() { // and the memory location pointed to by value is set to the value read. static bool ReadLongFromFile(const char *file, long *value) { bool ret = false; - int fd = open(file, O_RDONLY); +#if defined(_POSIX_C_SOURCE) + const int file_mode = (O_RDONLY | O_CLOEXEC); +#else + const int file_mode = O_RDONLY; +#endif + + int fd = open(file, file_mode); if (fd != -1) { char line[1024]; char *err; memset(line, '\0', sizeof(line)); - int len = read(fd, line, sizeof(line) - 1); + ssize_t len; + do { + len = read(fd, line, sizeof(line) - 1); + } while (len < 0 && errno == EINTR); if (len <= 0) { ret = false; } else { @@ -154,8 +232,8 @@ static int64_t ReadMonotonicClockNanos() { int rc = clock_gettime(CLOCK_MONOTONIC, &t); #endif if (rc != 0) { - perror("clock_gettime() failed"); - abort(); + ABSL_INTERNAL_LOG( + FATAL, "clock_gettime() failed: (" + std::to_string(errno) + ")"); } return int64_t{t.tv_sec} * 1000000000 + t.tv_nsec; } @@ -308,7 +386,7 @@ pid_t GetTID() { #endif pid_t GetTID() { - return syscall(SYS_gettid); + return static_cast<pid_t>(syscall(SYS_gettid)); } #elif defined(__akaros__) @@ -343,81 +421,33 @@ pid_t GetTID() { return tid; } -#else +#elif defined(__APPLE__) -// Fallback implementation of GetTID using pthread_getspecific. -ABSL_CONST_INIT static once_flag tid_once; -ABSL_CONST_INIT static pthread_key_t tid_key; -ABSL_CONST_INIT static absl::base_internal::SpinLock tid_lock( - absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY); - -// We set a bit per thread in this array to indicate that an ID is in -// use. ID 0 is unused because it is the default value returned by -// pthread_getspecific(). -ABSL_CONST_INIT static std::vector<uint32_t> *tid_array - ABSL_GUARDED_BY(tid_lock) = nullptr; -static constexpr int kBitsPerWord = 32; // tid_array is uint32_t. - -// Returns the TID to tid_array. -static void FreeTID(void *v) { - intptr_t tid = reinterpret_cast<intptr_t>(v); - int word = tid / kBitsPerWord; - uint32_t mask = ~(1u << (tid % kBitsPerWord)); - absl::base_internal::SpinLockHolder lock(&tid_lock); - assert(0 <= word && static_cast<size_t>(word) < tid_array->size()); - (*tid_array)[word] &= mask; +pid_t GetTID() { + uint64_t tid; + // `nullptr` here implies this thread. This only fails if the specified + // thread is invalid or the pointer-to-tid is null, so we needn't worry about + // it. + pthread_threadid_np(nullptr, &tid); + return static_cast<pid_t>(tid); } -static void InitGetTID() { - if (pthread_key_create(&tid_key, FreeTID) != 0) { - // The logging system calls GetTID() so it can't be used here. - perror("pthread_key_create failed"); - abort(); - } +#elif defined(__native_client__) - // Initialize tid_array. - absl::base_internal::SpinLockHolder lock(&tid_lock); - tid_array = new std::vector<uint32_t>(1); - (*tid_array)[0] = 1; // ID 0 is never-allocated. -} - -// Return a per-thread small integer ID from pthread's thread-specific data. pid_t GetTID() { - absl::call_once(tid_once, InitGetTID); - - intptr_t tid = reinterpret_cast<intptr_t>(pthread_getspecific(tid_key)); - if (tid != 0) { - return tid; - } - - int bit; // tid_array[word] = 1u << bit; - size_t word; - { - // Search for the first unused ID. - absl::base_internal::SpinLockHolder lock(&tid_lock); - // First search for a word in the array that is not all ones. - word = 0; - while (word < tid_array->size() && ~(*tid_array)[word] == 0) { - ++word; - } - if (word == tid_array->size()) { - tid_array->push_back(0); // No space left, add kBitsPerWord more IDs. - } - // Search for a zero bit in the word. - bit = 0; - while (bit < kBitsPerWord && (((*tid_array)[word] >> bit) & 1) != 0) { - ++bit; - } - tid = (word * kBitsPerWord) + bit; - (*tid_array)[word] |= 1u << bit; // Mark the TID as allocated. - } + auto* thread = pthread_self(); + static_assert(sizeof(pid_t) == sizeof(thread), + "In NaCL int expected to be the same size as a pointer"); + return reinterpret_cast<pid_t>(thread); +} - if (pthread_setspecific(tid_key, reinterpret_cast<void *>(tid)) != 0) { - perror("pthread_setspecific failed"); - abort(); - } +#else - return static_cast<pid_t>(tid); +// Fallback implementation of `GetTID` using `pthread_self`. +pid_t GetTID() { + // `pthread_t` need not be arithmetic per POSIX; platforms where it isn't + // should be handled above. + return static_cast<pid_t>(pthread_self()); } #endif @@ -426,7 +456,7 @@ pid_t GetTID() { // userspace construct) to avoid unnecessary system calls. Without this caching, // it can take roughly 98ns, while it takes roughly 1ns with this caching. pid_t GetCachedTID() { -#if ABSL_HAVE_THREAD_LOCAL +#ifdef ABSL_HAVE_THREAD_LOCAL static thread_local pid_t thread_id = GetTID(); return thread_id; #else |