From 424e0fed0207ddcb28b12a16b6e096d882e81d24 Mon Sep 17 00:00:00 2001 From: Luke Diamand Date: Wed, 22 Jul 2026 15:45:15 +0100 Subject: [PATCH] Add documentation on the relationship between BrightScript and SceneGraph - Nodes, Components and CompiledComponents - BrightScript objects and domains --- docs/DEVELOPER/performance-guide/_order.yaml | 3 +- .../copying-in-scenegraph.png | Bin 0 -> 76825 bytes .../performance-guide/sgnode-access.md | 717 ++++++++++++++++++ 3 files changed, 719 insertions(+), 1 deletion(-) create mode 100644 docs/DEVELOPER/performance-guide/copying-in-scenegraph.png create mode 100644 docs/DEVELOPER/performance-guide/sgnode-access.md diff --git a/docs/DEVELOPER/performance-guide/_order.yaml b/docs/DEVELOPER/performance-guide/_order.yaml index b1c0144a..96f76c89 100644 --- a/docs/DEVELOPER/performance-guide/_order.yaml +++ b/docs/DEVELOPER/performance-guide/_order.yaml @@ -2,4 +2,5 @@ - memory-management - optimization-techniques - data-transfer-apis -- measuring-channel-performance \ No newline at end of file +- measuring-channel-performance +- sgnode-access diff --git a/docs/DEVELOPER/performance-guide/copying-in-scenegraph.png b/docs/DEVELOPER/performance-guide/copying-in-scenegraph.png new file mode 100644 index 0000000000000000000000000000000000000000..bf20ea55f1db21fe187bd9ab3b1da6319de71994 GIT binary patch literal 76825 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%0DN?u8RV&7A~3`K?s)HPz{~qVBnXq2U^R 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 TXS3!3@bg?&MW#&3H1K}`dcpeL literal 0 HcmV?d00001 diff --git a/docs/DEVELOPER/performance-guide/sgnode-access.md b/docs/DEVELOPER/performance-guide/sgnode-access.md new file mode 100644 index 00000000..ce159f07 --- /dev/null +++ b/docs/DEVELOPER/performance-guide/sgnode-access.md @@ -0,0 +1,717 @@ +``` +title: "BrightScript access to SceneGraph Nodes - Performance Considerations" +excerpt: "Performance considerations of SceneGraph nodes, BrightScript and fields." +deprecated: false +hidden: false +metadata: + title: "BrightScript-to-SceneGraph bindings | Roku Developer Docs" + description: "Performance and memory costs of SceneGraph node fields, BrightScript copying, observers, and thread communication." + robots: index +next: + description: '' +``` + +# SceneGraph, Performance & Memory - A Rough Guide + +SceneGraph is built around a tree of _nodes_ which are then rendered onto the display. BrightScript can +manipulate these nodes. The built-in node classes can be extended by developers by defining +_component classes_. + +This document discusses some of the details of this, and their impact +on the performance and memory usage of a BrightScript/SceneGraph channel. + +## SceneGraph Nodes + +SceneGraph nodes are built upon a base C++ `Node` class (e.g. `Group`, `ContentNode`). `Node`s can have children +and can also reference other nodes through fields. These nodes are reference-counted in C++ via `std::shared_ptr` +and live independently of BrightScript. They are released when their reference count drops to zero. + +```mermaid +--- + config: + class: + hideEmptyMembersBox: true +--- + +classDiagram + Node <|-- ContentNode + Node <|-- Group + Group <|-- LabelBase + LabelBase <|-- Label + Group <|-- Rectangle + Group <|-- ArrayGrid + Node: refcount + Node: threadId + Node: fields + Node: children +``` + +### Thread Ownership + +The `threadId` is used to track "ownership" - which thread (task/SDK1 or render thread) "owns" this +node. If a non-render thread accesses a node owned by the render thread, it will _rendezvous_ the +operation. It is never possible for the render thread to encounter a node it does not own - the +APIs _transfer_ the ownership recursively over to the render thread first. + +This is the mechanism that ensures a task thread cannot access a node concurrently with the render +thread - after a task thread passes a node over to the render thread its ownership changes and +thereafter all operations by the task thread are rendezvoused over to the render thread - the task thread +blocks while the render thread performs the operation on its behalf (get/set/callfunc, etc). + +## SceneGraph Components + +SceneGraph's base C++ components can be extended using SceneGraph's XML markup: + +``` + +``` + +This creates an internal `CompiledComponent` object which records: + +- The parent compiled component (e.g. when one compiled component extends another). +- The list of field definitions. +- The set of interface functions. +- The set of functions used by this component (e.g. `init`), used for the namespacing support. + +When a component node is created (`CreateObject("roSGNode", "MyContentNode")`), this results in the creation of: + +- The base C++ node object (e.g. `ContentNode`). +- A `Component` instance, which references the `CompiledComponent`. This is referenced by the node. +- The individual fields, with values set to initial values defined in the `CompiledComponent`. +- The Component `m` array (`m.foo = some_value`). + +i.e. a "component" is a SceneGraph `Node` with an associated `Component` data structure +which extends the derived-`Node`'s behavior (refcounting, ownership, etc). +The words "component", "node", and "component node" are often used interchangeably +but as far as programming from BrightScript is concerned, all classes of "component" +are actually "nodes" with extended user-defined fields and functions and have +all the properties of a node. + + +```mermaid +--- + config: + class: + hideEmptyMembersBox: true +--- +classDiagram + + Component: XML fields + Component: dynamic fields + Component: m[2] + + Node "1" --> "1" Component + Node <|-- ContentNode + Component "*" --> "1" CompiledComponent + + CompiledComponent: field definitions + CompiledComponent: interface functions + CompiledComponent: BrightScript function table +``` + +Each CompiledComponent keeps a lookup table (hashmap) of functions - this is used for +the per-component function namespacing. + +💡 To minimize Component creation time, avoid deeply nested class hierarchies (`extends`), +keep the number of fields to a minimum, avoid using default values, and keep the `init()` +function(s) as short and fast as possible. This also reduces the memory overhead of the +`CompiledComponent` (although this is not normally significant). + +### Defining Fields - XML or `addField` ? + +Field creation is faster when defined in the XML compared to ad-hoc creation via `node.addField()`. +When fields are added via `addField`, each node must build its own per-node name-to-field +dictionary. When fields are defined via the XML, this dictionary is shared across all components +of the same type and built only once. + +Fields are looked-up in the name-to-field dictionary at each level in the component's class hierarchy, so deep class +hierarchies will be slower than shallow ones. + +# BrightScript Runtime + +Each BrightScript thread owns a control structure that owns a +BrightScript `domain`. When a BrightScript thread creates a BrightScript +object (e.g. via `CreateObject()` or `box()`) it is added to this +list with a refcount of `1`. When other references are created the +refcount is incremented, and when the refcount drops to zero it is +released. + +``` +foo = box("foo") ' roString with refcount 1 +myaa = {foo: foo} ' refcount = 2 +foo = invalid ' refcount = 1 +myaa.foo = invalid ' refcount = 0, recycled +``` + +Note: the terms "BrightScript component" and "BrightScript object" are used +interchangeably. + +A channel starts with a single BrightScript thread which runs the `main()` +subroutine. Creating a scene implicitly creates the render thread. +[Task threads](doc:task) create additional BrightScript threads. + +Threads can communicate with the render thread using a [Rendezvous](#Rendezvous), +[MessagePorts](#MessagePort) or the [roRenderThreadQueue](#RenderThreadQueue). + +# Bridging BrightScript to SceneGraph + +See [roSGNode](doc:rosgnode) + +BrightScript's `roSGNode` class is used to manage SceneGraph `Node` instances. +Each `roSGNode` instance has a `std::shared_ptr` which references that node. These +`roSGNode` instances of course also have their own _separate_ BrightScript refcount. Multiple +`roSGNode` instances can reference the same `Node` instance. + +For an XML file like this: + +``` + +``` + +Created like this: + +``` +n = CreateObject("roSGNode", "MyContentNode") +``` + +The `Node` instance will have a refcount of 1, as will the BrightScript `roSGNode` instance. + +```mermaid +--- + config: + class: + hideEmptyMembersBox: true +--- + +classDiagram + Script "1" --> "*" bsProc + bsProc *-- bscDomain + Node: SceneGraph refcount=1 + roSGNode: BrightScript refcount=1 + roSGNode: m_sgNode + bscDomain "1" --> "*" roSGNode + Node <|-- ContentNode + roSGNode "n" --> "1" Node + Node "1" --> "1" Component + Node: children + Node: observers + Component "*" --> "1" CompiledComponent +``` + +## Two Different Refcounts + +If that BrightScript variable is assigned to another variable, this increments +the refcount on the _BrightScript_ object, but not the underlying SceneGraph node: + +``` +m = n ' roSGNode BrightScript object's refcount is now 2 +``` + +The SceneGraph node's refcount will be incremented if some other SceneGraph object +references it, or if the `roSGNode` is cloned, for example: + +``` +m.top.addChild(n) ' SceneGraph Node refcount is now 2 +``` + +Note that when using the `/query/sgnodes` ECP command, the `osref` count that is reported +is calculated as the underlying `std::shared_ptr` refcount with `1` subtracted for each +referencing `roSGNode` instance. + +## Passing values between BrightScript and SceneGraph + +When values are passed from a BrightScript object to a SceneGraph node (via an `roSGNode` object) +using either "dot" notation or explicit `set` or `get` operations, the data is _copied_ to or from +the field. + +```mermaid +flowchart RL + BS_Obj["BrightScript Code"] + + subgraph SG_Group["Node"] + direction TB + SG_Node["SceneGraph Node Field"] + AA["AssocArray"] + foo["foo"] + bar["bar"] + + SG_Node -- "myfield" --> AA + AA --> foo + AA --> bar + end + + %% Explicit ordering constraint: BS_Obj precedes the subgraph. + BS_Obj -- "set\nCopy AA\nRendezvous" --> SG_Node + SG_Node -- "get\nCopy AA\nRendezvous" --> BS_Obj + + classDef bsObject stroke:#818cf8,fill:#eef2ff + classDef sgNode stroke:#2dd4bf,fill:#f0fdfa + classDef assocArray stroke:#a78bfa,fill:#f5f3ff + classDef element stroke:#fb923c,fill:#fff7ed + classDef group stroke:#2dd4bf,fill:transparent + + class BS_Obj bsObject + class SG_Node sgNode + class AA assocArray + class foo,bar element + class SG_Group group +``` + +Just like `set` and `get`, `callfunc` *also* copies its arguments and result, and *also* does a +rendezvous if ownership does not match. + +## Copying `roSGNode` + +An `roSGNode` can be copied from a task thread to the render thread. When this happens +the data is _not_ copied - only the `roSGNode` "shell" object is copied - this is fast. + +There is a small amount of overhead for setting the new owning thread-id, but this is +tiny (sub-microsecond per node). + +## Component-scope "m" and threads + +See: + +- [data scoping](doc:data-scoping) +- [Component global associative array](doc:threads#component-global-associative-array) + +The component owns a pair of BrightScript associative arrays which correspond to the `m` special +variable in component code, the component-scope `m`. + +``` +sub init() + m.foo = 42 ' stored in render-thread half of "m" +end sub +``` + +One side of this pair is used by the render thread, and the other side is used +when the component's code executes on a task thread (and is empty otherwise). + +When a task thread starts up, it will deep-clone the values in the render-thread's side across to the +task thread's side during the first rendezvous. + +💡 This can have a performance impact for large amounts of data in `m`. +💡 It is better to have a small number of long-lived task threads rather than spawning new ones +per-request - thread startup requires at least one rendezvous and so can easily take tens of +milliseconds, and block the render thread. + +## Common Performance Problems Copying In/Out of Node Fields + +The field copying that occurs when moving data from BrightScript into a SceneGraph field or +out again can often cause both performance and memory problems. + +The similarity in notation can easily trip up even the most experienced developers. This is +especially easy to do when mixing accesses to `m` and `m.top`. + +- `m` is a normal BrightScript associative array, so accesses are fast. The data references do still need to + be managed to ensure memory is recycled when no longer needed. +- `m.top` is a SceneGraph node. Accesses result in a **copy** of the field's data to construct a new +BrightScript associative array. Releasing it (when its refcount drops to zero) will take time. +- `m.global` is also a SceneGraph node, so the same performance penalties apply - accessing its fields +will copy the data in or out. + +Consider the following code: + +- It parses a JSON string. +- A reference is added to `m`. +- The JSON data is _copied_ into a SceneGraph node's field. +- The JSON data is read (copied) multiple times from the field. +- There is a write to a _subfield_ (`m.top.data.state.some_value`) but this merely mutates the _copy_ - the mutation is immediately lost. +- There is a write to the entire field - this updates it correctly but copies _all_ of the data. + +``` +' This just pays the JSON parse cost +data = ParseJson(json) + +' Cost is negligible but must now release *both* refs before data will be recycled. +' It is not uncommon for channels to forget to release one or other of these. +m.data = data + +' Copies the data into the field - slow for large data +m.top.data = data + +' Reads the whole of data *twice*, not just "state", and discards it *twice* +if m.top.data.state <> invalid and m.top.data.state.some_value = 42 then + do_thing(m.top.data.state) ' and reads + releases it again! + + ' Try to modify "some_value" + m.top.data.state.some_value = 43 ' Oops, only updates copy - mutation lost! + + data.state.some_value = 44 + m.top.data = data ' Success - updates entire field. +end if + +data = invalid ' Decrements refcount, still one more reference +m.data = invalid ' Memory released (takes time) +m.top.data = invalid ' Field data released (takes time) +``` + +### Copying - Patterns to Watch For + +| Code | What actually happens | Time complexity | +|---------------------------------|--------------------------------------------------------------|-------------| +| `m.data = data` | Store ref in AA, increment refcount | `O(1)` | +| `m.top.data = data` | Copy entire data into node field | `O(N)` | +| `m.top.data.state` | Copy entire data OUT of node → temp AA, read .state | `O(N)` | +| `m.top.data.state.some_value=43`| Copy entire data OUT → temp AA, mutate temp. Node unchanged | `O(N)`, wasted | +| `m.data = invalid` | Decrement refcount, release if zero | `O(N)` | +| `m.top.data = invalid` | Release field contents | `O(N)` | + +### Copying - Analyzing in Perfetto + +A Perfetto trace of this looks like this (some of the event names are truncated) + +![Perfetto trace](copying-in-scenegraph.png) + +- `bscCopyToDomainEx` is the internal function which clones BrightScript objects. +- The multiple `getField` and `bscCopyToDomainEx` blocks are the multiple field accesses in the code above. +- The gaps in the trace are where a pre-existing BrightScript object is being replaced, resulting in +object release, which takes time. +- The `bscDeleteStandaloneDomain` entry is where the old field value is replaced with the new. + +See also the discussion in [Referencing subsections of m.global](doc:data-management#referencing-subsections-of-mglobal). + +## SceneGraph `assocarray` and `array` Field Performance + +For historical reasons, fields of type `assocarray` have better performance than fields of type +`array`. + +For small fields this is not a consideration, but for large fields it can have an effect on performance: + +- Fields of type `assocarray` are accessed with time complexity `O(N)` in the number of BrightScript objects in the field. +- Fields of type `array` are accessed with time complexity `O(NlogN)`. + +### Passing Data to/from CallFunc() + +Data passed to [`CallFunc()`](doc:ifsgnodedict#callfuncfuncname-as-string--as-dynamic) is copied, as is the return +value. + +It uses the same algorithm used for `array` fields - even if an associative array is being passed. + +## Moving and Referencing + +It may be possible to reduce or eliminate the copies required when transferring data to/from +a node by using `moveIntoField()`, `moveFromField()`, `getRef()` and `setRef()`. + +`moveIntoField()` can be used to avoid copying data. However, the moving algorithm will +avoid moving data that is externally referenced. This means that if you know that your +data is externally referenced it may well be faster to simply copy it, since this avoids +the overhead of the external-referencing check. + +The `roRenderThreadQueue`'s `PostMessage()` API has the same performance limitation - if you +know that the data is heavily externally referenced, then it will likely be faster to use +`CopyMessage()`. + +`moveFromField()` is constant-time (`O(1)`) in all cases. + +See [Data Transfer APIs](doc:data-transfer-apis). + +# Cycles + +Cycles can create a leak - each object keeps the other object alive even though they +are no longer referenced from anywhere else in the system. Cycles can exist not only +between objects of the same family (BrightScript or SceneGraph) but also _across_ +object families - SceneGraph to BrightScript cycles are a common source of problems. + +## Cycles in BrightScript + +Creating an object cycle in BrightScript will keep the objects alive forever and cause a leak. + +``` +foo = {} +foo.bar = {} +foo.bar.cycle = foo ' cyclic - each references the other - refcount never drops to zero +``` + +```mermaid +flowchart LR + + foo --> bar + bar --> cycle + cycle --> foo +``` + +This can be detected at run time with `RunGarbageCollector()` which will walk the objects +in the domain (thread) that it is invoked on and find those that have outstanding +refcounts. Cycles can also be detected with Perfetto where they will be reported as unreachable +objects. + +`RunGarbageCollector()` should not normally be used in production - its execution time is linear +(`O(N)`) in the number of objects in the domain, so can become slow for non-trivial applications. + +See also [Garbage Collector](doc:data-management#garbage-collector) and +[Circular Dependencies in SceneGraph](doc:data-management#circular-dependencies-in-scenegraph). + +## Cycles in SceneGraph Trees - Child-to-Parent + +When child nodes are added, SceneGraph checks that the child being added is not already +a parent (recursively up the node tree). This means that building a tree of nodes is +quadratic in the depth (`O(N^2)`). In practice this overhead is small - on a typical device +constructing a tree of depth 10 is a few tens of microseconds per node. The cycle +detection does not visit sibling nodes (it is done merely to ensure that the tree +can always be traversed upwards without looping). + +Cycles between nodes due to (e.g.) node field references are only broken when the channel is +closed. This can also defeat the reference counting and cause a memory leak. + +## Cycles Between BrightScript and SceneGraph + +It is possible to create a cycle between BrightScript objects and SceneGraph objects. This will +prevent these objects from being cleaned up when expected. + +For example a component could store a reference to a parent or related component in its +component `m`. This will defeat the normal teardown and leave both parent and child "orphaned" when +the parent is removed from the tree. + +e.g. in the child: +``` +m.parent_cycle = m.top.getParent() ' BrightScript->SceneGraph cycle! +``` + +Now trying to delete the topmost node from the tree will leave it orphaned as it is being kept +alive by the reference in the component `m`. This can also happen with more complex cycles. + +A Perfetto heapgraph can reveal these cycles - it records the edges between all nodes. + + +## Cycles, Array Fields, and CallFunc() + +A long-standing bug means that if an `array` field has a cycle then the memory will be leaked even if the field itself +is destroyed. This is not true of `assocarray` fields - for these, a cyclic field structure is cleaned up when the +field is reassigned or destroyed. + +These `array` field leaks are not detectable with `RunGarbageCollector()`. The cycles can be viewed +in Perfetto, but any already-leaked cycles from this effect are not visible. + +The same problem also exists in `CallFunc()` - if the parameters or return value contain a cycle then this +will be irrecoverably leaked on each invocation. + +# Node Tree Operations + +## findNode() + +`roSGNode.findNode()` searches in two steps: first it looks up the id in a dictionary built from +all of the nodes constructed in the XML. This search is `O(logN)` in the number of nodes. +If the object is not found there, it then searches using a breadth-first search, which is +`O(N)` in the number of nodes in that subtree. + +💡 This search can become slow if used repeatedly on large trees of nodes. + +## appendChild() and removeChild() + +These operations are `O(N)` in the number of children, but still very fast (small tens of microseconds). +However, for renderable nodes, adding or removing a node will dirty the parent node. +Additionally, if there are observers on the parent node they will fire on every child addition +or removal - for an empty observer this will be in the region of an additional 25us-50us per addition +or removal on typical hardware. A large complex observer function on the parent +node could have quite a big impact. + +# Communication Between Threads + +## Rendezvous + +A [rendezvous](doc:threads#thread-rendezvous) is the mechanism used to synchronize between +task threads (and the SDK1 `main` thread) and the render thread. + +The task thread blocks waiting for the render thread to respond. Additionally, any SceneGraph objects +that are involved in the rendezvous become "owned" by the render thread. Thereafter all accesses +to that object and its child nodes by the task thread require a rendezvous. + +``` +' Task.brs + +sub runTask() + n = CreateObject("roSGNode", "MyContentNode") ' owned by task here + n.my_field = "hello" ' still owned by task, no blocking + m.top.some_field = n ' rendezvous - m.top is already owned by render thread + ' "n" is now owned by the render thread + ? n.my_field ' rendezvous - "n" now owned by render thread +end sub +``` + +### Where is the Rendezvous Imposed? + +The boundary where the rendezvous applies is the `roSGNode`. That is where the ownership +test takes place, and where the blocking takes place. + +An ordinary BrightScript array or AA does _not_ rendezvous. + +Because a rendezvous occurs on each access, and the accesses are not easily +visible in the syntax of your code, it can be easy to introduce performance +problems without realising. + +### Rendezvous Multiple Blocking Example + +This shows an example where a single line of code blocks twice on two +different `roSGNode` instances owned by the render thread. There is +no rendezvous blocking on the intermediate AA. + +``` +sub init() + ' + ' init runs on the render thread - no rendezvous here + ' + my_node = CreateObject("roSGNode", "ContentNode") + my_node.title = "Hello World" + m.top.aafield = {my_node: my_node} + + ' No rendezvous - all in the render thread + print m.top.aafield.my_node.title +end sub + +sub runTask() + ' Two rendezvous; m.top and my_node + print m.top.aafield.my_node.title +end sub +``` + +### Rendezvous Following Ownership Transfer + + +if the code inadvertently accesses a field after a +rendezvous has transferred over the ownership. This is an easy mistake to make as +it is not obvious from the code syntax that there is a performance problem. Consider +the following code - two identical statements that take very different amounts of time +following a rendezvous: + +``` +' MyTask.brs +sub RunTask() + data = get_my_content_node() ' Get a content node from somewhere + do_thing(data.foo) ' No problem, not a rendezvous, only cost is copying "foo" + + ' Rendezvous to render thread + m.top.data = data ' Rendezvous, data now owned by render thread + + do_thing(data.foo) ' Oops, this will also rendezvous! + + data = get_some_data() ' Get a new content node + do_thing(data.foo) ' No rendezvous, only a copy +end sub +``` + +The example above uses `m.top` which is always owned by the render thread, but it applies +to _any_ object owned by the render thread. + +### Rendezvous Overhead + +A single rendezvous costs in the order of 100us-200us on typical hardware (ignoring the cost of copying any field data). + +### Diagnosing Rendezvous Problems + +Tools you can use to diagnose rendezvous problems: + +- Perfetto +- The [`sgrendezvous`](doc:external-control-api) commands. +- Roku Resource Monitor + +## Observers + +### Observer Leaks + +When `observeField` and `observeFieldScopedEx` are called, this adds +a new observer even if an observer for the same field and callback already exists. It does _not_ replace an +existing observer watching on the same field name. + +Example: + +``` +m.top.observeFieldScopedEx("myfield", target) +m.top.observeFieldScopedEx("myfield", target) +``` + +The target will now be notified **twice** - the second call adds a new observer, it does not replace the +old one. This results in wasted CPU cycles due to duplicated observer notifications. There is +also a small amount of leaked memory. + +This can often happen with components that are repeatedly created and destroyed and observe a field +in their setup. + +Perfetto reports the number of observers in the system which can be used to diagnose this. + +#### Fixing Observer Leaks + +One way to fix this is to unobserve the field. Another way to fix such a leak is to choose +`observeField()` or `observeFieldScopedEx()` depending on the lifetime of the observing +and observed objects. + +- `node.observeField()` stores the observer in the observed object (`node`). +- `node.observeFieldScopedEx()` - stores the observer in the observing object, or in `m.global` +if being called from the SDK1/`main` thread. + +If the _observed_ object is being created and destroyed, then using `observeField()` will +ensure that the observer is automatically cleaned up when that observed object is +destroyed. + +Similarly, if the _observing_ object is being created and destroyed then +`observeFieldScopedEx()` is a better choice - otherwise the observed object will +have a dangling observer when the observer goes away, wasting memory and CPU cycles. + +Do not use `observeFieldScoped()` - it is retained for backward compatibility but does not +work properly, and stores the observer on the _observed_ field, like `observeField()`. + +See [ifSGNodeField](doc:ifsgnodefield). + +## `roMessagePort` + +See [roMessagePort](doc:romessageport) + +This will copy its data from the source field which could be a problem for large amounts of +data. If the data contains any SceneGraph nodes then the receiving task thread +could end up rendezvousing on every access to them since they will be owned by the +render thread. + +## `roRenderThreadQueue` + +This can be used by task threads and the SDK1/`main` thread to avoid blocking in +a rendezvous. It is useful for long-lived tasks that must periodically signal +the render thread and can do additional useful work if they are not blocked. + +See [roRenderThreadQueue](doc:rorenderthreadqueue) and [Data Transfer APIs](doc:data-transfer-apis). + +# BrightScript Compilation + +## Channel Store Compilation + +BrightScript channels are compiled off-line in the Channel Store before being +delivered to devices. This cuts down on startup time (seconds for a large +channel), and also reduces memory requirements. DCLs stored in the channel itself +are also compiled in the same way. + +This does _not_ happen for DCLs loaded from an external URL since the Channel Store does +not have access to the code. + +# Finding Performance Problems With Perfetto + +One way to find performance problems is with Perfetto. + +- [Capture a Perfetto timechart](doc:app-tracing) to visually see where the time is going. +- Use the [SQL query tool](doc:app-tracing#using-perfettosql-to-query-traces) to find the longest operations. +- Check the observer metrics for observer leaks. +- Add [custom tracepoints](doc:app-tracing#adding-custom-trace-data) around particular parts of the code by injecting Perfetto events from BrightScript. +- Use the [Perfetto heapgraph](doc:app-tracing#capturing-heap-graphs) to find large allocations - large amounts of data not only consume memory but they also take time to construct and destruct. +- Use the heapgraph in conjunction with post-processing tools to visualize cycles. + +This is described in more detail in [Perfetto](doc:app-tracing). + +# Performance Tips + +💡 Less is more - don't pass more data around than you need to - it will make your channel slower and use +more memory. If you can reduce the amount of JSON data sent by your server endpoints this can be an easy +way to improve both performance and memory use. + +💡 Try to read field values just once into a local variable rather than repeatedly copying from the same +field. + +💡 Try to avoid duplicating data in your fields inside long-lived members of `m` - they will be fast to +access but they still use memory. + +💡 Try to break up data structures - putting everything into a single field is convenient but can +result in unavoidable copying costs. + +💡 Watch out for accesses to a node in a task thread after it has been rendezvoused across to the render +thread - each access to that node and its children will now require a rendezvous. + +💡 Use Perfetto to find large or repeated copies, and repeated rendezvous operations. + +💡 Watch out for cycles. Use Perfetto to find them.