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