Better available cpu count determination.

With 'worker_processes auto;' the number of worker processes to create
is generally determined at runtime via sysconf(_SC_NPROCESSORS_ONLN);

However this value does not take into account any restrictions that have
been put in place via mechanisms like cpuset(7)'s and/or
sched_setaffinity(2).

So for example while a system may have 18 "cpus" available as returned
via sysconf(_SC_NPROCESSORS_ONLN) the actual number of allowed to run on
cpus may be much lower.

E.g.

On a 18 core system, with 'worker_processes auto;' nginx will create 18
worker processes (+ the master). E.g.

  $ pgrep -c nginx
  19

If however nginx has been restricted to run on just four. We will still
create 18 worker processes. E.g.

  $ taskset -a -c 0-3 ./sbin/nginx -c conf/minimal.conf
  $ pgrep -c nginx
  19

This can happen for example with 'docker --cpuset-cpus=', where you may
end up with many more worker processes than runnable cpus.

This commit uses sched_getaffinity() (where available, at least Linux &
FreeBSD) to determine the number of actual available runnable cpus.

So in the above example we now get

  $ taskset -a -c 0-3 ./sbin/nginx -c conf/minimal.conf
  $ pgrep -c nginx
  5

Four worker processes plus the master.

Closes: https://github.com/nginx/nginx/issues/855
This commit is contained in:
Andrew Clayton 2025-09-26 21:59:04 +01:00
parent 453b5b5caf
commit 1c59ff16d3
1 changed files with 22 additions and 0 deletions

View File

@ -64,6 +64,28 @@ ngx_os_init(ngx_log_t *log)
}
#endif
#if (NGX_HAVE_SCHED_GETAFFINITY)
if (ngx_ncpu > 0) {
int err;
size_t sz;
cpu_set_t *mask;
mask = CPU_ALLOC(ngx_ncpu);
if (mask == NULL) {
return NGX_ERROR;
}
sz = CPU_ALLOC_SIZE(ngx_ncpu);
err = sched_getaffinity(0, sz, mask);
if (err == 0) {
ngx_ncpu = CPU_COUNT_S(sz, mask);
}
CPU_FREE(mask);
}
#endif
if (ngx_ncpu < 1) {
ngx_ncpu = 1;
}