aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeongik Cha <jeongik@google.com>2023-05-20 00:32:32 +0900
committerJeongik Cha <jeongik@google.com>2023-05-22 13:23:08 +0900
commit49916af0a51e9eff9d2d45b8565837ba875e8baf (patch)
tree6e9e55044b0c98333affe91f5972543f98282be6
parent2f4ecd1728f9620adeea31d498abea7c8e66b3bf (diff)
downloadninja-49916af0a51e9eff9d2d45b8565837ba875e8baf.tar.gz
Add usesninjalogasweightlist option
If weight list is large(more than 100,000 lines), reading the whole list spends a few seconds(1-3s). It is ignorable in full build, but it might be considerable in small build or m nothing scenario. If weight list comes from ninja log, we can just directly read ninja log data instead of writing weight list from ninja log outside, and read the weight list. It doesn't spend additional time because ninja log is loaded by default. Bug: 271527305 Test: build with new option Change-Id: I1b4880ce993e5faaa03749b30f62a1236f63fe86
-rw-r--r--src/build.cc48
-rw-r--r--src/build.h2
-rw-r--r--src/ninja.cc11
3 files changed, 42 insertions, 19 deletions
diff --git a/src/build.cc b/src/build.cc
index d0d0681..d21115d 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -105,19 +105,6 @@ private:
std::unordered_set<HashedStr> key_data_;
std::unordered_map<HashedStrView, int64_t> map_data_;
};
-
-// Get weight from data source, it isn't related to Edge.weight because
-// Edge.weight is used for task distribution across pools which we don't
-// want to do that in this context.
-int64_t GetWeight(const WeightDataSource& data_source, Edge* edge) {
- if (!edge || edge->outputs_ready()) {
- return 0;
- }
- if (edge->is_phony()) {
- return 1;
- }
- return data_source.Get(edge->outputs_[0]->globalPath().h).value_or(1);
-}
} // namespace
Plan::Plan(Builder* builder)
@@ -646,8 +633,6 @@ void Builder::RefreshPriority(const std::vector<Node*>& start_nodes) {
}
}
}
- } else {
- Fatal("data_source should exist here.");
}
std::vector<std::pair<Edge*, int64_t>> todos;
std::unique_ptr<ThreadPool> thread_pool = CreateThreadPool();
@@ -656,10 +641,35 @@ void Builder::RefreshPriority(const std::vector<Node*>& start_nodes) {
todos.emplace_back(std::make_pair(node->in_edge(), 0));
}
}
+
+ // Get weight from data source or ninja log, it isn't related to Edge.weight,
+ // because Edge.weight is used for task distribution across pools which we don't
+ // want to do that in this context.
+ auto weight_getter = [&data_source, this](Edge* edge) -> int64_t {
+ if (!edge || edge->outputs_ready()) {
+ return 0;
+ }
+ if (edge->is_phony()) {
+ return 1;
+ }
+ if (config_.weight_list_path) {
+ return data_source.Get(edge->outputs_[0]->globalPath().h).value_or(1);
+ } else if (config_.ninja_log_as_weight_list) {
+ if (scan_.build_log()) {
+ auto* entry = scan_.build_log()->LookupByOutput(edge->outputs_[0]->globalPath());
+ if (entry) {
+ return entry->end_time - entry->start_time + 1;
+ }
+ }
+ return 1;
+ } else {
+ Fatal("either weight_list_path or ninja_log_as_weight_list should be set.");
+ }
+ };
while (!todos.empty()) {
// Traverse edges in BFS manner, and update each edge's critical path based priority from
// accumulated weight.
- const auto& result = ParallelMap(thread_pool.get(), todos, [&data_source] (auto& p) {
+ const auto& result = ParallelMap(thread_pool.get(), todos, [&weight_getter] (auto& p) {
// the pair is composed of a visiting edge and accumulated critical path based priority.
auto* e = p.first;
auto acc = p.second;
@@ -667,7 +677,7 @@ void Builder::RefreshPriority(const std::vector<Node*>& start_nodes) {
if (!e) {
return std::unordered_map<Edge*, int64_t>();
}
- auto run = GetWeight(data_source, e);
+ auto run = weight_getter(e);
auto new_priority = run + acc;
// Skip if priority isn't updated
if (new_priority <= e->priority()) {
@@ -688,7 +698,7 @@ void Builder::RefreshPriority(const std::vector<Node*>& start_nodes) {
std::unordered_map<Edge*, int64_t> next_todo_map;
for (auto* ne : next_edges) {
- auto next_run = GetWeight(data_source, ne);
+ auto next_run = weight_getter(ne);
if (next_run + e->priority() > ne->priority()) {
next_todo_map.try_emplace(ne, e->priority());
}
@@ -717,7 +727,7 @@ bool Builder::AddTargets(const std::vector<Node*> &nodes, string* err) {
if (!scan_.RecomputeNodesDirty(nodes, &validation_nodes, err))
return false;
- if (config_.weight_list_path) {
+ if (config_.weight_list_path || config_.ninja_log_as_weight_list) {
RefreshPriority(nodes);
}
diff --git a/src/build.h b/src/build.h
index 1283ee8..e58ac33 100644
--- a/src/build.h
+++ b/src/build.h
@@ -233,6 +233,8 @@ struct BuildConfig {
/// out/bin/bar,5
/// Note that the default weight is 1 for a module which isn't included in the list.
std::optional<std::string> weight_list_path;
+
+ bool ninja_log_as_weight_list;
};
/// Builder wraps the build process: starting commands, updating status.
diff --git a/src/ninja.cc b/src/ninja.cc
index 19fc605..75da99c 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -1308,6 +1308,7 @@ bool OptionEnable(const string& name, Options* options, BuildConfig* config) {
" that these warnings work:\n"
" undeclaredsymlinkoutputs\n"
" preremoveoutputs={yes,no} whether to remove outputs before running rule\n"
+" usesninjalogasweightlist={yes,no} whether to use ninja log as source of weight list\n"
" usesweightlist={<file path>,no} whether to prioritize some rules based on weight list from file\n");
return false;
} else if (name == "usesphonyoutputs=yes") {
@@ -1334,6 +1335,12 @@ bool OptionEnable(const string& name, Options* options, BuildConfig* config) {
} else if (auto n = name.find("usesweightlist=") != std::string::npos) {
config->weight_list_path = name.substr(n + strlen("usesweightlist=" ) - 1);
return true;
+ } else if (name == "usesninjalogasweightlist=yes") {
+ config->ninja_log_as_weight_list = true;
+ return true;
+ } else if (name == "usesninjalogasweightlist=no") {
+ config->ninja_log_as_weight_list = false;
+ return true;
} else {
const char* suggestion =
SpellcheckString(name.c_str(),
@@ -1627,6 +1634,10 @@ int ReadFlags(int* argc, char*** argv,
Fatal("preremoveoutputs=yes requires usesphonyoutputs=yes.");
}
+ if (config->weight_list_path && config->ninja_log_as_weight_list) {
+ Fatal("only one of --usesninjalogasweightlist=yes or --usesweightlist=<path> may be specified");
+ }
+
return -1;
}