Line | Count | Source |
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 "util.h" |
23 | | |
24 | | using namespace std; |
25 | | |
26 | 0 | void Pool::EdgeScheduled(const Edge& edge) { |
27 | 0 | if (depth_ != 0) |
28 | 0 | current_use_ += edge.weight(); |
29 | 0 | } |
30 | | |
31 | 0 | void Pool::EdgeFinished(const Edge& edge) { |
32 | 0 | if (depth_ != 0) |
33 | 0 | current_use_ -= edge.weight(); |
34 | 0 | } |
35 | | |
36 | 0 | void Pool::DelayEdge(Edge* edge) { |
37 | 0 | assert(depth_ != 0); |
38 | 0 | delayed_.insert(edge); |
39 | 0 | } |
40 | | |
41 | 0 | void Pool::RetrieveReadyEdges(EdgePriorityQueue* ready_queue) { |
42 | 0 | DelayedEdges::iterator it = delayed_.begin(); |
43 | 0 | while (it != delayed_.end()) { |
44 | 0 | Edge* edge = *it; |
45 | 0 | if (current_use_ + edge->weight() > depth_) |
46 | 0 | break; |
47 | 0 | ready_queue->push(edge); |
48 | 0 | EdgeScheduled(*edge); |
49 | 0 | ++it; |
50 | 0 | } |
51 | 0 | delayed_.erase(delayed_.begin(), it); |
52 | 0 | } |
53 | | |
54 | 0 | void Pool::Dump() const { |
55 | 0 | printf("%s (%d/%d) ->\n", name_.c_str(), current_use_, depth_); |
56 | 0 | for (DelayedEdges::const_iterator it = delayed_.begin(); |
57 | 0 | it != delayed_.end(); ++it) |
58 | 0 | { |
59 | 0 | printf("\t"); |
60 | 0 | (*it)->Dump(); |
61 | 0 | } |
62 | 0 | } |
63 | | |
64 | | Pool State::kDefaultPool("", 0); |
65 | | Pool State::kConsolePool("console", 1); |
66 | | |
67 | 587 | State::State() { |
68 | 587 | bindings_.AddRule(Rule::Phony()); |
69 | 587 | AddPool(&kDefaultPool); |
70 | 587 | AddPool(&kConsolePool); |
71 | 587 | } |
72 | | |
73 | 1.26k | void State::AddPool(Pool* pool) { |
74 | 1.26k | assert(LookupPool(pool->name()) == NULL); |
75 | 1.26k | pools_[pool->name()] = pool; |
76 | 1.26k | } |
77 | | |
78 | 1.38k | Pool* State::LookupPool(const string& pool_name) { |
79 | 1.38k | map<string, Pool*>::iterator i = pools_.find(pool_name); |
80 | 1.38k | if (i == pools_.end()) |
81 | 1.36k | return NULL; |
82 | 17 | return i->second; |
83 | 1.38k | } |
84 | | |
85 | 220k | Edge* State::AddEdge(const Rule* rule) { |
86 | 220k | Edge* edge = new Edge(); |
87 | 220k | edge->rule_ = rule; |
88 | 220k | edge->pool_ = &State::kDefaultPool; |
89 | 220k | edge->env_ = &bindings_; |
90 | 220k | edge->id_ = edges_.size(); |
91 | 220k | edges_.push_back(edge); |
92 | 220k | return edge; |
93 | 220k | } |
94 | | |
95 | 1.02M | Node* State::GetNode(StringPiece path, uint64_t slash_bits) { |
96 | 1.02M | Node* node = LookupNode(path); |
97 | 1.02M | if (node) |
98 | 717k | return node; |
99 | 302k | node = new Node(path.AsString(), slash_bits); |
100 | 302k | paths_[node->path()] = node; |
101 | 302k | return node; |
102 | 1.02M | } |
103 | | |
104 | 1.02M | Node* State::LookupNode(StringPiece path) const { |
105 | 1.02M | Paths::const_iterator i = paths_.find(path); |
106 | 1.02M | if (i != paths_.end()) |
107 | 721k | return i->second; |
108 | 302k | return NULL; |
109 | 1.02M | } |
110 | | |
111 | 0 | Node* State::SpellcheckNode(const string& path) { |
112 | 0 | const bool kAllowReplacements = true; |
113 | 0 | const int kMaxValidEditDistance = 3; |
114 | |
|
115 | 0 | int min_distance = kMaxValidEditDistance + 1; |
116 | 0 | Node* result = NULL; |
117 | 0 | for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) { |
118 | 0 | int distance = EditDistance( |
119 | 0 | i->first, path, kAllowReplacements, kMaxValidEditDistance); |
120 | 0 | if (distance < min_distance && i->second) { |
121 | 0 | min_distance = distance; |
122 | 0 | result = i->second; |
123 | 0 | } |
124 | 0 | } |
125 | 0 | return result; |
126 | 0 | } |
127 | | |
128 | 450k | void State::AddIn(Edge* edge, StringPiece path, uint64_t slash_bits) { |
129 | 450k | Node* node = GetNode(path, slash_bits); |
130 | 450k | node->set_generated_by_dep_loader(false); |
131 | 450k | edge->inputs_.push_back(node); |
132 | 450k | node->AddOutEdge(edge); |
133 | 450k | } |
134 | | |
135 | | bool State::AddOut(Edge* edge, StringPiece path, uint64_t slash_bits, |
136 | 220k | std::string* err) { |
137 | 220k | Node* node = GetNode(path, slash_bits); |
138 | 220k | if (Edge* other = node->in_edge()) { |
139 | 17 | if (other == edge) { |
140 | 4 | *err = path.AsString() + " is defined as an output multiple times"; |
141 | 13 | } else { |
142 | 13 | *err = "multiple rules generate " + path.AsString(); |
143 | 13 | } |
144 | 17 | return false; |
145 | 17 | } |
146 | 220k | edge->outputs_.push_back(node); |
147 | 220k | node->set_in_edge(edge); |
148 | 220k | node->set_generated_by_dep_loader(false); |
149 | 220k | return true; |
150 | 220k | } |
151 | | |
152 | 348k | void State::AddValidation(Edge* edge, StringPiece path, uint64_t slash_bits) { |
153 | 348k | Node* node = GetNode(path, slash_bits); |
154 | 348k | edge->validations_.push_back(node); |
155 | 348k | node->AddValidationOutEdge(edge); |
156 | 348k | node->set_generated_by_dep_loader(false); |
157 | 348k | } |
158 | | |
159 | 4.47k | bool State::AddDefault(StringPiece path, string* err) { |
160 | 4.47k | Node* node = LookupNode(path); |
161 | 4.47k | if (!node) { |
162 | 3 | *err = "unknown target '" + path.AsString() + "'"; |
163 | 3 | return false; |
164 | 3 | } |
165 | 4.46k | defaults_.push_back(node); |
166 | 4.46k | return true; |
167 | 4.47k | } |
168 | | |
169 | 0 | vector<Node*> State::RootNodes(string* err) const { |
170 | 0 | vector<Node*> root_nodes; |
171 | | // Search for nodes with no output. |
172 | 0 | for (vector<Edge*>::const_iterator e = edges_.begin(); |
173 | 0 | e != edges_.end(); ++e) { |
174 | 0 | for (vector<Node*>::const_iterator out = (*e)->outputs_.begin(); |
175 | 0 | out != (*e)->outputs_.end(); ++out) { |
176 | 0 | if ((*out)->out_edges().empty()) |
177 | 0 | root_nodes.push_back(*out); |
178 | 0 | } |
179 | 0 | } |
180 | |
|
181 | 0 | if (!edges_.empty() && root_nodes.empty()) |
182 | 0 | *err = "could not determine root nodes of build graph"; |
183 | |
|
184 | 0 | return root_nodes; |
185 | 0 | } |
186 | | |
187 | 0 | vector<Node*> State::DefaultNodes(string* err) const { |
188 | 0 | return defaults_.empty() ? RootNodes(err) : defaults_; |
189 | 0 | } |
190 | | |
191 | 0 | void State::Reset() { |
192 | 0 | for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) |
193 | 0 | i->second->ResetState(); |
194 | 0 | for (vector<Edge*>::iterator e = edges_.begin(); e != edges_.end(); ++e) { |
195 | 0 | (*e)->outputs_ready_ = false; |
196 | 0 | (*e)->deps_loaded_ = false; |
197 | 0 | (*e)->mark_ = Edge::VisitNone; |
198 | 0 | } |
199 | 0 | } |
200 | | |
201 | 0 | void State::Dump() { |
202 | 0 | for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) { |
203 | 0 | Node* node = i->second; |
204 | 0 | printf("%s %s [id:%d]\n", |
205 | 0 | node->path().c_str(), |
206 | 0 | node->status_known() ? (node->dirty() ? "dirty" : "clean") |
207 | 0 | : "unknown", |
208 | 0 | node->id()); |
209 | 0 | } |
210 | 0 | if (!pools_.empty()) { |
211 | 0 | printf("resource_pools:\n"); |
212 | 0 | for (map<string, Pool*>::const_iterator it = pools_.begin(); |
213 | 0 | it != pools_.end(); ++it) |
214 | 0 | { |
215 | 0 | if (!it->second->name().empty()) { |
216 | 0 | it->second->Dump(); |
217 | 0 | } |
218 | 0 | } |
219 | 0 | } |
220 | 0 | } |