Commit 40451c50 authored by sdefresne's avatar sdefresne Committed by Commit bot

Add support for user defined "pool" to GN.

Allow user to define pool of limited size to limit the number of
concurrent tasks that are executed for a given set of tools. The
pool object directly correspond to a ninja pool and can be shared
by multiple targets.

Design document:
https://docs.google.com/document/d/1b598i4WmeFOe3_iRBrjPKSXdcR5R32UPtgxqKmoY2-M/view

BUG=612786

Review-Url: https://codereview.chromium.org/2006923004
Cr-Commit-Position: refs/heads/master@{#397917}
parent 7737b321
...@@ -146,6 +146,8 @@ static_library("gn_lib") { ...@@ -146,6 +146,8 @@ static_library("gn_lib") {
"path_output.h", "path_output.h",
"pattern.cc", "pattern.cc",
"pattern.h", "pattern.h",
"pool.cc",
"pool.h",
"qt_creator_writer.cc", "qt_creator_writer.cc",
"qt_creator_writer.h", "qt_creator_writer.h",
"runtime_deps.cc", "runtime_deps.cc",
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "tools/gn/deps_iterator.h" #include "tools/gn/deps_iterator.h"
#include "tools/gn/err.h" #include "tools/gn/err.h"
#include "tools/gn/loader.h" #include "tools/gn/loader.h"
#include "tools/gn/pool.h"
#include "tools/gn/scheduler.h" #include "tools/gn/scheduler.h"
#include "tools/gn/settings.h" #include "tools/gn/settings.h"
#include "tools/gn/target.h" #include "tools/gn/target.h"
...@@ -263,6 +264,19 @@ bool Builder::ToolchainDefined(BuilderRecord* record, Err* err) { ...@@ -263,6 +264,19 @@ bool Builder::ToolchainDefined(BuilderRecord* record, Err* err) {
if (!AddDeps(record, toolchain->deps(), err)) if (!AddDeps(record, toolchain->deps(), err))
return false; return false;
for (int i = Toolchain::TYPE_NONE + 1; i < Toolchain::TYPE_NUMTYPES; i++) {
Toolchain::ToolType tool_type = static_cast<Toolchain::ToolType>(i);
Tool* tool = toolchain->GetTool(tool_type);
if (!tool || tool->pool().label.is_null())
continue;
BuilderRecord* dep_record = GetOrCreateRecordOfType(
tool->pool().label, tool->pool().origin, BuilderRecord::ITEM_POOL, err);
if (!dep_record)
return false;
record->AddDep(dep_record);
}
// The default toolchain gets generated by default. Also propogate the // The default toolchain gets generated by default. Also propogate the
// generate flag if it depends on items in a non-default toolchain. // generate flag if it depends on items in a non-default toolchain.
if (record->should_generate() || if (record->should_generate() ||
...@@ -429,6 +443,8 @@ bool Builder::ResolveItem(BuilderRecord* record, Err* err) { ...@@ -429,6 +443,8 @@ bool Builder::ResolveItem(BuilderRecord* record, Err* err) {
Toolchain* toolchain = record->item()->AsToolchain(); Toolchain* toolchain = record->item()->AsToolchain();
if (!ResolveDeps(&toolchain->deps(), err)) if (!ResolveDeps(&toolchain->deps(), err))
return false; return false;
if (!ResolvePools(toolchain, err))
return false;
} }
record->set_resolved(true); record->set_resolved(true);
...@@ -497,6 +513,29 @@ bool Builder::ResolveToolchain(Target* target, Err* err) { ...@@ -497,6 +513,29 @@ bool Builder::ResolveToolchain(Target* target, Err* err) {
return true; return true;
} }
bool Builder::ResolvePools(Toolchain* toolchain, Err* err) {
for (int i = Toolchain::TYPE_NONE + 1; i < Toolchain::TYPE_NUMTYPES; i++) {
Toolchain::ToolType tool_type = static_cast<Toolchain::ToolType>(i);
Tool* tool = toolchain->GetTool(tool_type);
if (!tool || tool->pool().label.is_null())
continue;
BuilderRecord* record =
GetResolvedRecordOfType(tool->pool().label, toolchain->defined_from(),
BuilderRecord::ITEM_POOL, err);
if (!record) {
*err = Err(tool->pool().origin, "Pool for tool not defined.",
"I was hoping to find a pool " +
tool->pool().label.GetUserVisibleName(false));
return false;
}
tool->set_pool(LabelPtrPair<Pool>(record->item()->AsPool()));
}
return true;
}
std::string Builder::CheckForCircularDependencies( std::string Builder::CheckForCircularDependencies(
const std::vector<const BuilderRecord*>& bad_records) const { const std::vector<const BuilderRecord*>& bad_records) const {
std::vector<const BuilderRecord*> cycle; std::vector<const BuilderRecord*> cycle;
......
...@@ -119,6 +119,7 @@ class Builder : public base::RefCountedThreadSafe<Builder> { ...@@ -119,6 +119,7 @@ class Builder : public base::RefCountedThreadSafe<Builder> {
bool ResolveDeps(LabelTargetVector* deps, Err* err); bool ResolveDeps(LabelTargetVector* deps, Err* err);
bool ResolveConfigs(UniqueVector<LabelConfigPair>* configs, Err* err); bool ResolveConfigs(UniqueVector<LabelConfigPair>* configs, Err* err);
bool ResolveToolchain(Target* target, Err* err); bool ResolveToolchain(Target* target, Err* err);
bool ResolvePools(Toolchain* toolchain, Err* err);
// Given a list of unresolved records, tries to find any circular // Given a list of unresolved records, tries to find any circular
// dependencies and returns the string describing the problem. If no circular // dependencies and returns the string describing the problem. If no circular
......
...@@ -26,6 +26,8 @@ const char* BuilderRecord::GetNameForType(ItemType type) { ...@@ -26,6 +26,8 @@ const char* BuilderRecord::GetNameForType(ItemType type) {
return "config"; return "config";
case ITEM_TOOLCHAIN: case ITEM_TOOLCHAIN:
return "toolchain"; return "toolchain";
case ITEM_POOL:
return "pool";
case ITEM_UNKNOWN: case ITEM_UNKNOWN:
default: default:
return "unknown"; return "unknown";
...@@ -41,6 +43,8 @@ bool BuilderRecord::IsItemOfType(const Item* item, ItemType type) { ...@@ -41,6 +43,8 @@ bool BuilderRecord::IsItemOfType(const Item* item, ItemType type) {
return !!item->AsConfig(); return !!item->AsConfig();
case ITEM_TOOLCHAIN: case ITEM_TOOLCHAIN:
return !!item->AsToolchain(); return !!item->AsToolchain();
case ITEM_POOL:
return !!item->AsPool();
case ITEM_UNKNOWN: case ITEM_UNKNOWN:
default: default:
return false; return false;
...@@ -55,6 +59,8 @@ BuilderRecord::ItemType BuilderRecord::TypeOfItem(const Item* item) { ...@@ -55,6 +59,8 @@ BuilderRecord::ItemType BuilderRecord::TypeOfItem(const Item* item) {
return ITEM_CONFIG; return ITEM_CONFIG;
if (item->AsToolchain()) if (item->AsToolchain())
return ITEM_TOOLCHAIN; return ITEM_TOOLCHAIN;
if (item->AsPool())
return ITEM_POOL;
NOTREACHED(); NOTREACHED();
return ITEM_UNKNOWN; return ITEM_UNKNOWN;
......
...@@ -35,7 +35,8 @@ class BuilderRecord { ...@@ -35,7 +35,8 @@ class BuilderRecord {
ITEM_UNKNOWN, ITEM_UNKNOWN,
ITEM_TARGET, ITEM_TARGET,
ITEM_CONFIG, ITEM_CONFIG,
ITEM_TOOLCHAIN ITEM_TOOLCHAIN,
ITEM_POOL
}; };
BuilderRecord(ItemType type, const Label& label); BuilderRecord(ItemType type, const Label& label);
......
...@@ -2142,6 +2142,47 @@ ...@@ -2142,6 +2142,47 @@
output_extension, public, sources, testonly, visibility output_extension, public, sources, testonly, visibility
```
## **pool**: Defines a pool object.
```
Pool objects can be applied to a tool to limit the parallelism of the
build. This object has a single property "depth" corresponding to
the number of tasks that may run simultaneously.
As the file containing the pool definition may be executed in the
of more than one toolchain it is recommended to specify an explicit
toolchain when definining and referencing a pool.
A pool is referenced by its label just like a target.
```
### **Variables**
```
depth*
* = required
```
### **Example**
```
if (current_toolchain == default_toolchain) {
pool("link_pool") {
depth = 1
}
}
toolchain("toolchain") {
tool("link") {
command = "..."
pool = ":link_pool($default_toolchain)")
}
}
``` ```
## **print**: Prints to the console. ## **print**: Prints to the console.
...@@ -2913,6 +2954,14 @@ ...@@ -2913,6 +2954,14 @@
"{{output_dir}}/{{target_output_name}}.lib", "{{output_dir}}/{{target_output_name}}.lib",
] ]
pool [label, optional]
Label of the pool to use for the tool. Pools are used to limit
the number of tasks that can execute concurrently during the
build.
See also "gn help pool".
link_output [string with substitutions] link_output [string with substitutions]
depend_output [string with substitutions] depend_output [string with substitutions]
runtime_link_output [string with substitutions] runtime_link_output [string with substitutions]
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include "tools/gn/err.h" #include "tools/gn/err.h"
#include "tools/gn/functions.h" #include "tools/gn/functions.h"
#include "tools/gn/label.h"
#include "tools/gn/label_ptr.h"
#include "tools/gn/parse_tree.h" #include "tools/gn/parse_tree.h"
#include "tools/gn/scheduler.h" #include "tools/gn/scheduler.h"
#include "tools/gn/scope.h" #include "tools/gn/scope.h"
...@@ -57,6 +59,31 @@ bool ReadString(Scope* scope, ...@@ -57,6 +59,31 @@ bool ReadString(Scope* scope,
return true; return true;
} }
// Reads the given label from the scope (if present) and puts the result into
// dest. If the value is not a label, sets the error and returns false.
bool ReadLabel(Scope* scope,
const char* var,
Tool* tool,
const ParseNode* origin,
const Label& current_toolchain,
void (Tool::*set)(const LabelPtrPair<Pool>&),
Err* err) {
const Value* v = scope->GetValue(var, true);
if (!v)
return true; // Not present is fine.
Label label =
Label::Resolve(scope->GetSourceDir(), current_toolchain, *v, err);
if (err->has_error())
return false;
LabelPtrPair<Pool> pair(label);
pair.origin = origin;
(tool->*set)(pair);
return true;
}
// Calls the given validate function on each type in the list. On failure, // Calls the given validate function on each type in the list. On failure,
// sets the error, blame the value, and return false. // sets the error, blame the value, and return false.
bool ValidateSubstitutionList(const std::vector<SubstitutionType>& list, bool ValidateSubstitutionList(const std::vector<SubstitutionType>& list,
...@@ -518,6 +545,14 @@ const char kTool_Help[] = ...@@ -518,6 +545,14 @@ const char kTool_Help[] =
" \"{{output_dir}}/{{target_output_name}}.lib\",\n" " \"{{output_dir}}/{{target_output_name}}.lib\",\n"
" ]\n" " ]\n"
"\n" "\n"
" pool [label, optional]\n"
"\n"
" Label of the pool to use for the tool. Pools are used to limit\n"
" the number of tasks that can execute concurrently during the\n"
" build.\n"
"\n"
" See also \"gn help pool\".\n"
"\n"
" link_output [string with substitutions]\n" " link_output [string with substitutions]\n"
" depend_output [string with substitutions]\n" " depend_output [string with substitutions]\n"
" runtime_link_output [string with substitutions]\n" " runtime_link_output [string with substitutions]\n"
...@@ -908,7 +943,9 @@ Value RunTool(Scope* scope, ...@@ -908,7 +943,9 @@ Value RunTool(Scope* scope,
!ReadPattern(&block_scope, "rspfile", subst_validator, tool.get(), !ReadPattern(&block_scope, "rspfile", subst_validator, tool.get(),
&Tool::set_rspfile, err) || &Tool::set_rspfile, err) ||
!ReadPattern(&block_scope, "rspfile_content", subst_validator, tool.get(), !ReadPattern(&block_scope, "rspfile_content", subst_validator, tool.get(),
&Tool::set_rspfile_content, err)) { &Tool::set_rspfile_content, err) ||
!ReadLabel(&block_scope, "pool", tool.get(), function, toolchain->label(),
&Tool::set_pool, err)) {
return Value(); return Value();
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "tools/gn/err.h" #include "tools/gn/err.h"
#include "tools/gn/input_file.h" #include "tools/gn/input_file.h"
#include "tools/gn/parse_tree.h" #include "tools/gn/parse_tree.h"
#include "tools/gn/pool.h"
#include "tools/gn/scheduler.h" #include "tools/gn/scheduler.h"
#include "tools/gn/scope.h" #include "tools/gn/scope.h"
#include "tools/gn/settings.h" #include "tools/gn/settings.h"
...@@ -678,6 +679,94 @@ Value RunSetSourcesAssignmentFilter(Scope* scope, ...@@ -678,6 +679,94 @@ Value RunSetSourcesAssignmentFilter(Scope* scope,
return Value(); return Value();
} }
// pool ------------------------------------------------------------------------
const char kPool[] = "pool";
const char kPool_HelpShort[] =
"pool: Defines a pool object.";
const char kPool_Help[] =
"pool: Defines a pool object.\n"
"\n"
" Pool objects can be applied to a tool to limit the parallelism of the\n"
" build. This object has a single property \"depth\" corresponding to\n"
" the number of tasks that may run simultaneously.\n"
"\n"
" As the file containing the pool definition may be executed in the\n"
" of more than one toolchain it is recommended to specify an explicit\n"
" toolchain when definining and referencing a pool.\n"
"\n"
" A pool is referenced by its label just like a target.\n"
"\n"
"Variables\n"
"\n"
" depth*\n"
" * = required\n"
"\n"
"Example\n"
"\n"
" if (current_toolchain == default_toolchain) {\n"
" pool(\"link_pool\") {\n"
" depth = 1\n"
" }\n"
" }\n"
"\n"
" toolchain(\"toolchain\") {\n"
" tool(\"link\") {\n"
" command = \"...\"\n"
" pool = \":link_pool($default_toolchain)\")\n"
" }\n"
" }\n";
const char kDepth[] = "depth";
Value RunPool(const FunctionCallNode* function,
const std::vector<Value>& args,
Scope* scope,
Err* err) {
NonNestableBlock non_nestable(scope, function, "pool");
if (!non_nestable.Enter(err))
return Value();
if (!EnsureSingleStringArg(function, args, err) ||
!EnsureNotProcessingImport(function, scope, err))
return Value();
Label label(MakeLabelForScope(scope, function, args[0].string_value()));
if (g_scheduler->verbose_logging())
g_scheduler->Log("Defining pool", label.GetUserVisibleName(true));
// Get the pool depth. It is an error to define a pool without a depth,
// so check first for the presence of the value.
const Value* depth = scope->GetValue(kDepth, true);
if (!depth) {
*err = Err(function, "Can't define a pool without depth.");
return Value();
}
if (!depth->VerifyTypeIs(Value::INTEGER, err))
return Value();
if (depth->int_value() < 0) {
*err = Err(function, "depth must be positive or nul.");
return Value();
}
// Create the new pool.
std::unique_ptr<Pool> pool(new Pool(scope->settings(), label));
pool->set_depth(depth->int_value());
// Save the generated item.
Scope::ItemVector* collector = scope->GetItemCollector();
if (!collector) {
*err = Err(function, "Can't define a pool in this context.");
return Value();
}
collector->push_back(pool.release());
return Value();
}
// print ----------------------------------------------------------------------- // print -----------------------------------------------------------------------
const char kPrint[] = "print"; const char kPrint[] = "print";
...@@ -826,6 +915,7 @@ struct FunctionInfoInitializer { ...@@ -826,6 +915,7 @@ struct FunctionInfoInitializer {
INSERT_FUNCTION(GetPathInfo, false) INSERT_FUNCTION(GetPathInfo, false)
INSERT_FUNCTION(GetTargetOutputs, false) INSERT_FUNCTION(GetTargetOutputs, false)
INSERT_FUNCTION(Import, false) INSERT_FUNCTION(Import, false)
INSERT_FUNCTION(Pool, false)
INSERT_FUNCTION(Print, false) INSERT_FUNCTION(Print, false)
INSERT_FUNCTION(ProcessFileTemplate, false) INSERT_FUNCTION(ProcessFileTemplate, false)
INSERT_FUNCTION(ReadFile, false) INSERT_FUNCTION(ReadFile, false)
......
...@@ -222,6 +222,14 @@ Value RunLoadableModule(Scope* scope, ...@@ -222,6 +222,14 @@ Value RunLoadableModule(Scope* scope,
BlockNode* block, BlockNode* block,
Err* err); Err* err);
extern const char kPool[];
extern const char kPool_HelpShort[];
extern const char kPool_Help[];
Value RunPool(const FunctionCallNode* function,
const std::vector<Value>& args,
Scope* block_scope,
Err* err);
extern const char kPrint[]; extern const char kPrint[];
extern const char kPrint_HelpShort[]; extern const char kPrint_HelpShort[];
extern const char kPrint_Help[]; extern const char kPrint_Help[];
......
...@@ -146,6 +146,8 @@ ...@@ -146,6 +146,8 @@
'path_output.h', 'path_output.h',
'pattern.cc', 'pattern.cc',
'pattern.h', 'pattern.h',
'pool.cc',
'pool.h',
'qt_creator_writer.cc', 'qt_creator_writer.cc',
'qt_creator_writer.h', 'qt_creator_writer.h',
'runtime_deps.cc', 'runtime_deps.cc',
......
...@@ -20,6 +20,12 @@ Config* Item::AsConfig() { ...@@ -20,6 +20,12 @@ Config* Item::AsConfig() {
const Config* Item::AsConfig() const { const Config* Item::AsConfig() const {
return nullptr; return nullptr;
} }
Pool* Item::AsPool() {
return nullptr;
}
const Pool* Item::AsPool() const {
return nullptr;
}
Target* Item::AsTarget() { Target* Item::AsTarget() {
return nullptr; return nullptr;
} }
...@@ -40,6 +46,8 @@ std::string Item::GetItemTypeName() const { ...@@ -40,6 +46,8 @@ std::string Item::GetItemTypeName() const {
return "target"; return "target";
if (AsToolchain()) if (AsToolchain())
return "toolchain"; return "toolchain";
if (AsPool())
return "pool";
NOTREACHED(); NOTREACHED();
return "this thing that I have no idea what it is"; return "this thing that I have no idea what it is";
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
class Config; class Config;
class ParseNode; class ParseNode;
class Pool;
class Settings; class Settings;
class Target; class Target;
class Toolchain; class Toolchain;
...@@ -38,6 +39,8 @@ class Item { ...@@ -38,6 +39,8 @@ class Item {
// Manual RTTI. // Manual RTTI.
virtual Config* AsConfig(); virtual Config* AsConfig();
virtual const Config* AsConfig() const; virtual const Config* AsConfig() const;
virtual Pool* AsPool();
virtual const Pool* AsPool() const;
virtual Target* AsTarget(); virtual Target* AsTarget();
virtual const Target* AsTarget() const; virtual const Target* AsTarget() const;
virtual Toolchain* AsToolchain(); virtual Toolchain* AsToolchain();
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "tools/gn/filesystem_utils.h" #include "tools/gn/filesystem_utils.h"
#include "tools/gn/input_file_manager.h" #include "tools/gn/input_file_manager.h"
#include "tools/gn/ninja_utils.h" #include "tools/gn/ninja_utils.h"
#include "tools/gn/pool.h"
#include "tools/gn/scheduler.h" #include "tools/gn/scheduler.h"
#include "tools/gn/switches.h" #include "tools/gn/switches.h"
#include "tools/gn/target.h" #include "tools/gn/target.h"
...@@ -129,24 +130,26 @@ NinjaBuildWriter::NinjaBuildWriter( ...@@ -129,24 +130,26 @@ NinjaBuildWriter::NinjaBuildWriter(
const std::vector<const Settings*>& all_settings, const std::vector<const Settings*>& all_settings,
const Toolchain* default_toolchain, const Toolchain* default_toolchain,
const std::vector<const Target*>& default_toolchain_targets, const std::vector<const Target*>& default_toolchain_targets,
const std::vector<const Pool*>& all_pools,
std::ostream& out, std::ostream& out,
std::ostream& dep_out) std::ostream& dep_out)
: build_settings_(build_settings), : build_settings_(build_settings),
all_settings_(all_settings), all_settings_(all_settings),
default_toolchain_(default_toolchain), default_toolchain_(default_toolchain),
default_toolchain_targets_(default_toolchain_targets), default_toolchain_targets_(default_toolchain_targets),
all_pools_(all_pools),
out_(out), out_(out),
dep_out_(dep_out), dep_out_(dep_out),
path_output_(build_settings->build_dir(), path_output_(build_settings->build_dir(),
build_settings->root_path_utf8(), ESCAPE_NINJA) { build_settings->root_path_utf8(),
} ESCAPE_NINJA) {}
NinjaBuildWriter::~NinjaBuildWriter() { NinjaBuildWriter::~NinjaBuildWriter() {
} }
bool NinjaBuildWriter::Run(Err* err) { bool NinjaBuildWriter::Run(Err* err) {
WriteNinjaRules(); WriteNinjaRules();
WriteLinkPool(); WriteAllPools();
WriteSubninjas(); WriteSubninjas();
return WritePhonyAndAllRules(err); return WritePhonyAndAllRules(err);
} }
...@@ -157,13 +160,14 @@ bool NinjaBuildWriter::RunAndWriteFile( ...@@ -157,13 +160,14 @@ bool NinjaBuildWriter::RunAndWriteFile(
const std::vector<const Settings*>& all_settings, const std::vector<const Settings*>& all_settings,
const Toolchain* default_toolchain, const Toolchain* default_toolchain,
const std::vector<const Target*>& default_toolchain_targets, const std::vector<const Target*>& default_toolchain_targets,
const std::vector<const Pool*>& all_pools,
Err* err) { Err* err) {
ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, "build.ninja"); ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, "build.ninja");
std::stringstream file; std::stringstream file;
std::stringstream depfile; std::stringstream depfile;
NinjaBuildWriter gen(build_settings, all_settings, default_toolchain, NinjaBuildWriter gen(build_settings, all_settings, default_toolchain,
default_toolchain_targets, file, depfile); default_toolchain_targets, all_pools, file, depfile);
if (!gen.Run(err)) if (!gen.Run(err))
return false; return false;
...@@ -224,10 +228,17 @@ void NinjaBuildWriter::WriteNinjaRules() { ...@@ -224,10 +228,17 @@ void NinjaBuildWriter::WriteNinjaRules() {
out_ << std::endl; out_ << std::endl;
} }
void NinjaBuildWriter::WriteLinkPool() { void NinjaBuildWriter::WriteAllPools() {
out_ << "pool link_pool\n" out_ << "pool link_pool\n"
<< " depth = " << default_toolchain_->concurrent_links() << std::endl << " depth = " << default_toolchain_->concurrent_links() << std::endl
<< std::endl; << std::endl;
for (const Pool* pool : all_pools_) {
std::string pool_name = pool->GetNinjaName(default_toolchain_->label());
out_ << "pool " << pool_name << std::endl
<< " depth = " << pool->depth() << std::endl
<< std::endl;
}
} }
void NinjaBuildWriter::WriteSubninjas() { void NinjaBuildWriter::WriteSubninjas() {
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
class BuildSettings; class BuildSettings;
class Err; class Err;
class Pool;
class Settings; class Settings;
class Target; class Target;
class Toolchain; class Toolchain;
...@@ -28,12 +29,14 @@ class NinjaBuildWriter { ...@@ -28,12 +29,14 @@ class NinjaBuildWriter {
const std::vector<const Settings*>& all_settings, const std::vector<const Settings*>& all_settings,
const Toolchain* default_toolchain, const Toolchain* default_toolchain,
const std::vector<const Target*>& default_toolchain_targets, const std::vector<const Target*>& default_toolchain_targets,
const std::vector<const Pool*>& all_pools,
Err* err); Err* err);
NinjaBuildWriter(const BuildSettings* settings, NinjaBuildWriter(const BuildSettings* settings,
const std::vector<const Settings*>& all_settings, const std::vector<const Settings*>& all_settings,
const Toolchain* default_toolchain, const Toolchain* default_toolchain,
const std::vector<const Target*>& default_toolchain_targets, const std::vector<const Target*>& default_toolchain_targets,
const std::vector<const Pool*>& all_pools,
std::ostream& out, std::ostream& out,
std::ostream& dep_out); std::ostream& dep_out);
~NinjaBuildWriter(); ~NinjaBuildWriter();
...@@ -42,7 +45,7 @@ class NinjaBuildWriter { ...@@ -42,7 +45,7 @@ class NinjaBuildWriter {
private: private:
void WriteNinjaRules(); void WriteNinjaRules();
void WriteLinkPool(); void WriteAllPools();
void WriteSubninjas(); void WriteSubninjas();
bool WritePhonyAndAllRules(Err* err); bool WritePhonyAndAllRules(Err* err);
...@@ -52,6 +55,7 @@ class NinjaBuildWriter { ...@@ -52,6 +55,7 @@ class NinjaBuildWriter {
std::vector<const Settings*> all_settings_; std::vector<const Settings*> all_settings_;
const Toolchain* default_toolchain_; const Toolchain* default_toolchain_;
std::vector<const Target*> default_toolchain_targets_; std::vector<const Target*> default_toolchain_targets_;
std::vector<const Pool*> all_pools_;
std::ostream& out_; std::ostream& out_;
std::ostream& dep_out_; std::ostream& dep_out_;
PathOutput path_output_; PathOutput path_output_;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "tools/gn/ninja_build_writer.h" #include "tools/gn/ninja_build_writer.h"
#include "tools/gn/pool.h"
#include "tools/gn/scheduler.h" #include "tools/gn/scheduler.h"
#include "tools/gn/target.h" #include "tools/gn/target.h"
#include "tools/gn/test_with_scope.h" #include "tools/gn/test_with_scope.h"
...@@ -31,12 +32,19 @@ TEST(NinjaBuildWriter, TwoTargets) { ...@@ -31,12 +32,19 @@ TEST(NinjaBuildWriter, TwoTargets) {
target_bar.SetToolchain(setup.toolchain()); target_bar.SetToolchain(setup.toolchain());
ASSERT_TRUE(target_bar.OnResolved(&err)); ASSERT_TRUE(target_bar.OnResolved(&err));
Pool swiming_pool(setup.settings(),
Label(SourceDir("//swiming/"), "pool",
SourceDir("//other/"), "toolchain"));
swiming_pool.set_depth(42);
std::ostringstream ninja_out; std::ostringstream ninja_out;
std::ostringstream depfile_out; std::ostringstream depfile_out;
std::vector<const Settings*> all_settings = {setup.settings()}; std::vector<const Settings*> all_settings = {setup.settings()};
std::vector<const Target*> targets = {&target_foo, &target_bar}; std::vector<const Target*> targets = {&target_foo, &target_bar};
std::vector<const Pool*> all_pools = {&swiming_pool};
NinjaBuildWriter writer(setup.build_settings(), all_settings, NinjaBuildWriter writer(setup.build_settings(), all_settings,
setup.toolchain(), targets, ninja_out, depfile_out); setup.toolchain(), targets, all_pools, ninja_out,
depfile_out);
ASSERT_TRUE(writer.Run(&err)); ASSERT_TRUE(writer.Run(&err));
const char expected_rule_gn[] = "rule gn\n"; const char expected_rule_gn[] = "rule gn\n";
...@@ -48,6 +56,9 @@ TEST(NinjaBuildWriter, TwoTargets) { ...@@ -48,6 +56,9 @@ TEST(NinjaBuildWriter, TwoTargets) {
const char expected_link_pool[] = const char expected_link_pool[] =
"pool link_pool\n" "pool link_pool\n"
" depth = 0\n" " depth = 0\n"
"\n"
"pool other_toolchain_swiming_pool\n"
" depth = 42\n"
"\n"; "\n";
const char expected_toolchain[] = const char expected_toolchain[] =
"subninja toolchain.ninja\n" "subninja toolchain.ninja\n"
...@@ -102,8 +113,10 @@ TEST(NinjaBuildWriter, DuplicateOutputs) { ...@@ -102,8 +113,10 @@ TEST(NinjaBuildWriter, DuplicateOutputs) {
std::ostringstream depfile_out; std::ostringstream depfile_out;
std::vector<const Settings*> all_settings = { setup.settings() }; std::vector<const Settings*> all_settings = { setup.settings() };
std::vector<const Target*> targets = { &target_foo, &target_bar }; std::vector<const Target*> targets = { &target_foo, &target_bar };
std::vector<const Pool*> all_pools;
NinjaBuildWriter writer(setup.build_settings(), all_settings, NinjaBuildWriter writer(setup.build_settings(), all_settings,
setup.toolchain(), targets, ninja_out, depfile_out); setup.toolchain(), targets, all_pools, ninja_out,
depfile_out);
ASSERT_FALSE(writer.Run(&err)); ASSERT_FALSE(writer.Run(&err));
const char expected_help_test[] = const char expected_help_test[] =
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "tools/gn/build_settings.h" #include "tools/gn/build_settings.h"
#include "tools/gn/filesystem_utils.h" #include "tools/gn/filesystem_utils.h"
#include "tools/gn/ninja_utils.h" #include "tools/gn/ninja_utils.h"
#include "tools/gn/pool.h"
#include "tools/gn/settings.h" #include "tools/gn/settings.h"
#include "tools/gn/substitution_writer.h" #include "tools/gn/substitution_writer.h"
#include "tools/gn/target.h" #include "tools/gn/target.h"
...@@ -113,6 +114,10 @@ void NinjaToolchainWriter::WriteToolRule(const Toolchain::ToolType type, ...@@ -113,6 +114,10 @@ void NinjaToolchainWriter::WriteToolRule(const Toolchain::ToolType type,
type == Toolchain::TYPE_SOLINK_MODULE || type == Toolchain::TYPE_SOLINK_MODULE ||
type == Toolchain::TYPE_LINK) { type == Toolchain::TYPE_LINK) {
out_ << kIndent << "pool = link_pool\n"; out_ << kIndent << "pool = link_pool\n";
} else if (tool->pool().ptr) {
std::string pool_name =
tool->pool().ptr->GetNinjaName(settings_->default_toolchain_label());
out_ << kIndent << "pool = " << pool_name << std::endl;
} }
if (tool->restat()) if (tool->restat())
......
...@@ -29,9 +29,11 @@ bool NinjaWriter::RunAndWriteFiles(const BuildSettings* build_settings, ...@@ -29,9 +29,11 @@ bool NinjaWriter::RunAndWriteFiles(const BuildSettings* build_settings,
std::vector<const Settings*> all_settings; std::vector<const Settings*> all_settings;
std::vector<const Target*> default_targets; std::vector<const Target*> default_targets;
if (!writer.WriteToolchains(&all_settings, &default_targets, err)) std::vector<const Pool*> all_pools;
if (!writer.WriteToolchains(&all_settings, &default_targets, &all_pools, err))
return false; return false;
return writer.WriteRootBuildfiles(all_settings, default_targets, err); return writer.WriteRootBuildfiles(all_settings, default_targets, all_pools,
err);
} }
// static // static
...@@ -42,11 +44,14 @@ bool NinjaWriter::RunAndWriteToolchainFiles( ...@@ -42,11 +44,14 @@ bool NinjaWriter::RunAndWriteToolchainFiles(
Err* err) { Err* err) {
NinjaWriter writer(build_settings, builder); NinjaWriter writer(build_settings, builder);
std::vector<const Target*> default_targets; std::vector<const Target*> default_targets;
return writer.WriteToolchains(all_settings, &default_targets, err); std::vector<const Pool*> all_pools;
return writer.WriteToolchains(all_settings, &default_targets, &all_pools,
err);
} }
bool NinjaWriter::WriteToolchains(std::vector<const Settings*>* all_settings, bool NinjaWriter::WriteToolchains(std::vector<const Settings*>* all_settings,
std::vector<const Target*>* default_targets, std::vector<const Target*>* default_targets,
std::vector<const Pool*>* all_pools,
Err* err) { Err* err) {
// Categorize all targets by toolchain. // Categorize all targets by toolchain.
typedef std::map<Label, std::vector<const Target*> > CategorizedMap; typedef std::map<Label, std::vector<const Target*> > CategorizedMap;
...@@ -79,6 +84,7 @@ bool NinjaWriter::WriteToolchains(std::vector<const Settings*>* all_settings, ...@@ -79,6 +84,7 @@ bool NinjaWriter::WriteToolchains(std::vector<const Settings*>* all_settings,
// Write out the toolchain buildfiles, and also accumulate the set of // Write out the toolchain buildfiles, and also accumulate the set of
// all settings and find the list of targets in the default toolchain. // all settings and find the list of targets in the default toolchain.
UniqueVector<const Pool*> pools;
for (const auto& i : categorized) { for (const auto& i : categorized) {
const Settings* settings = const Settings* settings =
builder_->loader()->GetToolchainSettings(i.first); builder_->loader()->GetToolchainSettings(i.first);
...@@ -91,8 +97,16 @@ bool NinjaWriter::WriteToolchains(std::vector<const Settings*>* all_settings, ...@@ -91,8 +97,16 @@ bool NinjaWriter::WriteToolchains(std::vector<const Settings*>* all_settings,
"Couldn't open toolchain buildfile(s) for writing").PrintToStdout(); "Couldn't open toolchain buildfile(s) for writing").PrintToStdout();
return false; return false;
} }
for (int j = Toolchain::TYPE_NONE + 1; j < Toolchain::TYPE_NUMTYPES; j++) {
Toolchain::ToolType tool_type = static_cast<Toolchain::ToolType>(j);
const Tool* tool = toolchain->GetTool(tool_type);
if (tool && tool->pool().ptr)
pools.push_back(tool->pool().ptr);
}
} }
*all_pools = pools.vector();
*default_targets = categorized[default_label]; *default_targets = categorized[default_label];
return true; return true;
} }
...@@ -100,6 +114,7 @@ bool NinjaWriter::WriteToolchains(std::vector<const Settings*>* all_settings, ...@@ -100,6 +114,7 @@ bool NinjaWriter::WriteToolchains(std::vector<const Settings*>* all_settings,
bool NinjaWriter::WriteRootBuildfiles( bool NinjaWriter::WriteRootBuildfiles(
const std::vector<const Settings*>& all_settings, const std::vector<const Settings*>& all_settings,
const std::vector<const Target*>& default_targets, const std::vector<const Target*>& default_targets,
const std::vector<const Pool*>& all_pools,
Err* err) { Err* err) {
// All Settings objects should have the same default toolchain, and there // All Settings objects should have the same default toolchain, and there
// should always be at least one settings object in the build. // should always be at least one settings object in the build.
...@@ -110,5 +125,5 @@ bool NinjaWriter::WriteRootBuildfiles( ...@@ -110,5 +125,5 @@ bool NinjaWriter::WriteRootBuildfiles(
// Write the root buildfile. // Write the root buildfile.
return NinjaBuildWriter::RunAndWriteFile(build_settings_, all_settings, return NinjaBuildWriter::RunAndWriteFile(build_settings_, all_settings,
default_toolchain, default_targets, default_toolchain, default_targets,
err); all_pools, err);
} }
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
class Builder; class Builder;
class BuildSettings; class BuildSettings;
class Err; class Err;
class Pool;
class Settings; class Settings;
class Target; class Target;
...@@ -36,12 +37,13 @@ class NinjaWriter { ...@@ -36,12 +37,13 @@ class NinjaWriter {
NinjaWriter(const BuildSettings* build_settings, Builder* builder); NinjaWriter(const BuildSettings* build_settings, Builder* builder);
~NinjaWriter(); ~NinjaWriter();
bool WriteToolchains( bool WriteToolchains(std::vector<const Settings*>* all_settings,
std::vector<const Settings*>* all_settings, std::vector<const Target*>* default_targets,
std::vector<const Target*>* default_targets, std::vector<const Pool*>* all_pools,
Err* err); Err* err);
bool WriteRootBuildfiles(const std::vector<const Settings*>& all_settings, bool WriteRootBuildfiles(const std::vector<const Settings*>& all_settings,
const std::vector<const Target*>& default_targets, const std::vector<const Target*>& default_targets,
const std::vector<const Pool*>& all_pools,
Err* err); Err* err);
const BuildSettings* build_settings_; const BuildSettings* build_settings_;
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "tools/gn/pool.h"
#include <sstream>
#include "base/logging.h"
Pool::Pool(const Settings* settings, const Label& label)
: Item(settings, label) {}
Pool::~Pool() {}
Pool* Pool::AsPool() {
return this;
}
const Pool* Pool::AsPool() const {
return this;
}
std::string Pool::GetNinjaName(const Label& default_toolchain) const {
bool include_toolchain = label().toolchain_dir() != default_toolchain.dir() ||
label().toolchain_name() != default_toolchain.name();
return GetNinjaName(include_toolchain);
}
std::string Pool::GetNinjaName(bool include_toolchain) const {
std::ostringstream buffer;
if (include_toolchain) {
DCHECK(label().toolchain_dir().is_source_absolute());
std::string toolchain_dir = label().toolchain_dir().value();
for (std::string::size_type i = 2; i < toolchain_dir.size(); ++i) {
buffer << (toolchain_dir[i] == '/' ? '_' : toolchain_dir[i]);
}
buffer << label().toolchain_name() << "_";
}
DCHECK(label().dir().is_source_absolute());
std::string label_dir = label().dir().value();
for (std::string::size_type i = 2; i < label_dir.size(); ++i) {
buffer << (label_dir[i] == '/' ? '_' : label_dir[i]);
}
buffer << label().name();
return buffer.str();
}
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TOOLS_GN_POOL_H_
#define TOOLS_GN_POOL_H_
#include <string>
#include "tools/gn/item.h"
// Represents a named pool in the dependency graph.
//
// A pool is used to limit the parallelism of task invocation in the
// generated ninja build. Pools are referenced by toolchains.
class Pool : public Item {
public:
Pool(const Settings* settings, const Label& label);
~Pool() override;
Pool(const Pool&) = delete;
Pool& operator=(const Pool&) = delete;
// Item implementation.
Pool* AsPool() override;
const Pool* AsPool() const override;
// The pool depth (number of task to run simultaneously).
int64_t depth() const { return depth_; }
void set_depth(int64_t depth) { depth_ = depth; }
// The pool name in generated ninja files.
std::string GetNinjaName(const Label& default_toolchain) const;
private:
std::string GetNinjaName(bool include_toolchain) const;
int64_t depth_ = 0;
};
#endif // TOOLS_GN_POOL_H_
...@@ -9,9 +9,13 @@ ...@@ -9,9 +9,13 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "tools/gn/label.h"
#include "tools/gn/label_ptr.h"
#include "tools/gn/substitution_list.h" #include "tools/gn/substitution_list.h"
#include "tools/gn/substitution_pattern.h" #include "tools/gn/substitution_pattern.h"
class Pool;
class Tool { class Tool {
public: public:
enum DepsFormat { enum DepsFormat {
...@@ -173,6 +177,9 @@ class Tool { ...@@ -173,6 +177,9 @@ class Tool {
rspfile_content_ = content; rspfile_content_ = content;
} }
const LabelPtrPair<Pool>& pool() const { return pool_; }
void set_pool(const LabelPtrPair<Pool>& pool) { pool_ = pool; }
// Other functions ---------------------------------------------------------- // Other functions ----------------------------------------------------------
// Called when the toolchain is saving this tool, after everything is filled // Called when the toolchain is saving this tool, after everything is filled
...@@ -191,6 +198,8 @@ class Tool { ...@@ -191,6 +198,8 @@ class Tool {
return substitution_bits_; return substitution_bits_;
} }
bool OnResolved(Err* err);
private: private:
SubstitutionPattern command_; SubstitutionPattern command_;
std::string default_output_extension_; std::string default_output_extension_;
...@@ -209,6 +218,7 @@ class Tool { ...@@ -209,6 +218,7 @@ class Tool {
bool restat_; bool restat_;
SubstitutionPattern rspfile_; SubstitutionPattern rspfile_;
SubstitutionPattern rspfile_content_; SubstitutionPattern rspfile_content_;
LabelPtrPair<Pool> pool_;
bool complete_; bool complete_;
......
...@@ -86,6 +86,11 @@ std::string Toolchain::ToolTypeToName(ToolType type) { ...@@ -86,6 +86,11 @@ std::string Toolchain::ToolTypeToName(ToolType type) {
} }
} }
Tool* Toolchain::GetTool(ToolType type) {
DCHECK(type != TYPE_NONE);
return tools_[static_cast<size_t>(type)].get();
}
const Tool* Toolchain::GetTool(ToolType type) const { const Tool* Toolchain::GetTool(ToolType type) const {
DCHECK(type != TYPE_NONE); DCHECK(type != TYPE_NONE);
return tools_[static_cast<size_t>(type)].get(); return tools_[static_cast<size_t>(type)].get();
......
...@@ -78,6 +78,7 @@ class Toolchain : public Item { ...@@ -78,6 +78,7 @@ class Toolchain : public Item {
static std::string ToolTypeToName(ToolType type); static std::string ToolTypeToName(ToolType type);
// Returns null if the tool hasn't been defined. // Returns null if the tool hasn't been defined.
Tool* GetTool(ToolType type);
const Tool* GetTool(ToolType type) const; const Tool* GetTool(ToolType type) const;
// Set a tool. When all tools are configured, you should call // Set a tool. When all tools are configured, you should call
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment