diff --git a/src/libstore/build/worker.cc b/src/libstore/build/worker.cc index 9317a5ac2..5be706e42 100644 --- a/src/libstore/build/worker.cc +++ b/src/libstore/build/worker.cc @@ -258,11 +258,13 @@ void Worker::childTerminated(GoalPtr goal) } -void Worker::updateStatistics() -{ - // only update progress info while running. this notably excludes updating - // progress info while destroying, which causes the progress bar to assert - if (running && statisticsOutdated) { +kj::Promise> Worker::updateStatistics() +try { + while (true) { + statisticsUpdateInhibitor = co_await statisticsUpdateSignal.acquire(); + + // only update progress info while running. this notably excludes updating + // progress info while destroying, which causes the progress bar to assert actDerivations.progress( doneBuilds, expectedBuilds + doneBuilds, runningBuilds, failedBuilds ); @@ -275,8 +277,11 @@ void Worker::updateStatistics() act.setExpected(actFileTransfer, expectedDownloadSize + doneDownloadSize); act.setExpected(actCopyPath, expectedNarSize + doneNarSize); - statisticsOutdated = false; + // limit to 50fps. that should be more than good enough for anything we do + co_await aio.provider->getTimer().afterDelay(20 * kj::MILLISECONDS); } +} catch (...) { + co_return result::failure(std::current_exception()); } std::vector Worker::run(std::function req) @@ -287,14 +292,12 @@ std::vector Worker::run(std::function req) running = true; Finally const _stop([&] { running = false; }); - updateStatistics(); - topGoals.clear(); for (auto & [goal, _promise] : _topGoals) { topGoals.insert(goal); } - auto promise = runImpl(); + auto promise = runImpl().exclusiveJoin(updateStatistics()); // TODO GC interface? if (auto localStore = dynamic_cast(&store); localStore && settings.minFree != 0) { diff --git a/src/libstore/build/worker.hh b/src/libstore/build/worker.hh index bb51a2114..d6cde8384 100644 --- a/src/libstore/build/worker.hh +++ b/src/libstore/build/worker.hh @@ -167,16 +167,17 @@ private: /** * Pass current stats counters to the logger for progress bar updates. */ - void updateStatistics(); + kj::Promise> updateStatistics(); - bool statisticsOutdated = true; + AsyncSemaphore statisticsUpdateSignal{1}; + std::optional statisticsUpdateInhibitor; /** * Mark statistics as outdated, such that `updateStatistics` will be called. */ void updateStatisticsLater() { - statisticsOutdated = true; + statisticsUpdateInhibitor = {}; } kj::Promise> runImpl();