Hi,

I've attached a test case Makefile, in an attempt to illustrate the
following behaviour.

For example:

both: lib1-build lib2-build

If both lib1-build and lib2-build take a substantial amount of time,
then there is the possibility that lib2-build's dependencies will
be satisfied on the first pass, while lib1-build's are satisfied
in conjunction with lib2-build's own job, and lib2-build's run will
continue, and make will miss an opportunity to run lib1-build in parallel.

To test this with the attached Makefile, run the following in a
clean directory:

        mkdir Nothing
        make -j16 -d

In my test case (the attached Log file) you'll notice that 'sleep 15s'
happens first (the lib2-build case), while 'sleep 5s' happens later
(the lib1-build case) and 'sleep 5s' waits until sleep 15s is finished,
even though this is not required.

Here's the abbreviated log to show what's happening:

Considering target file `all'.
 File `all' does not exist.
 Looking for an implicit rule for `all'.
 Trying pattern rule with stem `all'.
 Considering target file `both'.
  File `both' does not exist.
  Considering target file `lib1-build'.
   File `lib1-build' does not exist.
   Considering target file `lib2-dir'.
    File `lib2-dir' does not exist.
    Finished prerequisites of target file `lib2-dir'.
   Must remake target `lib2-dir'.
   Successfully remade target file `lib2-dir'.
   Considering target file `lib1-dir'.
    File `lib1-dir' does not exist.
    Finished prerequisites of target file `lib1-dir'.
   Must remake target `lib1-dir'.
Need a job token; we don't have children
mkdir lib1-dir
Putting child 0x0807e930 (lib1-dir) PID 12258 on the chain.
   Commands of `lib1-dir' are being run.
   Considering target file `Nothing'.
    Finished prerequisites of target file `Nothing'.
   No need to remake target `Nothing'.
   Finished prerequisites of target file `lib1-build'.
  The prerequisites of `lib1-build' are being made.
  Considering target file `lib2-build'.
   File `lib2-build' does not exist.
   Pruning file `lib2-dir'.
   Finished prerequisites of target file `lib2-build'.
  Must remake target `lib2-build'.
Live child 0x0807e930 (lib1-dir) PID 12258 
Reaping winning child 0x0807e930 PID 12258 
Removing child 0x0807e930 PID 12258 from chain.
Need a job token; we don't have children
sleep 15s
Putting child 0x0807e930 (lib2-build) PID 12259 on the chain.
  Commands of `lib2-build' are being run.
  Finished prerequisites of target file `both'.
 The prerequisites of `both' are being made.
 Finished prerequisites of target file `all'.
The prerequisites of `all' are being made.


At this point all dependencies for lib1-build and lib2-build are
complete, but they are not running in parallel.  A new pass would
discover this, but make waits for the lib2-build dependency to finish first.


Live child 0x0807e930 (lib2-build) PID 12259 
Reaping winning child 0x0807e930 PID 12259 
touch lib2-build
Live child 0x0807e930 (lib2-build) PID 12260 
Reaping winning child 0x0807e930 PID 12260 
Removing child 0x0807e930 PID 12260 from chain.
Considering target file `all'.
 File `all' does not exist.
 Considering target file `both'.
  File `both' does not exist.
  Considering target file `lib1-build'.
   File `lib1-build' does not exist.
   Considering target file `lib2-dir'.
   File `lib2-dir' was considered already.
   Considering target file `lib1-dir'.
   File `lib1-dir' was considered already.
   Considering target file `Nothing'.
   File `Nothing' was considered already.
   Finished prerequisites of target file `lib1-build'.
  Must remake target `lib1-build'.
Need a job token; we don't have children
sleep 5s
Putting child 0x0807eb20 (lib1-build) PID 12261 on the chain.
  Commands of `lib1-build' are being run.
  Considering target file `a'.


I had to really work to get this small test case to behave this way, and
without the -d option, make is fast enough to behave differently.
In my work makefile, this happens easily, since the file is so big.

I suspect the problem is that make doesn't perform a new pass after every
finished job.  It looks like the first job finished at the same time the
second job started (sleep 15s) and this first job was not seen as a trigger
to start a new pass.

For long-running jobs, this can be a significant bottleneck.

Thanks,
- Chris

Attachment: Log.bz2
Description: BZip2 compressed data

LIB1DIR = lib1-dir
LIB2DIR = lib2-dir

all: both

$(LIB1DIR):
        mkdir $(LIB1DIR)

$(LIB2DIR):
#       mkdir $(LIB2DIR)

lib1: lib1-build
        touch lib1

lib1-build: $(LIB2DIR) $(LIB1DIR) Nothing
        sleep 5s
        touch lib1-build

lib2: lib2-build
        touch lib2

lib2-build: $(LIB2DIR)
        sleep 15s
        touch lib2-build

a:
b:
c:
d:
e:
f:
g:
h:
i:
j:
k:
l:
m:
n:
o:
p:
q:
r:
s:
t:
u:
v:
w:
x:
y:
z:

both: lib1-build a b c d e f g h i j k l m n o p q r s t u v w x y z lib2-build
        $(MAKE) both-build
        touch both

both-build:
        sleep 2s
        touch both-build

clean:
        rm -rf [a-z]*

# This make sure that all variables in this file are exported to the
# environment for each command.
.EXPORT_ALL_VARIABLES:

# This avoids make deleting intermediate files in our implicit rules,
# such as ...configure and ...Makefile, which are needed in later builds.
.SECONDARY:

_______________________________________________
Bug-make mailing list
Bug-make@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-make

Reply via email to