[Top][All Lists]

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

RE: Parallel builds across makefiles

From: Gardell, Steven
Subject: RE: Parallel builds across makefiles
Date: Sat, 30 Jul 2016 18:13:21 +0000

Thanks for the insights and apologies for the delayed response. My measurements seem to bear out the inference about Orecurse. These were done in succession on the same HP G9 server with 28 physical cores (56 hyper-threads) and TMDIR set to /tmp:


Build with leaf makefiles at j=32, and parallel suppressed in higher level Makefiles – 1:37 (hours:minutes)

Build with low level makefiles at j=32, parallel enabled for the “list of makefiles” makefiles and -Orecurse – 1:11

Build with low level makefiles at j=32, parallel enabled for the “list of makefiles” makefiles and -Onone– 1:04

Build with low level makefiles at j=32, parallel enabled for the “list of makefiles” makefiles and -Otarget – 8:55

Build with j=1 – 4:45


These are wall clock times on a shared machine, so certainly subject to some modest variation; it is likely that the Onone and Orecurse times are effectively the same.


Somewhat naively, I guess, the most surprising thing here is the -Otarget time. I would not be awfully surprised to see it asymptotically approach the no-parallel-building time. But to see it repeatably much longer just seems a bit bizarre.


From: Brian Vandenberg [mailto:address@hidden
Sent: Wednesday, July 27, 2016 4:59 PM
To: Gardell, Steven <address@hidden>
Cc: address@hidden
Subject: Re: Parallel builds across makefiles


I haven't seen similar issues but I have a hypothesis: make is single-threaded and therefore it consumes output from jobs in the same thread it uses to reap/spawn new jobs.  If make is spending a large enough amount of time consuming output then this will impacts the rate at which it can spawn/reap new jobs.


I ran some tests to see when make attempts to consume output from child processes and here's what I learned:


(a) For jobs executing within a single instance of make (not recursive) it doesn't appear to begin consuming text until a recipe completes (I only tested this with --output-sync=target; I expect similar to be true of other sync modes excluding none).

(b) If you use --output-sync=target and a recipe contains the string ${MAKE} at all -- even if it doesn't actually start a recursive make instance -- the way it consumes output is different (more on that below)

(c) make will not stop reading job output until there's nothing left to consume.  During that time it cannot reap/spawn new jobs.  If your jobs produce a large enough amount of text this could create enough small delays that aggregate into the noticeable delays you're seeing.


As an example to demonstrate (b):



SHELL := bash

OUTER := $(shell echo -n {0..15})

INNER := $(shell echo -n {16..32})

all: outer

outer: ${OUTER}

inner: ${INNER}



<@${MAKE} -f /tmp/makefile inner



<@perl -e 'my $$tmp = "${MAKE}"; map { printf "x\n"; sleep 1 } (0..100)'



I executed with (make 4.1):


make -j64 --output-sync=target


... and it begins printing output almost immediately in spite of the fact none of the recipes could have finished.  If you take ${MAKE} out of the recipe then it behaves as expected.


Now consider what I said w/regard to (c): it will only move on to spawning/reaping other jobs (or consuming other inputs) if there's nothing to read for the job it's currently consuming text from.


When I use --output-sync=recurse I don't see the same behavior, but if your build recurses more than 1 level then perhaps each sub-make attempts to consume output from its recursive make calls, possibly eating away at time it could spend spawning/reaping jobs.


If I'm right this could be completely avoided for those of us who would rather have log files instead of having everything dumped to the terminal.  If the parent make still needs to consume the output text, though, then the limiting factor is: make is single-threaded and consumes input from recursive jobs in the same thread it spawns/reaps new jobs.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]