Skip to content

Benchmarks

Measured on each release. Micro-Manager first (what a user of the adapter sees), then the command-line renderer.

Micro-Manager live (MMCore)

The adapter as Micro-Manager drives it: the shipped inSiliScope_Basic.cfg at 256 x 256 px, every Channel preset, a continuous sequence acquisition (Micro-Manager's live view) per exposure, its steady rate (0.5 s after its first frame; a dSTORM preset after 30 s of acquisition, once its initial-ON dyes have switched off), measured through pymmcore-plus by tools/bench_live.py --profile on the release workflow's Windows runner (4 CPUs; renderer: CPU (only a software adapter is available (Microsoft Basic Render Driver))). Without a usable GPU every frame renders on the CPU; a desktop GPU makes DNA-PAINT faster. The phase times come from the adapter itself (Simulation/Timing.h, Camera Test_ProfileWriteTo).

Frames per second, by version

At 10 ms exposure (at most 100 fps).

version date AF647 dSTORM ATTO655 DNA-PAINT BrightField mEGFP WideField mEos3.2 PALM first image (ms)
v0.1.0-rc16 2026-10-29 89.8 81.3 100.1 100.0 91.5 3139
v0.1.0-rc15 2026-10-29 0.0 74.3 100.0 97.9 89.6 4387
v0.1.0-rc14 2026-10-23 0.0 70.9 100.0 97.0 92.6 3188
v0.1.0-rc13 2026-10-22 0.0 74.3 100.0 39.6 89.8 4048
v0.1.0-rc11 2026-10-21 0.0 75.4 100.0 100.2 90.6 3108
v0.1.0-rc10 2026-10-20 0.0 72.5 100.0 43.4 91.8 4192
v0.1.0-rc9 2026-10-17 0.0 13.4 100.1 96.5 89.3 4591
v0.1.0-rc8 2026-10-12 82.6 65.3 100.0 99.4 84.4 2872
v0.1.0-rc7 2026-10-10 68.3 85.9 100.0 100.5 88.4 1127

Latest release (v0.1.0-rc16): frame rate and render time

fps achieved / the exposure's maximum; render = the producer's time per frame (ms); gap = the longest interval between two frames (ms).

Channel 5 ms 10 ms 20 ms 50 ms
AF647 dSTORM 128.4 / 200, render 1.0, gap 33 89.8 / 100, render 0.5, gap 60 50.0 / 50, render 0.7, gap 48 19.9 / 20, render 0.7, gap 66
ATTO655 DNA-PAINT 82.8 / 200, render 0.1, gap 42 81.3 / 100, render 0.2, gap 34 48.2 / 50, render 0.2, gap 38 20.0 / 20, render 0.1, gap 58
BrightField 200.0 / 200, render 1.8, gap 6 100.1 / 100, render 2.0, gap 11 50.0 / 50, render 2.1, gap 21 20.0 / 20, render 2.2, gap 51
mEGFP WideField 180.4 / 200, render 0.1, gap 22 100.0 / 100, render 0.4, gap 19 49.1 / 50, render 0.2, gap 34 20.0 / 20, render 0.2, gap 51
mEos3.2 PALM 174.7 / 200, render 0.1, gap 36 91.5 / 100, render 0.1, gap 34 49.5 / 50, render 0.2, gap 53 20.0 / 20, render 0.2, gap 89

Where a live frame's time goes

Time per published frame on the producer thread, at the exposure above, by phase (frames from the render-ahead queue were rendered by its helper thread meanwhile, ahead.batch):

live.state read settings, pose, drift live.ahead-wait wait for a render-ahead batch live.spec+clock build the scene spec, illumination clocks live.begin movie setup (light path, kernels, dye queries) live.render render the photons (splat / GPU) live.lamp BrightField image live.noise camera noise live.publish hand the frame to the camera

AF647 dSTORM
0.8 ms, 89.8 fps
ATTO655 DNA-PAINT
0.5 ms, 81.3 fps
BrightField
1.9 ms, 100.1 fps
mEGFP WideField
0.6 ms, 100.0 fps
mEos3.2 PALM
0.2 ms, 91.5 fps
AF647 dSTORM, 10 ms: every phase
phase what per frame (ms) longest (ms) count
ahead.batch render-ahead helper: one batch of frames (setup, render, noise) 116.42 138.03 9
fl.total 116.33 137.94 9
ahead.cpu.render+noise render-ahead helper: the batch's frames on the CPU 106.60 128.39 9
fl.frame.blinks (batches) splat the blinks, or bin them (binned FFT) in dense frames (CPU) 80.56 102.71 9
fl.frame.onFrame 23.11 26.45 9
mm.wait-frame (sequence) sequence thread: waiting for a fresh frame 11.11 42.50 135
live.idle producer: waiting for the next exposure slot 10.19 42.22 136
fl.setup movie setup total 9.80 10.18 8
fl.events-query blink events of the frame from the core 3.82 3.85 8
fl.dye-counts count the dyes of continuous populations 3.52 3.73 8
fl.frame.continuous add the continuous populations 2.83 2.93 9
fl.windows per-dye emission windows 1.91 2.05 8
fl.windows-query the windows still open, from the core (each dye on its own clock) 1.91 2.05 8
fl.survey the populations' survival over the map (the mean-field switch) 1.56 2.89 16
live.frame producer: one frame from reading the state to publishing it (the render time) 0.84 23.91 136
live.state read settings, pose, drift 0.52 23.70 136
live.publish hand the frame to the camera 0.31 22.35 136
mm.frame-age age of a frame when taken (publish -> take) 0.29 22.44 135
fl.make-setup camera, light path, labels 0.24 0.28 8
live.ahead-submit producer: hand the next batch to the render-ahead helper 0.11 0.12 8
fl.events-sort group and bucket the events 0.11 0.13 8
fl.psf-kernels PSF kernels (memo hit, or computed) 0.07 0.08 8
fl.clock-map the light history's clock map over the query (each dye's clock at its own place; core ABI 14) 0.05 0.07 8
mm.insert-image MMCore InsertImage (circular buffer) 0.04 0.14 135
mm.copy+history copy into the camera buffer, add its light to the illumination history 0.01 0.07 135
ATTO655 DNA-PAINT, 10 ms: every phase
phase what per frame (ms) longest (ms) count
ahead.batch render-ahead helper: one batch of frames (setup, render, noise) 162.80 201.32 8
fl.total 162.55 201.11 8
ahead.cpu.render+noise render-ahead helper: the batch's frames on the CPU 157.40 197.75 8
fl.frame.blinks (batches) splat the blinks, or bin them (binned FFT) in dense frames (CPU) 130.29 170.82 8
fl.frame.onFrame 26.87 27.61 8
mm.wait-frame (sequence) sequence thread: waiting for a fresh frame 12.21 33.76 122
live.idle producer: waiting for the next exposure slot 11.27 33.07 126
fl.setup movie setup total 3.68 4.04 8
fl.events-query blink events of the frame from the core 3.06 3.39 8
live.frame producer: one frame from reading the state to publishing it (the render time) 0.54 22.06 127
live.state read settings, pose, drift 0.43 21.61 127
fl.make-setup camera, light path, labels 0.23 0.25 8
mm.frame-age age of a frame when taken (publish -> take) 0.19 3.36 122
fl.events-sort group and bucket the events 0.18 0.21 8
live.ahead-submit producer: hand the next batch to the render-ahead helper 0.13 0.18 8
fl.psf-kernels PSF kernels (memo hit, or computed) 0.12 0.32 8
live.publish hand the frame to the camera 0.08 1.64 127
mm.insert-image MMCore InsertImage (circular buffer) 0.06 0.22 122
fl.clock-map the light history's clock map over the query (each dye's clock at its own place; core ABI 14) 0.05 0.05 8
live.ahead-wait wait for a render-ahead batch 0.04 1.57 110
mm.copy+history copy into the camera buffer, add its light to the illumination history 0.01 0.02 122
BrightField, 10 ms: every phase
phase what per frame (ms) longest (ms) count
mm.wait-frame (sequence) sequence thread: waiting for a fresh frame 9.95 10.72 150
live.idle producer: waiting for the next exposure slot 8.09 8.44 150
live.frame producer: one frame from reading the state to publishing it (the render time) 1.87 2.64 150
live.noise camera noise 1.70 2.44 150
live.lamp BrightField image 0.09 0.15 150
live.state read settings, pose, drift 0.07 0.15 150
mm.frame-age age of a frame when taken (publish -> take) 0.07 0.11 150
mm.insert-image MMCore InsertImage (circular buffer) 0.03 0.11 150
live.publish hand the frame to the camera 0.01 0.02 150
mEGFP WideField, 10 ms: every phase
phase what per frame (ms) longest (ms) count
ahead.batch render-ahead helper: one batch of frames (setup, render, noise) 82.63 105.14 9
fl.total 82.55 105.05 9
ahead.cpu.render+noise render-ahead helper: the batch's frames on the CPU 42.38 50.70 9
fl.setup movie setup total 40.21 54.39 9
fl.frame.onFrame 25.31 25.89 9
fl.dye-counts count the dyes of continuous populations 21.99 29.09 9
fl.frame.continuous add the continuous populations 16.67 24.65 9
mm.wait-frame (sequence) sequence thread: waiting for a fresh frame 9.95 18.64 150
fl.survey the populations' survival over the map (the mean-field switch) 9.38 24.53 18
live.idle producer: waiting for the next exposure slot 9.31 11.45 150
wf.basis-async-start live: the next bleach basis started on its own thread (a copy of the scene) 6.23 6.78 2
fl.mean-field-weights per-column dye clocks -> photons 6.20 9.84 18
fl.mean-field-render weighted mean-field image 1.92 7.76 18
live.frame producer: one frame from reading the state to publishing it (the render time) 0.64 7.64 150
fl.mean-field-rate-frame a later frame of a movie: each cell bleached at its own light 0.55 0.88 270
fl.mean-field-scene mean-field scene update 0.50 0.81 18
wf.scene.finish 0.50 0.81 18
live.state read settings, pose, drift 0.44 4.65 150
fl.frame.blinks (batches) splat the blinks, or bin them (binned FFT) in dense frames (CPU) 0.32 0.38 9
fl.make-setup camera, light path, labels 0.26 0.34 10
live.publish hand the frame to the camera 0.15 1.56 150
live.ahead-submit producer: hand the next batch to the render-ahead helper 0.13 0.17 10
live.ahead-wait wait for a render-ahead batch 0.10 1.51 80
fl.psf-kernels PSF kernels (memo hit, or computed) 0.09 0.12 10
fl.events-query blink events of the frame from the core 0.08 0.09 10
mm.frame-age age of a frame when taken (publish -> take) 0.07 1.55 150
fl.clock-map the light history's clock map over the query (each dye's clock at its own place; core ABI 14) 0.05 0.07 10
mm.insert-image MMCore InsertImage (circular buffer) 0.04 0.12 150
mEos3.2 PALM, 10 ms: every phase
phase what per frame (ms) longest (ms) count
ahead.batch render-ahead helper: one batch of frames (setup, render, noise) 102.30 131.14 9
fl.total 101.87 130.87 9
ahead.cpu.render+noise render-ahead helper: the batch's frames on the CPU 92.79 114.61 9
fl.frame.blinks (batches) splat the blinks, or bin them (binned FFT) in dense frames (CPU) 54.86 68.37 9
fl.frame.onFrame 21.02 25.52 9
fl.frame.continuous add the continuous populations 16.56 25.03 9
mm.wait-frame (sequence) sequence thread: waiting for a fresh frame 10.85 34.60 137
live.idle producer: waiting for the next exposure slot 9.81 22.83 145
fl.setup movie setup total 9.37 16.42 9
fl.events-query blink events of the frame from the core 3.84 4.75 10
wf.basis-async-start live: the next bleach basis started on its own thread (a copy of the scene) 3.55 4.10 2
fl.dye-counts count the dyes of continuous populations 1.11 1.38 9
fl.mean-field-render weighted mean-field image 0.87 4.71 18
fl.mean-field-scene mean-field scene update 0.62 1.08 18
wf.scene.finish 0.62 1.08 18
mm.frame-age age of a frame when taken (publish -> take) 0.62 13.79 137
fl.mean-field-rate-frame a later frame of a movie: each cell bleached at its own light 0.52 1.53 270
fl.mean-field-weights per-column dye clocks -> photons 0.46 0.83 18
fl.make-setup camera, light path, labels 0.27 0.32 10
live.frame producer: one frame from reading the state to publishing it (the render time) 0.18 1.36 145
fl.psf-kernels PSF kernels (memo hit, or computed) 0.17 0.29 10
live.ahead-submit producer: hand the next batch to the render-ahead helper 0.14 0.18 10
live.state read settings, pose, drift 0.13 1.24 145
fl.events-sort group and bucket the events 0.08 0.10 10
fl.clock-map the light history's clock map over the query (each dye's clock at its own place; core ABI 14) 0.05 0.06 10
live.publish hand the frame to the camera 0.05 1.27 145
mm.insert-image MMCore InsertImage (circular buffer) 0.04 0.10 137
fl.survey the populations' survival over the map (the mean-field switch) 0.01 0.04 18

