1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-08-05 19:35:52 +03:00

linux: fix accuracy of get_nprocs and get_nprocs_conf [BZ #28865]

get_nprocs() and get_nprocs_conf() use various methods to obtain an
accurate number of processors.  Re-introduce __get_nprocs_sched() as
a source of information, and fix the order in which these methods are
used to return the most accurate information.  The primary source of
information used in both functions remains unchanged.

This also changes __get_nprocs_sched() error return value from 2 to 0,
but all its users are already prepared to handle that.

Old fallback order:
  get_nprocs:
    /sys/devices/system/cpu/online -> /proc/stat -> 2
  get_nprocs_conf:
    /sys/devices/system/cpu/ -> /proc/stat -> 2

New fallback order:
  get_nprocs:
    /sys/devices/system/cpu/online -> /proc/stat -> sched_getaffinity -> 2
  get_nprocs_conf:
    /sys/devices/system/cpu/ -> /proc/stat -> sched_getaffinity -> 2

Fixes: 342298278e ("linux: Revert the use of sched_getaffinity on get_nproc")
Closes: BZ #28865
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
This commit is contained in:
Dmitry V. Levin
2022-02-05 08:00:00 +00:00
parent 1b0c60f95b
commit e1d32b8364

View File

@@ -50,9 +50,8 @@ __get_nprocs_sched (void)
is an arbitrary values assuming such systems should be rare and there is an arbitrary values assuming such systems should be rare and there
is no offline cpus. */ is no offline cpus. */
return max_num_cpus; return max_num_cpus;
/* Some other error. 2 is conservative (not a uniprocessor system, so /* Some other error. */
atomics are needed). */ return 0;
return 2;
} }
static char * static char *
@@ -108,22 +107,19 @@ next_line (int fd, char *const buffer, char **cp, char **re,
} }
static int static int
get_nproc_stat (char *buffer, size_t buffer_size) get_nproc_stat (void)
{ {
enum { buffer_size = 1024 };
char buffer[buffer_size];
char *buffer_end = buffer + buffer_size; char *buffer_end = buffer + buffer_size;
char *cp = buffer_end; char *cp = buffer_end;
char *re = buffer_end; char *re = buffer_end;
int result = 0;
/* Default to an SMP system in case we cannot obtain an accurate
number. */
int result = 2;
const int flags = O_RDONLY | O_CLOEXEC; const int flags = O_RDONLY | O_CLOEXEC;
int fd = __open_nocancel ("/proc/stat", flags); int fd = __open_nocancel ("/proc/stat", flags);
if (fd != -1) if (fd != -1)
{ {
result = 0;
char *l; char *l;
while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL) while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL)
/* The current format of /proc/stat has all the cpu* entries /* The current format of /proc/stat has all the cpu* entries
@@ -139,8 +135,8 @@ get_nproc_stat (char *buffer, size_t buffer_size)
return result; return result;
} }
int static int
__get_nprocs (void) get_nprocs_cpu_online (void)
{ {
enum { buffer_size = 1024 }; enum { buffer_size = 1024 };
char buffer[buffer_size]; char buffer[buffer_size];
@@ -179,7 +175,8 @@ __get_nprocs (void)
} }
} }
result += m - n + 1; if (m >= n)
result += m - n + 1;
l = endp; l = endp;
if (l < re && *l == ',') if (l < re && *l == ',')
@@ -188,28 +185,18 @@ __get_nprocs (void)
while (l < re && *l != '\n'); while (l < re && *l != '\n');
__close_nocancel_nostatus (fd); __close_nocancel_nostatus (fd);
if (result > 0)
return result;
} }
return get_nproc_stat (buffer, buffer_size); return result;
} }
libc_hidden_def (__get_nprocs)
weak_alias (__get_nprocs, get_nprocs)
static int
/* On some architectures it is possible to distinguish between configured get_nprocs_cpu (void)
and active cpus. */
int
__get_nprocs_conf (void)
{ {
/* Try to use the sysfs filesystem. It has actual information about int count = 0;
online processors. */
DIR *dir = __opendir ("/sys/devices/system/cpu"); DIR *dir = __opendir ("/sys/devices/system/cpu");
if (dir != NULL) if (dir != NULL)
{ {
int count = 0;
struct dirent64 *d; struct dirent64 *d;
while ((d = __readdir64 (dir)) != NULL) while ((d = __readdir64 (dir)) != NULL)
@@ -224,12 +211,57 @@ __get_nprocs_conf (void)
__closedir (dir); __closedir (dir);
return count;
} }
return count;
}
enum { buffer_size = 1024 }; static int
char buffer[buffer_size]; get_nprocs_fallback (void)
return get_nproc_stat (buffer, buffer_size); {
int result;
/* Try /proc/stat first. */
result = get_nproc_stat ();
if (result != 0)
return result;
/* Try sched_getaffinity. */
result = __get_nprocs_sched ();
if (result != 0)
return result;
/* We failed to obtain an accurate number. Be conservative: return
the smallest number meaning that this is not a uniprocessor system,
so atomics are needed. */
return 2;
}
int
__get_nprocs (void)
{
/* Try /sys/devices/system/cpu/online first. */
int result = get_nprocs_cpu_online ();
if (result != 0)
return result;
/* Fall back to /proc/stat and sched_getaffinity. */
return get_nprocs_fallback ();
}
libc_hidden_def (__get_nprocs)
weak_alias (__get_nprocs, get_nprocs)
/* On some architectures it is possible to distinguish between configured
and active cpus. */
int
__get_nprocs_conf (void)
{
/* Try /sys/devices/system/cpu/ first. */
int result = get_nprocs_cpu ();
if (result != 0)
return result;
/* Fall back to /proc/stat and sched_getaffinity. */
return get_nprocs_fallback ();
} }
libc_hidden_def (__get_nprocs_conf) libc_hidden_def (__get_nprocs_conf)
weak_alias (__get_nprocs_conf, get_nprocs_conf) weak_alias (__get_nprocs_conf, get_nprocs_conf)