Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions utilities/perfetto-custom-events/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Perfetto Custom Events

This sample shows how to generate various custom Perfetto events from an app.

## Instantaneous Events

Instantaneous Events are the simplest. They have no duration, but can have additonal paramaters associated with them. In `main.brs` the app generates two of these events, one with parameters and one without.

```
' instantaneous events
tracer.instantEvent("instantaneous_event")
' instantaneous event with parameters
tracer.instantEvent("instantaneous_event_params", {p1: 42, p2: "hello world"})
```

## Duration Events

Duration events have a beginning and an end. In addition, you can nest them so that they appear as a stack in the Perfetto viewer. In `main.brs` the app generates a series of three nested duration events.

```
' duration events
tracer.beginEvent("duration_event")
sleep(500)
' events can be nested and will be shwon as a stack in the Perfetto viewer
tracer.beginEvent("duration_subevent_1")
sleep(500)
tracer.beginEvent("duration_subevent_2")
sleep(500)
' it is important that the number of endEvent() calls matches the number of beginEvent() calls
tracer.endEvent()
sleep(500)
tracer.endEvent()
tracer.endEvent()
```

# Scoped Events

Scoped events are similar to duration events, except that you do not end them explicitly. They end automatically when the returned object goes out of scope. In `main.brs` the app defines a function `DoScopedEvents()` that demonstrates this mechanism.

```
sub DoScopedEvent()
tracer = CreateObject("roPerfetto")
scoped_event = tracer.createScopedEvent("scoped_event")
sleep(500)
' the event will end automatically when scoped_event goes out of scope
end sub
```

## Flow Events

Flow events allow you to connect a series of events. In the Perfetto viewer they will be shown with arrows between them. In `MyTask.brs` the app generates a series of flow events starting in its `Init()` and continuing in `MyTaskFunction()`. Then, in `MyScene.brs` the app terminates the flow in the observer function `OnTaskDone()`

```
sub Init()
tracer = CreateObject("roPerfetto")
' flow id can be any integer value
' it is used to correlate flow events, so it's important to use the same id
' for all events that are part of the same flow
flow_id = 42
tracer.flowEvent(flow_id, "task_init")

m.top.functionName = "MyTaskFunction"
end sub

sub MyTaskFunction()
tracer = CreateObject("roPerfetto")
flow_id = 42 ' flow id must match the one used to start the flow
tracer.flowEvent(flow_id, "task_function")

sleep(50) ' simulate work being done

m.top.done = true
end sub
```
```
sub OnTaskDone()
tracer = CreateObject("roPerfetto")
flow_id = 42 ' flow id must match the one used to start the flow
tracer.terminateFlow(flow_id, "task_done")
end sub
```
13 changes: 13 additions & 0 deletions utilities/perfetto-custom-events/components/MyScene.brs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
' Copyright (c) 2025 Roku, Inc. All rights reserved.

sub Init()
my_task = m.top.FindNode("myTask")
my_task.ObserveField("done", "OnTaskDone")
my_task.control = "run"
end sub

sub OnTaskDone()
tracer = CreateObject("roPerfetto")
flow_id = 42 ' flow id must match the one used to start the flow
tracer.terminateFlow(flow_id, "task_done")
end sub
16 changes: 16 additions & 0 deletions utilities/perfetto-custom-events/components/MyScene.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version = "1.0" encoding = "utf-8" ?>
<!-- Copyright (c) 2025 Roku, Inc. All rights reserved. -->
<component name="MyScene" extends="Scene">
<children>
<myTask id="myTask" />
<Label
id="myLabel"
text="Perfetto Custom Events"
translation="[100, 100]"
width="600"
height="50"
/>
</children>

<script type="text/brightscript" uri="MyScene.brs" />
</component>
22 changes: 22 additions & 0 deletions utilities/perfetto-custom-events/components/MyTask.brs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
' Copyright (c) 2025 Roku, Inc. All rights reserved.

sub Init()
tracer = CreateObject("roPerfetto")
' flow id can be any integer value
' it is used to correlate flow events, so it's important to use the same id
' for all events that are part of the same flow
flow_id = 42
tracer.flowEvent(flow_id, "task_init")

m.top.functionName = "MyTaskFunction"
end sub

sub MyTaskFunction()
tracer = CreateObject("roPerfetto")
flow_id = 42 ' flow id must match the one used to start the flow
tracer.flowEvent(flow_id, "task_function")

sleep(50) ' simulate work being done

m.top.done = true
end sub
9 changes: 9 additions & 0 deletions utilities/perfetto-custom-events/components/MyTask.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version = "1.0" encoding = "utf-8" ?>
<!-- Copyright (c) 2025 Roku, Inc. All rights reserved. -->
<component name="MyTask" extends="Task">
<interface>
<field id="done" type="bool" value="false" />
</interface>

<script type="text/brightscript" uri="MyTask.brs" />
</component>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions utilities/perfetto-custom-events/manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
title=Sample - roPerfetto Custom Events
major_version=1
minor_version=0
build_version=1

mm_icon_focus_hd=pkg:/images/rde_mm_focus_hd.jpg
mm_icon_focus_sd=pkg:/images/rde_mm_focus_sd.jpg

splash_screen_sd=pkg:/images/rde_splash_sd.jpg
splash_screen_hd=pkg:/images/rsgde_splash_hd.jpg
splash_screen_fhd=pkg:/images/rde_splash_fhd.jpg

splash_color=#662D91
splash_min_time=1000

ui_resolutions=hd
rsg_version=1.2

run_as_process=1
50 changes: 50 additions & 0 deletions utilities/perfetto-custom-events/source/main.brs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
' Copyright (c) 2025 Roku, Inc. All rights reserved.

sub Main(args)
' you can reuse a single roPerfetto object to record multiple events
tracer = CreateObject("roPerfetto")

' instantaneous events
tracer.instantEvent("instantaneous_event")
' instantaneous event with parameters
tracer.instantEvent("instantaneous_event_params", {p1: 42, p2: "hello world"})

' duration events
tracer.beginEvent("duration_event")
sleep(500)
' events can be nested and will be shwon as a stack in the Perfetto viewer
tracer.beginEvent("duration_subevent_1")
sleep(500)
tracer.beginEvent("duration_subevent_2")
sleep(500)
' it is important that the number of endEvent() calls matches the number of beginEvent() calls
tracer.endEvent()
sleep(500)
tracer.endEvent()
tracer.endEvent()

' scoped events
DoScopedEvent()

screen = CreateObject("roSGScreen")
port = CreateObject("roMessagePort")
screen.setMessagePort(port)
scene = screen.CreateScene("MyScene")
screen.show()

while(true)
msg = wait(0, port)
msgType = type(msg)

if msgType = "roSGScreenEvent"
if msg.isScreenClosed() then return
end if
end while
end sub

sub DoScopedEvent()
tracer = CreateObject("roPerfetto")
scoped_event = tracer.createScopedEvent("scoped_event")
sleep(500)
' the event will end automatically when scoped_event goes out of scope
end sub