1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "state.h"
16
17 #include <assert.h>
18 #include <stdio.h>
19
20 #include "edit_distance.h"
21 #include "graph.h"
22 #include "metrics.h"
23 #include "util.h"
24
25
EdgeScheduled(const Edge & edge)26 void Pool::EdgeScheduled(const Edge& edge) {
27 if (depth_ != 0)
28 current_use_ += edge.weight();
29 }
30
EdgeFinished(const Edge & edge)31 void Pool::EdgeFinished(const Edge& edge) {
32 if (depth_ != 0)
33 current_use_ -= edge.weight();
34 }
35
DelayEdge(Edge * edge)36 void Pool::DelayEdge(Edge* edge) {
37 assert(depth_ != 0);
38 delayed_.insert(edge);
39 }
40
RetrieveReadyEdges(set<Edge * > * ready_queue)41 void Pool::RetrieveReadyEdges(set<Edge*>* ready_queue) {
42 DelayedEdges::iterator it = delayed_.begin();
43 while (it != delayed_.end()) {
44 Edge* edge = *it;
45 if (current_use_ + edge->weight() > depth_)
46 break;
47 ready_queue->insert(edge);
48 EdgeScheduled(*edge);
49 ++it;
50 }
51 delayed_.erase(delayed_.begin(), it);
52 }
53
Dump() const54 void Pool::Dump() const {
55 printf("%s (%d/%d) ->\n", name_.c_str(), current_use_, depth_);
56 for (DelayedEdges::const_iterator it = delayed_.begin();
57 it != delayed_.end(); ++it)
58 {
59 printf("\t");
60 (*it)->Dump();
61 }
62 }
63
64 // static
WeightedEdgeCmp(const Edge * a,const Edge * b)65 bool Pool::WeightedEdgeCmp(const Edge* a, const Edge* b) {
66 if (!a) return b;
67 if (!b) return false;
68 int weight_diff = a->weight() - b->weight();
69 return ((weight_diff < 0) || (weight_diff == 0 && a < b));
70 }
71
72 Pool State::kDefaultPool("", 0);
73 Pool State::kConsolePool("console", 1);
74 const Rule State::kPhonyRule("phony");
75
State()76 State::State() {
77 bindings_.AddRule(&kPhonyRule);
78 AddPool(&kDefaultPool);
79 AddPool(&kConsolePool);
80 }
81
AddPool(Pool * pool)82 void State::AddPool(Pool* pool) {
83 assert(LookupPool(pool->name()) == NULL);
84 pools_[pool->name()] = pool;
85 }
86
LookupPool(const string & pool_name)87 Pool* State::LookupPool(const string& pool_name) {
88 map<string, Pool*>::iterator i = pools_.find(pool_name);
89 if (i == pools_.end())
90 return NULL;
91 return i->second;
92 }
93
AddEdge(const Rule * rule)94 Edge* State::AddEdge(const Rule* rule) {
95 Edge* edge = new Edge();
96 edge->rule_ = rule;
97 edge->pool_ = &State::kDefaultPool;
98 edge->env_ = &bindings_;
99 edges_.push_back(edge);
100 return edge;
101 }
102
GetNode(StringPiece path,uint64_t slash_bits)103 Node* State::GetNode(StringPiece path, uint64_t slash_bits) {
104 Node* node = LookupNode(path);
105 if (node)
106 return node;
107 node = new Node(path.AsString(), slash_bits);
108 paths_[node->path()] = node;
109 return node;
110 }
111
LookupNode(StringPiece path) const112 Node* State::LookupNode(StringPiece path) const {
113 METRIC_RECORD("lookup node");
114 Paths::const_iterator i = paths_.find(path);
115 if (i != paths_.end())
116 return i->second;
117 return NULL;
118 }
119
SpellcheckNode(const string & path)120 Node* State::SpellcheckNode(const string& path) {
121 const bool kAllowReplacements = true;
122 const int kMaxValidEditDistance = 3;
123
124 int min_distance = kMaxValidEditDistance + 1;
125 Node* result = NULL;
126 for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) {
127 int distance = EditDistance(
128 i->first, path, kAllowReplacements, kMaxValidEditDistance);
129 if (distance < min_distance && i->second) {
130 min_distance = distance;
131 result = i->second;
132 }
133 }
134 return result;
135 }
136
AddIn(Edge * edge,StringPiece path,uint64_t slash_bits)137 void State::AddIn(Edge* edge, StringPiece path, uint64_t slash_bits) {
138 Node* node = GetNode(path, slash_bits);
139 edge->inputs_.push_back(node);
140 node->AddOutEdge(edge);
141 }
142
AddOut(Edge * edge,StringPiece path,uint64_t slash_bits)143 bool State::AddOut(Edge* edge, StringPiece path, uint64_t slash_bits) {
144 Node* node = GetNode(path, slash_bits);
145 if (node->in_edge())
146 return false;
147 edge->outputs_.push_back(node);
148 node->set_in_edge(edge);
149 return true;
150 }
151
AddDefault(StringPiece path,string * err)152 bool State::AddDefault(StringPiece path, string* err) {
153 Node* node = LookupNode(path);
154 if (!node) {
155 *err = "unknown target '" + path.AsString() + "'";
156 return false;
157 }
158 defaults_.push_back(node);
159 return true;
160 }
161
RootNodes(string * err) const162 vector<Node*> State::RootNodes(string* err) const {
163 vector<Node*> root_nodes;
164 // Search for nodes with no output.
165 for (vector<Edge*>::const_iterator e = edges_.begin();
166 e != edges_.end(); ++e) {
167 for (vector<Node*>::const_iterator out = (*e)->outputs_.begin();
168 out != (*e)->outputs_.end(); ++out) {
169 if ((*out)->out_edges().empty())
170 root_nodes.push_back(*out);
171 }
172 }
173
174 if (!edges_.empty() && root_nodes.empty())
175 *err = "could not determine root nodes of build graph";
176
177 return root_nodes;
178 }
179
DefaultNodes(string * err) const180 vector<Node*> State::DefaultNodes(string* err) const {
181 return defaults_.empty() ? RootNodes(err) : defaults_;
182 }
183
Reset()184 void State::Reset() {
185 for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i)
186 i->second->ResetState();
187 for (vector<Edge*>::iterator e = edges_.begin(); e != edges_.end(); ++e) {
188 (*e)->outputs_ready_ = false;
189 (*e)->deps_loaded_ = false;
190 (*e)->mark_ = Edge::VisitNone;
191 }
192 }
193
Dump()194 void State::Dump() {
195 for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) {
196 Node* node = i->second;
197 printf("%s %s [id:%d]\n",
198 node->path().c_str(),
199 node->status_known() ? (node->dirty() ? "dirty" : "clean")
200 : "unknown",
201 node->id());
202 }
203 if (!pools_.empty()) {
204 printf("resource_pools:\n");
205 for (map<string, Pool*>::const_iterator it = pools_.begin();
206 it != pools_.end(); ++it)
207 {
208 if (!it->second->name().empty()) {
209 it->second->Dump();
210 }
211 }
212 }
213 }
214