From: Stefan Becker Date: Sun, 12 Nov 2017 16:58:55 +0200 Subject: [PATCH] Ignore jobserver when -jN is forced on command line This emulates the behaviour of GNU make. - add parallelism_from_cmdline flag to build configuration - set the flag when -jN is given on command line - pass the flag to TokenPool::Get() - GNUmakeTokenPool::Setup() * prints a warning when the flag is true and jobserver was detected * returns false, i.e. jobserver will be ignored - ignore config.parallelism in CanRunMore() when we have a valid TokenPool, because it gets always initialized to a default when not given on the command line --- src/build.cc | 10 ++++++---- src/build.h | 4 +++- src/ninja.cc | 1 + src/tokenpool-gnu-make.cc | 34 +++++++++++++++++++--------------- src/tokenpool-none.cc | 4 ++-- src/tokenpool.h | 4 ++-- 6 files changed, 33 insertions(+), 24 deletions(-) diff --git a/src/build.cc b/src/build.cc index 219bb9f1ff48..bc26bdade61b 100644 --- a/src/build.cc +++ b/src/build.cc @@ -507,7 +507,7 @@ struct RealCommandRunner : public CommandRunner { }; RealCommandRunner::RealCommandRunner(const BuildConfig& config) : config_(config) { - tokens_ = TokenPool::Get(); + tokens_ = TokenPool::Get(config_.parallelism_from_cmdline); } RealCommandRunner::~RealCommandRunner() { @@ -529,9 +529,11 @@ void RealCommandRunner::Abort() { } bool RealCommandRunner::CanRunMore() { - size_t subproc_number = - subprocs_.running_.size() + subprocs_.finished_.size(); - return (int)subproc_number < config_.parallelism + bool parallelism_limit_not_reached = + tokens_ || // ignore config_.parallelism + ((int) (subprocs_.running_.size() + + subprocs_.finished_.size()) < config_.parallelism); + return parallelism_limit_not_reached && (subprocs_.running_.empty() || (config_.max_load_average <= 0.0f || GetLoadAverage() < config_.max_load_average)); diff --git a/src/build.h b/src/build.h index ca605e62e0e3..6bc6fea26e94 100644 --- a/src/build.h +++ b/src/build.h @@ -128,7 +128,8 @@ struct CommandRunner { /// Options (e.g. verbosity, parallelism) passed to a build. struct BuildConfig { - BuildConfig() : verbosity(NORMAL), dry_run(false), parallelism(1), + BuildConfig() : verbosity(NORMAL), dry_run(false), + parallelism(1), parallelism_from_cmdline(false), failures_allowed(1), max_load_average(-0.0f) {} enum Verbosity { @@ -139,6 +140,7 @@ struct BuildConfig { Verbosity verbosity; bool dry_run; int parallelism; + bool parallelism_from_cmdline; int failures_allowed; /// The maximum load average we must not exceed. A negative value /// means that we do not have any limit. diff --git a/src/ninja.cc b/src/ninja.cc index ed004ac8f1fe..4332636c1b64 100644 --- a/src/ninja.cc +++ b/src/ninja.cc @@ -1063,6 +1063,7 @@ int ReadFlags(int* argc, char*** argv, if (*end != 0 || value <= 0) Fatal("invalid -j parameter"); config->parallelism = value; + config->parallelism_from_cmdline = true; break; } case 'k': { diff --git a/src/tokenpool-gnu-make.cc b/src/tokenpool-gnu-make.cc index 396bb7d87443..af4be05a31cf 100644 --- a/src/tokenpool-gnu-make.cc +++ b/src/tokenpool-gnu-make.cc @@ -1,4 +1,4 @@ -// Copyright 2016 Google Inc. All Rights Reserved. +// Copyright 2016-2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -35,7 +35,7 @@ struct GNUmakeTokenPool : public TokenPool { virtual void Clear(); virtual int GetMonitorFd(); - bool Setup(); + bool Setup(bool ignore); private: int available_; @@ -100,7 +100,7 @@ bool GNUmakeTokenPool::SetAlarmHandler() { } } -bool GNUmakeTokenPool::Setup() { +bool GNUmakeTokenPool::Setup(bool ignore) { const char *value = getenv("MAKEFLAGS"); if (value) { // GNU make <= 4.1 @@ -109,16 +109,20 @@ bool GNUmakeTokenPool::Setup() { if (!jobserver) jobserver = strstr(value, "--jobserver-auth="); if (jobserver) { - int rfd = -1; - int wfd = -1; - if ((sscanf(jobserver, "%*[^=]=%d,%d", &rfd, &wfd) == 2) && - CheckFd(rfd) && - CheckFd(wfd) && - SetAlarmHandler()) { - printf("ninja: using GNU make jobserver.\n"); - rfd_ = rfd; - wfd_ = wfd; - return true; + if (ignore) { + printf("ninja: warning: -jN forced on command line; ignoring GNU make jobserver.\n"); + } else { + int rfd = -1; + int wfd = -1; + if ((sscanf(jobserver, "%*[^=]=%d,%d", &rfd, &wfd) == 2) && + CheckFd(rfd) && + CheckFd(wfd) && + SetAlarmHandler()) { + printf("ninja: using GNU make jobserver.\n"); + rfd_ = rfd; + wfd_ = wfd; + return true; + } } } } @@ -206,9 +210,9 @@ int GNUmakeTokenPool::GetMonitorFd() { return(rfd_); } -struct TokenPool *TokenPool::Get(void) { +struct TokenPool *TokenPool::Get(bool ignore) { GNUmakeTokenPool *tokenpool = new GNUmakeTokenPool; - if (tokenpool->Setup()) + if (tokenpool->Setup(ignore)) return tokenpool; else delete tokenpool; diff --git a/src/tokenpool-none.cc b/src/tokenpool-none.cc index 602b3316f54d..199b22264bc6 100644 --- a/src/tokenpool-none.cc +++ b/src/tokenpool-none.cc @@ -1,4 +1,4 @@ -// Copyright 2016 Google Inc. All Rights Reserved. +// Copyright 2016-2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -22,6 +22,6 @@ #include // No-op TokenPool implementation -struct TokenPool *TokenPool::Get(void) { +struct TokenPool *TokenPool::Get(bool ignore) { return NULL; } diff --git a/src/tokenpool.h b/src/tokenpool.h index 301e1998ee8e..878a0933c2f0 100644 --- a/src/tokenpool.h +++ b/src/tokenpool.h @@ -1,4 +1,4 @@ -// Copyright 2016 Google Inc. All Rights Reserved. +// Copyright 2016-2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -28,5 +28,5 @@ struct TokenPool { #endif // returns NULL if token pool is not available - static struct TokenPool *Get(void); + static struct TokenPool *Get(bool ignore); };