aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2022-03-08 10:57:52 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2022-03-08 10:59:20 +0200
commit2ede341d59b4ab259caf808dfa65c0ac380ba347 (patch)
treea69e7b9f6a943692cc81b22cd98c8df97c1e9e19
parentc5022fa04b64a9b572cd468837b934eaf5999e1a (diff)
Improve performance of update during match for multiple targets
-rw-r--r--libbuild2/adhoc-rule-buildscript.cxx14
-rw-r--r--libbuild2/algorithm.cxx69
-rw-r--r--libbuild2/algorithm.hxx13
-rw-r--r--libbuild2/cc/link-rule.cxx14
-rw-r--r--libbuild2/target-state.hxx4
5 files changed, 95 insertions, 19 deletions
diff --git a/libbuild2/adhoc-rule-buildscript.cxx b/libbuild2/adhoc-rule-buildscript.cxx
index fa60556..25ef1b7 100644
--- a/libbuild2/adhoc-rule-buildscript.cxx
+++ b/libbuild2/adhoc-rule-buildscript.cxx
@@ -456,17 +456,13 @@ namespace build2
// If we have any update during match prerequisites, now is the time to
// update them.
//
- // Note also that we ignore the result and whether it renders us out of
- // date, leaving it to the common execute logic in perform_update_*().
+ // Note that we ignore the result and whether it renders us out of date,
+ // leaving it to the common execute logic in perform_update_*().
+ //
+ // Note also that update_during_match() spoils prerequisite_target::data.
//
if (a == perform_update_id)
- {
- for (const prerequisite_target& pt: pts)
- {
- if ((pt.include & 2) != 0)
- update_during_match (trace, a, *pt.target);
- }
- }
+ update_during_match (trace, a, pts, 2 /* mask */);
// See if this is not update or not on a file-based target.
//
diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx
index cbf0495..d72e95e 100644
--- a/libbuild2/algorithm.cxx
+++ b/libbuild2/algorithm.cxx
@@ -2119,6 +2119,75 @@ namespace build2
}
}
+ bool
+ update_during_match (tracer& trace,
+ action a,
+ prerequisite_targets& pts,
+ uintptr_t mask)
+ {
+ // On the first pass detect and handle unchanged tragets. Note that we
+ // have to do it in a separate pass since we cannot call matched_state()
+ // once we've switched the phase.
+ //
+ context* ctx (nullptr);
+
+ for (prerequisite_target& p: pts)
+ {
+ if ((p.include & mask) != 0)
+ {
+ if (p.target != nullptr)
+ {
+ const target& pt (*p.target);
+
+ target_state os (pt.matched_state (a));
+
+ if (os != target_state::unchanged)
+ {
+ if (ctx == nullptr)
+ ctx = &pt.ctx;
+
+ p.data = static_cast<uintptr_t> (os);
+ continue;
+ }
+ }
+
+ p.data = 0;
+ }
+ }
+
+ // If all unchanged, we are done.
+ //
+ if (ctx == nullptr)
+ return false;
+
+ phase_switch ps (*ctx, run_phase::execute);
+
+ bool r (false);
+
+ for (prerequisite_target& p: pts)
+ {
+ if ((p.include & mask) != 0 && p.data != 0)
+ {
+ const target& pt (*p.target);
+
+ target_state os (static_cast<target_state> (p.data));
+ target_state ns (execute_direct (a, pt));
+
+ if (ns != os && ns != target_state::unchanged)
+ {
+ l6 ([&]{trace << "updated " << pt
+ << "; old state " << os
+ << "; new state " << ns;});
+ r = true;
+ }
+
+ p.data = 0;
+ }
+ }
+
+ return r;
+ }
+
static inline void
blank_adhoc_member (const target*&)
{
diff --git a/libbuild2/algorithm.hxx b/libbuild2/algorithm.hxx
index c30680a..788138b 100644
--- a/libbuild2/algorithm.hxx
+++ b/libbuild2/algorithm.hxx
@@ -609,6 +609,19 @@ namespace build2
action, const target&,
timestamp = timestamp_unknown);
+ // As above, but update all the targets in prerequisite_targets that have
+ // the specified mask in prerequisite_target::include. Return true if any of
+ // them have changed.
+ //
+ // Note that this function spoils prerequisite_target::data (which is used
+ // for temporary storage). But it resets data to 0 once done.
+ //
+ LIBBUILD2_SYMEXPORT bool
+ update_during_match (tracer&,
+ action,
+ prerequisite_targets&,
+ uintptr_t mask);
+
// The default prerequisite execute implementation. Call execute_async() on
// each non-ignored (non-NULL) prerequisite target in a loop and then wait
// for their completion. Return target_state::changed if any of them were
diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx
index c507155..b72e5a0 100644
--- a/libbuild2/cc/link-rule.cxx
+++ b/libbuild2/cc/link-rule.cxx
@@ -1226,17 +1226,13 @@ namespace build2
// example, object file matches may need the headers to be already
// updated).
//
- // Note also that we ignore the result and whether it renders us out of
- // date, leaving it to the common execute logic in perform_update().
+ // Note that we ignore the result and whether it renders us out of date,
+ // leaving it to the common execute logic in perform_update().
+ //
+ // Note also that update_during_match() spoils prerequisite_target::data.
//
if (update_match)
- {
- for (const prerequisite_target& pto: pts)
- {
- if ((pto.include & 2) != 0)
- update_during_match (trace, a, *pto.target);
- }
- }
+ update_during_match (trace, a, pts, 2 /* mask */);
// Check if we have any binful utility libraries.
//
diff --git a/libbuild2/target-state.hxx b/libbuild2/target-state.hxx
index 3457b13..48d683d 100644
--- a/libbuild2/target-state.hxx
+++ b/libbuild2/target-state.hxx
@@ -18,9 +18,11 @@ namespace build2
// Note that postponed is "greater" than unchanged since it may result in
// the changed state.
//
+ // Note also that value 0 is available to indicate absent/invalid state.
+ //
enum class target_state: uint8_t
{
- unknown,
+ unknown = 1,
unchanged,
postponed,
busy,