#define _GNU_SOURCE #include #include #include #include #include #include #include // gcc -fPIC -shared -O2 -o ncpu{.so,.c} // NCPU=16 LD_PRELOAD=$PWD/ncpu.so command args... static char prog_full_path[PATH_MAX]; long sysconf(int name) { if (name == _SC_NPROCESSORS_ONLN || name == _SC_NPROCESSORS_CONF) { const char *ncpu = getenv("NCPU"); int n; n = ncpu ? atoi(ncpu) : CPU_SETSIZE; if (n < 0 || n > CPU_SETSIZE) n = CPU_SETSIZE; return n; } errno = EINVAL; return -1; } /* return a cpu_set having the first $NCPU set */ int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) { const char *ncpu; int i, n; CPU_ZERO_S(cpusetsize, mask); ncpu = getenv("NCPU"); n = ncpu ? atoi(ncpu) : CPU_SETSIZE; if (n < 0 || n > CPU_SETSIZE) n = CPU_SETSIZE; for (i = 0; i < n; i++) CPU_SET_S(i, cpusetsize, mask); return 0; } /* silently ignore the operation */ int sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask) { return 0; } void usage(const char *argv0) { fprintf(stderr, "Usage: %s [-n ncpu] [cmd [args...]]\n" " Will install itself in LD_PRELOAD before calling with args.\n" " The number of CPUs may also come from variable NCPU or default to %d.\n" "\n" "", argv0, CPU_SETSIZE); exit(1); } /* Called in wrapper mode, no longer supported on recent glibc */ int main(int argc, char **argv) { const char *argv0 = argv[0]; char *preload; int plen; prog_full_path[0] = 0; plen = readlink("/proc/self/exe", prog_full_path, sizeof(prog_full_path) - 1); if (plen != -1) prog_full_path[plen] = 0; else plen = snprintf(prog_full_path, sizeof(prog_full_path), "%s", argv[0]); while (1) { argc--; argv++; if (argc < 1) usage(argv0); if (strcmp(argv[0], "--") == 0) { argc--; argv++; break; } else if (strcmp(argv[0], "-n") == 0) { if (argc < 2) usage(argv0); if (setenv("NCPU", argv[1], 1) != 0) usage(argv0); argc--; argv++; } else { /* unknown arg, that's the command */ break; } } /* here the only args left start with the cmd name */ /* now we'll concatenate ourselves at the end of the LD_PRELOAD variable */ preload = getenv("LD_PRELOAD"); if (preload) { int olen = strlen(preload); preload = realloc(preload, olen + 1 + plen + 1); if (!preload) { perror("realloc"); exit(2); } preload[olen] = ' '; memcpy(preload + olen + 1, prog_full_path, plen); preload[olen + 1 + plen] = 0; } else { preload = prog_full_path; } if (setenv("LD_PRELOAD", preload, 1) < 0) { perror("setenv"); exit(2); } execvp(*argv, argv); perror("execve"); exit(2); }