Skip to content

Perf/decision task - #1050

Draft
marco-c wants to merge 3 commits into
taskcluster:mainfrom
marco-c:perf/decision-task
Draft

marco-c wants to merge 3 commits into
taskcluster:mainfrom
marco-c:perf/decision-task

Conversation

@marco-c

@marco-c marco-c commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

I haven't yet reviewed all the commits, I'll probably drop some of them, but I want to see if codspeed picks anything up.

@codspeed

codspeed Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 30 untouched benchmarks
🆕 2 new benchmarks

Performance Changes

Benchmark BASE HEAD Efficiency
🆕 test_create_tasks[btree] N/A 3.8 s N/A
🆕 test_create_tasks[fan] N/A 4 s N/A

Comparing marco-c:perf/decision-task (7c4a13b) with main (77cbc3b)

Open in CodSpeed

@sylvestre

Copy link
Copy Markdown

wahou

@marco-c

marco-c commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

@codspeedbot run the new benchmarks against the base of pr, and display the performance changes with the head of the PR, with the link to the corresponding CodSpeed compare runs page

1 similar comment
@marco-c

marco-c commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

@codspeedbot run the new benchmarks against the base of pr, and display the performance changes with the head of the PR, with the link to the corresponding CodSpeed compare runs page

@codspeed

codspeed Bot commented Sep 24, 2026

Copy link
Copy Markdown

@codspeedbot run the new benchmarks against the base of pr, and display the performance changes with the head of the PR, with the link to the corresponding CodSpeed compare runs page

Only members of the taskcluster organization on CodSpeed can ask the performance wizard for help here. Once you've joined it on CodSpeed, comment again.

@JohanLorenzo

Copy link
Copy Markdown
Contributor

@codspeedbot run the new benchmarks against the base of pr, and display the performance changes with the head of the PR, with the link to the corresponding CodSpeed compare runs page

@codspeed

codspeed Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

@codspeedbot run the new benchmarks against the base of pr, and display the performance changes with the head of the PR, with the link to the corresponding CodSpeed compare runs page

I ran the PR's benchmark suite (test/test_graph_perf.py) on the PR base (064375f) and then on the PR head (55031b8). Both runs used CPU simulation mode in the same environment. On the base run I used the PR's version of test_graph_perf.py, minus the two graph._visit_order.cache_clear() lines, because _visit_order only exists on the head.

Compare runs page: https://app.codspeed.io/taskcluster/taskgraph/compare/6ab631c04cedfe38851b4dfa..6ab6348ca84b5010809f92e6
(base run: 6ab631c0, head run: 6ab6348c)

New benchmarks (base → head)

Benchmark BASE (064375f) HEAD (55031b8) Change
⚡ test_create_tasks[btree] 12.6 s 1.9 s ×6.7
⚡ test_create_tasks[fan] 12.6 s 2.1 s ×6.1
⚡ test_resolve_timestamps 2.61 s 2.08 s +25.6%
test_resolve_task_references 2.11 s 1.84 s ~+15% (CodSpeed counts this as unchanged)

Existing benchmarks, same pair of runs

Benchmark BASE HEAD Change
⚡ test_for_each_task[diamond] 1,213 ms 28.1 ms ×43
⚡ test_for_each_task[fan] 91.4 ms 28.1 ms ×3.2
⚡ test_for_each_task[btree] 75.3 ms 28.1 ms ×2.7
⚡ test_for_each_task[linear] 75.3 ms 28.2 ms ×2.7
⚡ test_taskgraph_to_json[fan] 136.5 ms 73.6 ms +85.5%
⚡ test_taskgraph_to_json[btree] 122.0 ms 73.3 ms +66.5%
⚡ test_taskgraph_to_json[linear] 121.2 ms 73.4 ms +65.2%

The other 17 benchmarks (links_dict, transitive_closure, visit_*order, transform_sequence) didn't change.

How to read these numbers

  • These runs were in the CodSpeed sandbox, not CI. Absolute values are lower than in the PR report. For example, test_for_each_task[diamond] is 1.2 s here and 2.5 s in CI. Compare base and head within one table, not against the PR report. The ratios match what CI reported for the benchmarks both sets have.
  • test_create_tasks spends most of its time in syscalls. Most of that is thread-pool waiting: about 11,000–12,600 s of system time on base, 2,000–2,700 s on head. Simulation mode leaves syscalls out of the measured value, so the ×6–7 figure covers CPU work only and understates the real cost on both sides. The system-time numbers point the same way: the head waits much less.
  • The environment-difference warning on the compare page doesn't matter here. It comes from the two virtualenvs sitting at different paths. The libraries have identical build IDs.

I didn't change anything on the PR branch.

Summary
  • Warming up the performance wizard...
  • Inspect the new benchmarks and CI setup — Copied the PR's test/test_graph_perf.py onto the base commit (without the _visit_order.cache_clear() calls, which only exist on the PR head)
  • Run the new benchmarks on the PR base (064375f) — Run 6ab631c04cedfe38851b4dfa
  • Run the benchmarks on the PR head (55031b8) — Run 6ab6348ca84b5010809f92e6
  • Compare runs and report — Compare runs and report
  • Handling comment — Comment handling finished successfully

Was this response helpful? React with 👍 or 👎 to help us improve CodSpeedBot.

@adriencaccia

Copy link
Copy Markdown

Hey @marco-c, @JohanLorenzo, the correct compare page URL is: https://app.codspeed.io/taskcluster/taskgraph/runs/compare/6ab631c04cedfe38851b4dfa..6ab6348ca84b5010809f92e6
We will deploy a fix to ensure that the agent will get it right.

create_tasks rescanned every not yet submitted task each time a
createTask call completed, rebuilding its set of dependencies and
checking whether their futures were done. This is quadratic in the
number of tasks, and runs on the main thread while holding the GIL. It
also recursed once per completed batch, so a dependency chain of a few
thousand tasks raised RecursionError.

Now the number of pending dependencies of each task is computed once,
and decremented as dependencies are created. A task is submitted as soon
as its count drops to zero. As before, tasks depending on a task that
failed to be created are not submitted.

With createTask mocked out, creating a 20,000 task graph takes 1.9s
instead of 6.2s (binary tree) and 2.0s instead of 4.6s (fan-out/fan-in).
To decide whether a task can be replaced, replace_tasks computes the
latest deadline of its dependents. It resolved the deadline of every
dependent for every task, although tasks such as docker images or
toolchains share thousands of dependents. Now each task's deadline is
resolved at most once, relative to a single `now`.

Similarly, IndexSearch parsed the same deadline (and the expiration of
tasks used as replacement for multiple tasks) over and over, so parsed
timestamps are now cached.

On a synthetic graph of 20,210 tasks where the 210 build and docker
tasks are replaced, replace_tasks takes 0.17s instead of 0.24s.
Before loading a kind, the generator filtered all the tasks loaded so
far to find the ones belonging to the kind's dependencies (copying them
first when loading kinds in parallel). This is proportional to the
number of kinds times the number of tasks, and in parallel mode it
happens on the main thread, delaying the submission of newly unblocked
kinds.

Now loaded tasks are also grouped by kind, so the tasks of each kind
dependency are looked up directly. They are still passed in the order in
which kinds were loaded.

With 150 kinds of 270 tasks each (40,500 tasks), each depending on three
other kinds, gathering the kind dependency tasks takes 0.01s in total
instead of 0.42s.
@marco-c
marco-c force-pushed the perf/decision-task branch from 55031b8 to 7c4a13b Compare October 5, 2026 10:17

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants