Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use /proc/loadavg on Linux #2218

Open
reddwarf69 opened this issue Nov 28, 2022 · 4 comments
Open

Use /proc/loadavg on Linux #2218

reddwarf69 opened this issue Nov 28, 2022 · 4 comments

Comments

@reddwarf69
Copy link

reddwarf69 commented Nov 28, 2022

GNU Make uses /proc/loadavg on Linux to decide whether to start another task: https://lwn.net/Articles/913253/ / https://git.savannah.gnu.org/cgit/make.git/commit/src/job.c?id=d8728efc80b720c630e6b12dbd34a3d44e060690. I would like Ninja to do the same.

Since /proc/loadavg provides "number of processes currently runnable (running or on ready queue)" (https://www.kernel.org/doc/html/latest/filesystems/proc.html), Ninja would be able to take better decisions than by looking only at the info provided by getloadavg().

@reddwarf69
Copy link
Author

reddwarf69 commented Nov 29, 2022

To have some numbers, I have a Jenkins slave with 64 cores. When pushing to a repository, multiple jobs are triggered. Those jobs are independent, and there is no easy way to have a common "jobserver" to limit the number of parallel tasks. All the makes/ninjas are run with "-j 64 -l 128".

With GNU Make 4.4 the peak 1 minute average load is 132, and the peak memory usage 55 GiB.
With Ninja the peak 1 minute average load is 562, and the peak memory usage 222 GiB.

With GNU Make 4.4 it takes a 1.7% less time to complete (clean builds).

@reddwarf69
Copy link
Author

reddwarf69 commented Dec 1, 2022

I'm not creating a PR because I'm not sure about the licence implications of me "basing" it on the GPL make patch. Maybe /proc/loadavg should be kept open the whole time instead of opening and closing in continuously, the parsing could maybe be made more robust, etc.

But this does the trick.

--- a/src/util.cc
+++ b/src/util.cc
@@ -818,6 +818,38 @@ double GetLoadAverage() {
 double GetLoadAverage() {
     return -0.0f;
 }
+#elif defined(linux)
+double GetLoadAverage() {
+  int fd = open("/proc/loadavg", O_RDONLY);
+  if(fd == -1) {
+    return -0.0f;
+  }
+
+  char avg[65];
+  int size = read(fd, avg, 64);
+  close(fd);
+  if(size == -1) {
+    return -0.0f;
+  }
+  avg[size] = '\0';
+
+  const char *p = strchr(avg, ' ');
+  if (p) {
+    p = strchr(p+1, ' ');
+  }
+  if (p) {
+    p = strchr(p+1, ' ');
+  }
+  if (!p) {
+    return -0.0f;
+  }
+
+  if((unsigned)p[1] - '0' > 9) {
+    return -0.0f;
+  }
+
+  return atoi(p+1);
+}
 #else
 double GetLoadAverage() {
   double loadavg[3] = { 0.0f, 0.0f, 0.0f };

0001-Use-proc-loadavg-on-Linux.log

I'm using it in production and my builds are now a 6.7% faster than without the patch (plus the OOM killer never kills them).

@SuperSandro2000
Copy link

I'm not sure about the licence implications of me "basing" it on the GPL make patch.

There is none if you don't the copy code. If you just take the idea and reimplement it in a different program then that is fine.

entrope added a commit to entrope/ninja that referenced this issue Mar 6, 2023
…d#2218)

The /proc/loadavg file includes the traditional 1-, 5- and 15-minute
loads plus an instantaneous count of processes that are ready to run.
This lets us respond faster to new processes being launched by other
processes.
entrope added a commit to entrope/ninja that referenced this issue Mar 30, 2023
…d#2218)

The /proc/loadavg file includes the traditional 1-, 5- and 15-minute
loads plus an instantaneous count of processes that are ready to run.
This lets us respond faster to new processes being launched by other
processes.
@haampie
Copy link

haampie commented Oct 27, 2023

Yeah, this would be pretty convenient. Given that ninja still doesn't support the GNU jobserver (#1139) , supporting /proc/loadavg would be a possibly simpler way to deal with the issue of many ninja instances spawned somewhere down the line by make -j <n>.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants