# Performance

Strand aims to be fast when something moves and to cost nothing when
nothing does. This page says how it gets there, and how to measure
your own shell.


## An idle shell does no work

The program is one graph of values (see
[state and reactivity](/concepts/state.html.md)). When nothing is written, nothing is
recomputed and no frame is asked for. A service wakes the shell only
as often as what you read from it changes: a clock that shows minutes
wakes it once a minute, and the battery when the battery changes.
Services nobody reads are not running at all.


## Only what changed is painted

Each frame repaints only the area that changed, its **damage**. When
the clock ticks, Strand repaints the clock's text, not the bar. On the
demo bar (`strand run --demo`), 2560 px wide at scale 1 and 1.25, a
minute tick, even one that
changes every digit and the text's width, repaints at most 2,000 px².


Layout is just as narrow. `x`, `y`, `scale`, `rotate` and `opacity`
never lay the tree out again, and a size that springs lays out only the
part of the tree under the nearest ancestor whose size stays put (see
[layout](/concepts/layout.html.md#what-lays-the-tree-out-again)).

## CPU and GPU

Strand draws on the CPU by default, into shared memory, with exact
damage: that is the cheapest way to draw a bar whose clock ticks. When
a large area animates, the GPU is faster, so a surface moves to it:

- **A surface moves to the GPU** at the first large frame (at least
  200,000 pixels of damage) of an animation, such as a panel opening, a
  scroll or a theme crossfade, or at the third large frame in a row of
  something that animates with no spring, such as a shader's clock.
- **It goes back to the CPU** once it has been settled, with only small
  frames or none, for 3 seconds. A surface that animates again within
  30 seconds of going back waits 15 seconds the next time, so one you
  use every few seconds is not handed back and forth.
- **A small animation the CPU draws slowly** (4 ms or more a frame)
  keeps its surface on the GPU.
- **The GPU device is started with the shell**, off the drawing path,
  and kept, so an animation never waits for it. Where no GPU can exist,
  Strand never asks for one. After 3 lost devices in one run the GPU
  stays off until Strand restarts, and everything is drawn on the CPU.


`strand report` shows each
surface's backend and why.

Strand's own build is held to memory and speed budgets, set in
[design.md](https://github.com/jakeb-grant/strand/blob/main/docs/design.md#rendering-performance-and-memory-budget).
They catch a change that makes Strand slower or bigger, and are never
a limit on what your shell may do.


## Measuring your own shell

`strand report` describes the running shell: the process's PSS, the
GPU's status, and for each surface its backend, why it is on the GPU
and its frame times (p50, p95 and p99 over the frames drawn among its
last 600 paints).
