Skip to content

Cut the main-thread cost of opening and re-rendering a visualisation - #2037

Open
NAThompson wants to merge 1 commit into
silx-kit:mainfrom
NAThompson:perf/first-paint-and-domain-scan
Open

Cut the main-thread cost of opening and re-rendering a visualisation#2037
NAThompson wants to merge 1 commit into
silx-kit:mainfrom
NAThompson:perf/first-paint-and-domain-scan

Conversation

@NAThompson

Copy link
Copy Markdown

Profiling the h5wasm demo on a 2068x2162 uint16 frame put most of the time between clicking a dataset and seeing pixels in avoidable allocation and shader recompilation. Click-to-figure goes from $211$ ms to $102$ ms.

Per-element allocation: getBounds and getBoundsWithErrors walked values with for..of and .entries(), which allocate per element in V8 and JSC -- scanning a 34 MB Float64Array triggered 4037 young-generation collections where an indexed loop triggers 4 ($3.25\times$ in V8, $1.25\times$ in SpiderMonkey, which already elides most of it). The complex visualisations allocated their outputs with Array.from({ length: n }), whose PACKED_ELEMENTS kind boxes every value written in; a Float64Array and indexed iteration take $4.19$M values from $572$ ms to $160$ ms. Both are tested against naive reference implementations, since hand-written expectations would not pin down code written this way.

Shader recompilation: HeatmapMaterial and GlyphMaterial rebuilt their args object every render, and R3F compares it element by element, so each re-render replaced the ShaderMaterial and relinked its GLSL -- $1.9$ ms in Chrome, $4.7$ ms in Firefox. Both now memoize on what actually appears in the shader source and update the rest in place. useWarmUpWebGL moves the first context's $9$ ms of driver setup into idle time.

Profiling the h5wasm demo on a 2068x2162 uint16 frame put most of the time
between clicking a dataset and seeing pixels in avoidable allocation and shader
recompilation. Click-to-figure goes from $211$ ms to $102$ ms.

Per-element allocation: `getBounds` and `getBoundsWithErrors` walked values with
`for..of` and `.entries()`, which allocate per element in V8 and JSC -- scanning
a 34 MB `Float64Array` triggered 4037 young-generation collections where an
indexed loop triggers 4 ($3.25\times$ in V8, $1.25\times$ in SpiderMonkey, which
already elides most of it). The complex visualisations allocated their outputs
with `Array.from({ length: n })`, whose `PACKED_ELEMENTS` kind boxes every value
written in; a `Float64Array` and indexed iteration take $4.19$M values from
$572$ ms to $160$ ms. Both are tested against naive reference implementations,
since hand-written expectations would not pin down code written this way.

Shader recompilation: `HeatmapMaterial` and `GlyphMaterial` rebuilt their `args`
object every render, and R3F compares it element by element, so each re-render
replaced the `ShaderMaterial` and relinked its GLSL -- $1.9$ ms in Chrome,
$4.7$ ms in Firefox. Both now memoize on what actually appears in the shader
source and update the rest in place. `useWarmUpWebGL` moves the first context's
$9$ ms of driver setup into idle time.
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