Visual Assembly Canvas - Performance

Goal

  • Run the canvas at 60FPS.
  • Support real-time audio synthesis.
  • Support running at 1ms per tick or less.
    • Can we do 1000 computations per second or more?
    • Identify what is blocking
  • Support computation with a lot of machines

Caching Opcodes

  • HashMap<u16, Op>; mapping between program counter and parsed opcode. No need to decode every time.
  • Makes SMC impossible :(

Scheduler

  • Machine Clock: machine should be able to execute on the fastest speed possible, but configurable to slow down execution.
  • Audio: Schedule the audio at the right time. Uses Tone.js.
    • note: do we need to consider AudioContext scheduler?
  • Plotter: canvas 60 frames per second max.
  • Clock: at the specified delay interval.
  • React: should not render over 24 FPS.

Compute vs Audio

Technical

  • Use requestAnimationFrame to tick every frame - better than using setTimeout.

Poll versus Push

  • Poll: collect_audio_effects()
  • Push: add_audio_effects_callback(JsValue)
// Polling using schedulers on JavaScript side
Scheduler.on('audio', () => {
  const fx = ctx.collect_audio_effects()
  fx.forEach(handleAudioEffect)
})
// Pushing, using event listeners on the Rust side.
ctx.add_audio_effects_callback((messages) => {
 
})

Metrics to Profile

  • Data transfer between JavaScript and Rust
    • How the space complexity scales as we add large program and canvas modules.
  • Mean tick time
  • Tick time in JavaScript side
  • Tick time in Rust/WebAssembly side

Optimization strategies

  • Plotter: can we either send only the updated integers for JavaScript to reconcile, rather than sending the whole array of number every tick/frame?
    • Concern: the diff-and-reconcile procedure might actually be slower than just sending over 100 integers across wasm!

Handling event loop and event listeners on Rust.

  • Note that JS still has to call the Rust tick() function, as it can't sleep. Therefore, the JavaScript scheduler that wraps requestAnimationFrame must be implemented.
  • Can we batch ticks in Rust, then? For example, we tick an increment amount of frames
  • Is doing it in Rust -> JS more efficient?
pub struct EventLoop {
  audio: Vec<js_sys::Function>
}
 
impl EventLoop {
  pub fn tick(&mut self) {
    self.canvas.update()
  }
}

Scheduler A: multiple loops at once

const FPS = 60
 
class Scheduler {
  setup() {
	  requestAnimationFrame(this.updatePlotter)
  }
 
  updatePlotter() {
    const diffs = ctx.collect_plot_diffs()
    applyPlotDiffs(diffs)
 
	  requestAnimationFrame(this.updatePlotter)
  }
}

Design notes for Visual Assembly Canvas