tech-toolchain archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: make: dynamic scaling of maxJobs ?



On Fri, 2 Aug 2013 15:45:19 -0700, Simon Gerraty writes:
>I'm playing with a patch to do this, and wondering if there is general
>interest in the idea.

Ok here's the current patch (its against bmake, since testing on
multiple platforms):

diff -r 2912767531ba job.c
--- a/job.c     Thu Aug 01 13:32:25 2013 -0700
+++ b/job.c     Sun Aug 04 10:31:40 2013 -0700
@@ -188,6 +188,12 @@
 int not_parallel = 0;              /* set if .NOT_PARALLEL */
 
 /*
+ * If set, we run it occasionally to adjust maxJobTokens
+ */
+static char *jobs_cmd = NULL;
+static int jobTokensAdjust = 0;            /* only relevant if jobs_cmd set */
+
+/*
  * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file
  * is a char! So when we go above 127 we turn negative!
  */
@@ -376,6 +382,104 @@
 
 const char *malloc_options="A";
 
+/*
+ * Job_maxTokens - dynamically determine .MAKE.JOBS
+ *
+ * This is only used by the initial instance of make
+ * which usually the one that runs the longest.
+ * We run an external tool which reports the maxJobTokens
+ * value we should use.
+ * We get called from JobFinish() and if it has been more than
+ * ${.MAKE.JOBS.CMD.INTERVAL} seconds we re-run ${.MAKE.JOBS.CMD}.
+ * If the result is higher than before (limited by maxJobs) we add
+ * tokens to the queue, and if less avoid re-adding until the
+ * adjustment is completed.
+ */
+#ifndef DEFAULT_MAKE_JOBS_CMD_INTERVAL
+# define DEFAULT_MAKE_JOBS_CMD_INTERVAL 300
+#endif
+int
+Job_maxTokens(int old)
+{
+    static time_t interval, last = 0, utc;
+    char *cp = NULL;
+    const char *ep;
+    int max_tokens = old;
+
+    if (!last) {
+       /*
+        * First time.
+        * We split initializtion since we can be called before
+        * and after makefiles have been read.
+        */
+       last = 1;                       /* initialized */
+       interval = 0;                   /* not */
+       jobs_cmd = Var_Subst(NULL, "${.MAKE.JOBS.CMD}", VAR_GLOBAL, 0);
+       if (jobs_cmd) {
+           if (!jobs_cmd[0]) {
+               free(jobs_cmd);
+               jobs_cmd = NULL;
+           }
+       }
+    }
+    if (!jobs_cmd)
+       return old;
+    if (old) {
+       /* makefiles have been read by now */
+       time(&utc);
+       if (!interval) {
+           interval = getInt(".MAKE.JOBS.CMD.INTERVAL",
+                             DEFAULT_MAKE_JOBS_CMD_INTERVAL);
+       }
+       if (utc - last < interval)
+           return old;
+       last = utc;
+    }
+    cp = Cmd_Exec(jobs_cmd, &ep);
+    if (cp && *cp) {
+       max_tokens = atoi(cp);
+    }
+    if (DEBUG(JOB)) {
+       (void)fprintf(debug_file,
+                     "Job_maxTokens: cmd=%s interval=%u old=%d new=%d\n",
+                     jobs_cmd, interval, old, max_tokens);
+    }
+    if (old) {
+       /* sanity checks */
+       if (max_tokens > maxJobs)
+           max_tokens = maxJobs;
+       else if (max_tokens < 1)
+           max_tokens = old;
+       if (max_tokens == old) {
+           jobTokensAdjust = 0;
+       } else {
+           jobTokensAdjust = max_tokens - old;
+           if (DEBUG(JOB)) {
+               (void)fprintf(debug_file,
+                             "Job_maxTokens: adjust %+d tokens\n",
+                             jobTokensAdjust);
+           }
+       }
+       /*
+        * Token reduction happens via Job_TokenReturn
+        * addition is done here.
+        */
+       if (jobTokensAdjust > 0) {
+           while (jobTokensAdjust-- > 0) {
+               JobTokenAdd();
+               maxJobTokens++;
+           }
+       }
+    }
+    if (cp) {
+       /* adjust what we pass to sub-makes */
+       if (max_tokens != old)
+           Var_Set(".MAKE.JOBS", cp, VAR_GLOBAL, 0);
+       free(cp);
+    }
+    return max_tokens;
+}
+
 static void
 job_table_dump(const char *where)
 {
@@ -1116,6 +1220,8 @@
         */
        Finish(errors);
     }
+    if (jobs_cmd)
+       Job_maxTokens(maxJobTokens);
 }
 
 /*-
@@ -2211,9 +2317,26 @@
  *     lists and counters are initialized
  *-----------------------------------------------------------------------
  */
