* @brief Get the processor affinity of the current thread using the current platform's native API. This should work on Windows and Linux, but is not possible on macOS and Android as the native API does not allow it. * * @return An `std::optional` object, optionally containing the processor affinity of the current thread as an `std::vector ` where each element corresponds to a logica
| 996 | * @return An `std::optional` object, optionally containing the processor affinity of the current thread as an `std::vector<bool>` where each element corresponds to a logical processor. If the returned object does not contain a value, then the affinity could not be determined. On macOS and Android, this function always returns `std::nullopt`. |
| 997 | */ |
| 998 | [[nodiscard]] static std::optional<std::vector<bool>> get_os_thread_affinity() |
| 999 | { |
| 1000 | #if defined(_WIN32) |
| 1001 | // Windows does not have a `GetThreadAffinityMask()` function, but `SetThreadAffinityMask()` returns the previous affinity mask, so we can use that to get the current affinity and then restore it. It's a bit of a hack, but it works. Since the thread affinity must be a subset of the process affinity, we use the process affinity as the temporary value. |
| 1002 | DWORD_PTR process_mask = 0; |
| 1003 | DWORD_PTR system_mask = 0; |
| 1004 | if (GetProcessAffinityMask(GetCurrentProcess(), &process_mask, &system_mask) == 0) |
| 1005 | return std::nullopt; |
| 1006 | const DWORD_PTR previous_mask = SetThreadAffinityMask(GetCurrentThread(), process_mask); |
| 1007 | if (previous_mask == 0) |
| 1008 | return std::nullopt; |
| 1009 | SetThreadAffinityMask(GetCurrentThread(), previous_mask); |
| 1010 | #ifdef __cpp_lib_int_pow2 |
| 1011 | const std::size_t num_cpus = static_cast<std::size_t>(std::bit_width(system_mask)); |
| 1012 | #else |
| 1013 | std::size_t num_cpus = 0; |
| 1014 | if (system_mask != 0) |
| 1015 | { |
| 1016 | num_cpus = 1; |
| 1017 | while ((system_mask >>= 1U) != 0U) |
| 1018 | ++num_cpus; |
| 1019 | } |
| 1020 | #endif |
| 1021 | std::vector<bool> affinity(num_cpus); |
| 1022 | for (std::size_t i = 0; i < num_cpus; ++i) |
| 1023 | affinity[i] = ((previous_mask & (1ULL << i)) != 0ULL); |
| 1024 | return affinity; |
| 1025 | #elif defined(__linux__) && !defined(__ANDROID__) |
| 1026 | cpu_set_t cpu_set; |
| 1027 | CPU_ZERO(&cpu_set); |
| 1028 | if (pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpu_set) != 0) |
| 1029 | return std::nullopt; |
| 1030 | const int num_cpus = get_nprocs(); |
| 1031 | if (num_cpus < 1) |
| 1032 | return std::nullopt; |
| 1033 | std::vector<bool> affinity(static_cast<std::size_t>(num_cpus)); |
| 1034 | for (std::size_t i = 0; i < affinity.size(); ++i) |
| 1035 | affinity[i] = CPU_ISSET(i, &cpu_set); |
| 1036 | return affinity; |
| 1037 | #else |
| 1038 | return std::nullopt; |
| 1039 | #endif |
| 1040 | } |
| 1041 | |
| 1042 | /** |
| 1043 | * @brief Set the processor affinity of the current thread using the current platform's native API. This should work on Windows and Linux, but is not possible on macOS and Android as the native API does not allow it. Note that the thread affinity must be a subset of the process affinity (as obtained using `BS::get_os_process_affinity()`) for the containing process of a thread. |