diff options
| author | Richard Purdie <rpurdie@linux.intel.com> | 2009-07-21 19:44:23 +0100 |
|---|---|---|
| committer | Richard Purdie <rpurdie@linux.intel.com> | 2009-07-21 19:44:23 +0100 |
| commit | 8f5363d16de17459b654ca780e5bbd6e04b6bb73 (patch) | |
| tree | 7c8d6bf31d85c65210a9e1b9fe7ab227963970f3 /bitbake-dev/lib/bb/runqueue.py | |
| parent | 133e9e6064195942a95ff58c18a6578de7bcadc7 (diff) | |
| download | poky-8f5363d16de17459b654ca780e5bbd6e04b6bb73.tar.gz | |
bitbake: Optimise runqueue recursive dependency calculations removing a bottleneck in world builds
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
Diffstat (limited to 'bitbake-dev/lib/bb/runqueue.py')
| -rw-r--r-- | bitbake-dev/lib/bb/runqueue.py | 190 |
1 files changed, 75 insertions, 115 deletions
diff --git a/bitbake-dev/lib/bb/runqueue.py b/bitbake-dev/lib/bb/runqueue.py index 4f0996dad6..1be2aa0db2 100644 --- a/bitbake-dev/lib/bb/runqueue.py +++ b/bitbake-dev/lib/bb/runqueue.py | |||
| @@ -340,9 +340,10 @@ class RunQueue: | |||
| 340 | to optimise the execution order. | 340 | to optimise the execution order. |
| 341 | """ | 341 | """ |
| 342 | 342 | ||
| 343 | depends = [] | ||
| 344 | runq_build = [] | 343 | runq_build = [] |
| 345 | recursive_tdepends = {} | 344 | recursive_tdepends = {} |
| 345 | runq_recrdepends = [] | ||
| 346 | tdepends_fnid = {} | ||
| 346 | 347 | ||
| 347 | taskData = self.taskData | 348 | taskData = self.taskData |
| 348 | 349 | ||
| @@ -354,9 +355,9 @@ class RunQueue: | |||
| 354 | 355 | ||
| 355 | # Step A - Work out a list of tasks to run | 356 | # Step A - Work out a list of tasks to run |
| 356 | # | 357 | # |
| 357 | # Taskdata gives us a list of possible providers for a every target | 358 | # Taskdata gives us a list of possible providers for every build and run |
| 358 | # ordered by priority (build_targets, run_targets). It also gives | 359 | # target ordered by priority. It also gives information on each of those |
| 359 | # information on each of those providers. | 360 | # providers. |
| 360 | # | 361 | # |
| 361 | # To create the actual list of tasks to execute we fix the list of | 362 | # To create the actual list of tasks to execute we fix the list of |
| 362 | # providers and then resolve the dependencies into task IDs. This | 363 | # providers and then resolve the dependencies into task IDs. This |
| @@ -364,10 +365,14 @@ class RunQueue: | |||
| 364 | # rdeptast, recrdeptask, idepends). | 365 | # rdeptast, recrdeptask, idepends). |
| 365 | 366 | ||
| 366 | for task in range(len(taskData.tasks_name)): | 367 | for task in range(len(taskData.tasks_name)): |
| 368 | depends = [] | ||
| 369 | recrdepends = [] | ||
| 367 | fnid = taskData.tasks_fnid[task] | 370 | fnid = taskData.tasks_fnid[task] |
| 368 | fn = taskData.fn_index[fnid] | 371 | fn = taskData.fn_index[fnid] |
| 369 | task_deps = self.dataCache.task_deps[fn] | 372 | task_deps = self.dataCache.task_deps[fn] |
| 370 | 373 | ||
| 374 | bb.msg.debug(2, bb.msg.domain.RunQueue, "Processing %s:%s" %(fn, taskData.tasks_name[task])) | ||
| 375 | |||
| 371 | if fnid not in taskData.failed_fnids: | 376 | if fnid not in taskData.failed_fnids: |
| 372 | 377 | ||
| 373 | # Resolve task internal dependencies | 378 | # Resolve task internal dependencies |
| @@ -407,6 +412,8 @@ class RunQueue: | |||
| 407 | # | 412 | # |
| 408 | # e.g. do_sometask[depends] = "targetname:do_someothertask" | 413 | # e.g. do_sometask[depends] = "targetname:do_someothertask" |
| 409 | # (makes sure sometask runs after targetname's someothertask) | 414 | # (makes sure sometask runs after targetname's someothertask) |
| 415 | if fnid not in tdepends_fnid: | ||
| 416 | tdepends_fnid[fnid] = set() | ||
| 410 | idepends = taskData.tasks_idepends[task] | 417 | idepends = taskData.tasks_idepends[task] |
| 411 | for (depid, idependtask) in idepends: | 418 | for (depid, idependtask) in idepends: |
| 412 | if depid in taskData.build_targets: | 419 | if depid in taskData.build_targets: |
| @@ -414,122 +421,37 @@ class RunQueue: | |||
| 414 | depdata = taskData.build_targets[depid][0] | 421 | depdata = taskData.build_targets[depid][0] |
| 415 | if depdata is not None: | 422 | if depdata is not None: |
| 416 | dep = taskData.fn_index[depdata] | 423 | dep = taskData.fn_index[depdata] |
| 417 | depends.append(taskData.gettask_id(dep, idependtask)) | 424 | taskid = taskData.gettask_id(dep, idependtask) |
| 418 | 425 | depends.append(taskid) | |
| 419 | # Create a list of recursive dependent tasks (from tdepends) and cache | 426 | if depdata != fnid: |
| 420 | def get_recursive_tdepends(task): | 427 | tdepends_fnid[fnid].add(taskid) |
| 421 | if not task: | 428 | |
| 422 | return [] | 429 | |
| 423 | if task in recursive_tdepends: | 430 | # Resolve recursive 'recrdeptask' dependencies (A) |
| 424 | return recursive_tdepends[task] | ||
| 425 | |||
| 426 | fnid = taskData.tasks_fnid[task] | ||
| 427 | taskids = taskData.gettask_ids(fnid) | ||
| 428 | |||
| 429 | rectdepends = taskids | ||
| 430 | nextdeps = taskids | ||
| 431 | while len(nextdeps) != 0: | ||
| 432 | newdeps = [] | ||
| 433 | for nextdep in nextdeps: | ||
| 434 | for tdepend in taskData.tasks_tdepends[nextdep]: | ||
| 435 | if tdepend not in rectdepends: | ||
| 436 | rectdepends.append(tdepend) | ||
| 437 | newdeps.append(tdepend) | ||
| 438 | nextdeps = newdeps | ||
| 439 | recursive_tdepends[task] = rectdepends | ||
| 440 | return rectdepends | ||
| 441 | |||
| 442 | # Using the list of tdepends for this task create a list of | ||
| 443 | # the recursive idepends we have | ||
| 444 | def get_recursive_idepends(task): | ||
| 445 | if not task: | ||
| 446 | return [] | ||
| 447 | rectdepends = get_recursive_tdepends(task) | ||
| 448 | |||
| 449 | recidepends = [] | ||
| 450 | for tdepend in rectdepends: | ||
| 451 | for idepend in taskData.tasks_idepends[tdepend]: | ||
| 452 | recidepends.append(idepend) | ||
| 453 | return recidepends | ||
| 454 | |||
| 455 | def add_recursive_build(depid, depfnid): | ||
| 456 | """ | ||
| 457 | Add build depends of depid to depends | ||
| 458 | (if we've not see it before) | ||
| 459 | (calls itself recursively) | ||
| 460 | """ | ||
| 461 | if str(depid) in dep_seen: | ||
| 462 | return | ||
| 463 | dep_seen.append(depid) | ||
| 464 | if depid in taskData.build_targets: | ||
| 465 | depdata = taskData.build_targets[depid][0] | ||
| 466 | if depdata is not None: | ||
| 467 | dep = taskData.fn_index[depdata] | ||
| 468 | # Need to avoid creating new tasks here | ||
| 469 | taskid = taskData.gettask_id(dep, taskname, False) | ||
| 470 | if taskid is not None: | ||
| 471 | depends.append(taskid) | ||
| 472 | fnid = taskData.tasks_fnid[taskid] | ||
| 473 | #print "Added %s (%s) due to %s" % (taskid, taskData.fn_index[fnid], taskData.fn_index[depfnid]) | ||
| 474 | else: | ||
| 475 | fnid = taskData.getfn_id(dep) | ||
| 476 | for nextdepid in taskData.depids[fnid]: | ||
| 477 | if nextdepid not in dep_seen: | ||
| 478 | add_recursive_build(nextdepid, fnid) | ||
| 479 | for nextdepid in taskData.rdepids[fnid]: | ||
| 480 | if nextdepid not in rdep_seen: | ||
| 481 | add_recursive_run(nextdepid, fnid) | ||
| 482 | for (idependid, idependtask) in get_recursive_idepends(taskid): | ||
| 483 | if idependid not in dep_seen: | ||
| 484 | add_recursive_build(idependid, fnid) | ||
| 485 | |||
| 486 | def add_recursive_run(rdepid, depfnid): | ||
| 487 | """ | ||
| 488 | Add runtime depends of rdepid to depends | ||
| 489 | (if we've not see it before) | ||
| 490 | (calls itself recursively) | ||
| 491 | """ | ||
| 492 | if str(rdepid) in rdep_seen: | ||
| 493 | return | ||
| 494 | rdep_seen.append(rdepid) | ||
| 495 | if rdepid in taskData.run_targets: | ||
| 496 | depdata = taskData.run_targets[rdepid][0] | ||
| 497 | if depdata is not None: | ||
| 498 | dep = taskData.fn_index[depdata] | ||
| 499 | # Need to avoid creating new tasks here | ||
| 500 | taskid = taskData.gettask_id(dep, taskname, False) | ||
| 501 | if taskid is not None: | ||
| 502 | depends.append(taskid) | ||
| 503 | fnid = taskData.tasks_fnid[taskid] | ||
| 504 | #print "Added %s (%s) due to %s" % (taskid, taskData.fn_index[fnid], taskData.fn_index[depfnid]) | ||
| 505 | else: | ||
| 506 | fnid = taskData.getfn_id(dep) | ||
| 507 | for nextdepid in taskData.depids[fnid]: | ||
| 508 | if nextdepid not in dep_seen: | ||
| 509 | add_recursive_build(nextdepid, fnid) | ||
| 510 | for nextdepid in taskData.rdepids[fnid]: | ||
| 511 | if nextdepid not in rdep_seen: | ||
| 512 | add_recursive_run(nextdepid, fnid) | ||
| 513 | for (idependid, idependtask) in get_recursive_idepends(taskid): | ||
| 514 | if idependid not in dep_seen: | ||
| 515 | add_recursive_build(idependid, fnid) | ||
| 516 | |||
| 517 | # Resolve recursive 'recrdeptask' dependencies | ||
| 518 | # | 431 | # |
| 519 | # e.g. do_sometask[recrdeptask] = "do_someothertask" | 432 | # e.g. do_sometask[recrdeptask] = "do_someothertask" |
| 520 | # (makes sure sometask runs after someothertask of all DEPENDS, RDEPENDS and intertask dependencies, recursively) | 433 | # (makes sure sometask runs after someothertask of all DEPENDS, RDEPENDS and intertask dependencies, recursively) |
| 434 | # We cover the recursive part of the dependencies below | ||
| 521 | if 'recrdeptask' in task_deps and taskData.tasks_name[task] in task_deps['recrdeptask']: | 435 | if 'recrdeptask' in task_deps and taskData.tasks_name[task] in task_deps['recrdeptask']: |
| 522 | for taskname in task_deps['recrdeptask'][taskData.tasks_name[task]].split(): | 436 | for taskname in task_deps['recrdeptask'][taskData.tasks_name[task]].split(): |
| 523 | dep_seen = [] | 437 | recrdepends.append(taskname) |
| 524 | rdep_seen = [] | 438 | for depid in taskData.rdepids[fnid]: |
| 525 | idep_seen = [] | 439 | if depid in taskData.run_targets: |
| 440 | depdata = taskData.run_targets[depid][0] | ||
| 441 | if depdata is not None: | ||
| 442 | dep = taskData.fn_index[depdata] | ||
| 443 | taskid = taskData.gettask_id(dep, taskname, False) | ||
| 444 | if taskid is not None: | ||
| 445 | depends.append(taskid) | ||
| 526 | for depid in taskData.depids[fnid]: | 446 | for depid in taskData.depids[fnid]: |
| 527 | add_recursive_build(depid, fnid) | 447 | # Won't be in build_targets if ASSUME_PROVIDED |
| 528 | for rdepid in taskData.rdepids[fnid]: | 448 | if depid in taskData.build_targets: |
| 529 | add_recursive_run(rdepid, fnid) | 449 | depdata = taskData.build_targets[depid][0] |
| 530 | deptaskid = taskData.gettask_id(fn, taskname, False) | 450 | if depdata is not None: |
| 531 | for (idependid, idependtask) in get_recursive_idepends(deptaskid): | 451 | dep = taskData.fn_index[depdata] |
| 532 | add_recursive_build(idependid, fnid) | 452 | taskid = taskData.gettask_id(dep, taskname, False) |
| 453 | if taskid is not None: | ||
| 454 | depends.append(taskid) | ||
| 533 | 455 | ||
| 534 | # Rmove all self references | 456 | # Rmove all self references |
| 535 | if task in depends: | 457 | if task in depends: |
| @@ -540,13 +462,51 @@ class RunQueue: | |||
| 540 | newdep.append(dep) | 462 | newdep.append(dep) |
| 541 | depends = newdep | 463 | depends = newdep |
| 542 | 464 | ||
| 543 | |||
| 544 | self.runq_fnid.append(taskData.tasks_fnid[task]) | 465 | self.runq_fnid.append(taskData.tasks_fnid[task]) |
| 545 | self.runq_task.append(taskData.tasks_name[task]) | 466 | self.runq_task.append(taskData.tasks_name[task]) |
| 546 | self.runq_depends.append(set(depends)) | 467 | self.runq_depends.append(set(depends)) |
| 547 | self.runq_revdeps.append(set()) | 468 | self.runq_revdeps.append(set()) |
| 548 | 469 | ||
| 549 | runq_build.append(0) | 470 | runq_build.append(0) |
| 471 | runq_recrdepends.append(recrdepends) | ||
| 472 | |||
| 473 | # | ||
| 474 | # Build a list of recursive cumulative dependencies for each fnid | ||
| 475 | # We do this by fnid, since if A depends on some task in B | ||
| 476 | # we're interested in later tasks B's fnid might have but B itself | ||
| 477 | # doesn't depend on | ||
| 478 | # | ||
| 479 | # Algorithm is O(tasks) + O(tasks)*O(fnids) | ||
| 480 | # | ||
| 481 | reccumdepends = {} | ||
| 482 | for task in range(len(self.runq_fnid)): | ||
| 483 | fnid = self.runq_fnid[task] | ||
| 484 | if fnid not in reccumdepends: | ||
| 485 | reccumdepends[fnid] = set() | ||
| 486 | if task in self.runq_depends: | ||
| 487 | reccumdepends[fnid].update(self.runq_depends[task]) | ||
| 488 | if fnid in tdepends_fnid: | ||
| 489 | reccumdepends[fnid].update(tdepends_fnid[fnid]) | ||
| 490 | for task in range(len(self.runq_fnid)): | ||
| 491 | taskfnid = self.runq_fnid[task] | ||
| 492 | for fnid in reccumdepends: | ||
| 493 | if task in reccumdepends[fnid]: | ||
| 494 | reccumdepends[fnid].add(task) | ||
| 495 | if taskfnid in reccumdepends: | ||
| 496 | reccumdepends[fnid].update(reccumdepends[taskfnid]) | ||
| 497 | |||
| 498 | |||
| 499 | # Resolve recursive 'recrdeptask' dependencies (B) | ||
| 500 | # | ||
| 501 | # e.g. do_sometask[recrdeptask] = "do_someothertask" | ||
| 502 | # (makes sure sometask runs after someothertask of all DEPENDS, RDEPENDS and intertask dependencies, recursively) | ||
| 503 | for task in range(len(self.runq_fnid)): | ||
| 504 | if len(runq_recrdepends[task]) > 0: | ||
| 505 | taskfnid = self.runq_fnid[task] | ||
| 506 | for dep in reccumdepends[taskfnid]: | ||
| 507 | for taskname in runq_recrdepends[task]: | ||
| 508 | if taskData.tasks_name[dep] == taskname: | ||
| 509 | self.runq_depends[task].add(dep) | ||
| 550 | 510 | ||
| 551 | # Step B - Mark all active tasks | 511 | # Step B - Mark all active tasks |
| 552 | # | 512 | # |
