summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2023-11-28 16:48:33 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2023-12-06 22:28:03 +0000
commit0f4fe4f7630b45228bcbb893f08a86e00109296c (patch)
treeb40f5a538658e030060b62acbb11be7c46d2d567 /bitbake/lib/bb
parent028b6f62263c08097494f72ba43e2febe59b74e8 (diff)
downloadpoky-0f4fe4f7630b45228bcbb893f08a86e00109296c.tar.gz
bitbake: runqueue: Improve inter setscene task dependency handling
The way the code currently handles dependencies between setscene tasks is fairly poor, basically by deleting chunks of dependencies and adding reversed dependency relationships. This was once the best way to handle things but now a lot of the surrounding code has changed and this approach is suboptimal and can be improved. This change firstly adds debug logging for "hard" setscene task dependencies since previously the codepaths were missing from logs making them very hard to read. The changes to the setscene dependency graph are removed entirely this these altered graphs were a significant source of problems. Instead, if a hard dependency is run into, we mark the hard dependency as buildable and defer the task until the hard dependencies are met. The code now also skips the check_dependencies() code for hard dependencies since previously that code was having to list all possible hard dependencies. We don't need to do that as we can safely assume hard dependencies are required. With these changes to runqueue's behaviour, we stand some chance of being able to fix other bugs in OE-Core related to useradd for example. (Bitbake rev: 367789b53c1c22ec26e0f4836cdf2bdd9c7d84fa) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb')
-rw-r--r--bitbake/lib/bb/runqueue.py41
1 files changed, 28 insertions, 13 deletions
diff --git a/bitbake/lib/bb/runqueue.py b/bitbake/lib/bb/runqueue.py
index 02d7ff9768..864708ee4a 100644
--- a/bitbake/lib/bb/runqueue.py
+++ b/bitbake/lib/bb/runqueue.py
@@ -1813,6 +1813,7 @@ class RunQueueExecute:
1813 self.build_stamps2 = [] 1813 self.build_stamps2 = []
1814 self.failed_tids = [] 1814 self.failed_tids = []
1815 self.sq_deferred = {} 1815 self.sq_deferred = {}
1816 self.sq_needed_harddeps = set()
1816 1817
1817 self.stampcache = {} 1818 self.stampcache = {}
1818 1819
@@ -2140,7 +2141,10 @@ class RunQueueExecute:
2140 # Find the next setscene to run 2141 # Find the next setscene to run
2141 for nexttask in self.sorted_setscene_tids: 2142 for nexttask in self.sorted_setscene_tids:
2142 if nexttask in self.sq_buildable and nexttask not in self.sq_running and self.sqdata.stamps[nexttask] not in self.build_stamps.values(): 2143 if nexttask in self.sq_buildable and nexttask not in self.sq_running and self.sqdata.stamps[nexttask] not in self.build_stamps.values():
2143 if nexttask not in self.sqdata.unskippable and self.sqdata.sq_revdeps[nexttask] and self.sqdata.sq_revdeps[nexttask].issubset(self.scenequeue_covered) and self.check_dependencies(nexttask, self.sqdata.sq_revdeps[nexttask]): 2144 if nexttask not in self.sqdata.unskippable and self.sqdata.sq_revdeps[nexttask] and \
2145 nexttask not in self.sq_needed_harddeps and \
2146 self.sqdata.sq_revdeps[nexttask].issubset(self.scenequeue_covered) and \
2147 self.check_dependencies(nexttask, self.sqdata.sq_revdeps[nexttask]):
2144 if nexttask not in self.rqdata.target_tids: 2148 if nexttask not in self.rqdata.target_tids:
2145 logger.debug2("Skipping setscene for task %s" % nexttask) 2149 logger.debug2("Skipping setscene for task %s" % nexttask)
2146 self.sq_task_skip(nexttask) 2150 self.sq_task_skip(nexttask)
@@ -2148,6 +2152,18 @@ class RunQueueExecute:
2148 if nexttask in self.sq_deferred: 2152 if nexttask in self.sq_deferred:
2149 del self.sq_deferred[nexttask] 2153 del self.sq_deferred[nexttask]
2150 return True 2154 return True
2155 if nexttask in self.sqdata.sq_harddeps_rev and not self.sqdata.sq_harddeps_rev[nexttask].issubset(self.scenequeue_covered | self.scenequeue_notcovered):
2156 logger.debug2("Deferring %s due to hard dependencies" % nexttask)
2157 updated = False
2158 for dep in self.sqdata.sq_harddeps_rev[nexttask]:
2159 if dep not in self.sq_needed_harddeps:
2160 logger.debug2("Enabling task %s as it is a hard dependency" % dep)
2161 self.sq_buildable.add(dep)
2162 self.sq_needed_harddeps.add(dep)
2163 updated = True
2164 if updated:
2165 return True
2166 continue
2151 # If covered tasks are running, need to wait for them to complete 2167 # If covered tasks are running, need to wait for them to complete
2152 for t in self.sqdata.sq_covered_tasks[nexttask]: 2168 for t in self.sqdata.sq_covered_tasks[nexttask]:
2153 if t in self.runq_running and t not in self.runq_complete: 2169 if t in self.runq_running and t not in self.runq_complete:
@@ -2596,8 +2612,8 @@ class RunQueueExecute:
2596 update_tasks2 = [] 2612 update_tasks2 = []
2597 for tid in update_tasks: 2613 for tid in update_tasks:
2598 harddepfail = False 2614 harddepfail = False
2599 for t in self.sqdata.sq_harddeps: 2615 for t in self.sqdata.sq_harddeps_rev[tid]:
2600 if tid in self.sqdata.sq_harddeps[t] and t in self.scenequeue_notcovered: 2616 if t in self.scenequeue_notcovered:
2601 harddepfail = True 2617 harddepfail = True
2602 break 2618 break
2603 if not harddepfail and self.sqdata.sq_revdeps[tid].issubset(self.scenequeue_covered | self.scenequeue_notcovered): 2619 if not harddepfail and self.sqdata.sq_revdeps[tid].issubset(self.scenequeue_covered | self.scenequeue_notcovered):
@@ -2629,12 +2645,13 @@ class RunQueueExecute:
2629 2645
2630 if changed: 2646 if changed:
2631 self.stats.updateCovered(len(self.scenequeue_covered), len(self.scenequeue_notcovered)) 2647 self.stats.updateCovered(len(self.scenequeue_covered), len(self.scenequeue_notcovered))
2648 self.sq_needed_harddeps = set()
2632 self.holdoff_need_update = True 2649 self.holdoff_need_update = True
2633 2650
2634 def scenequeue_updatecounters(self, task, fail=False): 2651 def scenequeue_updatecounters(self, task, fail=False):
2635 2652
2636 for dep in sorted(self.sqdata.sq_deps[task]): 2653 if fail and task in self.sqdata.sq_harddeps:
2637 if fail and task in self.sqdata.sq_harddeps and dep in self.sqdata.sq_harddeps[task]: 2654 for dep in sorted(self.sqdata.sq_harddeps[task]):
2638 if dep in self.scenequeue_covered or dep in self.scenequeue_notcovered: 2655 if dep in self.scenequeue_covered or dep in self.scenequeue_notcovered:
2639 # dependency could be already processed, e.g. noexec setscene task 2656 # dependency could be already processed, e.g. noexec setscene task
2640 continue 2657 continue
@@ -2644,6 +2661,7 @@ class RunQueueExecute:
2644 logger.debug2("%s was unavailable and is a hard dependency of %s so skipping" % (task, dep)) 2661 logger.debug2("%s was unavailable and is a hard dependency of %s so skipping" % (task, dep))
2645 self.sq_task_failoutright(dep) 2662 self.sq_task_failoutright(dep)
2646 continue 2663 continue
2664 for dep in sorted(self.sqdata.sq_deps[task]):
2647 if self.sqdata.sq_revdeps[dep].issubset(self.scenequeue_covered | self.scenequeue_notcovered): 2665 if self.sqdata.sq_revdeps[dep].issubset(self.scenequeue_covered | self.scenequeue_notcovered):
2648 if dep not in self.sq_buildable: 2666 if dep not in self.sq_buildable:
2649 self.sq_buildable.add(dep) 2667 self.sq_buildable.add(dep)
@@ -2780,6 +2798,7 @@ class SQData(object):
2780 self.sq_revdeps = {} 2798 self.sq_revdeps = {}
2781 # Injected inter-setscene task dependencies 2799 # Injected inter-setscene task dependencies
2782 self.sq_harddeps = {} 2800 self.sq_harddeps = {}
2801 self.sq_harddeps_rev = {}
2783 # Cache of stamp files so duplicates can't run in parallel 2802 # Cache of stamp files so duplicates can't run in parallel
2784 self.stamps = {} 2803 self.stamps = {}
2785 # Setscene tasks directly depended upon by the build 2804 # Setscene tasks directly depended upon by the build
@@ -2907,6 +2926,7 @@ def build_scenequeue_data(sqdata, rqdata, sqrq):
2907 idepends = rqdata.taskData[mc].taskentries[realtid].idepends 2926 idepends = rqdata.taskData[mc].taskentries[realtid].idepends
2908 sqdata.stamps[tid] = bb.parse.siggen.stampfile_mcfn(taskname, taskfn, extrainfo=False) 2927 sqdata.stamps[tid] = bb.parse.siggen.stampfile_mcfn(taskname, taskfn, extrainfo=False)
2909 2928
2929 sqdata.sq_harddeps_rev[tid] = set()
2910 for (depname, idependtask) in idepends: 2930 for (depname, idependtask) in idepends:
2911 2931
2912 if depname not in rqdata.taskData[mc].build_targets: 2932 if depname not in rqdata.taskData[mc].build_targets:
@@ -2919,20 +2939,15 @@ def build_scenequeue_data(sqdata, rqdata, sqrq):
2919 if deptid not in rqdata.runtaskentries: 2939 if deptid not in rqdata.runtaskentries:
2920 bb.msg.fatal("RunQueue", "Task %s depends upon non-existent task %s:%s" % (realtid, depfn, idependtask)) 2940 bb.msg.fatal("RunQueue", "Task %s depends upon non-existent task %s:%s" % (realtid, depfn, idependtask))
2921 2941
2942 logger.debug2("Adding hard setscene dependency %s for %s" % (deptid, tid))
2943
2922 if not deptid in sqdata.sq_harddeps: 2944 if not deptid in sqdata.sq_harddeps:
2923 sqdata.sq_harddeps[deptid] = set() 2945 sqdata.sq_harddeps[deptid] = set()
2924 sqdata.sq_harddeps[deptid].add(tid) 2946 sqdata.sq_harddeps[deptid].add(tid)
2925 2947 sqdata.sq_harddeps_rev[tid].add(deptid)
2926 sq_revdeps_squash[tid].add(deptid)
2927 # Have to zero this to avoid circular dependencies
2928 sq_revdeps_squash[deptid] = set()
2929 2948
2930 rqdata.init_progress_reporter.next_stage() 2949 rqdata.init_progress_reporter.next_stage()
2931 2950
2932 for task in sqdata.sq_harddeps:
2933 for dep in sqdata.sq_harddeps[task]:
2934 sq_revdeps_squash[dep].add(task)
2935
2936 rqdata.init_progress_reporter.next_stage() 2951 rqdata.init_progress_reporter.next_stage()
2937 2952
2938 #for tid in sq_revdeps_squash: 2953 #for tid in sq_revdeps_squash: