summaryrefslogtreecommitdiffstats
path: root/bitbake/lib
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2024-11-04 17:42:33 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2024-11-07 13:36:04 +0000
commit79f193ffa0394301242d25800a715b970c2a0b95 (patch)
treede4b73448fef9191085f873a1e03244a4d93a367 /bitbake/lib
parent330720015aa0974082905eefb3f5fc25309291f5 (diff)
downloadpoky-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.py73
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
129runQueuePrepare = 2 129runQueuePrepare = 2
130runQueueSceneInit = 3 130runQueueSceneInit = 3
131runQueueDumpSigs = 4
131runQueueRunning = 6 132runQueueRunning = 6
132runQueueFailed = 7 133runQueueFailed = 7
133runQueueCleanUp = 8 134runQueueCleanUp = 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):