Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BenchmarkSystem that implements benchmarking #52

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
6 changes: 6 additions & 0 deletions Filelists.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,19 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/admin/cmake")

option(BUILD_UNIT_TESTS "Build unit tests" OFF)

option(BUILD_BENCHMARK "Build benchmark mode" OFF)

add_compile_options(
"$<$<COMPILE_LANG_AND_ID:CXX,Clang,GNU>:-O2;-g3;-Werror;-Wall;-Wvla;-Woverloaded-virtual>"
)

add_compile_options(
"$<$<COMPILE_LANG_AND_ID:C,Clang,GNU>:-O2;-g3;-Werror;-Wall>")

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_hwio`

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.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 @@ -18,3 +18,4 @@ Some simple lessons to get new users up and running.
can/index
uds/index
hwio/index
benchmark/index
4 changes: 4 additions & 0 deletions executables/referenceApp/application/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ add_executable(
${app.referenceAppExtraSources}
src/main.cpp)

if (BUILD_BENCHMARK)
target_sources(app.referenceApp PRIVATE src/systems/BenchmarkSystem.cpp)
endif ()

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

if (TARGET startUp)
Expand Down
10 changes: 10 additions & 0 deletions executables/referenceApp/application/include/app/BenchmarkLogger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2024 Accenture.

#ifndef GUARD_A2388DF9_4B35_42D5_8B75_DFC18C21C372
#define GUARD_A2388DF9_4B35_42D5_8B75_DFC18C21C372

#include "util/logger/Logger.h"

DECLARE_LOGGER_COMPONENT(BENCH)

#endif /* GUARD_A2388DF9_4B35_42D5_8B75_DFC18C21C372 */
156 changes: 156 additions & 0 deletions executables/referenceApp/application/include/systems/BenchmarkSystem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// Copyright 2024 Accenture.

#ifndef GUARD_F5601CAB_D60E_48CB_B6A0_1E86BE0C6F24
#define GUARD_F5601CAB_D60E_48CB_B6A0_1E86BE0C6F24

#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>

#define GET_HW_COUNTER() (DWT->CYCCNT)

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

namespace systems
{
class BenchmarkSystem
: public ::lifecycle::AsyncLifecycleComponent
, private ::async::IRunnable
{
public:
explicit BenchmarkSystem(
::async::ContextType context,
::lifecycle::ILifecycleManager& lifecycleManager,
::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 = GET_HW_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 = GET_HW_COUNTER();
_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 = GET_HW_COUNTER(); }

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

#endif /* GUARD_F5601CAB_D60E_48CB_B6A0_1E86BE0C6F24 */
20 changes: 20 additions & 0 deletions 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/SysAdminSystem.h"

Expand Down Expand Up @@ -69,9 +72,15 @@ LifecycleManager lifecycleManager{
TASK_SYSADMIN,
::lifecycle::LifecycleManager::GetTimestampType::create<&getSystemTimeUs32Bit>()};

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

#ifdef PLATFORM_SUPPORT_UDS
::estd::typed_mem<::transport::TransportSystem> transportSystem;
Expand Down Expand Up @@ -133,8 +142,10 @@ void run()

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

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

lifecycleManager.transitionToLevel(MaxNumLevels);

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

while (true)
Expand All @@ -190,8 +208,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 @@ -19,6 +19,7 @@
DEFINE_LOGGER_COMPONENT(BSP);
DEFINE_LOGGER_COMPONENT(COMMON);
DEFINE_LOGGER_COMPONENT(DEMO);
DEFINE_LOGGER_COMPONENT(BENCH);
DEFINE_LOGGER_COMPONENT(GLOBAL);
DEFINE_LOGGER_COMPONENT(UDS);

Expand All @@ -31,6 +32,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 @@ -45,6 +47,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