Say I'm a developer for foo, and users can run several instances of foo in parallel using a Makefile.
To minimize bottlenecking, I would like to distribute job slots evenly. For instance, when calling "make -j12" on four instances of foo, each instance should launch three threads. Ideally I would like to calculate the thread-count-per-instance from entirely within foo. I managed to get the thread count, but I am having trouble counting the number of instances currently running. As far as I know, this number is not passed by Make. So far I have been resorting to counting the bytes in the jobserver pipe, and subtracting this count from the total thread count. I am calling ioctl() for this. Users are expected to have Linux and gnulib, so I don't have to worry about ioctl()'s portability. My problems are twofold: 1) somehow foo reads more bytes from the pipe than the number of available tokens, and 2) different instances often read different numbers of bytes from the pipe. I have attached a minimal working example of foo (that does nothing but print how many bytes are in the jobserver pipe) and Makefile. I'm having Make run four foo instances in parallel, so on -j12 each foo should read eight bytes from the pipe. On my machine, I almost always see the first three instances reading 10 bytes, and the last one reading 11. But my bigger point is whether I am missing some better approach. Maybe Make does pass the instance count somehow?
#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <getopt.h> #include <wordexp.h> #include <sys/file.h> #include <sys/ioctl.h> int main() { /* Skipping error checks for simplicity. The real file has error checks. */ /* All but the last two lines before the return statement are about parsing MAKEFLAGS. The parsing works fine, it's only the last two lines that aren't working the way I expected. */ size_t jobs; wordexp_t args; long pid=(long)getpid(); int i, read_fd=-1, write_fd=-1, tokencount=0; char *makecommand, *makeflags=getenv("MAKEFLAGS"); printf("MAKEFLAGS: %s\n", makeflags); makecommand=malloc(strlen(makeflags)+3); strcpy(makecommand, "a "); strcat(makecommand, makeflags); wordexp(makecommand, &args, 0); free(makecommand); opterr=0; while(1) { static struct option long_options[] = { {"jobserver-auth", optional_argument, 0, 0}, {0, 0, 0, 0} }; int option_index=0; i = getopt_long(args.we_wordc, args.we_wordv, "j::", long_options, &option_index); if(i==-1) break; switch(i) { case 0: sscanf(optarg, "%d,%d", &read_fd, &write_fd); break; case 'j': if(optarg==NULL) jobs=8; else sscanf(optarg, "%zu", &jobs); break; default: break; } } wordfree(&args); printf("jobs: %zu, read_fd: %d, write_fd: %d\n", jobs, read_fd, write_fd); ioctl(read_fd, FIONREAD, &tokencount); printf("token count: %d\n", tokencount); return 0; }
Makefile
Description: Binary data