Minimal perf marks (CPU vs submit split)
Minimal Perf Marks
Code
perf.min.html
// Smallest demonstration of the renderer's CPU vs GPU-submit split.
// Marks are runtime-gated via setPerfMarksEnabled — they are
// available in any build.
import NiiVue from '@niivue/niivue'
import { setPerfMarksEnabled } from '../src/view/NVPerfMarks.ts'
const FRAMES = 100
const WARMUP = 20
const nv = new NiiVue({ isColorbarVisible: false })
await nv.attachToCanvas(gl1)
await nv.loadVolumes([{ url: '/volumes/mni152.nii.gz' }])
const median = (xs) => {
const s = [...xs].sort((a, b) => a - b)
return s.length ? s[Math.floor(s.length / 2)] : null
}
const fmt = (n) => (n == null ? '—' : `${n.toFixed(2)} ms`)
runBtn.onclick = async () => {
runBtn.disabled = true
statusEl.textContent = 'Measuring...'
// The renderer emits three named `performance.measure` entries per
// render() call: render-cpu, render-submit, render-frame. We only
// need the first two — wall time we can take ourselves.
const cpu = []
const submit = []
const observer = new PerformanceObserver((list) => {
for (const e of list.getEntries()) {
if (e.name === 'niivue:render-cpu') cpu.push(e.duration)
else if (e.name === 'niivue:render-submit') submit.push(e.duration)
}
})
observer.observe({ entryTypes: ['measure'] })
setPerfMarksEnabled(true)
for (let i = 0; i < WARMUP; i++) nv.view.render()
// Drop warmup samples.
observer.takeRecords()
cpu.length = 0
submit.length = 0
const wall = new Float64Array(FRAMES)
for (let i = 0; i < FRAMES; i++) {
const t = performance.now()
nv.view.render()
wall[i] = performance.now() - t
}
// Let the observer drain any pending entries.
await new Promise((r) => setTimeout(r, 0))
setPerfMarksEnabled(false)
observer.disconnect()
const wallMed = median(wall)
const fps = wallMed ? 1000 / wallMed : null
out.textContent = [
`frames: ${FRAMES}`,
`wall median: ${fmt(wallMed)} (~${fps == null ? '—' : fps.toFixed(1)} fps)`,
`cpu median: ${fmt(median(cpu))}`,
`submit median: ${fmt(median(submit))}`,
].join('\n')
statusEl.textContent = 'Done.'
runBtn.disabled = false
}