-
Notifications
You must be signed in to change notification settings - Fork 6.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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]>
- Loading branch information
Showing
4 changed files
with
173 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
cmake_minimum_required(VERSION 3.20.0) | ||
|
||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) | ||
project(instrumentation) | ||
|
||
target_sources(app PRIVATE src/main.c) |
36 changes: 36 additions & 0 deletions
36
samples/subsys/instrumentation/boards/b_u585i_iot02a.overlay
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
* Copyright 2023 Linaro | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <common/mem.h> | ||
|
||
/ { | ||
sram@200BF000 { | ||
compatible = "zephyr,memory-region", "mmio-sram"; | ||
reg = <0x200BF000 0x20>; | ||
zephyr,memory-region = "RetainedMem"; | ||
status = "okay"; | ||
|
||
retainedmem { | ||
compatible = "zephyr,retained-ram"; | ||
status = "okay"; | ||
#address-cells = <1>; | ||
#size-cells = <1>; | ||
|
||
retention0: retention@0 { | ||
compatible = "zephyr,retention"; | ||
status = "okay"; | ||
|
||
reg = <0x0 0x20>; | ||
|
||
prefix = [BE EF]; | ||
}; | ||
}; | ||
}; | ||
}; | ||
|
||
&sram0 { | ||
reg = <0x20000000 DT_SIZE_K(764)>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
CONFIG_INSTRUMENTATION=y | ||
CONFIG_MAIN_STACK_SIZE=4096 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
/* | ||
* Copyright 2023 Linaro | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <zephyr/kernel.h> | ||
#include <zephyr/instrumentation/instrumentation.h> | ||
|
||
/* | ||
* This sample shows the instrumentation subsystem tracing and profiling | ||
* features. It basically consists in two threads in a ping-pong mode, taking | ||
* turns to execute loops that spend some CPU cycles. | ||
* | ||
* After one flashes this sample to the target, it must be possible to | ||
* collect and visualize traces and profiling info using the instrumentation CLI | ||
* tool, zaru. Please _note_ that this subsystem uses the retained_mem driver, | ||
* hence it's necessary to add the proper devicetree overlay for the target | ||
* board (see './boards/b_u585i_iot02a.overlay' in this dir. as a reference). | ||
* | ||
* Example: | ||
* | ||
* $ export ZEPHYR_BASE=~/zephyrproject/zephyr | ||
* | ||
* $ west build -p always -b b_u585i_iot02a samples/subsys/instrumentation -t flash | ||
* (wait ~2 seconds so the sample finishes 2 rounds of ping-pong between 'main' | ||
* and 'thread_A') | ||
* | ||
* (check instrumentation status) | ||
* $ scripts/zaru.py status | ||
* | ||
* (set the tracing / profiling location; in this sample the function | ||
* 'get_sem_and_exec_function' is the one interesting to allow the observation | ||
* of context switches) | ||
* $ scripts/zaru.py trace -v -c get_sem_and_exec_function | ||
* | ||
* (reboot target so tracing/profiling at the location is effective) | ||
* $ scripts/zaru.py reboot | ||
* (wait ~2 seconds so the sample finishes 2 rounds of ping-pong between 'main' | ||
* and 'thread_A') | ||
* | ||
* (get traces) | ||
* $ scripts/zaru.py trace -v | ||
* | ||
* (.. and get profile) | ||
* $ scripts/zaru.py profile -v -n 10 | ||
* | ||
* Or alternatively, export the traces to Perfetto: | ||
* | ||
* (it's necessary to reboot because 'zaru.py trace' dumped the buffer and it's | ||
* now empty) | ||
* $ scripts/zaru.py reboot | ||
* (wait ~2 seconds so the sample finishes 2 rounds of ping-pong between 'main' | ||
* and 'thread_A') | ||
* | ||
* $ scripts/zaru.py trace -v --perfetto --output perfetto_zephyr.json | ||
* (then go to http://perfetto.dev, Trace Viewer, and load perfetto_zephyr.json) | ||
* | ||
*/ | ||
|
||
#define SLEEPTIME 10 | ||
#define STACKSIZE 1024 | ||
#define PRIORITY 7 | ||
|
||
void __no_optimization loop_0(void) | ||
{ | ||
/* Just loop to spend some cycles */ | ||
for (int i = 0; i < 1024; i++) { | ||
/* Empty */ | ||
}; | ||
} | ||
|
||
void __no_optimization loop_1(void) | ||
{ | ||
/* Just loop to spend some cycles */ | ||
for (int i = 0; i < 1024*512; i++) { | ||
/* Empty */ | ||
}; | ||
} | ||
|
||
/* | ||
* 'main' thread can take its mutex promptly and run. 'thread_A' needs to wait 'main' give its | ||
* (thread_A) mutex to run. | ||
*/ | ||
K_SEM_DEFINE(main_sem, 1, 1); /* Initialized as ready to be taken */ | ||
K_SEM_DEFINE(thread_a_sem, 0, 1); /* Initialized as already taken (blocked) */ | ||
|
||
K_THREAD_STACK_DEFINE(thread_a_stack, STACKSIZE); | ||
static struct k_thread thread_a_data; | ||
|
||
static int counter; | ||
|
||
void get_sem_and_exec_function(struct k_sem *my_sem, struct k_sem *other_sem, void (*func)(void)) | ||
{ | ||
while (counter < 4) { | ||
k_sem_take(my_sem, K_FOREVER); | ||
|
||
func(); | ||
k_msleep(SLEEPTIME); | ||
|
||
counter++; | ||
k_sem_give(other_sem); | ||
} | ||
} | ||
|
||
void thread_A(void *notused0, void *notused1, void *notused2) | ||
{ | ||
ARG_UNUSED(notused0); | ||
ARG_UNUSED(notused1); | ||
ARG_UNUSED(notused2); | ||
|
||
get_sem_and_exec_function(&thread_a_sem, &main_sem, loop_0); | ||
} | ||
|
||
int main(void) | ||
{ | ||
k_tid_t thread_a; | ||
|
||
/* Create Thread A */ | ||
thread_a = k_thread_create(&thread_a_data, thread_a_stack, STACKSIZE, thread_A, NULL, NULL, | ||
NULL, PRIORITY, 0, K_NO_WAIT); | ||
|
||
k_thread_name_set(thread_a, "thread_A"); | ||
|
||
/* Start ping-pong between 'main' and 'thread_A' */ | ||
get_sem_and_exec_function(&main_sem, &thread_a_sem, loop_1); | ||
} |