@@ -89,6 +89,7 @@ void Plan::Reset() {
89
89
}
90
90
91
91
bool Plan::AddTarget (const Node* target, string* err) {
92
+ targets_.push_back (target);
92
93
return AddSubTarget (target, NULL , err, NULL );
93
94
}
94
95
@@ -128,8 +129,6 @@ bool Plan::AddSubTarget(const Node* node, const Node* dependent, string* err,
128
129
if (node->dirty () && want == kWantNothing ) {
129
130
want = kWantToStart ;
130
131
EdgeWanted (edge);
131
- if (!dyndep_walk && edge->AllInputsReady ())
132
- ScheduleWork (want_ins.first );
133
132
}
134
133
135
134
if (dyndep_walk)
@@ -156,10 +155,10 @@ void Plan::EdgeWanted(const Edge* edge) {
156
155
Edge* Plan::FindWork () {
157
156
if (ready_.empty ())
158
157
return NULL ;
159
- EdgeSet::iterator e = ready_. begin ();
160
- Edge* edge = *e ;
161
- ready_.erase (e );
162
- return edge ;
158
+
159
+ Edge* work = ready_. top () ;
160
+ ready_.pop ( );
161
+ return work ;
163
162
}
164
163
165
164
void Plan::ScheduleWork (map<Edge*, Want>::iterator want_e) {
@@ -180,7 +179,7 @@ void Plan::ScheduleWork(map<Edge*, Want>::iterator want_e) {
180
179
pool->RetrieveReadyEdges (&ready_);
181
180
} else {
182
181
pool->EdgeScheduled (*edge);
183
- ready_.insert (edge);
182
+ ready_.push (edge);
184
183
}
185
184
}
186
185
@@ -442,6 +441,121 @@ void Plan::UnmarkDependents(const Node* node, set<Node*>* dependents) {
442
441
}
443
442
}
444
443
444
+ namespace {
445
+
446
+ template <typename T>
447
+ struct SeenBefore {
448
+ std::set<const T*>* seen_;
449
+
450
+ SeenBefore (std::set<const T*>* seen) : seen_(seen) {}
451
+
452
+ bool operator () (const T* item) {
453
+ // Return true if the item has been seen before
454
+ return !seen_->insert (item).second ;
455
+ }
456
+ };
457
+
458
+ // Heuristic for edge priority weighting.
459
+ // Phony edges are free (0 cost), all other edges are weighted equally.
460
+ int64_t EdgeWeightHeuristic (Edge *edge) {
461
+ return edge->is_phony () ? 0 : 1 ;
462
+ }
463
+
464
+ } // namespace
465
+
466
+ void Plan::ComputeCriticalPath () {
467
+ METRIC_RECORD (" ComputeCriticalPath" );
468
+ // Remove duplicate targets
469
+ {
470
+ std::set<const Node*> seen;
471
+ SeenBefore<Node> seen_before (&seen);
472
+ targets_.erase (std::remove_if (targets_.begin (), targets_.end (), seen_before),
473
+ targets_.end ());
474
+ }
475
+
476
+ // Use backflow algorithm to compute the critical path for all
477
+ // nodes, starting from the destination nodes.
478
+ // XXX: ignores pools
479
+ std::queue<Edge*> work_queue; // Queue, for breadth-first traversal
480
+ // The set of edges currently in work_queue, to avoid duplicates.
481
+ std::set<const Edge*> active_edges;
482
+ SeenBefore<Edge> seen_edge (&active_edges);
483
+
484
+ for (size_t i = 0 ; i < targets_.size (); ++i) {
485
+ const Node* target = targets_[i];
486
+ if (Edge* in = target->in_edge ()) {
487
+ int64_t edge_weight = EdgeWeightHeuristic (in);
488
+ in->set_critical_path_weight (
489
+ std::max<int64_t >(edge_weight, in->critical_path_weight ()));
490
+ if (!seen_edge (in)) {
491
+ work_queue.push (in);
492
+ }
493
+ }
494
+ }
495
+
496
+ while (!work_queue.empty ()) {
497
+ Edge* e = work_queue.front ();
498
+ work_queue.pop ();
499
+ // If the critical path of any dependent edges is updated, this
500
+ // edge may need to be processed again. So re-allow insertion.
501
+ active_edges.erase (e);
502
+
503
+ for (std::vector<Node*>::iterator it = e->inputs_ .begin (),
504
+ end = e->inputs_ .end ();
505
+ it != end; ++it) {
506
+ Edge* in = (*it)->in_edge ();
507
+ if (!in) {
508
+ continue ;
509
+ }
510
+ // Only process edge if this node offers a higher weighted path
511
+ const int64_t edge_weight = EdgeWeightHeuristic (in);
512
+ const int64_t proposed_weight = e->critical_path_weight () + edge_weight;
513
+ if (proposed_weight > in->critical_path_weight ()) {
514
+ in->set_critical_path_weight (proposed_weight);
515
+ if (!seen_edge (in)) {
516
+ work_queue.push (in);
517
+ }
518
+ }
519
+ }
520
+ }
521
+ }
522
+
523
+ void Plan::ScheduleInitialEdges () {
524
+ // Add ready edges to queue.
525
+ assert (ready_.empty ());
526
+ std::set<Pool*> pools;
527
+
528
+ for (std::map<Edge*, Plan::Want>::iterator it = want_.begin (),
529
+ end = want_.end (); it != end; ++it) {
530
+ Edge* edge = it->first ;
531
+ Plan::Want want = it->second ;
532
+ if (!(want == kWantToStart && edge->AllInputsReady ())) {
533
+ continue ;
534
+ }
535
+
536
+ Pool* pool = edge->pool ();
537
+ if (pool->ShouldDelayEdge ()) {
538
+ pool->DelayEdge (edge);
539
+ pools.insert (pool);
540
+ } else {
541
+ ScheduleWork (it);
542
+ }
543
+ }
544
+
545
+ // Call RetrieveReadyEdges only once at the end so higher priority
546
+ // edges are retrieved first, not the ones that happen to be first
547
+ // in the want_ map.
548
+ for (std::set<Pool*>::iterator it=pools.begin (),
549
+ end = pools.end (); it != end; ++it) {
550
+ (*it)->RetrieveReadyEdges (&ready_);
551
+ }
552
+ }
553
+
554
+ void Plan::PrepareQueue () {
555
+ ComputeCriticalPath ();
556
+ ScheduleInitialEdges ();
557
+ }
558
+
445
559
void Plan::Dump () const {
446
560
printf (" pending: %d\n " , (int )want_.size ());
447
561
for (map<Edge*, Want>::const_iterator e = want_.begin (); e != want_.end (); ++e) {
@@ -611,6 +725,7 @@ bool Builder::AlreadyUpToDate() const {
611
725
612
726
bool Builder::Build (string* err) {
613
727
assert (!AlreadyUpToDate ());
728
+ plan_.PrepareQueue ();
614
729
615
730
status_->PlanHasTotalEdges (plan_.command_edge_count ());
616
731
int pending_commands = 0 ;
0 commit comments