Compare commits

...

1 commit

Author SHA1 Message Date
66e255d355 Better CPU affinity, if ag is invoked with a nontrivial CPU mask
On a Ryzen 5700U CPU, Linux 5.10.0, Debian bullseye, and `nosmt` on the
kernel commandline, every task is effectively pinned to the CPU mask
0x5555:
```
On-line CPU(s) list:             0,2,4,6,8,10,12,14
Off-line CPU(s) list:            1,3,5,7,9,11,13,15
```

In order to avoid failures of `pthread_setaffinity_np`, check the CPUs
that the main thread has available (and use it to set num_cores!) and
then each time a thread is created, find the next set bit.

This also fixes the behavior when ag is deliberately pinned to some
smaller number of CPUs than those on-line:
```
$ taskset 0x5555 ./ag -D booboo | ag "Using \d+ workers"
DEBUG: Using 7 workers
$ taskset 0x55 ag -D booboo | ag "Using \d+ workers"
DEBUG: Using 3 workers
```
2021-09-01 09:26:56 -05:00
2 changed files with 23 additions and 7 deletions

View file

@ -64,7 +64,7 @@ AC_CHECK_HEADERS([sys/cpuset.h err.h])
AC_CHECK_MEMBER([struct dirent.d_type], [AC_DEFINE([HAVE_DIRENT_DTYPE], [], [Have dirent struct member d_type])], [], [[#include <dirent.h>]]) AC_CHECK_MEMBER([struct dirent.d_type], [AC_DEFINE([HAVE_DIRENT_DTYPE], [], [Have dirent struct member d_type])], [], [[#include <dirent.h>]])
AC_CHECK_MEMBER([struct dirent.d_namlen], [AC_DEFINE([HAVE_DIRENT_DNAMLEN], [], [Have dirent struct member d_namlen])], [], [[#include <dirent.h>]]) AC_CHECK_MEMBER([struct dirent.d_namlen], [AC_DEFINE([HAVE_DIRENT_DNAMLEN], [], [Have dirent struct member d_namlen])], [], [[#include <dirent.h>]])
AC_CHECK_FUNCS(fgetln fopencookie getline realpath strlcpy strndup vasprintf madvise posix_fadvise pthread_setaffinity_np pledge) AC_CHECK_FUNCS(fgetln fopencookie getline realpath strlcpy strndup vasprintf madvise posix_fadvise pthread_getaffinity_np pthread_setaffinity_np pledge)
AC_CONFIG_FILES([Makefile the_silver_searcher.spec]) AC_CONFIG_FILES([Makefile the_silver_searcher.spec])
AC_CONFIG_HEADERS([src/config.h]) AC_CONFIG_HEADERS([src/config.h])

View file

@ -36,7 +36,7 @@ typedef struct {
int main(int argc, char **argv) { int main(int argc, char **argv) {
char **base_paths = NULL; char **base_paths = NULL;
char **paths = NULL; char **paths = NULL;
int i; int i, j;
int pcre_opts = PCRE_MULTILINE; int pcre_opts = PCRE_MULTILINE;
int study_opts = 0; int study_opts = 0;
worker_t *workers = NULL; worker_t *workers = NULL;
@ -77,6 +77,18 @@ int main(int argc, char **argv) {
GetSystemInfo(&si); GetSystemInfo(&si);
num_cores = si.dwNumberOfProcessors; num_cores = si.dwNumberOfProcessors;
} }
#elif defined(HAVE_PTHREAD_SETAFFINITY_NP) && defined(HAVE_PTHREAD_GETAFFINITY_NP) && (defined(USE_CPU_SET) || defined(HAVE_SYS_CPUSET_H))
#if defined(__linux__) || defined(__midipix__)
cpu_set_t avail_cpu_set;
#elif __FreeBSD__
cpuset_t avail_cpu_set;
#endif
int rv = pthread_getaffinity_np(pthread_self(), sizeof(avail_cpu_set), &avail_cpu_set);
for (i = num_cores = 0; i < CPU_SETSIZE; i++) {
if (CPU_ISSET(i, &avail_cpu_set)) {
num_cores++;
}
}
#else #else
num_cores = (int)sysconf(_SC_NPROCESSORS_ONLN); num_cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
#endif #endif
@ -146,13 +158,13 @@ int main(int argc, char **argv) {
if (opts.search_stream) { if (opts.search_stream) {
search_stream(stdin, ""); search_stream(stdin, "");
} else { } else {
for (i = 0; i < workers_len; i++) { for (i = j = 0; i < workers_len; i++) {
workers[i].id = i; workers[i].id = i;
int rv = pthread_create(&(workers[i].thread), NULL, &search_file_worker, &(workers[i].id)); rv = pthread_create(&(workers[i].thread), NULL, &search_file_worker, &(workers[i].id));
if (rv != 0) { if (rv != 0) {
die("Error in pthread_create(): %s", strerror(rv)); die("Error in pthread_create(): %s", strerror(rv));
} }
#if defined(HAVE_PTHREAD_SETAFFINITY_NP) && (defined(USE_CPU_SET) || defined(HAVE_SYS_CPUSET_H)) #if defined(HAVE_PTHREAD_SETAFFINITY_NP) && defined(HAVE_PTHREAD_GETAFFINITY_NP) && (defined(USE_CPU_SET) || defined(HAVE_SYS_CPUSET_H))
if (opts.use_thread_affinity) { if (opts.use_thread_affinity) {
#if defined(__linux__) || defined(__midipix__) #if defined(__linux__) || defined(__midipix__)
cpu_set_t cpu_set; cpu_set_t cpu_set;
@ -160,13 +172,17 @@ int main(int argc, char **argv) {
cpuset_t cpu_set; cpuset_t cpu_set;
#endif #endif
CPU_ZERO(&cpu_set); CPU_ZERO(&cpu_set);
CPU_SET(i % num_cores, &cpu_set); do {
j = (j + 1) % CPU_SETSIZE;
} while (!CPU_ISSET(j, &avail_cpu_set));
CPU_SET(j++, &cpu_set);
rv = pthread_setaffinity_np(workers[i].thread, sizeof(cpu_set), &cpu_set); rv = pthread_setaffinity_np(workers[i].thread, sizeof(cpu_set), &cpu_set);
if (rv) { if (rv) {
log_err("Error in pthread_setaffinity_np(): %s", strerror(rv)); log_err("Error in pthread_setaffinity_np(): %s", strerror(rv));
log_err("Performance may be affected. Use --noaffinity to suppress this message."); log_err("Performance may be affected. Use --noaffinity to suppress this message.");
} else { } else {
log_debug("Thread %i set to CPU %i", i, i); log_debug("Thread %i set to CPU %i", i, j);
} }
} else { } else {
log_debug("Thread affinity disabled."); log_debug("Thread affinity disabled.");