]> git.lttng.org Git - lttng-tools.git/commitdiff
lttng-ctl/lttng: Move enable-channel memory check to client
authorKienan Stewart <kstewart@efficios.com>
Wed, 13 Nov 2024 20:37:36 +0000 (15:37 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 3 Dec 2024 18:35:06 +0000 (13:35 -0500)
Change-Id: I855284c3f2a6910363a075e6a7bb4c6d55b22685
Signed-off-by: Kienan Stewart <kstewart@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
src/bin/lttng/commands/enable_channels.cpp
src/common/utils.cpp
src/lib/lttng-ctl/lttng-ctl.cpp

index 4e5f2eb15534147b28ea05233600862652d3408e..bbce3e4b62890e73339ec2df13a4bb5a7f502742 100644 (file)
@@ -135,6 +135,45 @@ static void set_default_attr(struct lttng_domain *dom)
        }
 }
 
+static bool system_has_memory_for_channel_buffers(char *session_name, struct lttng_channel *channel, uint64_t *bytes_required, uint64_t *bytes_available) {
+       /*
+        * Verify that the amount of memory required to create the requested
+        * buffer is available on the system at the moment.
+        */
+       unsigned long total_buffer_size_needed_per_cpu {0};
+       const auto spec = lttng::cli::session_spec(lttng::cli::session_spec::type::NAME, session_name);
+       const auto sessions = list_sessions(spec);
+       int ncpus {0};
+
+       if (sessions.size() <= 0) {
+               /* Session not found */
+               ERR_FMT("Session not found, name='{}'", session_name);
+               return false;
+       }
+
+       if (channel->attr.num_subbuf > UINT64_MAX / channel->attr.subbuf_size) {
+               /* Overflow */
+               ERR_FMT("Integer overflow calculating total buffer size per CPU on channel '{}': num_subbuf={}, subbuf_size={}", channel->name, channel->attr.num_subbuf, channel->attr.subbuf_size)
+               return false;
+       }
+
+       total_buffer_size_needed_per_cpu = channel->attr.num_subbuf * channel->attr.subbuf_size;
+       try {
+               ncpus = utils_get_cpu_count();
+       } catch (const std::exception &ex) {
+               ERR_FMT("Exception when getting CPU count: {}", ex.what());
+               return false;
+       }
+
+       /* In snapshot mode, an extra set of buffers is required. */
+       const auto _bytes_required = static_cast<uint64_t>(total_buffer_size_needed_per_cpu * ncpus + sessions[0].snapshot_mode);
+       if (bytes_required != nullptr) {
+               *bytes_required = _bytes_required;
+       }
+
+       return utils_check_enough_available_memory(_bytes_required, bytes_available) == LTTNG_OK;
+}
+
 /*
  * Adding channel using the lttng API.
  */
@@ -142,6 +181,8 @@ static int enable_channel(char *session_name, char *channel_list)
 {
        struct lttng_channel *channel = nullptr;
        int ret = CMD_SUCCESS, warn = 0, error = 0, success = 0;
+       auto bytes_required = static_cast<uint64_t>(0);
+       auto bytes_available = static_cast<uint64_t>(0);
        char *channel_name;
        struct lttng_domain dom;
 
@@ -280,8 +321,17 @@ static int enable_channel(char *session_name, char *channel_list)
                        }
                }
 
-               DBG("Enabling channel %s", channel_name);
+               if (!system_has_memory_for_channel_buffers(
+                           session_name, channel, &bytes_required, &bytes_available)) {
+                       ERR_FMT("Not enough system memory available for channel '{}'. At least {}MiB required, {}MiB available",
+                               channel->name,
+                               bytes_required / 1024 / 1024,
+                               bytes_available / 1024 / 1024);
+                       error = 1;
+                       goto error;
+               }
 
