From 7ecfac6ee9e5ff4d8fb95c765305e7c22f62459f Mon Sep 17 00:00:00 2001 From: Evan Martin Date: Tue, 30 Nov 2010 09:56:17 -0800 Subject: [PATCH] build in parallel --- build.cc | 53 +++++++++++++++++++++++++++++------------------------ build.h | 2 ++ build_test.cc | 8 +++++++- 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/build.cc b/build.cc index d2d9a8d..58bbcfa 100644 --- a/build.cc +++ b/build.cc @@ -86,6 +86,7 @@ void Plan::Dump() { struct RealCommandRunner : public CommandRunner { virtual ~RealCommandRunner() {} + virtual bool CanRunMore(); virtual bool StartCommand(Edge* edge); virtual void WaitForCommands(string* err); virtual Edge* NextFinishedCommand(); @@ -94,6 +95,11 @@ struct RealCommandRunner : public CommandRunner { map subproc_to_edge_; }; +bool RealCommandRunner::CanRunMore() { + const size_t kConcurrency = 3; // XXX make configurable etc. + return subprocs_.running_.size() < kConcurrency; +} + bool RealCommandRunner::StartCommand(Edge* edge) { string err; string command = edge->EvaluateCommand(); @@ -165,35 +171,25 @@ bool Builder::Build(string* err) { return true; } - Edge* edge = plan_.FindWork(); - if (!edge) { - *err = "unable to find work"; - return false; - } - - do { - if (edge->rule_ != &State::kPhonyRule) { - if (!StartEdge(edge, err)) - return false; + while (plan_.more_to_do()) { + while (command_runner_->CanRunMore()) { + Edge* edge = plan_.FindWork(); + if (!edge) + break; - while (!(edge = command_runner_->NextFinishedCommand())) { - command_runner_->WaitForCommands(err); + if (edge->rule_ == &State::kPhonyRule) { + FinishEdge(edge); + continue; } - } - for (vector::iterator i = edge->outputs_.begin(); - i != edge->outputs_.end(); ++i) { - // XXX check that the output actually changed - // XXX just notify node and have it propagate? - (*i)->dirty_ = false; + if (!StartEdge(edge, err)) + return false; } - plan_.EdgeFinished(edge); - } while ((edge = plan_.FindWork()) != NULL); - if (plan_.more_to_do()) { - *err = "ran out of work"; - plan_.Dump(); - return false; + if (Edge* edge = command_runner_->NextFinishedCommand()) + FinishEdge(edge); + else + command_runner_->WaitForCommands(err); } return true; @@ -218,3 +214,12 @@ bool Builder::StartEdge(Edge* edge, string* err) { return true; } +void Builder::FinishEdge(Edge* edge) { + for (vector::iterator i = edge->outputs_.begin(); + i != edge->outputs_.end(); ++i) { + // XXX check that the output actually changed + // XXX just notify node and have it propagate? + (*i)->dirty_ = false; + } + plan_.EdgeFinished(edge); +} diff --git a/build.h b/build.h index 467bd09..c80d460 100644 --- a/build.h +++ b/build.h @@ -46,6 +46,7 @@ private: // RealCommandRunner is an implementation that actually runs commands. struct CommandRunner { virtual ~CommandRunner() {} + virtual bool CanRunMore() = 0; virtual bool StartCommand(Edge* edge) = 0; virtual void WaitForCommands(string* err) = 0; virtual Edge* NextFinishedCommand() = 0; @@ -58,6 +59,7 @@ struct Builder { bool Build(string* err); bool StartEdge(Edge* edge, string* err); + void FinishEdge(Edge* edge); State* state_; Plan plan_; diff --git a/build_test.cc b/build_test.cc index a057755..091c118 100644 --- a/build_test.cc +++ b/build_test.cc @@ -162,7 +162,8 @@ struct BuildTest : public StateTestWithBuiltinRules, // Mark dependents of a path dirty. void Touch(const string& path); - // CommandRunner override + // CommandRunner impl + virtual bool CanRunMore(); virtual bool StartCommand(Edge* edge); virtual void WaitForCommands(string* err); virtual Edge* NextFinishedCommand(); @@ -208,6 +209,11 @@ void BuildTest::Touch(const string& path) { node->MarkDependentsDirty(); } +bool BuildTest::CanRunMore() { + // Only run one at a time. + return last_command_ == NULL; +} + bool BuildTest::StartCommand(Edge* edge) { assert(!last_command_); commands_ran_.push_back(edge->EvaluateCommand()); -- 2.7.4