From 230e7cb0bab4582132de2bc411e355eacbacff4a Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 8 Apr 2022 08:10:32 +0200 Subject: Add phase switch contention to build statistics --- build2/b.cxx | 36 ++++++++++++++++++++++++++---------- libbuild2/context.cxx | 8 ++++++++ libbuild2/context.hxx | 7 ++++++- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/build2/b.cxx b/build2/b.cxx index 556cf36..e615ef5 100644 --- a/build2/b.cxx +++ b/build2/b.cxx @@ -268,6 +268,10 @@ main (int argc, char* argv[]) options ops; scheduler sched; + // Statistics. + // + size_t phase_switch_contention (0); + try { // Parse the command line. @@ -412,9 +416,17 @@ main (int argc, char* argv[]) // below). // unique_ptr pctx; - auto new_context = [&ops, &cmdl, &pctx, &sched, &mutexes, &fcache] + auto new_context = [&ops, &cmdl, + &sched, &mutexes, &fcache, + &phase_switch_contention, + &pctx] { - pctx = nullptr; // Free first. + if (pctx != nullptr) + { + phase_switch_contention += pctx->phase_mutex.contention; + pctx = nullptr; // Free first to reuse memory. + } + pctx.reset (new context (sched, mutexes, fcache, @@ -1389,6 +1401,8 @@ main (int argc, char* argv[]) cout << endl; } #endif + + phase_switch_contention += pctx->phase_mutex.contention; } catch (const failed&) { @@ -1410,16 +1424,18 @@ main (int argc, char* argv[]) { text << '\n' << "build statistics:" << "\n\n" - << " thread_max_active " << st.thread_max_active << '\n' - << " thread_max_total " << st.thread_max_total << '\n' - << " thread_helpers " << st.thread_helpers << '\n' - << " thread_max_waiting " << st.thread_max_waiting << '\n' + << " thread_max_active " << st.thread_max_active << '\n' + << " thread_max_total " << st.thread_max_total << '\n' + << " thread_helpers " << st.thread_helpers << '\n' + << " thread_max_waiting " << st.thread_max_waiting << '\n' + << '\n' + << " task_queue_depth " << st.task_queue_depth << '\n' + << " task_queue_full " << st.task_queue_full << '\n' << '\n' - << " task_queue_depth " << st.task_queue_depth << '\n' - << " task_queue_full " << st.task_queue_full << '\n' + << " wait_queue_slots " << st.wait_queue_slots << '\n' + << " wait_queue_collisions " << st.wait_queue_collisions << '\n' << '\n' - << " wait_queue_slots " << st.wait_queue_slots << '\n' - << " wait_queue_collisions " << st.wait_queue_collisions << '\n'; + << " phase_switch_contention " << phase_switch_contention << '\n'; } return r; diff --git a/libbuild2/context.cxx b/libbuild2/context.cxx index 80343bd..d460fa7 100644 --- a/libbuild2/context.cxx +++ b/libbuild2/context.cxx @@ -765,6 +765,8 @@ namespace build2 } else if (ctx_.phase != n) { + ++contention; + ctx_.sched.deactivate (false /* external */); for (; ctx_.phase != n; v->wait (l)) ; r = !fail_; @@ -781,6 +783,8 @@ namespace build2 { if (!lm_.try_lock ()) { + ++contention; + ctx_.sched.deactivate (false /* external */); lm_.lock (); ctx_.sched.activate (false /* external */); @@ -901,6 +905,8 @@ namespace build2 } else // phase != n { + ++contention; + ctx_.sched.deactivate (false /* external */); for (; ctx_.phase != n; v->wait (l)) ; r = !fail_; @@ -913,6 +919,8 @@ namespace build2 { if (!lm_.try_lock ()) { + ++contention; + ctx_.sched.deactivate (false /* external */); lm_.lock (); ctx_.sched.activate (false /* external */); diff --git a/libbuild2/context.hxx b/libbuild2/context.hxx index ef628c9..0595413 100644 --- a/libbuild2/context.hxx +++ b/libbuild2/context.hxx @@ -43,6 +43,11 @@ namespace build2 bool relock (run_phase unlock, run_phase lock); + // Statistics. + // + public: + size_t contention = 0; // # of contentious phase (re)locks. + private: friend class context; @@ -61,7 +66,7 @@ namespace build2 // is exclusive so we have a separate mutex to serialize it (think of it // as a second level locking). // - // When the mutex is unlocked (all three counters become zero, the phase + // When the mutex is unlocked (all three counters become zero), the phase // is always changed to load (this is also the initial state). // context& ctx_; -- cgit v1.1