unix,win: add uv_available_parallelism() (#3499)
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 #3493.
This commit is contained in:
parent
c40f8cb9f8
commit
f250c6c73e
@ -334,11 +334,30 @@ API
|
|||||||
|
|
||||||
.. versionadded:: 1.16.0
|
.. 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)
|
.. 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
|
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`.
|
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)
|
.. 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`.
|
Frees the `cpu_infos` array previously allocated with :c:func:`uv_cpu_info`.
|
||||||
|
|||||||
@ -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_getpriority(uv_pid_t pid, int* priority);
|
||||||
UV_EXTERN int uv_os_setpriority(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 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);
|
UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
|
||||||
|
|
||||||
|
|||||||
@ -84,6 +84,7 @@ extern char** environ;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
|
# include <sched.h>
|
||||||
# include <sys/syscall.h>
|
# include <sys/syscall.h>
|
||||||
# define uv__accept4 accept4
|
# define uv__accept4 accept4
|
||||||
#endif
|
#endif
|
||||||
@ -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 */
|
/* Out of tokens (path entries), and no match found */
|
||||||
return UV_EINVAL;
|
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__ */
|
||||||
|
}
|
||||||
|
|||||||
@ -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) {
|
int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
|
||||||
uv_cpu_info_t* cpu_infos;
|
uv_cpu_info_t* cpu_infos;
|
||||||
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
|
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
|
||||||
|
|||||||
@ -41,6 +41,7 @@ TEST_IMPL(platform_output) {
|
|||||||
uv_interface_address_t* interfaces;
|
uv_interface_address_t* interfaces;
|
||||||
uv_passwd_t pwd;
|
uv_passwd_t pwd;
|
||||||
uv_utsname_t uname;
|
uv_utsname_t uname;
|
||||||
|
unsigned par;
|
||||||
int count;
|
int count;
|
||||||
int i;
|
int i;
|
||||||
int err;
|
int err;
|
||||||
@ -88,6 +89,10 @@ TEST_IMPL(platform_output) {
|
|||||||
printf(" maximum resident set size: %llu\n",
|
printf(" maximum resident set size: %llu\n",
|
||||||
(unsigned long long) rusage.ru_maxrss);
|
(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);
|
err = uv_cpu_info(&cpus, &count);
|
||||||
#if defined(__CYGWIN__) || defined(__MSYS__)
|
#if defined(__CYGWIN__) || defined(__MSYS__)
|
||||||
ASSERT(err == UV_ENOSYS);
|
ASSERT(err == UV_ENOSYS);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user