diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2017-03-15 18:38:03 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2017-03-15 18:38:03 +0200 |
commit | 430e46f7e352b1146f289e82f614d0b68c75aab5 (patch) | |
tree | 8ede58e3ada80b63ce15a3e3e93e4850d60986f7 | |
parent | 925d2d0eabe40517254380c5a12baa338b099d3e (diff) |
Implement parallel testscript execution for single target
-rw-r--r-- | build2/scheduler | 2 | ||||
-rw-r--r-- | build2/test/rule.cxx | 81 | ||||
-rw-r--r-- | build2/test/script/parser.cxx | 9 |
3 files changed, 78 insertions, 14 deletions
diff --git a/build2/scheduler b/build2/scheduler index a8f81cd..86a48df 100644 --- a/build2/scheduler +++ b/build2/scheduler @@ -399,7 +399,7 @@ namespace build2 // struct task_data { - std::aligned_storage<sizeof (void*) * 7>::type data; + std::aligned_storage<sizeof (void*) * 8>::type data; void (*thunk) (scheduler&, lock&, void*); }; diff --git a/build2/test/rule.cxx b/build2/test/rule.cxx index 0a346d8..33ffb90 100644 --- a/build2/test/rule.cxx +++ b/build2/test/rule.cxx @@ -370,6 +370,7 @@ namespace build2 // which case it should be the only one. // bool one; + size_t count (0); { optional<bool> o; for (const target* pt: t.prerequisite_targets) @@ -378,6 +379,8 @@ namespace build2 // if (const testscript* ts = pt->is_a<testscript> ()) { + count++; + bool r (ts->name == "testscript"); if ((r && o) || (!r && o && *o)) @@ -434,14 +437,23 @@ namespace build2 // bool mk (!one); - // Run all the testscripts. + // Start asynchronous execution of the testscripts. + // + wait_guard wg (target::count_busy (), t.task_count); + + // Result vector. // + using script::scope_state; + + vector<scope_state> result; + result.reserve (count); // Make sure there are no reallocations. + for (const target* pt: t.prerequisite_targets) { if (const testscript* ts = pt->is_a<testscript> ()) { - // If this is just the testscript, then its id path is empty (and - // it can only be ignored by ignoring the test target, which makes + // If this is just the testscript, then its id path is empty (and it + // can only be ignored by ignoring the test target, which makes // sense since it's the only testscript file). // if (one || test (t, path (ts->name))) @@ -458,16 +470,67 @@ namespace build2 text << "test " << t << " with " << *ts << " on " << tt; } - script::parser p; - script::script s (t, *ts, wd); - p.pre_parse (s); - - script::default_runner r (*this); - p.execute (s, r); + result.push_back (scope_state::unknown); + scope_state& r (result.back ()); + + if (!sched.async (target::count_busy (), + t.task_count, + [this] (scope_state& r, + const target& t, + const testscript& ts, + const dir_path& wd, + const diag_frame* ds) noexcept + { + diag_frame df (ds); + try + { + script::script s (t, ts, wd); + + { + script::parser p; + p.pre_parse (s); + + script::default_runner r (*this); + p.execute (s, r); + } + + r = s.state; + } + catch (const failed&) + { + r = scope_state::failed; + } + }, + ref (r), + cref (t), + cref (*ts), + cref (wd), + diag_frame::stack)) + { + // Executed synchronously. If failed and we were not asked to + // keep going, bail out. + // + if (r == scope_state::failed && !keep_going) + throw failed (); + } } } } + wg.wait (); + + // Re-examine. + // + for (scope_state r: result) + { + switch (r) + { + case scope_state::passed: break; + case scope_state::failed: throw failed (); + case scope_state::unknown: assert (false); + } + } + // Cleanup. // if (!one && !mk) diff --git a/build2/test/script/parser.cxx b/build2/test/script/parser.cxx index fd21a58..9d17304 100644 --- a/build2/test/script/parser.cxx +++ b/build2/test/script/parser.cxx @@ -2832,8 +2832,8 @@ namespace build2 if (!s.empty ()) execute (s, s, r); - - s.state = scope_state::passed; + else + s.state = scope_state::passed; } void parser:: @@ -2972,7 +2972,7 @@ namespace build2 // if (!sched.async (task_count, [] (scope& s, script& scr, runner& r, - const diag_frame* ds) + const diag_frame* ds) noexcept { diag_frame df (ds); @@ -2980,7 +2980,6 @@ namespace build2 { parser p; p.execute (s, scr, r); - s.state = scope_state::passed; } catch (const failed&) { @@ -3024,6 +3023,8 @@ namespace build2 assert (false); runner_->leave (*scope_, scope_->end_loc_); + + scope_->state = scope_state::passed; } void parser:: |