From: Kienan Stewart Date: Wed, 13 Nov 2024 19:53:03 +0000 (-0500) Subject: common: Add helper to get max possible CPU count X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=f338ec6562c62f8d88a6c5fe968bc5f555d2afe4;p=lttng-tools.git common: Add helper to get max possible CPU count `get_max_possible_cpu_id()` is adapted from lttng-ust[1]. [1]: https://github.com/lttng/lttng-ust/blob/c0de10a2dab6d5cc6568e12c0ad3b97d85e0dc6b/src/common/smp.c#L197 Change-Id: I2697be51b21dad424c74d7397c1e6649ca7456bb Signed-off-by: Kienan Stewart Signed-off-by: Jérémie Galarneau --- diff --git a/src/common/defaults.hpp b/src/common/defaults.hpp index 8ca8bc026..a0c218622 100644 --- a/src/common/defaults.hpp +++ b/src/common/defaults.hpp @@ -380,6 +380,9 @@ */ #define DEFAULT_ROTATE_PENDING_TIMER CONFIG_DEFAULT_ROTATE_PENDING_TIMER +#define DEFAULT_LINUX_POSSIBLE_CPU_PATH "/sys/devices/system/cpu/possible" +#define DEFAULT_LINUX_POSSIBLE_CPU_MASK_LENGTH 4096 + /* * Returns the default subbuf size. * diff --git a/src/common/exception.hpp b/src/common/exception.hpp index 1d53e6402..08afbb920 100644 --- a/src/common/exception.hpp +++ b/src/common/exception.hpp @@ -18,6 +18,16 @@ #include #include +/* + * Indicate internal functions for which the caller should check exceptions + * that may be thrown. + * + * As the project is transitioning from C-style error return codes towards + * exception-based error handling in C++, this may be applied to function + * declarations alert users to the use of the different error-handling mechanism. + */ +#define LTTNG_MAY_THROW noexcept(false) + #define LTTNG_SOURCE_LOCATION() lttng::source_location(__FILE__, __func__, __LINE__) #define LTTNG_THROW_CTL(msg, error_code) \ diff --git a/src/common/utils.cpp b/src/common/utils.cpp index 701a9f275..b1478c80a 100644 --- a/src/common/utils.cpp +++ b/src/common/utils.cpp @@ -17,9 +17,12 @@ #include #include #include +#include +#include #include #include #include +#include #include #include @@ -1384,3 +1387,85 @@ int utils_parse_unsigned_long_long(const char *str, unsigned long long *value) end: return ret; } + +/* + * Get the highest CPU id from a CPU mask. + * + * Returns the highest CPU id from the mask or throws an exception on error. + */ +namespace { +unsigned int get_max_possible_cpu_id() LTTNG_MAY_THROW +{ + constexpr unsigned int cpu_mask_buffer_length{ DEFAULT_LINUX_POSSIBLE_CPU_MASK_LENGTH }; + std::array possible_cpu_mask{}; + static int max_possible_cpu_id{ 0 }; + size_t possible_cpu_mask_len{ 0 }; + unsigned long cpu_index{ 0 }; + int i{}; + + if (max_possible_cpu_id != 0) { + return max_possible_cpu_id; + } + + auto possible_cpu_mask_fd = [] { + int raw_handle = open(DEFAULT_LINUX_POSSIBLE_CPU_PATH, O_RDONLY); + if (raw_handle < 0) { + LTTNG_THROW_POSIX( + lttng::format("Failed to open possible CPU file, path='{}'", + DEFAULT_LINUX_POSSIBLE_CPU_PATH), + errno); + } + return lttng::file_descriptor(raw_handle); + }(); + + const ssize_t bytes_read = + read(possible_cpu_mask_fd.fd(), possible_cpu_mask.data(), cpu_mask_buffer_length); + if (bytes_read == cpu_mask_buffer_length) { + uint8_t next{}; + if (read(possible_cpu_mask_fd.fd(), &next, 1) != 0) { + LTTNG_THROW_ERROR(lttng::format( + "Possible CPU mask length exceeds maximum configured size: path='{}', max_size={}", + DEFAULT_LINUX_POSSIBLE_CPU_PATH, + cpu_mask_buffer_length)); + } + } + + possible_cpu_mask_len = (size_t) bytes_read; + if (possible_cpu_mask_len < 1) { + LTTNG_THROW_ERROR(lttng::format("0 bytes read from possible cpu file path={}", + DEFAULT_LINUX_POSSIBLE_CPU_PATH)); + } + + /* Start from the end to read the last CPU index. */ + i = possible_cpu_mask_len; + for (auto iter = possible_cpu_mask.crbegin(); iter != possible_cpu_mask.crend(); iter++) { + /* Break when we hit the first separator. */ + if ((possible_cpu_mask[i] == ',') || (possible_cpu_mask[i] == '-')) { + i++; + break; + } + i--; + } + + cpu_index = strtoul((const char *) &possible_cpu_mask.data()[i], + (char **) &possible_cpu_mask.data()[possible_cpu_mask_len], + 10); + if ((i != possible_cpu_mask_len) && (cpu_index < INT_MAX)) { + max_possible_cpu_id = (unsigned int) cpu_index; + return max_possible_cpu_id; + } + + LTTNG_THROW_ERROR("Unable to determine maximum possible CPU id"); + return 0; +} +} /* namespace */ + +/* + * Return the count of possible CPUs on the system. + * + * Throws an error on failure. + */ +unsigned int utils_get_cpu_count() LTTNG_MAY_THROW +{ + return get_max_possible_cpu_id() + 1; +} diff --git a/src/common/utils.hpp b/src/common/utils.hpp index a15aa02a7..0d9f59afe 100644 --- a/src/common/utils.hpp +++ b/src/common/utils.hpp @@ -9,6 +9,7 @@ #define _COMMON_UTILS_H #include +#include #include @@ -60,6 +61,9 @@ int utils_get_memory_total(uint64_t *value); int utils_change_working_directory(const char *path); enum lttng_error_code utils_user_id_from_name(const char *user_name, uid_t *user_id); enum lttng_error_code utils_group_id_from_name(const char *group_name, gid_t *group_id); +unsigned int utils_get_cpu_count() LTTNG_MAY_THROW; +enum lttng_error_code utils_check_enough_available_memory(uint64_t num_bytes, + uint64_t *bytes_available); /* * Parse `str` as an unsigned long long value.