diff options
author | Alexey Sheplyakov <asheplyakov@altlinux.org> | 2021-04-27 14:48:53 +0400 |
---|---|---|
committer | Alexey Sheplyakov <asheplyakov@altlinux.org> | 2021-04-27 19:07:00 +0400 |
commit | ac121434aae7d16053d005c508073bf1a8108095 (patch) | |
tree | bf050de6f61b7ec0aeb90af25da1a84d67461d9f | |
parent | de21b1a43737fbcf47967a706dab4c60521dbbb1 (diff) | |
download | distcc-git-ac121434aae7d16053d005c508073bf1a8108095.tar.gz |
prefork: use available cores more efficiently
Observed behavior
-----------------
When compiling a big C project (Linux kernel) with
distcc compilation nodes never use 100% of CPU time, instead a system
is 25 -- 40% idle (despite --jobs is set to 3x the number of cores).
Analysis
--------
Linux kernel consists of many relatively small C sources and header
files. Compiling a single source file typically takes a fraction of
a second (although there are quite a number of "heavier" sources).
`dcc_preforked_child` exits after 50 requests. Thus a typical lifetime
of a worker process is just a few seconds. However `dcc_create_kids`
sleeps for a second after every fork. Also `dcc_preforked_child` sleeps
for yet another second. Which is >= 25% of a typical child lifetime.
As a result distccd is unable to use available CPU time (system load
is always <= 75% during the compilation).
Fix
---
Removed `sleep` from `dcc_preforking_parent` and `dcc_create_kids`.
Also made `dcc_preforked_child` process compilation jobs for at least
60 seconds.
Result
------
Kernel compilation time (two 6-core nodes) reduced almost 2x:
before: 20 minutes, after: 12 minutes
Closes: #420
-rw-r--r-- | src/prefork.c | 17 |
1 files changed, 7 insertions, 10 deletions
diff --git a/src/prefork.c b/src/prefork.c index 38e3a19..d7e1d84 100644 --- a/src/prefork.c +++ b/src/prefork.c @@ -37,6 +37,7 @@ #include <syslog.h> #include <signal.h> #include <fcntl.h> +#include <time.h> #include <sys/stat.h> #include <sys/types.h> @@ -91,10 +92,6 @@ int dcc_preforking_parent(int listen_fd) /* wait for any children to exit, and then start some more */ dcc_reap_kids(TRUE); - - /* Another little safety brake here: since children should not exit - * too quickly, pausing before starting them should be harmless. */ - sleep(1); } } } @@ -133,10 +130,6 @@ static void dcc_create_kids(int listen_fd) { ++dcc_nkids; rs_trace("up to %d children", dcc_nkids); } - - /* Don't start them too quickly, or we might overwhelm a machine - * that's having trouble. */ - sleep(1); } } @@ -151,9 +144,12 @@ static void dcc_create_kids(int listen_fd) { static int dcc_preforked_child(int listen_fd) { int ireq; - const int child_lifetime = 50; + time_t start, now; + const int child_requests = 50; + const time_t child_lifetime = 60 /* seconds */; + start = now = time(NULL); - for (ireq = 0; ireq < child_lifetime; ireq++) { + for (ireq = 0; ireq < child_requests || now - start < child_lifetime; ireq++) { int acc_fd; struct dcc_sockaddr_storage cli_addr; socklen_t cli_len; @@ -188,6 +184,7 @@ static int dcc_preforked_child(int listen_fd) (struct sockaddr *) &cli_addr, cli_len); dcc_close(acc_fd); + now = time(NULL); } rs_log_info("worn out"); |