Latencies (call -> image, 20 ms exposure)

action ms largest phases
first image after loading the configuration 3139 live.begin 3071, init.preload (background) 2382, fl.configure 2331, psf.compute 2135
snap 46 live.begin 24, live.render 20, fl.frame.blinks (batches) 19, fl.events-query 10
30 um stage move + snap 1614 live.begin 1541, fl.mean-field-weights 357, fl.mean-field-scene 342, fl.dye-counts 312
objective switch + snap 4375 live.begin 4331, fl.mean-field-render 1546, wf.basis 1402, wf.plane-spectra 1255
objective switch back + snap 2726 live.begin 2698, fl.mean-field-render 1373, wf.basis 1224, wf.plane-spectra 1057
1 um focus move + snap 2751 live.begin 2727, fl.mean-field-render 1672, wf.basis 1397, wf.plane-spectra 1270
Channel switch to AF647 dSTORM + snap 1981 live.begin 1921, fl.psf-kernels 1121, psf.compute 1101, psf.zernike-planes 794
Channel switch to ATTO655 DNA-PAINT + snap 597 live.begin 549, fl.events-query 526, live.idle 36, fl.bg-map-prefetch 32
Channel switch to BrightField + snap 1026 live.lamp 1021, bf.scene 1002, bf.image 18, live.idle 10
Channel switch to mEGFP WideField + snap 3105 live.begin 3096, fl.dye-counts 1377, fl.dye-index-ahead 1353, fl.psf-kernels 1091
Channel switch to mEos3.2 PALM + snap 1908 live.begin 1893, wf.plane-spectra-async 1845, fl.psf-kernels 1226, psf.compute 1205