+               DBG("Enabling channel %s", channel_name);
                ret = lttng_enable_channel(handle, channel);
                if (ret < 0) {
                        bool msg_already_printed = false;
index b1478c80a11990e143388bd118d6e228dd0b758f..78d7beb5a49f62419de9a3ec8b557563e2b8a9cb 100644 (file)
@@ -1469,3 +1469,53 @@ unsigned int utils_get_cpu_count() LTTNG_MAY_THROW
 {
        return get_max_possible_cpu_id() + 1;
 }
+
+/**
+ * Returns LTTNG_OK if the system as num_bytes available.
+ *
+ * If bytes_available is not NULL, the best estimate of the available memory
+ * will be recorded at that address.
+ */
+enum lttng_error_code utils_check_enough_available_memory(uint64_t num_bytes, uint64_t *bytes_available)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       auto best_mem_info = static_cast<uint64_t>(0);
+
+       /*
+        * Try to get the `MemAvail` field of `/proc/meminfo`. This is the most
+        * reliable estimate we can get but it is only exposed by the kernel
+        * since 3.14. (See Linux kernel commit:
+        * 34e431b0ae398fc54ea69ff85ec700722c9da773)
+        */
+       ret = utils_get_memory_available(&best_mem_info);
+       if (ret >= 0) {
+               goto success;
+       }
+
+       /*
+        * As a backup plan, use `MemTotal` field of `/proc/meminfo`. This
+        * is a sanity check for obvious user error.
+        */
+       ret = utils_get_memory_total(&best_mem_info);
+       if (ret >= 0) {
+               goto success;
+       }
+
+       /* No valid source of information. */
+       ret_code = LTTNG_ERR_NOMEM;
+       goto end;
+
+success:
+       if (bytes_available != nullptr) {
+               *bytes_available = best_mem_info;
+       }
+
+       if (best_mem_info >= num_bytes) {
+               ret_code = LTTNG_OK;
+       } else {
+               ret_code = LTTNG_ERR_NOMEM;
+       }
+end:
+       return ret_code;
+}
index 8ba7d657af924aa0f0312d10bd4dd259f31e7ef3..9af768fb1ac045831a6bb85a0e7cf5b27aa783f2 100644 (file)
@@ -297,67 +297,6 @@ end:
        return ret;
 }
 
-static enum lttng_error_code check_enough_available_memory(uint64_t num_bytes_requested_per_cpu)
-{
-       int ret;
-       enum lttng_error_code ret_code;
-       long num_cpu;
-       uint64_t best_mem_info;
-       uint64_t num_bytes_requested_total;
-
-       /*
-        * Get the number of CPU currently online to compute the amount of
-        * memory needed to create a buffer for every CPU.
-        */
-       try {
-               num_cpu = long(utils_get_cpu_count());
-       } catch (const std::exception& ex) {
-               ret_code = LTTNG_ERR_FATAL;
-               goto end;
-       }
-
-       if (num_bytes_requested_per_cpu > UINT64_MAX / (uint64_t) num_cpu) {
-               /* Overflow */
-               ret_code = LTTNG_ERR_OVERFLOW;
-               goto end;
-       }
-
-       num_bytes_requested_total = num_bytes_requested_per_cpu * (uint64_t) num_cpu;
-
-       /*
-        * Try to get the `MemAvail` field of `/proc/meminfo`. This is the most
-        * reliable estimate we can get but it is only exposed by the kernel
-        * since 3.14. (See Linux kernel commit:
-        * 34e431b0ae398fc54ea69ff85ec700722c9da773)
-        */
-       ret = utils_get_memory_available(&best_mem_info);
-       if (ret >= 0) {
-               goto success;
-       }
-
-       /*
-        * As a backup plan, use `MemTotal` field of `/proc/meminfo`. This
-        * is a sanity check for obvious user error.
-        */
-       ret = utils_get_memory_total(&best_mem_info);
-       if (ret >= 0) {
-               goto success;
-       }
-
-       /* No valid source of information. */
-       ret_code = LTTNG_ERR_NOMEM;
-       goto end;
-
-success:
-       if (best_mem_info >= num_bytes_requested_total) {
-               ret_code = LTTNG_OK;
-       } else {
-               ret_code = LTTNG_ERR_NOMEM;
-       }
-end:
-       return ret_code;
-}
-
 /*
  * Try connect to session daemon with sock_path.
  *
@@ -1611,7 +1550,6 @@ int lttng_enable_channel(struct lttng_handle *handle, struct lttng_channel *in_c
        int ret;
        struct lttng_dynamic_buffer buffer;
        struct lttcomm_session_msg lsm;
-       uint64_t total_buffer_size_needed_per_cpu = 0;
        struct lttng_channel *channel = nullptr;
 
        lttng_dynamic_buffer_init(&buffer);
@@ -1622,23 +1560,6 @@ int lttng_enable_channel(struct lttng_handle *handle, struct lttng_channel *in_c
                goto end;
        }
 
-       /*
-        * Verify that the amount of memory required to create the requested
-        * buffer is available on the system at the moment.
-        */
-       if (in_chan->attr.num_subbuf > UINT64_MAX / in_chan->attr.subbuf_size) {
-               /* Overflow */
-               ret = -LTTNG_ERR_OVERFLOW;
-               goto end;
-       }
-
-       total_buffer_size_needed_per_cpu = in_chan->attr.num_subbuf * in_chan->attr.subbuf_size;
-       ret_code = check_enough_available_memory(total_buffer_size_needed_per_cpu);
-       if (ret_code != LTTNG_OK) {
-               ret = -ret_code;
-               goto end;
-       }
-
        /* Copy the channel for easier manipulation. */
        channel = lttng_channel_copy(in_chan);
        if (!channel) {
This page took 0.033641 seconds and 4 git commands to generate.