+#ifndef DEFAULT_MAKE_JOBS_MAX
+# define DEFAULT_MAKE_JOBS_MAX 64
+#endif
 void
 Job_Init(void)
 {
+    if (makelevel == 0 && !jobs_cmd) {
+       maxJobTokens = Job_maxTokens(maxJobTokens);
+       if (!maxJobTokens)
+           maxJobTokens = maxJobs;
+    }
+    if (jobs_cmd) {
+       maxJobs = getInt(".MAKE.JOBS.MAX",
+                        MAX(maxJobTokens, DEFAULT_MAKE_JOBS_MAX));
+       if (DEBUG(JOB)) {
+           (void)fprintf(debug_file, "Job_Init: tokens=%d max=%d\n",
+                         maxJobTokens, maxJobs);
+       }
+    }
+
     /* Allocate space for all the job info */
     job_table = bmake_malloc(maxJobs * sizeof *job_table);
     memset(job_table, 0, maxJobs * sizeof *job_table);
@@ -2856,10 +2979,9 @@
 
     JobCreatePipe(&tokenWaitJob, 15);
 
-    snprintf(jobarg, sizeof(jobarg), "%d,%d",
+    snprintf(jobarg, sizeof(jobarg), "-J%d,%d",
            tokenWaitJob.inPipe, tokenWaitJob.outPipe);
 
-    Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL);
     Var_Append(MAKEFLAGS, jobarg, VAR_GLOBAL);                 
 
     /*
@@ -2888,8 +3010,14 @@
     jobTokensRunning--;
     if (jobTokensRunning < 0)
        Punt("token botch");
-    if (jobTokensRunning || JOB_TOKENS[aborting] != '+')
-       JobTokenAdd();
+    if (jobTokensRunning || JOB_TOKENS[aborting] != '+') {
+       if (jobTokensAdjust < 0 && maxJobTokens > 1) {
+           jobTokensAdjust++;
+           maxJobTokens--;
+       } else {
+           JobTokenAdd();
+       }
+    }
 }
 
 /*-
diff -r 2912767531ba job.h
--- a/job.h     Thu Aug 01 13:32:25 2013 -0700
+++ b/job.h     Sun Aug 04 10:31:40 2013 -0700
@@ -247,6 +247,7 @@
 
 extern int     jobTokensRunning; /* tokens currently "out" */
 extern int     maxJobs;        /* Max jobs we can run */
+extern int     maxJobTokens;   /* almost the same thing */
 
 void Shell_Init(void);
 const char *Shell_GetNewline(void);
diff -r 2912767531ba main.c
--- a/main.c    Thu Aug 01 13:32:25 2013 -0700
+++ b/main.c    Sun Aug 04 10:31:40 2013 -0700
@@ -155,7 +155,7 @@
 static Boolean         printVars;      /* print value of one or more vars */
 static Lst             variables;      /* list of variables to print */
 int                    maxJobs;        /* -j argument */
-static int             maxJobTokens;   /* -j argument */
+int                    maxJobTokens;   /* -j argument */
 Boolean                        compatMake;     /* -B argument */
 int                    debug;          /* -d argument */
 Boolean                        debugVflag;     /* -dV */
@@ -543,15 +543,20 @@
                case 'j':
                        if (argvalue == NULL) goto noarg;
                        forceJobs = TRUE;
-                       maxJobs = strtol(argvalue, &p, 0);
-                       if (*p != '\0' || maxJobs < 1) {
+                       if (argvalue[0] == '/') {
+                           /* we are going to do dynamic scaling */
+                           Var_Set(".MAKE.JOBS.CMD", argvalue, VAR_GLOBAL, 0);
+                           maxJobs = Job_maxTokens(0);
+                       } else {
+                           maxJobs = strtol(argvalue, &p, 0);
+                           if (*p != '\0' || maxJobs < 1) {
                                (void)fprintf(stderr, "%s: illegal argument to 
-j -- must be positive integer!\n",
                                    progname);
                                exit(1);
+                           }
+                           Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL, 0);
                        }
-                       Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);
-                       Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
-                       Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL, 0);
+                       Var_Append(MAKEFLAGS, "-j${.MAKE.JOBS}", VAR_GLOBAL);
                        maxJobTokens = maxJobs;
                        break;
                case 'k':
@@ -1991,3 +1996,21 @@
     }
     return (bf);
 }
+
+int
+getInt(const char *name, int i)
+{
+    char tmp[64];
+    char *cp;
+
+    if (snprintf(tmp, sizeof(tmp), "${%s}", name) < (int)(sizeof(tmp))) {
+       cp = Var_Subst(NULL, tmp, VAR_GLOBAL, 0);
+
+       if (cp) {
+           if (*cp)
+               i = atoi(cp);
+           free(cp);
+       }
+    }
+    return (i);
+}
diff -r 2912767531ba make.h
--- a/make.h    Thu Aug 01 13:32:25 2013 -0700
+++ b/make.h    Sun Aug 04 10:31:40 2013 -0700
@@ -426,6 +426,8 @@
 extern char    *makeDependfile; /* .depend */
 extern char    **savedEnv;      /* if we replaced environ this will be 
non-NULL */
 
+extern int     makelevel;
+
 /*
  * We cannot vfork() in a child of vfork().
  * Most systems do not enforce this but some do.
@@ -495,6 +497,9 @@
 Boolean Main_SetObjdir(const char *);
 int mkTempFile(const char *, char **);
 int str2Lst_Append(Lst, char *, const char *);
+int getInt(const char *, int);
+int Job_maxTokens(int);
+
 
 #ifdef __GNUC__
 #define UNCONST(ptr)   ({              \
diff -r 2912767531ba var.c
--- a/var.c     Thu Aug 01 13:32:25 2013 -0700
+++ b/var.c     Sun Aug 04 10:31:40 2013 -0700
@@ -139,7 +139,6 @@
 #include    "dir.h"
 #include    "job.h"
 
-extern int makelevel;
 /*
  * This lets us tell if we have replaced the original environ
  * (which we cannot free).



Home | Main Index | Thread Index | Old Index