insiliscope_cli

insiliscope_cli wall-clock (best of the repeats, includes process start and TIFF write), measured by the release workflow on a GitHub-hosted Linux runner. Runner hardware varies between runs, so compare trends, not single numbers. Configurations: tools/bench.py.

Frames per second (higher is better)

version date CPUs sr-128px-200f sr-256px-200f sr-dense-128px wf-128px-20f wf-256px-20f wf-128px-x2 sr-128px-1000f wf-256px-200f bf-256px-q3 bf-256px-q4 dstorm-128px-1000f palm-green-128px-1000f paint-bg-128px-1000f wf-2group-256px-200f
v0.1.0-rc16 2026-10-29 4 68.4 31.1 15.6 9.1 7.7 9.1 145.5 64.3 8.2 3.1 194.6 208.7 46.1 27.9
v0.1.0-rc15 2026-10-29 4 57.0 28.1 13.4 7.3 6.1 7.2 131.2 52.9 6.8 2.5 170.8 175.8 39.7 23.4
v0.1.0-rc14 2026-10-23 4 80.7 33.1 15.0 11.9 10.0 11.9 157.5 84.7 10.3 3.9 206.0 255.4 45.6 29.5
v0.1.0-rc13 2026-10-22 4 56.7 28.5 13.7 7.2 6.1 7.2 132.8 53.1 6.9 2.5 171.5 175.8 41.0 23.6
v0.1.0-rc11 2026-10-21 4 55.1 26.3 12.6 7.1 6.0 7.1 124.5 51.9 6.8 2.5 162.6 171.3 38.2 22.5
v0.1.0-rc10 2026-10-20 4 65.4 30.2 14.2 8.9 7.5 8.8 143.4 63.8 8.2 3.0 190.0 202.4 41.8 25.8
v0.1.0-rc9 2026-10-17 4 53.9 26.7 12.4 6.5 5.3 5.3 124.4 43.9 6.9 2.6 164.0 140.2 36.8 20.2
v0.1.0-rc8 2026-10-12 4 62.0 28.4 13.1 7.8 6.1 7.9 129.5 56.6 7.1 2.6 143.6 175.3 39.3 24.0
v0.1.0-rc7 2026-10-10 4 61.4 30.2 14.8 7.3 5.6 7.4 135.6 51.2 7.3 2.4 150.2 177.5 42.9 24.2
v0.1.0-rc6 2026-10-06 4 50.9 15.5 7.4 13.8 9.5 13.8 66.0 84.0 6.8 2.5 92.6 119.8 20.8 14.8
v0.1.0-rc5 2026-10-05 4 65.9 19.2 9.6 21.6 15.0 22.5 81.3 128.7 11.1 4.1 114.0 146.2 24.8 17.3
v0.1.0-rc4 2026-10-04 4 36.5 10.2 5.1 14.1 11.3 13.3 46.0 89.7 6.3 2.3
v0.1.0-rc3 2026-10-04 4 63.8 18.6 10.0 17.4 13.4 16.1 86.3 107.9 6.8 1.9
v0.1.0-rc2 2026-10-01 4 59.5 17.7 10.2 11.2 8.9 10.6
v0.1.0-rc1 2026-10-01 4 374.4 180.0 305.7 28.8 17.6 27.0

