Skip to content
Draft
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
5 changes: 5 additions & 0 deletions Filelists.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/admin/cmake")
option(BUILD_UNIT_TESTS "Build unit tests" OFF)

option(BUILD_TRACING "Build CTF tracing" OFF)
option(BUILD_BENCHMARK "Build benchmark mode" OFF)

add_compile_options(
"$<$<COMPILE_LANG_AND_ID:CXX,Clang,GNU>:-O2;-g3;-Werror;-Wall;-Wextra;-Wvla;-Wno-deprecated-volatile>"
Expand All @@ -41,6 +42,10 @@ add_compile_options(

add_link_options(-Wl,--noinhibit-exec)

if (BUILD_BENCHMARK)
add_compile_definitions(BENCHMARK=1)
endif ()

if (BUILD_UNIT_TESTS)
add_compile_definitions(UNIT_TEST=1)
include(GoogleTest)
Expand Down
26 changes: 26 additions & 0 deletions doc/learning/benchmark/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.. _learning_benchmark:

Benchmark mode
==============

Previous: :ref:`learning_tracing`

The reference app can be built to run benchmark tests. There is a BenchmarkSystem class that
implements the following tests:

* interrupt latency test - to measure the time between raising the interrupt line and entering the ISR
* task switch latency test - to measure the time between an async runnable setting an event
and another (woken up) runnable starting execution
* task switch after timeout latency test - to measure the time between scheduling an async runnable
and its start of execution (woken up by a timer)
* load test - record CPU idle time during cyclic artificial load across various tasks

Use the following command to build the reference app in benchmark mode for the S32K148EVB:

.. code-block:: bash

cmake -B cmake-build-s32k148-benchmark -S executables/referenceApp -DBUILD_TARGET_PLATFORM="S32K148EVB" \
-DBUILD_BENCHMARK=ON --toolchain ../../admin/cmake/ArmNoneEabi-gcc.cmake
cmake --build cmake-build-s32k148-benchmark --target app.referenceApp -j

When started, the application runs benchmark tests and prints out measurement results on the console.
1 change: 1 addition & 0 deletions doc/learning/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ Some simple lessons to get new users up and running.
uds/index
hwio/index
tracing/index
benchmark/index
7 changes: 7 additions & 0 deletions executables/referenceApp/application/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ add_executable(
${app.referenceAppExtraSources}
src/main.cpp)

if (BUILD_BENCHMARK)
if (BUILD_TARGET_PLATFORM STREQUAL "POSIX")
message(FATAL_ERROR "Benchmarking not supported on POSIX")
endif ()
target_sources(app.referenceApp PRIVATE src/systems/BenchmarkSystem.cpp)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we maybe add a check here that prevents the benchmarking build on Posix? This might be slightly out of place, but currently it will fail due to a compiler error which is also not good. So you could just add:
if (BUILD_TARGET_PLATFORM STREQUAL "POSIX") message(FATAL_ERROR "Benchmarking not supported on POSIX") endif ()

endif ()

set_target_properties(app.referenceApp PROPERTIES SUFFIX ".elf")

if (TARGET startUp)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright 2024 Accenture.

#pragma once

#include "util/logger/Logger.h"

DECLARE_LOGGER_COMPONENT(BENCH)
149 changes: 149 additions & 0 deletions executables/referenceApp/application/include/systems/BenchmarkSystem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Copyright 2024 Accenture.

#pragma once

#include "app/BenchmarkLogger.h"

#include <async/AsyncBinding.h>
#include <async/FutureSupport.h>
#include <console/AsyncCommandWrapper.h>
#include <lifecycle/AsyncLifecycleComponent.h>
#include <lifecycle/console/LifecycleControlCommand.h>
#include <mcu/mcu.h>
#include <runtime/StatisticsContainer.h>

using ::util::logger::BENCH;
using ::util::logger::Logger;

namespace systems
{
class BenchmarkSystem
: public ::lifecycle::AsyncLifecycleComponent
, private ::async::IRunnable
{
public:
explicit BenchmarkSystem(
::async::ContextType context, ::async::AsyncBinding::RuntimeMonitorType& runtimeMonitor);

BenchmarkSystem(BenchmarkSystem const&) = delete;
BenchmarkSystem& operator=(BenchmarkSystem const&) = delete;

void init() override;
void run() override;
void shutdown() override;

void cyclic();

private:
void execute() override;

uint32_t getPercentage(uint64_t value, uint64_t total);
void startTaskSwitchLatencyTest();
void handleTaskSwitchLatencyTest();
void startTaskSwitchAfterTimeoutLatencyTest();
void handleTaskSwitchAfterTimeoutLatencyTest();
void startInterruptLatencyTest();
void handleInterruptLatencyTest();
void startLoadTest();
void handleLoadTest();
uint32_t calculateTimeDifference(uint32_t start, uint32_t end);

private:
using TaskStatistics = ::runtime::declare::StatisticsContainer<
::runtime::RuntimeStatistics,
::async::AsyncBindingType::AdapterType::FREERTOS_TASK_COUNT>;

class EventWaiterRunnable : public ::async::IRunnable
{
public:
explicit EventWaiterRunnable(::async::FutureSupport& future, uint32_t& latencyEnd)
: _future(future), _timestamp(latencyEnd)
{}

void execute() override
{
_future.wait();
_timestamp = DWT->CYCCNT; /* HW cycle counter */
}

private:
::async::FutureSupport& _future;
uint32_t& _timestamp;
};

class EventSetterRunnable : public ::async::IRunnable
{
public:
explicit EventSetterRunnable(::async::FutureSupport& future, uint32_t& latencyStart)
: _future(future), _timestamp(latencyStart)
{}

void execute() override
{
_timestamp = DWT->CYCCNT;
_future.notify();
}

private:
::async::FutureSupport& _future;
uint32_t& _timestamp;
};

class TimoutWaiterRunnable : public ::async::IRunnable
{
public:
explicit TimoutWaiterRunnable(uint32_t& latencyEnd) : _timestamp(latencyEnd) {}

void execute() override { _timestamp = DWT->CYCCNT; }

private:
uint32_t& _timestamp;
};

class LoadRunnable : public ::async::IRunnable
{
public:
explicit LoadRunnable(uint32_t limit) : _limit(limit) {}

void execute() override
{
uint32_t volatile counter = 0;
while (counter++ < _limit) {}
}

private:
uint32_t _limit;
};
friend class EventWaiterRunnable;
friend class EventSetterRunnable;
friend class TimoutWaiterRunnable;
::async::ContextType const _context;
uint32_t _taskSwitchLatencyStart;
uint32_t _taskSwitchLatencyEnd;
uint32_t _taskSwitchAfterTimeoutLatencyStart;
uint32_t _taskSwitchAfterTimeoutLatencyEnd;
::async::TimeoutType _timeout;
::async::TimeoutType _taskSwitchTimeout;
::async::TimeoutType _sysadminTimeout;
::async::TimeoutType _canTimeout;
::async::TimeoutType _demoTimeout;
::async::TimeoutType _udsTimeout;
::async::TimeoutType _bgTimeout;
::async::FutureSupport _future;
EventWaiterRunnable _eventWaiterRunnable;
EventSetterRunnable _eventSetterRunnable;
TimoutWaiterRunnable _timeoutWaiterRunnable;
LoadRunnable _sysadminLoadRunnable;
LoadRunnable _canLoadRunnable;
LoadRunnable _demoLoadRunnable;
LoadRunnable _udsLoadRunnable;
LoadRunnable _bgLoadRunnable;
bool _taskSwitchLatencyTestRunning;
bool _taskSwitchAfterTimeoutLatencyTestRunning;
bool _interruptLatencyTestRunning;
bool _loadTestRunning;
bool _runtimeMonitorRunning;
::async::AsyncBinding::RuntimeMonitorType& _runtimeMonitor;
};

} // namespace systems
20 changes: 19 additions & 1 deletion executables/referenceApp/application/src/app/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#include "logger/logger.h"
#include "reset/softwareSystemReset.h"
#include "systems/DemoSystem.h"
#ifdef BENCHMARK
#include "systems/BenchmarkSystem.h"
#endif
#include "systems/RuntimeSystem.h"
#include "systems/SafetySystem.h"
#include "systems/SysAdminSystem.h"
Expand Down Expand Up @@ -73,9 +76,13 @@ LifecycleManager lifecycleManager{
TASK_SYSADMIN,
::lifecycle::LifecycleManager::GetTimestampType::create<&getSystemTimeUs32Bit>()};

#ifdef BENCHMARK
::estd::typed_mem<::systems::BenchmarkSystem> benchmarkSystem;
#else
::estd::typed_mem<::systems::RuntimeSystem> runtimeSystem;
::estd::typed_mem<::systems::SysAdminSystem> sysAdminSystem;
::estd::typed_mem<::systems::DemoSystem> demoSystem;
#endif
::estd::typed_mem<::systems::SysAdminSystem> sysAdminSystem;
::estd::typed_mem<::systems::SafetySystem> safetySystem;

#ifdef PLATFORM_SUPPORT_UDS
Expand Down Expand Up @@ -142,8 +149,10 @@ void run()

/* runlevel 1 */
::platform::platformLifecycleAdd(lifecycleManager, 1U);
#ifndef BENCHMARK
lifecycleManager.addComponent(
"runtime", runtimeSystem.emplace(TASK_BACKGROUND, runtimeMonitor), 1U);
#endif
lifecycleManager.addComponent(
"safety", safetySystem.emplace(TASK_SAFETY, lifecycleManager), 1U);
/* runlevel 2 */
Expand Down Expand Up @@ -175,6 +184,7 @@ void run()

/* runlevel 8 */
::platform::platformLifecycleAdd(lifecycleManager, 8U);
#ifndef BENCHMARK
lifecycleManager.addComponent(
"demo",
demoSystem.emplace(
Expand All @@ -186,10 +196,16 @@ void run()
#endif
),
8U);
#else
lifecycleManager.addComponent(
"benchmark", benchmarkSystem.emplace(TASK_DEMO, runtimeMonitor), 8U);
#endif

lifecycleManager.transitionToLevel(MaxNumLevels);

#ifndef BENCHMARK
runtimeMonitor.start();
#endif
AsyncAdapter::run();

while (true)
Expand All @@ -201,8 +217,10 @@ void run()
void idle(AsyncAdapter::TaskContextType& taskContext)
{
taskContext.dispatchWhileWork();
#ifndef BENCHMARK
::logger::run();
::console::run();
#endif
if (lifecycleMonitor.isReadyForReset())
{
staticShutdown();
Expand Down
18 changes: 18 additions & 0 deletions executables/referenceApp/application/src/logger/logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
DEFINE_LOGGER_COMPONENT(BSP);
DEFINE_LOGGER_COMPONENT(COMMON);
DEFINE_LOGGER_COMPONENT(DEMO);
DEFINE_LOGGER_COMPONENT(BENCH);
DEFINE_LOGGER_COMPONENT(GLOBAL);
DEFINE_LOGGER_COMPONENT(SAFETY);
DEFINE_LOGGER_COMPONENT(UDS);
Expand All @@ -33,6 +34,7 @@ DEFINE_LOGGER_COMPONENT(UDS);

START_LOGGER_COMPONENT_MAPPING_INFO_TABLE(loggerComponentInfoTable)
/* start: adding logger components */
#ifndef BENCHMARK
LOGGER_COMPONENT_MAPPING_INFO(_DEBUG, BSP, ::util::format::Color::DEFAULT_COLOR)
LOGGER_COMPONENT_MAPPING_INFO(_DEBUG, COMMON, ::util::format::Color::DEFAULT_COLOR)
LOGGER_COMPONENT_MAPPING_INFO(_DEBUG, DEMO, ::util::format::Color::DEFAULT_COLOR)
Expand All @@ -48,6 +50,22 @@ LOGGER_COMPONENT_MAPPING_INFO(_DEBUG, DOCAN, ::util::format::Color::LIGHT_GRAY)
LOGGER_COMPONENT_MAPPING_INFO(_DEBUG, UDS, ::util::format::Color::LIGHT_YELLOW)
LOGGER_COMPONENT_MAPPING_INFO(_DEBUG, TPROUTER, ::util::format::Color::LIGHT_YELLOW)
#endif // PLATFORM_SUPPORT_UDS
#else
LOGGER_COMPONENT_MAPPING_INFO(_WARN, BSP, ::util::format::Color::DEFAULT_COLOR)
LOGGER_COMPONENT_MAPPING_INFO(_WARN, COMMON, ::util::format::Color::DEFAULT_COLOR)
LOGGER_COMPONENT_MAPPING_INFO(_INFO, BENCH, ::util::format::Color::DEFAULT_COLOR)
LOGGER_COMPONENT_MAPPING_INFO(_INFO, GLOBAL, ::util::format::Color::DEFAULT_COLOR)
LOGGER_COMPONENT_MAPPING_INFO(_WARN, LIFECYCLE, ::util::format::Color::DARK_GRAY)
LOGGER_COMPONENT_MAPPING_INFO(_WARN, CONSOLE, ::util::format::Color::DEFAULT_COLOR)
#ifdef PLATFORM_SUPPORT_CAN
LOGGER_COMPONENT_MAPPING_INFO(_WARN, CAN, ::util::format::Color::LIGHT_BLUE)
LOGGER_COMPONENT_MAPPING_INFO(_WARN, DOCAN, ::util::format::Color::LIGHT_GRAY)
#endif // PLATFORM_SUPPORT_CAN
#ifdef PLATFORM_SUPPORT_UDS
LOGGER_COMPONENT_MAPPING_INFO(_WARN, UDS, ::util::format::Color::LIGHT_YELLOW)
LOGGER_COMPONENT_MAPPING_INFO(_WARN, TPROUTER, ::util::format::Color::LIGHT_YELLOW)
#endif // PLATFORM_SUPPORT_UDS
#endif
/* end: adding logger components */
END_LOGGER_COMPONENT_MAPPING_INFO_TABLE();

Expand Down
Loading
Loading