diff options
| author | Richard Purdie <richard.purdie@linuxfoundation.org> | 2024-11-04 17:42:33 +0000 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2024-11-07 13:36:04 +0000 |
| commit | 79f193ffa0394301242d25800a715b970c2a0b95 (patch) | |
| tree | de4b73448fef9191085f873a1e03244a4d93a367 /bitbake/lib | |
| parent | 330720015aa0974082905eefb3f5fc25309291f5 (diff) | |
| download | poky-79f193ffa0394301242d25800a715b970c2a0b95.tar.gz | |
bitbake: runqueue: Avoid dumpsigs idle loop blocking
We're seeing some failures on hosts where slow "idle" loop iterations are
causing bitbake server timeouts. These seem to happen particularly in the
dump_signatures() function within runqueue.
That isn't entirely surprising since it creates a pool of threads to execute
work an at best can take around 10s to execture and return control backto the
main loop. On a slow system, it is understandable this can take longer,
particularly as these functions are creating large chunks of IO.
Since the work is being done in threads, we can launch them, return to idle
and check on the results periodically as they complete.
This should hopefully address some of the remaining timeout issues we see on
the autobuilder in oe-selftest sstate tests.
(Bitbake rev: e66f1b643b4b77404ba31f2704cda5af9bf00a57)
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib')
| -rw-r--r-- | bitbake/lib/bb/runqueue.py | 73 |
1 files changed, 44 insertions, 29 deletions
diff --git a/bitbake/lib/bb/runqueue.py b/bitbake/lib/bb/runqueue.py index 3462ed4457..1b5b58f352 100644 --- a/bitbake/lib/bb/runqueue.py +++ b/bitbake/lib/bb/runqueue.py | |||
| @@ -128,6 +128,7 @@ class RunQueueStats: | |||
| 128 | # runQueue state machine | 128 | # runQueue state machine |
| 129 | runQueuePrepare = 2 | 129 | runQueuePrepare = 2 |
| 130 | runQueueSceneInit = 3 | 130 | runQueueSceneInit = 3 |
| 131 | runQueueDumpSigs = 4 | ||
| 131 | runQueueRunning = 6 | 132 | runQueueRunning = 6 |
| 132 | runQueueFailed = 7 | 133 | runQueueFailed = 7 |
| 133 | runQueueCleanUp = 8 | 134 | runQueueCleanUp = 8 |
| @@ -1588,14 +1589,19 @@ class RunQueue: | |||
| 1588 | self.rqdata.init_progress_reporter.next_stage() | 1589 | self.rqdata.init_progress_reporter.next_stage() |
| 1589 | self.rqexe = RunQueueExecute(self) | 1590 | self.rqexe = RunQueueExecute(self) |
| 1590 | 1591 | ||
| 1591 | dump = self.cooker.configuration.dump_signatures | 1592 | dumpsigs = self.cooker.configuration.dump_signatures |
| 1592 | if dump: | 1593 | if dumpsigs: |
| 1593 | self.rqdata.init_progress_reporter.finish() | 1594 | self.rqdata.init_progress_reporter.finish() |
| 1594 | if 'printdiff' in dump: | 1595 | if 'printdiff' in dumpsigs: |
| 1595 | invalidtasks = self.print_diffscenetasks() | 1596 | self.invalidtasks_dump = self.print_diffscenetasks() |
| 1596 | self.dump_signatures(dump) | 1597 | self.state = runQueueDumpSigs |
| 1597 | if 'printdiff' in dump: | 1598 | |
| 1598 | self.write_diffscenetasks(invalidtasks) | 1599 | if self.state is runQueueDumpSigs: |
| 1600 | dumpsigs = self.cooker.configuration.dump_signatures | ||
| 1601 | retval = self.dump_signatures(dumpsigs) | ||
| 1602 | if retval is False: | ||
| 1603 | if 'printdiff' in dumpsigs: | ||
| 1604 | self.write_diffscenetasks(self.invalidtasks_dump) | ||
| 1599 | self.state = runQueueComplete | 1605 | self.state = runQueueComplete |
| 1600 | 1606 | ||
| 1601 | if self.state is runQueueSceneInit: | 1607 | if self.state is runQueueSceneInit: |
| @@ -1686,33 +1692,42 @@ class RunQueue: | |||
| 1686 | bb.parse.siggen.dump_sigtask(taskfn, taskname, dataCaches[mc].stamp[taskfn], True) | 1692 | bb.parse.siggen.dump_sigtask(taskfn, taskname, dataCaches[mc].stamp[taskfn], True) |
| 1687 | 1693 | ||
| 1688 | def dump_signatures(self, options): | 1694 | def dump_signatures(self, options): |
| 1689 | if bb.cooker.CookerFeatures.RECIPE_SIGGEN_INFO not in self.cooker.featureset: | 1695 | if not hasattr(self, "dumpsigs_launched"): |
| 1690 | bb.fatal("The dump signatures functionality needs the RECIPE_SIGGEN_INFO feature enabled") | 1696 | if bb.cooker.CookerFeatures.RECIPE_SIGGEN_INFO not in self.cooker.featureset: |
| 1691 | 1697 | bb.fatal("The dump signatures functionality needs the RECIPE_SIGGEN_INFO feature enabled") | |
| 1692 | bb.note("Writing task signature files") | 1698 | |
| 1693 | 1699 | bb.note("Writing task signature files") | |
| 1694 | max_process = int(self.cfgData.getVar("BB_NUMBER_PARSE_THREADS") or os.cpu_count() or 1) | 1700 | |
| 1695 | def chunkify(l, n): | 1701 | max_process = int(self.cfgData.getVar("BB_NUMBER_PARSE_THREADS") or os.cpu_count() or 1) |
| 1696 | return [l[i::n] for i in range(n)] | 1702 | def chunkify(l, n): |
| 1697 | tids = chunkify(list(self.rqdata.runtaskentries), max_process) | 1703 | return [l[i::n] for i in range(n)] |
| 1698 | # We cannot use the real multiprocessing.Pool easily due to some local data | 1704 | dumpsigs_tids = chunkify(list(self.rqdata.runtaskentries), max_process) |
| 1699 | # that can't be pickled. This is a cheap multi-process solution. | 1705 | |
| 1700 | launched = [] | 1706 | # We cannot use the real multiprocessing.Pool easily due to some local data |
| 1701 | while tids: | 1707 | # that can't be pickled. This is a cheap multi-process solution. |
| 1702 | if len(launched) < max_process: | 1708 | self.dumpsigs_launched = [] |
| 1703 | p = Process(target=self._rq_dump_sigtid, args=(tids.pop(), )) | 1709 | |
| 1710 | for tids in dumpsigs_tids: | ||
| 1711 | p = Process(target=self._rq_dump_sigtid, args=(tids, )) | ||
| 1704 | p.start() | 1712 | p.start() |
| 1705 | launched.append(p) | 1713 | self.dumpsigs_launched.append(p) |
| 1706 | for q in launched: | 1714 | |
| 1707 | # The finished processes are joined when calling is_alive() | 1715 | return 1.0 |
| 1708 | if not q.is_alive(): | 1716 | |
| 1709 | launched.remove(q) | 1717 | for q in self.dumpsigs_launched: |
| 1710 | for p in launched: | 1718 | # The finished processes are joined when calling is_alive() |
| 1719 | if not q.is_alive(): | ||
| 1720 | self.dumpsigs_launched.remove(q) | ||
| 1721 | |||
| 1722 | if self.dumpsigs_launched: | ||
| 1723 | return 1.0 | ||
| 1724 | |||
| 1725 | for p in self.dumpsigs_launched: | ||
| 1711 | p.join() | 1726 | p.join() |
| 1712 | 1727 | ||
| 1713 | bb.parse.siggen.dump_sigs(self.rqdata.dataCaches, options) | 1728 | bb.parse.siggen.dump_sigs(self.rqdata.dataCaches, options) |
| 1714 | 1729 | ||
| 1715 | return | 1730 | return False |
| 1716 | 1731 | ||
| 1717 | def print_diffscenetasks(self): | 1732 | def print_diffscenetasks(self): |
| 1718 | def get_root_invalid_tasks(task, taskdepends, valid, noexec, visited_invalid): | 1733 | def get_root_invalid_tasks(task, taskdepends, valid, noexec, visited_invalid): |