Machines

  • v0.1.0-rc16: cli Linux-7.0.0-1017-azure-x86_64-with-glibc2.39; Micro-Manager Windows-2025Server-10.0.26100-SP0, 4 CPUs, pymmcore 12.5.0.75.0
  • v0.1.0-rc15: cli Linux-7.0.0-1017-azure-x86_64-with-glibc2.39; Micro-Manager Windows-2025Server-10.0.26100-SP0, 4 CPUs, pymmcore 12.5.0.75.0
  • v0.1.0-rc14: cli Linux-6.17.0-1022-azure-x86_64-with-glibc2.39; Micro-Manager Windows-2025Server-10.0.26100-SP0, 4 CPUs, pymmcore 12.5.0.75.0
  • v0.1.0-rc13: cli Linux-7.0.0-1017-azure-x86_64-with-glibc2.39; Micro-Manager Windows-2025Server-10.0.26100-SP0, 4 CPUs, pymmcore 12.5.0.75.0
  • v0.1.0-rc11: cli Linux-7.0.0-1017-azure-x86_64-with-glibc2.39; Micro-Manager Windows-2025Server-10.0.26100-SP0, 4 CPUs, pymmcore 12.5.0.75.0
  • v0.1.0-rc10: cli Linux-7.0.0-1017-azure-x86_64-with-glibc2.39; Micro-Manager Windows-2025Server-10.0.26100-SP0, 4 CPUs, pymmcore 12.5.0.75.0
  • v0.1.0-rc9: cli Linux-6.17.0-1022-azure-x86_64-with-glibc2.39; Micro-Manager Windows-2025Server-10.0.26100-SP0, 4 CPUs, pymmcore 12.5.0.75.0
  • v0.1.0-rc8: cli Linux-6.17.0-1022-azure-x86_64-with-glibc2.39; Micro-Manager Windows-2025Server-10.0.26100-SP0, 4 CPUs, pymmcore 12.5.0.75.0
  • v0.1.0-rc7: cli Linux-6.17.0-1022-azure-x86_64-with-glibc2.39; Micro-Manager Windows-2025Server-10.0.26100-SP0, 4 CPUs, pymmcore 12.5.0.75.0
  • v0.1.0-rc6: cli Linux-6.17.0-1022-azure-x86_64-with-glibc2.39
  • v0.1.0-rc5: cli Linux-6.17.0-1022-azure-x86_64-with-glibc2.39
  • v0.1.0-rc4: cli Linux-6.17.0-1022-azure-x86_64-with-glibc2.39
  • v0.1.0-rc3: cli Linux-6.17.0-1022-azure-x86_64-with-glibc2.39
  • v0.1.0-rc2: cli Linux-6.17.0-1022-azure-x86_64-with-glibc2.39
  • v0.1.0-rc1: cli Linux-6.17.0-1022-azure-x86_64-with-glibc2.39