commit:     d9e02f319d92d82bac098e56ac7ea2dc33d904a7
Author:     Michał Górny <mgorny <AT> gentoo <DOT> org>
AuthorDate: Mon Dec  8 12:07:26 2025 +0000
Commit:     Michał Górny <mgorny <AT> gentoo <DOT> org>
CommitDate: Mon Dec  8 12:07:26 2025 +0000
URL:        https://gitweb.gentoo.org/proj/steve.git/commit/?id=d9e02f31

Use /proc/loadavg for more accurate load measurement

Signed-off-by: Michał Górny <mgorny <AT> gentoo.org>

 steve.cxx | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 57 insertions(+), 7 deletions(-)

diff --git a/steve.cxx b/steve.cxx
index 92615bd..2e69a36 100644
--- a/steve.cxx
+++ b/steve.cxx
@@ -14,6 +14,7 @@
 #include <cstddef>
 #include <cstdio>
 #include <cstdlib>
+#include <cstring>
 #include <cerrno>
 #include <climits>
 #include <csignal>
@@ -93,6 +94,7 @@ struct steve_state {
        std::deque<steve_waiter> waiters;
        std::unordered_map<uint64_t, steve_process> processes;
        struct event_base *evb;
+       int loadavg_fd{-2};
 
        /* to workaround lack of fuse_buf_free(), keep a global buffer */
        /* https://github.com/libfuse/libfuse/issues/1373 */
@@ -106,6 +108,57 @@ enum class steve_token_availability {
        load_exceeded,
 };
 
+static void steve_get_load(steve_state *state)
+{
+       if (state->loadavg_fd == -2) {
+               state->loadavg_fd = open("/proc/loadavg", O_RDONLY);
+               if (state->loadavg_fd == -1)
+                       perror("Unable to open /proc/loadavg, falling back to 
getloadavg()");
+       }
+
+       if (state->loadavg_fd != -1) {
+               char buf[64];
+               ssize_t rd;
+
+               if (lseek(state->loadavg_fd, 0, SEEK_SET) == 0 && (rd = 
read(state->loadavg_fd, &buf, sizeof(buf) - 1)) > 0) {
+                       buf[rd] = 0;
+
+                       char *begin = buf;
+                       for (int field = 0; *begin && field != 3; ++begin) {
+                               if (*begin == ' ')
+                                       ++field;
+                       }
+                       char *end = strchr(buf, '/');
+
+                       if (*begin && *end) {
+                               *end = 0;
+                               long load;
+                               /* Decrease by one to account for our process. 
*/
+                               if (arg_to_long(begin, &load)) {
+                                       state->load_avg = load - 1;
+                                       return;
+                               }
+                       }
+
+                       std::print(stderr, "Parsing /proc/loadavg failed, value 
= {}\n", buf);
+               } else
+                       perror("Reading /proc/loadavg failed, falling back to 
getloadavg()");
+
+               close(state->loadavg_fd);
+               state->loadavg_fd = -1;
+       }
+
+       if (getloadavg(&state->load_avg, 1) == -1) {
+               static bool warned = false;
+               if (!warned) {
+                       perror("getloadavg() failed, will ignore (further 
warnings will be suppressed)");
+                       warned = true;
+               }
+               /* to make it clear it failed */
+               state->load_avg = -0.0;
+       }
+}
+
 static steve_token_availability steve_can_give_token(steve_state *state, 
uint64_t pid)
 {
        /* if there is a token reserved, we give it immediately (even if load 
is exceeded now) */
@@ -117,13 +170,8 @@ static steve_token_availability 
steve_can_give_token(steve_state *state, uint64_
        if (state->max_load_avg > 0) {
                if (state->jobs < state->min_jobs + state->tokens)
                        return steve_token_availability::available;
-               if (getloadavg(&state->load_avg, 1) == -1) {
-                       static bool warned = false;
-                       if (!warned) {
-                               perror("getloadavg() failed, will ignore 
(further warnings will be suppressed)");
-                               warned = true;
-                       }
-               } else if (state->load_avg > state->max_load_avg)
+               steve_get_load(state);
+               if (state->load_avg > state->max_load_avg)
                        return steve_token_availability::load_exceeded;
        }
 
@@ -268,6 +316,8 @@ static void steve_destroy(void *userdata)
 
        state->waiters.clear();
        state->processes.clear();
+       if (state->loadavg_fd >= 0)
+               close(state->loadavg_fd);
 }
 
 static void steve_open(fuse_req_t req, struct fuse_file_info *fi)

Reply via email to