Skip to content

How Myaku works ​

Frames ​

Myaku wraps requestAnimationFrame. The first callback with a new timestamp starts a frame. A frame's interval runs from its start to the next frame's start, which is the gap the player sees. Its CPU time is how long its frame callbacks ran.

GPU work ​

Myaku wraps getContext on canvases and offscreen canvases. On each WebGL context it counts draw* calls, texture and buffer uploads with their byte sizes, and shader compiles and program links. On 2D contexts it counts drawing calls. Contexts created before myaku starts aren't counted, which is why it should load first.

Attribution ​

Chromium reports Long Animation Frames: for any frame over 50 ms, which scripts ran, from which file and function, and how long style and layout took. Myaku keeps these entries and matches them to frames by time.

Because myaku's wrapper calls your frame callbacks, the browser attributes them to myaku. So when a callback is first registered, myaku records where it came from (one stack capture per distinct callback, cached), and points the verdict there instead.

Garbage collection ​

In Chromium, performance.memory gives the heap size. A drop of a megabyte or more between frames, while the game's code was idle, is a strong sign of a collection.

Cost ​

Frames live in fixed-size typed arrays, so recording a frame doesn't allocate, and myaku doesn't cause the GC it's looking for. Its own time per frame is measured and reported as overheadMs. Verdicts are only computed when you ask for them.

The first 10 frames (scripts compiling, assets decoding) are warm-up and aren't counted as play.

What myaku can't see ​

  • GPU time. A GPU-bound frame shows as unknown, with a hint when draw calls are high.
  • Inside an engine's loop, without spans.
  • Script locations outside Chromium. Other browsers still get frame times, counts and spans.
  • Workers. Only the main thread is profiled.

The design is recorded in ADR 0011.