Skip to content

Commit 5d02fac

Browse files
gromeronashif
authored andcommitted
samples: instrumentation: Add a sample for instrumentation subsys
Adds a sample to show the tracing and profiling features when the instrumentation subsystem is enabled (CONFIG_INSTRUMENTATION=y). The sample consists in two threads in ping-pong mode, taking turns to execute loops that spend some CPU cycles. This allows a couple of context switches and so to demonstrate tracing of thread scheduling events. The sample also has an example on how to capture and show traces and profile info via the CLI tool zaru and also how to export the traces so they can be loaded in the Perfetto Trace Viewer tool. Signed-off-by: Gustavo Romero <[email protected]> Signed-off-by: Kevin Townsend <[email protected]> Signed-off-by: Maciej Sobkowski <[email protected]>
1 parent 9f402bd commit 5d02fac

File tree

6 files changed

+256
-0
lines changed

6 files changed

+256
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
5+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
6+
project(instrumentation)
7+
8+
target_sources(app PRIVATE src/main.c)
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
.. zephyr:code-sample:: instrumentation
2+
:name: Instrumentation
3+
4+
Demonstrate the instrumentation subsystem tracing and profiling features.
5+
6+
Overview
7+
********
8+
9+
This sample shows the instrumentation subsystem tracing and profiling
10+
features. It basically consists of two threads in a ping-pong mode, taking
11+
turns to execute loops that spend some CPU cycles.
12+
13+
Requirements
14+
************
15+
16+
A Linux host and a UART console is required to run this sample.
17+
18+
Building and Running
19+
********************
20+
21+
Build and flash the sample as follows, changing ``mps2/an385`` for your
22+
board.
23+
24+
.. zephyr-app-commands::
25+
:zephyr-app: samples/subsys/instrumentation
26+
:host-os: unix
27+
:board: mps2/an385
28+
:goals: build flash
29+
:compact:
30+
31+
Alternatively you can run this using QEMU:
32+
33+
.. zephyr-app-commands::
34+
:zephyr-app: samples/subsys/instrumentation
35+
:host-os: unix
36+
:board: mps2/an385
37+
:goals: run
38+
:gen-args: '-DQEMU_SOCKET=y'
39+
:compact:
40+
41+
After the sample is flashed to the target (or QEMU is running), it must be possible to
42+
collect and visualize traces and profiling info using the instrumentation CLI
43+
tool, :zephyr_file:`scripts/zaru.py`.
44+
45+
.. note::
46+
Please note, that this subsystem uses the ``retained_mem`` driver, hence it's necessary
47+
to add the proper devicetree overlay for the target board. See
48+
:zephyr_file:`./samples/subsys/instrumentation/boards/mps2_an385.overlay` for an example.
49+
50+
Connect the board's UART port to the host device and
51+
run the :zephyr_file:`scripts/zaru.py` script on the host.
52+
53+
Source the :zephyr_file:`zephyr-env.sh` file to set the ``ZEPHYR_BASE`` variable and get
54+
:zephyr_file:`scripts/zaru.py` in your PATH:
55+
56+
.. code-block:: console
57+
58+
. zephyr-env.sh
59+
60+
Check instrumentation status:
61+
62+
.. code-block:: console
63+
64+
zaru.py status
65+
66+
Set the tracing/profiling trigger; in this sample the function
67+
``get_sem_and_exec_function`` is the one interesting to allow the observation
68+
of context switches:
69+
70+
.. code-block:: console
71+
72+
zaru.py trace -v -c get_sem_and_exec_function
73+
74+
Reboot target so tracing/profiling at the location is effective:
75+
76+
.. code-block:: console
77+
78+
zaru.py reboot
79+
80+
Wait ~2 seconds so the sample finishes 2 rounds of ping-pong between ``main``
81+
and ``thread_A``, and get the traces:
82+
83+
.. code-block:: console
84+
85+
zaru.py trace -v
86+
87+
Get the profile:
88+
89+
.. code-block:: console
90+
91+
zaru.py profile -v -n 10
92+
93+
Or alternatively, export the traces to Perfetto (it's necessary
94+
to reboot because ``zaru.py trace`` dumped the buffer and it's now empty):
95+
96+
.. code-block:: console
97+
98+
zaru.py reboot
99+
zaru.py trace -v --perfetto --output perfetto_zephyr.json
100+
101+
Then, go to http://perfetto.dev, Trace Viewer, and load ``perfetto_zephyr.json``.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2023 Linaro
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <common/mem.h>
8+
9+
/ {
10+
sram@200bf000 {
11+
compatible = "zephyr,memory-region", "mmio-sram";
12+
reg = <0x200bf000 0x20>;
13+
zephyr,memory-region = "RetainedMem";
14+
status = "okay";
15+
16+
retainedmem {
17+
compatible = "zephyr,retained-ram";
18+
status = "okay";
19+
#address-cells = <1>;
20+
#size-cells = <1>;
21+
22+
instrumentation_triggers: retention@0 {
23+
compatible = "zephyr,retention";
24+
status = "okay";
25+
26+
reg = <0x0 0x20>;
27+
28+
prefix = [be ef];
29+
};
30+
};
31+
};
32+
};
33+
34+
&sram0 {
35+
reg = <0x20000000 DT_SIZE_K(764)>;
36+
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2023 Linaro
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/ {
8+
sram@203fffe0 {
9+
compatible = "zephyr,memory-region", "mmio-sram";
10+
reg = <0x203fffe0 0x20>;
11+
zephyr,memory-region = "RetainedMem";
12+
status = "okay";
13+
14+
retainedmem {
15+
compatible = "zephyr,retained-ram";
16+
status = "okay";
17+
#address-cells = <1>;
18+
#size-cells = <1>;
19+
20+
instrumentation_triggers: retention@0 {
21+
compatible = "zephyr,retention";
22+
status = "okay";
23+
24+
reg = <0x0 0x20>;
25+
26+
prefix = [be ef];
27+
};
28+
};
29+
};
30+
};
31+
32+
&sram0 {
33+
reg = <0x20000000 0x3FFFE0>;
34+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CONFIG_INSTRUMENTATION=y
2+
CONFIG_MAIN_STACK_SIZE=4096
3+
CONFIG_TIMESLICE_SIZE=0
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2023 Linaro
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/instrumentation/instrumentation.h>
9+
10+
#define SLEEPTIME 10
11+
#define STACKSIZE 1024
12+
#define PRIORITY 7
13+
14+
void __no_optimization loop_0(void)
15+
{
16+
/* Wait to spend some cycles */
17+
k_busy_wait(10);
18+
}
19+
20+
void __no_optimization loop_1(void)
21+
{
22+
/* Wait to spend some cycles */
23+
k_busy_wait(1000);
24+
}
25+
26+
/*
27+
* 'main' thread can take its mutex promptly and run. 'thread_A' needs to wait 'main' give its
28+
* (thread_A) mutex to run.
29+
*/
30+
K_SEM_DEFINE(main_sem, 1, 1); /* Initialized as ready to be taken */
31+
K_SEM_DEFINE(thread_a_sem, 0, 1); /* Initialized as already taken (blocked) */
32+
33+
K_THREAD_STACK_DEFINE(thread_a_stack, STACKSIZE);
34+
static struct k_thread thread_a_data;
35+
36+
static int counter;
37+
38+
void get_sem_and_exec_function(struct k_sem *my_sem, struct k_sem *other_sem, void (*func)(void))
39+
{
40+
while (counter < 4) {
41+
k_sem_take(my_sem, K_FOREVER);
42+
43+
func();
44+
k_msleep(SLEEPTIME);
45+
46+
counter++;
47+
k_sem_give(other_sem);
48+
}
49+
}
50+
51+
void thread_A(void *notused0, void *notused1, void *notused2)
52+
{
53+
ARG_UNUSED(notused0);
54+
ARG_UNUSED(notused1);
55+
ARG_UNUSED(notused2);
56+
57+
get_sem_and_exec_function(&thread_a_sem, &main_sem, loop_0);
58+
}
59+
60+
int main(void)
61+
{
62+
k_tid_t thread_a;
63+
64+
/* Create Thread A */
65+
thread_a = k_thread_create(&thread_a_data, thread_a_stack, STACKSIZE,
66+
thread_A, NULL, NULL, NULL, PRIORITY, 0, K_NO_WAIT);
67+
68+
k_thread_name_set(thread_a, "thread_A");
69+
70+
/* Start ping-pong between 'main' and 'thread_A' */
71+
get_sem_and_exec_function(&main_sem, &thread_a_sem, loop_1);
72+
73+
return 0;
74+
}

0 commit comments

Comments
 (0)