> For the complete documentation index, see [llms.txt](https://postica.gitbook.io/binding-system-3/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://postica.gitbook.io/binding-system-3/tutorials/find-the-cost.md).

# Finding the Binding That Costs You Frames

Find the expensive bindings, and the four fixes in the order that pays.

Bindings are cheap individually and a project has a lot of them. When a scene gets slower, "is it the bindings?" is a reasonable question, and guessing at it is not a reasonable answer.

This tutorial measures instead. It also fixes things in a specific order, because the four available fixes differ enormously in effort and in payoff, and doing them in the wrong order means a lot of work for the last few percent.

## What you will do

Measure the cost of every active binding in a running scene, find the ones that dominate, and apply the cheapest effective fix to each.

<figure><img src="https://3048705056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLUfBXR02sJ5i0MxwYbaV%2Fuploads%2FtzV8S90ESUAKmHmqnpZd%2FScreenshot%202026-09-27%20at%2018.25.26.png?alt=media&amp;token=0c8e9af9-9dd1-4fd1-8ee4-008b165be678" alt=""><figcaption><p>The Bindings Monitor, sorted by execution time</p></figcaption></figure>

**About 25 minutes.**

## What you need

A scene with a decent number of bindings running. Your own project is much better than a test scene here, because the point is to find something you did not know about.

## 1. Get a measurement, not an impression

**Window ▸ Binding System ▸ Bindings Monitor**. Outside play mode it says *Enter Play Mode to monitor active bindings*.

Enter play mode. Let the scene settle for a few seconds: first frames include one-off resolution work that is not representative of anything.

Now press **Reset**. That clears the accumulated measurements, so everything from here is steady-state.

Play normally for a while. Do whatever the scene does, not whatever is easiest to leave running.

## 2. Read the footer before the table

At the bottom: **Elements**, and **Total Exec Time** in milliseconds per update.

{% hint style="info" %}
Read carefully the **Total Exec Time**, it is in **milliseconds**, that is 0.005ms is 5 microseconds.
{% endhint %}

Read that total first and decide whether to continue. If every binding in the scene adds up to a fraction of a millisecond, the bindings are not your problem and this tutorial is the wrong tool. Go and profile something else.

If the number is large enough to care about, the footer also shows the filtered subset's share as a percentage, which is the number to work with as you narrow down. It answers "how much of the budget is this group" directly.

## 3. Sort by cost

Click the **Measurements** column to sort.

Execution time is a moving average over the last hundred samples, so it is stable enough to read while the game runs. Rows above a threshold are flagged *High average execution time!*

Look at the top few rows only. Binding cost is almost always dominated by a handful of entries, and the long tail is not worth your afternoon.

Expand a top row. It shows the current value and the rate in words: *Every Frame*, *Every 12 frames*, *Every 0.25 seconds*, or *Controlled*, meaning nothing updates it automatically.

<figure><img src="https://3048705056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLUfBXR02sJ5i0MxwYbaV%2Fuploads%2FuCdsaCiECqatJbhOG8FC%2FScreenshot%202026-09-27%20at%2018.27.41.png?alt=media&amp;token=991fe5a4-c8fb-46c4-9384-c5b93df44002" alt=""><figcaption><p>A row flagged for high average execution time, expanded</p></figcaption></figure>

{% hint style="info" %}
If the table is moving too fast to read, press **Pause**. That freezes the monitor, not the game. If the monitor itself is showing up in your frame time, raise **Refresh Interval**.
{% endhint %}

## 4. Fix in this order

For each expensive row, work down this list and stop at the first one that applies. They are ordered by payoff per unit of effort, and the first two solve most cases.

### First: does it need to run this often?

Use the row's focus action to jump to the binding, open **Update Points ▸ Update On**, and set an interval.

A number a human reads does not need sixty updates a second. Ten looks identical and costs a sixth as much. Switch the dropdown to **Seconds** and enter `0.1`, or to **Frames** and enter `6`.

This is first because it is one field and it can remove 80% of a binding's cost outright.

{% hint style="warning" %}
Not for anything animated. A [Value Smoother or Tween Animation](/binding-system-3/tutorials/smooth-values.md) on an interval is an animation with fewer frames, and it looks it. Those rows skip to the next fix.
{% endhint %}

### Second: is Optimized Update on?

In the same panel. With it on, the update does no work on frames where the source is inactive or the value has not changed.

New bindings get it by default, so a row without it is usually one somebody turned it off on, or one carried over from an older project. Turn it back on.

It composes correctly with animated modifiers, so there is no reason to leave it off on those either: a modifier that has work to do between source changes declares itself dynamic and the pipeline keeps evaluating it.

### Third: is the source mode expensive?

Look at the light under the source toggle on the bind row: its colour is the mode's cost, from green to violet. The mode dropdown in the source view shows the same cost as five dots.

<table><thead><tr><th width="230">Mode</th><th>What it costs</th></tr></thead><tbody><tr><td><strong>From Object</strong></td><td>Nothing. The reference is already in hand.</td></tr><tr><td><strong>From Variable</strong>, <strong>From Static Value</strong></td><td>Negligible. One table lookup.</td></tr><tr><td><strong>From Object with Tag</strong>, <strong>From Context</strong></td><td>Low. A tag search, or a <code>GetComponent</code> around one object.</td></tr><tr><td><strong>From Scene</strong></td><td>Moderate: a scan of every loaded scene.</td></tr><tr><td><strong>From Path</strong></td><td>High: a walk of the hierarchy by name.</td></tr><tr><td><strong>From Pattern</strong></td><td>The highest: a wildcard scan.</td></tr></tbody></table>

A [context](/binding-system-3/overview/sources.md#the-context) narrows the tag, path and pattern searches to one object's hierarchy, which is the cheapest fix when one of them has to stay.

Every mode caches its result, so those costs are the cost of a **miss**, not of every frame. Which leads to the thing actually worth checking:

**A source that cannot be found is the expensive case.** A failed lookup cannot be cached as a success, so it is retried, at full price, forever. A single binding pointing at an object that is not there can cost more than a hundred healthy ones.

Check the status light on the bind row. If a scan mode is genuinely needed and genuinely resolves, leave it: it resolves once. If it is failing, that is not a performance problem, it is a broken binding, and [the audit pass](/binding-system-3/tutorials/audit.md) is the tool for finding the rest of them.

### Fourth: generated accessors

Only when the first three are done and the number still matters.

**Project Settings ▸ Binding System ▸ Configuration ▸ Build-Time Optimized Accessors**. Off by default. With it on, the build replaces each qualifying bound path with a single generated static method, so the whole path costs one call.

It is last because it is project-wide, build-time only, and it does not apply to every binding: the source has to be a direct object reference, every segment has to be public, and the path has to be long enough to be worth it. A qualifying binding shows an **optimized badge** on its row, so you can check any individual one without opening a window.

If you turn it on, set **On Stale Build** to **Fail Build** on CI. A stale generated set means the build machine optimized a different set of bindings from the one the project now has.

## 5. Measure again

Press **Reset**, play for the same length of time, and read the footer.

Do this after each change rather than after all of them. Otherwise you have a project with four changes in it and no idea which one helped.

## What just happened

**The monitor only sees engine-driven bindings.** Proxy bindings with an update point, and `Bind<T>` fields with Auto Update on. A `Bind<T>` resolved lazily when your code reads it never appears, because the engine is doing nothing for it. That is not a gap in the tool: those bindings genuinely have no scheduled cost, and their cost belongs to the line of code that reads them. If you expected a row and it is not there, turn on **Show Inactive** to check whether it is registered at all.

**Reflection is not what you are measuring.** A bound path is resolved once, on first use, into a cached accessor keyed by type and path. What the monitor is timing is the accessor chain, the converter and the modifiers, multiplied by how often the binding is scheduled. Which is why "how often" is the first fix and "how fast" is the last one.

**Two of the four fixes cost nothing.** An interval and Optimized Update are one field each and reversible. The source mode is a design decision. Codegen is a project-wide build setting. Working up that ladder rather than down it is the whole method.

**The footer tells you whether phased bindings are on.** It is a readout, not a switch: the setting lives in **Project Settings ▸ Binding System ▸ Optimization**, and a binding reads it when it builds its pipeline. To compare the two, change the setting and re-enter play mode, resetting the table each time. See [Phased Bindings](/binding-system-3/project-tools/performance/phased-bindings.md).

## Try changing this

**Turn on Edit Time.** The monitor then tracks bindings at edit time, which is how you find an EDITOR-point binding that is quietly costing you editor responsiveness rather than frame time.

**Filter to one subsystem and read the percentage.** The footer shows the filtered subset's share of the total. That turns "the UI feels heavy" into a number you can put in a ticket.

**Pause a single binding.** Each row has a pause action. Pause the most expensive one and watch the total drop, which confirms the row you are about to spend an hour on is really the one that matters.

**Set an interval on something animated, on purpose.** Watch it get chunky, then take it off. Knowing what that failure looks like is worth the thirty seconds, because it is the one case where the first fix is the wrong one.

## Related pages

* [Bindings Monitor](/binding-system-3/project-tools/diagnostics/bindings-monitor.md): every column, control and readout.
* [Bind Modes and Update Points](/binding-system-3/overview/modes-and-updates.md): intervals and Optimized Update.
* [Sources](/binding-system-3/overview/sources.md): the cost of each source mode, and why a miss is the expensive case.
* [Build-Time Optimized Accessors](/binding-system-3/project-tools/performance/optimized-accessors.md): what qualifies, and what happens during a build.
* [Performance](/binding-system-3/project-tools/performance.md): the mechanisms behind all of it.
