Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Performance

One guard costs next to nothing. A level with hundreds of them is where cost shows. This chapter gives the measured numbers, then what keeps each part cheap.

The numbers are from one machine, in release builds. Yours will differ. The shape won’t.

Trees

examples/load in bevy_arbor_bt runs many agents. Each agent’s tree is a Select of four decorators over one running task.

AgentsSystem conditionsTyped conditions, nothing changingTyped conditions, a tenth changing each tick
10017 µs3.7 µs5.5 µs
50078 µs12 µs21 µs
2,000305 µs41 µs78 µs

Per agent, that’s about 150 nanoseconds when it asks four system conditions every tick. Asleep, it’s about 20. Run it yourself:

cargo run --release -p bevy_arbor_bt --example load

What keeps trees cheap:

  • Typed conditions over system conditions. A system condition is asked every tick. A typed condition is asked again only when what it reads changes. See Decorators.
  • set_if_neq. A component written every frame keeps every tree that reads it awake, even if the value is the same. Write it only when it changes. See Sleeping trees.
  • Noises at the rate they matter. A noise each tick wakes every tree listening, each tick.
  • Timing in tasks. A task that counts its own time doesn’t wake the tree to do it. See Large trees and sockets.

Sight

Without avian, sight finds what’s near through a spatial grid of its own. Its cells are as large as a typical sight, and it’s rebuilt on the ticks a sensor looks. This is a 2D micro-benchmark, in which a tenth of the agents look each tick:

AgentsThrough everythingThrough the grid
1,00058 µs38 µs
2,000196 µs81 µs
10,0004.13 ms435 µs

Looking through everything grows with the square of the agents. The grid grows in step with them, at about 10 nanoseconds a thing to rebuild.

With avian, sight asks avian’s colliders instead, which avian keeps up to date anyway: nothing to rebuild. See Occlusion and attitude.

What keeps perception cheap:

  • A longer interval. Sight looks five times a second by default, each agent at a moment of its own. Guards far from the player can look less often.
  • Perceivables on a layer of their own. With avian, a look asks for every collider in range. Set PerceivableLayers, so it skips walls and tiles.
  • Occlusion only where needed. A line-of-sight ray is cast only for what’s already in range and in the cone. Fewer colliders on the occluding layers make each ray cheaper. See Occlusion and attitude.

Queries

Queries share a time budget, EqsBudget, a millisecond each tick unless you set it. Queries over budget wait for the next tick, oldest first. At least one runs each tick. So many guards asking at once delay each other, rather than stall the frame. See Running queries.

What keeps queries cheap:

  • Few items. Every item runs every test. A donut of 3 rings of 16 is 48 points. Keep generators coarse.
  • Cheap filters first. Filters run cheapest first by each test’s Cost. A LineOfSight filter then casts rays only for what’s left.
  • test_all for setup. A test of your own that looks something up once a run, not once an item, should do it in test_all.
  • Ask when needed. Run a query when the guard needs an answer, not every tick.

Debugging costs

TreeTrace keeps a string per node and SurveyTrace a list per run. They’re kept only on agents you put them on. Leave them off in a shipped build. See Debugging.