Skip to content

Speed up the plotting UI - #21

Merged
winitzki merged 2 commits into
mainfrom
lazy-plots
Sep 30, 2026
Merged

winitzki merged 2 commits into
mainfrom
lazy-plots

Conversation

@winitzki

@winitzki winitzki commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

This PR will generally make the perf.brossa.io much more responsive.

  • Fix a bug where the standard deviations weren't shown correctly
  • All plots are now drawn lazily, as the user scrolls towards them (not all plots up front)
  • The Y axis setting will change the plots quickly, avoiding full redraw
  • All commit data is loaded in a single DB query rather than via multiple queries
  • Commits are loaded on demand rather than up front

Plots are drawn as they scroll into view, and the controls redraw only on-screen charts. The Y-axis toggle now changes only the axis setting instead of rebuilding the chart. The branch page embeds just the default master window (20 on master, 3 on branches) and fetches more from the new /master-series endpoint. materializeCommits uses two joined queries instead of one query per commit, benchmark and test. Error bars now line up with their own commits.

@chrisdone-artificial chrisdone-artificial left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I tested it locally and saw indeed a 50x speed up. Nice! 👏

main:

chris@linux:~/Work/artificialio/perfly$ time curl http://localhost:3000/branch/master -D/dev/stdout -o/dev/null

real	0m5.386s
user	0m0.003s
sys	0m0.003s

lazy-plots:

chris@linux:~/Work/artificialio/perfly$ time curl http://localhost:3000/branch/master -D/dev/stdout -o/dev/null

real	0m0.113s
user	0m0.004s
sys	0m0.004s

I had some feedback that you could maybe use Esqueleto to do these joins completely in the typed DSL and ran in SQLite, if you have time and are curious to do so.

Comment thread src/Perf/DB/Materialize.hs Outdated
let commitIds = map (.entityVal.mapBranchCommitCommitId) mappings
commits <- selectList [DB.CommitId <-. commitIds] []
let commitsById = Map.fromList [(entityKey commit, commit) | commit <- commits]
pure $ reverse $ mapMaybe (`Map.lookup` commitsById) commitIds

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also be Esqueleto.

Set.union
[ (testId, Set.singleton (Prim.GeneralFactor name value))
| (Single testId, Single name, Single value) <- factorRows
]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're dropping down to raw SQL to be able to express joins, under the hypothesis that it's faster, I think you could use Esqueleto for this, which is available as a drop-in DSL ontop of persistent, rather than the raw SQL construction.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll see if the esqueleto code is easier to read.

@winitzki
winitzki merged commit e127beb into main Sep 30, 2026
1 check passed
@winitzki
winitzki deleted the lazy-plots branch September 30, 2026 11:47

@chrisdone-artificial chrisdone-artificial left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, Esqueleto looks more controlled. 👌

orderBy [desc (mapping ^. DB.MapBranchCommitId)]
limit (fromIntegral maxCommits)
pure commit
pure (reverse commits)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, this is more DSL-y but it's clear where all the work is happening.

@chrisdone-artificial chrisdone-artificial Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW you can also just use a cartesian product for a slightly more readable go (SQLite's planner optimizes them to the same thing):

# main
portal_MjhkNzFlNWE1MThiMWM0O
# (0) time curl -s -o /dev/null http://localhost:3000/branch/master
# Started: 2026-09-30 16:37:44, exited: 2026-09-30 16:37:44 => 128.000 ms

# cartesian product
portal_MDM2OGE2ZTNjMTJiMDU2M
# (0) curl -s -o /dev/null http://localhost:3000/branch/master
# Started: 2026-09-30 16:36:38, exited: 2026-09-30 16:36:38 => 128.000 ms
   commits <- select $ do
-    (branch :& mapping :& commit) <-
-      from $
-        table @DB.Branch
-          `innerJoin` table @DB.MapBranchCommit
-            `on` ( \(branch :& mapping) ->
-                     branch ^. DB.BranchId ==. mapping ^. DB.MapBranchCommitBranchId
-                 )
-          `innerJoin` table @DB.Commit
-            `on` ( \(_branch :& mapping :& commit) ->
-                     mapping ^. DB.MapBranchCommitCommitId ==. commit ^. DB.CommitId
-                 )
-    where_ $ branch ^. DB.BranchName ==. val branchName
+    branch <- from $ table @DB.Branch
+    mapping <- from $ table @DB.MapBranchCommit
+    commit <- from $ table @DB.Commit
+    where_ $ mapping ^. DB.MapBranchCommitBranchId ==. branch ^. DB.BranchId &&.
+             mapping ^. DB.MapBranchCommitCommitId ==. commit ^. DB.CommitId &&.
+             branch ^. DB.BranchName ==. val branchName
     orderBy [desc (mapping ^. DB.MapBranchCommitId)]

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.

2 participants