From 0798dc8be4509c057e2ba62e611f53e6f873ea67 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 20 Oct 2022 07:06:18 +0200 Subject: Implement parallel execution of post hoc prerequisites --- libbuild2/algorithm.ixx | 4 ++-- libbuild2/operation.cxx | 53 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/libbuild2/algorithm.ixx b/libbuild2/algorithm.ixx index 3398595..3c6c2fa 100644 --- a/libbuild2/algorithm.ixx +++ b/libbuild2/algorithm.ixx @@ -431,7 +431,7 @@ namespace build2 target_state r (match_impl (a, t, 0, nullptr).second); - if (fail && r == target_state::failed) + if (r == target_state::failed && fail) throw failed (); return r; @@ -509,7 +509,7 @@ namespace build2 assert (ctx.phase == run_phase::match); target_state r (match_impl (a, t, sc, &tc).second); - if (fail && !ctx.keep_going && r == target_state::failed) + if (r == target_state::failed && fail && !ctx.keep_going) throw failed (); return r; diff --git a/libbuild2/operation.cxx b/libbuild2/operation.cxx index 908ebd6..3c7aee4 100644 --- a/libbuild2/operation.cxx +++ b/libbuild2/operation.cxx @@ -371,7 +371,7 @@ namespace build2 // the face of cycles does not work well (we will deadlock for the // reverse execution mode). // - // @@ TODO: match in parallel. + // @@ PERF: match in parallel (need match_direct_async(), etc). // for (const target* pt: p.prerequisite_targets) { @@ -496,8 +496,7 @@ namespace build2 << " post hoc prerequisites of " << t; }); - // @@ TODO: execute in parallel. - // +#if 0 for (const target* pt: p.prerequisite_targets) { target_state s (execute_direct_sync (a, *pt, false /* fail */)); @@ -510,7 +509,45 @@ namespace build2 break; } } +#else + // Note: similar logic/reasoning to below except we use direct + // execution. + // + atomic_count tc (0); + wait_guard wg (ctx, tc); + + for (const target* pt: p.prerequisite_targets) + { + target_state s (execute_direct_async (a, *pt, 0, tc, false /*fail*/)); + + if (s == target_state::failed) + { + posthoc_fail = true; + + if (!ctx.keep_going) + break; + } + } + + wg.wait (); + // Process the result. + // + for (const target* pt: p.prerequisite_targets) + { + // Similar to below, no need to wait. + // + target_state s (pt->executed_state (a, false /* fail */)); + + if (s == target_state::failed) + { + // Note: no need to keep going. + // + posthoc_fail = true; + break; + } + } +#endif if (posthoc_fail && !ctx.keep_going) break; } @@ -668,13 +705,15 @@ namespace build2 // targets so it seems the best we can do is just fail them all. // if (!posthoc_fail) - at.state = t.executed_state (a, false); + { + // Note that here we call executed_state() directly instead of + // execute_complete() since we know there is no need to wait. + // + at.state = t.executed_state (a, false /* fail */); + } else at.state = /*t.state[a].state =*/ target_state::failed; - // Note that here we call executed_state() directly instead of - // execute_complete() since we know there is no need to wait. - // switch (at.state) { case target_state::unknown: -- cgit v1.1