Skip to content

Commit

Permalink
unix,win: add uv_available_parallelism() (libuv#3499)
Browse files Browse the repository at this point in the history
Replacement for the usage pattern where people use uv_cpu_info() as an
imperfect heuristic for determining the amount of parallelism that is
available to their programs.

Fixes libuv#3493.
  • Loading branch information
bnoordhuis authored and JeffroMF committed May 16, 2022
1 parent 2a7e44b commit 9cc4bcf
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 0 deletions.
19 changes: 19 additions & 0 deletions docs/src/misc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -334,11 +334,30 @@ API
.. versionadded:: 1.16.0
.. c:function:: unsigned int uv_available_parallelism(void)
Returns an estimate of the default amount of parallelism a program should
use. Always returns a non-zero value.
On Linux, inspects the calling thread's CPU affinity mask to determine if
it has been pinned to specific CPUs.
On Windows, the available parallelism may be underreported on systems with
more than 64 logical CPUs.
On other platforms, reports the number of CPUs that the operating system
considers to be online.
.. versionadded:: 1.44.0
.. c:function:: int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count)
Gets information about the CPUs on the system. The `cpu_infos` array will
have `count` elements and needs to be freed with :c:func:`uv_free_cpu_info`.
Use :c:func:`uv_available_parallelism` if you need to know how many CPUs
are available for threads or child processes.
.. c:function:: void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count)
Frees the `cpu_infos` array previously allocated with :c:func:`uv_cpu_info`.
Expand Down
1 change: 1 addition & 0 deletions include/uv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,7 @@ UV_EXTERN uv_pid_t uv_os_getppid(void);
UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority);
UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority);

UV_EXTERN unsigned int uv_available_parallelism(void);
UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);

Expand Down
33 changes: 33 additions & 0 deletions src/unix/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ extern char** environ;
#endif

#if defined(__linux__)
# include <sched.h>
# include <sys/syscall.h>
# define uv__accept4 accept4
#endif
Expand Down Expand Up @@ -1648,3 +1649,35 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
/* Out of tokens (path entries), and no match found */
return UV_EINVAL;
}


unsigned int uv_available_parallelism(void) {
#ifdef __linux__
cpu_set_t set;
long rc;

memset(&set, 0, sizeof(set));

/* sysconf(_SC_NPROCESSORS_ONLN) in musl calls sched_getaffinity() but in
* glibc it's... complicated... so for consistency try sched_getaffinity()
* before falling back to sysconf(_SC_NPROCESSORS_ONLN).
*/
if (0 == sched_getaffinity(0, sizeof(set), &set))
rc = CPU_COUNT(&set);
else
rc = sysconf(_SC_NPROCESSORS_ONLN);

if (rc < 1)
rc = 1;

return (unsigned) rc;
#else /* __linux__ */
long rc;

rc = sysconf(_SC_NPROCESSORS_ONLN);
if (rc < 1)
rc = 1;

return (unsigned) rc;
#endif /* __linux__ */
}
17 changes: 17 additions & 0 deletions src/win/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,23 @@ int uv_uptime(double* uptime) {
}


unsigned int uv_available_parallelism(void) {
SYSTEM_INFO info;
unsigned rc;

/* TODO(bnoordhuis) Use GetLogicalProcessorInformationEx() to support systems
* with > 64 CPUs? See https://github.com/libuv/libuv/pull/3458
*/
GetSystemInfo(&info);

rc = info.dwNumberOfProcessors;
if (rc < 1)
rc = 1;

return rc;
}


int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
uv_cpu_info_t* cpu_infos;
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
Expand Down
5 changes: 5 additions & 0 deletions test/test-platform-output.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ TEST_IMPL(platform_output) {
uv_interface_address_t* interfaces;
uv_passwd_t pwd;
uv_utsname_t uname;
unsigned par;
int count;
int i;
int err;
Expand Down Expand Up @@ -88,6 +89,10 @@ TEST_IMPL(platform_output) {
printf(" maximum resident set size: %llu\n",
(unsigned long long) rusage.ru_maxrss);

par = uv_available_parallelism();
ASSERT_GE(par, 1);
printf("uv_available_parallelism: %u\n", par);

err = uv_cpu_info(&cpus, &count);
#if defined(__CYGWIN__) || defined(__MSYS__)
ASSERT(err == UV_ENOSYS);
Expand Down

0 comments on commit 9cc4bcf

Please sign in to comment.