From 01981910ec2a3776ca5bb98ea5ffe8ff75e90db0 Mon Sep 17 00:00:00 2001 From: Rodrigo Peixoto Date: Sun, 10 Dec 2023 15:01:41 -0300 Subject: [PATCH] samples: zbus: add priority boost sample to zbus This sample illustrates how to properly use zbus priority boost feature. Signed-off-by: Rodrigo Peixoto --- .../subsys/zbus/priority_boost/CMakeLists.txt | 8 + samples/subsys/zbus/priority_boost/README.rst | 197 ++++++++++++++++++ samples/subsys/zbus/priority_boost/prj.conf | 6 + .../subsys/zbus/priority_boost/sample.yaml | 81 +++++++ samples/subsys/zbus/priority_boost/src/main.c | 148 +++++++++++++ .../with_hlp_priority_boost_feature.svg | 75 +++++++ .../without_hlp_priority_boost_feature.svg | 67 ++++++ ...us_publishing_process_example_scenario.svg | 35 ++++ 8 files changed, 617 insertions(+) create mode 100644 samples/subsys/zbus/priority_boost/CMakeLists.txt create mode 100644 samples/subsys/zbus/priority_boost/README.rst create mode 100644 samples/subsys/zbus/priority_boost/prj.conf create mode 100644 samples/subsys/zbus/priority_boost/sample.yaml create mode 100644 samples/subsys/zbus/priority_boost/src/main.c create mode 100644 samples/subsys/zbus/priority_boost/with_hlp_priority_boost_feature.svg create mode 100644 samples/subsys/zbus/priority_boost/without_hlp_priority_boost_feature.svg create mode 100644 samples/subsys/zbus/priority_boost/zbus_publishing_process_example_scenario.svg diff --git a/samples/subsys/zbus/priority_boost/CMakeLists.txt b/samples/subsys/zbus/priority_boost/CMakeLists.txt new file mode 100644 index 000000000000..f2d9b7273216 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/CMakeLists.txt @@ -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(priority_boost) + +file(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/subsys/zbus/priority_boost/README.rst b/samples/subsys/zbus/priority_boost/README.rst new file mode 100644 index 000000000000..ca903a7183c5 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/README.rst @@ -0,0 +1,197 @@ +.. zephyr:code-sample:: zbus-priority-boost + :name: zbus Priority Boost + :relevant-api: zbus_apis + + Illustrates zbus priority boost feature with a priority inversion scenario. + +Overview +******** +This sample implements a simple application that illustrates the priority boost feature. The +application implements the below figure scenario. When the priority boost feature is disabled, the +execution sequence presents a priority inversion problem, which may not affect much of the +developer's application. Those who want to avoid priority inversions between message subscribers and +plain subscribers should use the priority boost strategy. + +.. code-block:: c + + ZBUS_CHAN_DEFINE(chan_a, + int, + NULL, + NULL, + ZBUS_OBSERVERS(l1, ms1, ms2, s1, l2), + 0 + ); + + +.. figure:: zbus_publishing_process_example_scenario.svg + :alt: ZBus priority boost scenario example. + :width: 45% + +.. note:: + + The developer must use the :c:func:`zbus_obs_attach_to_thread` function to ensure a proper + priority boost execution. + + +Building and Running +******************** + +The figure below illustrates the execution of the cited scenario but with the priority boost +disabled. + +.. figure:: without_hlp_priority_boost_feature.svg + :alt: ZBus example scenario for priority boost disabled. + :width: 70% + + +It can be built and executed on QEMU as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/zbus/priority_boost -- -DCONFIG_ZBUS_PRIORITY_BOOST=n + :host-os: unix + :board: qemu_x86 + :goals: run + +Sample Output +============= + +.. code-block:: console + + I: -------------- + I: 0 -> T1: prio before 5 + I: 0 ---> L1: T1 prio 5 + I: 0 -> MS1: T1 prio 5 + I: 0 -> MS2: T1 prio 5 + I: 0 ---> L2: T1 prio 5 + I: 0 -> T1: prio after 5 + I: N -> S1: T1 prio 5 + I: 0 -> S1: T1 prio 5 + I: -------------- + I: 1 -> T1: prio before 5 + I: 1 ---> L1: T1 prio 5 + I: 1 -> MS1: T1 prio 5 + I: 1 -> MS2: T1 prio 5 + I: 1 ---> L2: T1 prio 5 + I: 1 -> T1: prio after 5 + I: N -> S1: T1 prio 5 + I: 1 -> S1: T1 prio 5 + I: -------------- + I: 2 -> T1: prio before 5 + I: 2 ---> L1: T1 prio 5 + I: 2 -> MS1: T1 prio 5 + I: 2 ---> L2: T1 prio 5 + I: 2 -> T1: prio after 5 + I: 2 -> MS2: T1 prio 5 + I: -------------- + I: 3 -> T1: prio before 5 + I: 3 ---> L1: T1 prio 5 + I: 3 -> MS1: T1 prio 5 + I: 3 ---> L2: T1 prio 5 + I: 3 -> T1: prio after 5 + I: 3 -> MS2: T1 prio 5 + I: -------------- + I: 4 -> T1: prio before 5 + I: 4 ---> L1: T1 prio 5 + I: 4 ---> L2: T1 prio 5 + I: 4 -> T1: prio after 5 + I: 4 -> MS2: T1 prio 5 + I: -------------- + I: 5 -> T1: prio before 5 + I: 5 ---> L1: T1 prio 5 + I: 5 ---> L2: T1 prio 5 + I: 5 -> T1: prio after 5 + I: 5 -> MS2: T1 prio 5 + I: -------------- + I: 6 -> T1: prio before 5 + I: 6 ---> L1: T1 prio 5 + I: 6 -> MS1: T1 prio 5 + I: 6 -> MS2: T1 prio 5 + I: 6 ---> L2: T1 prio 5 + I: 6 -> T1: prio after 5 + I: N -> S1: T1 prio 5 + I: 6 -> S1: T1 prio 5 + I: -------------- + + + +Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. + + +The figure below illustrates the execution of the same scenario but with the priority boost enabled. +The developer must enable the priority boost and properly attach all the observers to their threads. + +.. figure:: with_hlp_priority_boost_feature.svg + :alt: ZBus example scenario for priority boost enabled. + :width: 75% + +To execute the sample with priority boost feature enabled, run the following command: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/zbus/priority_boost -- -DCONFIG_ZBUS_PRIORITY_BOOST=y + :host-os: unix + :board: qemu_x86 + :goals: run + +Sample Output +============= + +.. code-block:: console + + I: -------------- + I: 0 -> T1: prio before 5 + I: 0 ---> L1: T1 prio 1 + I: 0 ---> L2: T1 prio 1 + I: N -> S1: T1 prio 5 + I: 0 -> S1: T1 prio 5 + I: 0 -> MS1: T1 prio 5 + I: 0 -> MS2: T1 prio 5 + I: 0 -> T1: prio after 5 + I: -------------- + I: 1 -> T1: prio before 5 + I: 1 ---> L1: T1 prio 1 + I: 1 ---> L2: T1 prio 1 + I: N -> S1: T1 prio 5 + I: 1 -> S1: T1 prio 5 + I: 1 -> MS1: T1 prio 5 + I: 1 -> MS2: T1 prio 5 + I: 1 -> T1: prio after 5 + I: -------------- + I: 2 -> T1: prio before 5 + I: 2 ---> L1: T1 prio 2 + I: 2 ---> L2: T1 prio 2 + I: 2 -> MS1: T1 prio 5 + I: 2 -> MS2: T1 prio 5 + I: 2 -> T1: prio after 5 + I: -------------- + I: 3 -> T1: prio before 5 + I: 3 ---> L1: T1 prio 2 + I: 3 ---> L2: T1 prio 2 + I: 3 -> MS1: T1 prio 5 + I: 3 -> MS2: T1 prio 5 + I: 3 -> T1: prio after 5 + I: -------------- + I: 4 -> T1: prio before 5 + I: 4 ---> L1: T1 prio 3 + I: 4 ---> L2: T1 prio 3 + I: 4 -> MS2: T1 prio 5 + I: 4 -> T1: prio after 5 + I: -------------- + I: 5 -> T1: prio before 5 + I: 5 ---> L1: T1 prio 3 + I: 5 ---> L2: T1 prio 3 + I: 5 -> MS2: T1 prio 5 + I: 5 -> T1: prio after 5 + I: -------------- + I: 6 -> T1: prio before 5 + I: 6 ---> L1: T1 prio 1 + I: 6 ---> L2: T1 prio 1 + I: N -> S1: T1 prio 5 + I: 6 -> S1: T1 prio 5 + I: 6 -> MS1: T1 prio 5 + I: 6 -> MS2: T1 prio 5 + I: 6 -> T1: prio after 5 + I: -------------- + + + +Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. diff --git a/samples/subsys/zbus/priority_boost/prj.conf b/samples/subsys/zbus/priority_boost/prj.conf new file mode 100644 index 000000000000..67af0befda1a --- /dev/null +++ b/samples/subsys/zbus/priority_boost/prj.conf @@ -0,0 +1,6 @@ +CONFIG_LOG=y +CONFIG_LOG_MODE_MINIMAL=y +CONFIG_ZBUS_LOG_LEVEL_INF=y +CONFIG_ZBUS=y +CONFIG_ZBUS_MSG_SUBSCRIBER=y +CONFIG_HEAP_MEM_POOL_SIZE=1024 diff --git a/samples/subsys/zbus/priority_boost/sample.yaml b/samples/subsys/zbus/priority_boost/sample.yaml new file mode 100644 index 000000000000..5bbdc7720302 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/sample.yaml @@ -0,0 +1,81 @@ +sample: + name: Priority boost +tests: + sample.zbus.non_priority_boost: + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "I: 0 -> T1: prio before 5" + - "I: 0 ---> L1: T1 prio 5" + - "I: 0 ---> L2: T1 prio 5" + - "I: 0 -> T1: prio after 5" + - "I: 1 -> T1: prio before 5" + - "I: 1 ---> L1: T1 prio 5" + - "I: 1 ---> L2: T1 prio 5" + - "I: 1 -> T1: prio after 5" + - "I: 2 -> T1: prio before 5" + - "I: 2 ---> L1: T1 prio 5" + - "I: 2 ---> L2: T1 prio 5" + - "I: 2 -> T1: prio after 5" + - "I: 3 -> T1: prio before 5" + - "I: 3 ---> L1: T1 prio 5" + - "I: 3 ---> L2: T1 prio 5" + - "I: 3 -> T1: prio after 5" + - "I: 4 -> T1: prio before 5" + - "I: 4 ---> L1: T1 prio 5" + - "I: 4 ---> L2: T1 prio 5" + - "I: 4 -> T1: prio after 5" + - "I: 5 -> T1: prio before 5" + - "I: 5 ---> L1: T1 prio 5" + - "I: 5 ---> L2: T1 prio 5" + - "I: 5 -> T1: prio after 5" + - "I: 6 -> T1: prio before 5" + - "I: 6 ---> L1: T1 prio 5" + - "I: 6 ---> L2: T1 prio 5" + - "I: 6 -> T1: prio after 5" + extra_configs: + - CONFIG_ZBUS_PRIORITY_BOOST=n + tags: zbus + integration_platforms: + - qemu_x86 + sample.zbus.priority_boost: + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "I: 0 -> T1: prio before 5" + - "I: 0 ---> L1: T1 prio 1" + - "I: 0 ---> L2: T1 prio 1" + - "I: 0 -> T1: prio after 5" + - "I: 1 -> T1: prio before 5" + - "I: 1 ---> L1: T1 prio 1" + - "I: 1 ---> L2: T1 prio 1" + - "I: 1 -> T1: prio after 5" + - "I: 2 -> T1: prio before 5" + - "I: 2 ---> L1: T1 prio 2" + - "I: 2 ---> L2: T1 prio 2" + - "I: 2 -> T1: prio after 5" + - "I: 3 -> T1: prio before 5" + - "I: 3 ---> L1: T1 prio 2" + - "I: 3 ---> L2: T1 prio 2" + - "I: 3 -> T1: prio after 5" + - "I: 4 -> T1: prio before 5" + - "I: 4 ---> L1: T1 prio 3" + - "I: 4 ---> L2: T1 prio 3" + - "I: 4 -> T1: prio after 5" + - "I: 5 -> T1: prio before 5" + - "I: 5 ---> L1: T1 prio 3" + - "I: 5 ---> L2: T1 prio 3" + - "I: 5 -> T1: prio after 5" + - "I: 6 -> T1: prio before 5" + - "I: 6 ---> L1: T1 prio 1" + - "I: 6 ---> L2: T1 prio 1" + - "I: 6 -> T1: prio after 5" + extra_configs: + - CONFIG_ZBUS_PRIORITY_BOOST=y + tags: zbus + integration_platforms: + - qemu_x86 diff --git a/samples/subsys/zbus/priority_boost/src/main.c b/samples/subsys/zbus/priority_boost/src/main.c new file mode 100644 index 000000000000..b54a44468c28 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/src/main.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2023 Rodrigo Peixoto + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +LOG_MODULE_DECLARE(zbus, CONFIG_ZBUS_LOG_LEVEL); + +ZBUS_CHAN_DEFINE(chan_a, int, NULL, NULL, ZBUS_OBSERVERS(l1, ms1, ms2, s1, l2), 0); + +static void t1_thread(void *ptr1, void *ptr2, void *ptr3); +K_THREAD_DEFINE(t1_id, CONFIG_MAIN_STACK_SIZE, t1_thread, NULL, NULL, NULL, 5, 0, 0); + +ZBUS_SUBSCRIBER_DEFINE(s1, 4); +static void s1_thread(void *ptr1, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + int err; + int a = 0; + const struct zbus_channel *chan; + + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, (zbus_obs_attach_to_thread(&s1);)); + + while (1) { + err = zbus_sub_wait(&s1, &chan, K_FOREVER); + if (err) { + return; + } + + /* Faking some workload */ + k_busy_wait(200000); + + LOG_INF("N -> S1: T1 prio %d", k_thread_priority_get(t1_id)); + + err = zbus_chan_read(chan, &a, K_FOREVER); + if (err) { + return; + } + LOG_INF("%d -> S1: T1 prio %d", a, k_thread_priority_get(t1_id)); + } +} +K_THREAD_DEFINE(s1_id, CONFIG_MAIN_STACK_SIZE, s1_thread, NULL, NULL, NULL, 2, 0, 0); + +ZBUS_MSG_SUBSCRIBER_DEFINE(ms1); +static void ms1_thread(void *ptr1, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + int err; + const struct zbus_channel *chan; + int a = 0; + + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, (zbus_obs_attach_to_thread(&ms1);)); + + while (1) { + err = zbus_sub_wait_msg(&ms1, &chan, &a, K_FOREVER); + if (err) { + return; + } + + /* Faking some workload */ + k_busy_wait(200000); + + LOG_INF("%d -> MS1: T1 prio %d", a, k_thread_priority_get(t1_id)); + } +} +K_THREAD_DEFINE(ms1_id, CONFIG_MAIN_STACK_SIZE, ms1_thread, NULL, NULL, NULL, 3, 0, 0); + +ZBUS_MSG_SUBSCRIBER_DEFINE(ms2); +static void ms2_thread(void *ptr1, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + int err; + const struct zbus_channel *chan; + int a = 0; + + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, (zbus_obs_attach_to_thread(&ms2);)); + + while (1) { + err = zbus_sub_wait_msg(&ms2, &chan, &a, K_FOREVER); + if (err) { + return; + } + + /* Faking some workload */ + k_busy_wait(200 * USEC_PER_MSEC); + + LOG_INF("%d -> MS2: T1 prio %d", a, k_thread_priority_get(t1_id)); + } +} +K_THREAD_DEFINE(ms2_id, CONFIG_MAIN_STACK_SIZE, ms2_thread, NULL, NULL, NULL, 4, 0, 0); + +static void l1_callback(const struct zbus_channel *chan) +{ + LOG_INF("%d ---> L1: T1 prio %d", *((int *)zbus_chan_const_msg(chan)), + k_thread_priority_get(t1_id)); +} +ZBUS_LISTENER_DEFINE(l1, l1_callback); + +static void l2_callback(const struct zbus_channel *chan) +{ + LOG_INF("%d ---> L2: T1 prio %d", *((int *)zbus_chan_const_msg(chan)), + k_thread_priority_get(t1_id)); +} +ZBUS_LISTENER_DEFINE(l2, l2_callback); + +static void t1_thread(void *ptr1, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + int err; + int a = 0; + + while (1) { + LOG_INF("--------------"); + + if (a == 2) { + zbus_obs_set_enable(&s1, false); + } else if (a == 4) { + zbus_obs_set_enable(&ms1, false); + } else if (a == 6) { + zbus_obs_set_enable(&s1, true); + zbus_obs_set_enable(&ms1, true); + } + + LOG_INF("%d -> T1: prio before %d", a, k_thread_priority_get(k_current_get())); + err = zbus_chan_pub(&chan_a, &a, K_FOREVER); + if (err) { + return; + } + LOG_INF("%d -> T1: prio after %d", a, k_thread_priority_get(k_current_get())); + ++a; + + k_msleep(2000); + } +} diff --git a/samples/subsys/zbus/priority_boost/with_hlp_priority_boost_feature.svg b/samples/subsys/zbus/priority_boost/with_hlp_priority_boost_feature.svg new file mode 100644 index 000000000000..e1c58da9b289 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/with_hlp_priority_boost_feature.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/subsys/zbus/priority_boost/without_hlp_priority_boost_feature.svg b/samples/subsys/zbus/priority_boost/without_hlp_priority_boost_feature.svg new file mode 100644 index 000000000000..c912344567a2 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/without_hlp_priority_boost_feature.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/subsys/zbus/priority_boost/zbus_publishing_process_example_scenario.svg b/samples/subsys/zbus/priority_boost/zbus_publishing_process_example_scenario.svg new file mode 100644 index 000000000000..bf2df426e3ab --- /dev/null +++ b/samples/subsys/zbus/priority_boost/zbus_publishing_process_example_scenario.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +