aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2022-04-08 08:10:32 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2022-04-08 08:10:32 +0200
commit230e7cb0bab4582132de2bc411e355eacbacff4a (patch)
tree166ca16718762b679777b6fb198dc053187d3c89
parentd8cba1bae2b0212c7f8bc5af5c33709a6e622510 (diff)
Add phase switch contention to build statistics
-rw-r--r--build2/b.cxx36
-rw-r--r--libbuild2/context.cxx8
-rw-r--r--libbuild2/context.hxx7
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<context> 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_;