From ad9cdb9b172ecd7acf5e55b60f3f77626d72f14f Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 13 May 2021 09:02:17 +0200 Subject: Do lazy allocation of shadow task queues --- libbuild2/scheduler.cxx | 12 +++++------- libbuild2/scheduler.hxx | 3 +++ libbuild2/scheduler.txx | 3 +++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/libbuild2/scheduler.cxx b/libbuild2/scheduler.cxx index 8c0ea17..bdd703d 100644 --- a/libbuild2/scheduler.cxx +++ b/libbuild2/scheduler.cxx @@ -571,7 +571,8 @@ namespace build2 // phase helpers. The way we are going to do it is to temporarily (until // pop) replace such queues with empty ones. This should be ok since a // thread with such a "shadowed" queue won't wake up until we return to - // the old phase. + // the old phase (but the shadow queue may be used if the thread in + // question is also switching to the new phase). // // Note also that the assumption here is that while we may still have // "phase-less" threads milling around (e.g., transitioning from active to @@ -589,13 +590,10 @@ namespace build2 if (tq.size != 0) { - queued_task_count_.fetch_sub (tq.size, memory_order_release); - - // @@ TODO: should we make task_queue::data allocation lazy? On the - // other hand, we don't seem to get many non-empty queues here on - // real-world projects. + // Note that task_queue::data will be allocated lazily (there is a + // good chance this queue is not going to be used in the new phase). // - j->data.reset (new task_data[task_queue_depth_]); + queued_task_count_.fetch_sub (tq.size, memory_order_release); tq.swap (*j); } } diff --git a/libbuild2/scheduler.hxx b/libbuild2/scheduler.hxx index b85d353..da3f0c0 100644 --- a/libbuild2/scheduler.hxx +++ b/libbuild2/scheduler.hxx @@ -700,6 +700,9 @@ namespace build2 // tail, if enabled. If the mark is hit, then it is disabled until the // queue becomes empty or it is reset by a push. // + // Note also that the data array can be NULL (lazy allocation) and one + // must make sure it's allocated before calling push(). + // struct task_queue_data { size_t head = 0; diff --git a/libbuild2/scheduler.txx b/libbuild2/scheduler.txx index 9cfc411..5c6b339 100644 --- a/libbuild2/scheduler.txx +++ b/libbuild2/scheduler.txx @@ -54,6 +54,9 @@ namespace build2 if (tq->shutdown) throw_generic_error (ECANCELED); + if (tq->data == nullptr) + tq->data.reset (new task_data[task_queue_depth_]); + if (task_data* td = push (*tq)) { // Package the task (under lock). -- cgit v1.1