Skip to content

perf(coderd): build the workspace build fan-out maps once per batch - #28074

Draft
jscottmiller wants to merge 1 commit into
mainfrom
scott/plat-386-workspace-build-fanout
Draft

perf(coderd): build the workspace build fan-out maps once per batch#28074
jscottmiller wants to merge 1 commit into
mainfrom
scott/plat-386-workspace-build-fanout

Conversation

@jscottmiller

Copy link
Copy Markdown
Contributor

convertWorkspaceBuild rebuilt seven maps from the caller's global slices on every call and rescanned the provisioner daemon rows to filter by job ID. convertWorkspaceBuilds calls it once per build with identical slices, so map construction cost O(builds x rows) where O(rows) suffices — quadratic in the number of workspaces on GET /api/v2/workspaces.

The maps move into a workspaceBuildIndex built once per batch, keyed exactly as before and now including daemons by job ID. convertWorkspaceBuild takes the index instead of eight slices. Its parent already hoisted workspaceByID, jobByID, and templateVersionByID out of the same loop; this makes the rest consistent.

Agents are sorted while the index is built, so a resource read by several builds is sorted once rather than once per build. Same comparator over the same rows, so the order is unchanged; TestConvertWorkspaceBuildsAgentOrder covers it.

BenchmarkConvertWorkspaceBuilds, 5 resources x 2 agents x 4 apps per build:

builds ns/op B/op allocs/op
1 48.3k -> 48.1k 121k -> 125k 342 -> 359
25 12.7M -> 1.34M 38.0MB -> 3.2MB 69,621 -> 8,347
100 186M -> 5.67M 596MB -> 13.0MB 1,024,941 -> 33,080

Single-build conversion is a wash (one extra struct allocation); the quadratic term is gone.

Addresses the map-allocation half of PLAT-386 / #27205. Bounding the page size is separate (#28040) and does not remove this cost: at 100 workspaces per page it is still 100 passes over every resource, agent, app, script, log source, status, and daemon row in the page.


Created with Coder Agents on behalf of @jscottmiller.

convertWorkspaceBuild rebuilt seven maps from the caller's global slices
on every call and rescanned the provisioner daemon rows, so
convertWorkspaceBuilds paid that cost once per build over the same rows.

The maps move into a workspaceBuildIndex built once per batch, keyed as
before and now including daemons by job ID. Agents are sorted while the
index is built, so a resource read by several builds is sorted once
rather than once per build; the comparison and the rows are unchanged, so
the order is the same.
@linear-code

linear-code Bot commented Aug 12, 2026

Copy link
Copy Markdown

PLAT-386

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.

1 participant