M .gdbinit-1051 => .gdbinit-1051 +4 -0
@@ 15,3 15,7 @@ thread 2
tb main
b HardFault_Handler
b _exit
+b abort
+b WDOG1_IRQHandler
+b RTWDOG_IRQHandler
+b IntDefaultHandler
M .gitmodules => .gitmodules +3 -0
@@ 106,3 106,6 @@
path = third-party/reedgefs/src
url = ../reliance-edge.git
branch = mudita
+[submodule "third-party/msgpack11/msgpack11"]
+ path = third-party/msgpack11/msgpack11
+ url = https://github.com/ar90n/msgpack11.git
M cmake/modules/ProjectConfig.cmake => cmake/modules/ProjectConfig.cmake +8 -0
@@ 24,6 24,13 @@ else()
set (LOG_REDIRECT "RTT_JLINK" CACHE INTERNAL "")
endif()
+option(SYSTEM_PROFILE "SYSTEM_PROFILE" OFF)
+if(${SYSTEM_PROFILE} STREQUAL "ON")
+ set(PROF_ON 1 CACHE INTERNAL "")
+else()
+ set(PROF_ON 0 CACHE INTERNAL "")
+endif()
+
# add CurrentMeasurement enable option
option(CURRENT_MEASUREMENT "CURRENT_MEASUREMENT" OFF)
@@ 72,6 79,7 @@ set(PROJECT_CONFIG_DEFINITIONS
USBCDC_ECHO_ENABLED=${USBCDC_ECHO_ENABLED}
LOG_LUART_ENABLED=${LOG_LUART_ENABLED}
MAGIC_ENUM_RANGE_MAX=256
+ PROF_ON=${PROF_ON}
CACHE INTERNAL ""
)
M module-bluetooth/Bluetooth/interface/profiles/SCO/SCO.cpp => module-bluetooth/Bluetooth/interface/profiles/SCO/SCO.cpp +2 -2
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "SCO.hpp"
@@ 153,7 153,7 @@ void SCO::SCOImpl::writeToHostEndian(int16_t *buffer, uint8_t *packet, int lengt
void SCO::SCOImpl::receiveCvsd(uint8_t *packet, uint16_t size)
{
- std::array<int16_t, AUDIO_BUFFER_LENGTH> audioFrameOut;
+ std::array<int16_t, AUDIO_BUFFER_LENGTH> audioFrameOut{};
if (size > audioFrameOut.size()) {
LOG_WARN("SCO packet larger than local output buffer - dropping data.");
M module-bsp/bsp/common.cpp => module-bsp/bsp/common.cpp +21 -0
@@ 16,5 16,26 @@ namespace bsp{
break;
}
}
+
+ uint8_t CpuMHZToLevel(enum CpuFrequencyMHz val)
+ {
+ switch (val) {
+ case CpuFrequencyMHz::Level_0:
+ return 0;
+ case CpuFrequencyMHz::Level_1:
+ return 1;
+ case CpuFrequencyMHz::Level_2:
+ return 2;
+ case CpuFrequencyMHz::Level_3:
+ return 3;
+ case CpuFrequencyMHz::Level_4:
+ return 4;
+ case CpuFrequencyMHz::Level_5:
+ return 5;
+ case CpuFrequencyMHz::Level_6:
+ return 6;
+ }
+ return -1;
+ }
};
M module-bsp/bsp/common.hpp => module-bsp/bsp/common.hpp +3 -0
@@ 3,6 3,7 @@
#pragma once
+#include <cstdint>
namespace bsp
{
enum class RetCode{
@@ 24,6 25,8 @@ namespace bsp
Level_6 = 528
};
+ uint8_t CpuMHZToLevel(enum CpuFrequencyMHz val);
+
constexpr auto MHz_frequency_multiplier = 1000000U;
enum class Board{
M module-os/CMakeLists.txt => module-os/CMakeLists.txt +7 -0
@@ 34,6 34,9 @@ target_sources(module-os PRIVATE ${SOURCES})
if(NOT ${SYSTEM_VIEW_ENABLED})
target_sources(module-os PRIVATE FreeRTOS/tasks.c)
endif()
+if(${PROF_ON})
+ target_sources(module-os PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/FreeRTOS/prof.c)
+endif()
add_board_subdirectory(board)
@@ 80,3 83,7 @@ if((${PROJECT_TARGET} STREQUAL "TARGET_RT1051") AND (${SYSTEM_VIEW_ENABLED}))
endif()
target_link_libraries(${PROJECT_NAME} PUBLIC log-api board-config)
+
+if (${ENABLE_TESTS})
+ add_subdirectory(test)
+endif ()
M module-os/FreeRTOS/include/task.h => module-os/FreeRTOS/include/task.h +2 -0
@@ 1408,6 1408,7 @@ char *pcTaskGetName( TaskHandle_t xTaskToQuery ) PRIVILEGED_FUNCTION; /*lint !e9
* \ingroup TaskUtils
*/
TaskHandle_t xTaskGetHandle( const char *pcNameToQuery ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
+TaskHandle_t xTaskGetByTCBNumber(UBaseType_t uxTCBNumber ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
/**
* task.h
@@ 2366,6 2367,7 @@ void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBas
* Get the uxTCBNumber assigned to the task referenced by the xTask parameter.
*/
UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
+UBaseType_t uxTaskGetTCBNumber(TaskHandle_t xTask) PRIVILEGED_FUNCTION;
/*
* Set the uxTaskNumber of the task referenced by the xTask parameter to
A module-os/FreeRTOS/prof.c => module-os/FreeRTOS/prof.c +98 -0
@@ 0,0 1,98 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "prof.h"
+#include <stdlib.h>
+#include <string.h>
+
+struct prof_pool
+{
+ struct task_prof_data *pool;
+ unsigned int _overflow_counter;
+ unsigned int _pos;
+
+ struct prof_pool_init_data data;
+ void (*clean)();
+ void (*handle_overflow)(uint32_t id);
+ struct task_prof_data* (*get)(uint32_t id);
+};
+
+
+static struct prof_pool pool;
+
+static void _pool_clean()
+{
+ memset(pool.pool, 0, sizeof(*pool.pool)*pool.data.size);
+ pool._overflow_counter =0;
+ pool._pos = 0;
+}
+
+static void _pool_overflow(uint32_t id)
+{
+ pool._overflow_counter = id;
+}
+
+/// just meant to be fast get of element
+static struct task_prof_data* _pool_get(uint32_t id)
+{
+ if ( pool._pos == pool.data.size ) {
+ pool.handle_overflow(id);
+ }
+ for ( size_t i =0; i < pool.data.size && i != pool._pos; ++i ) {
+ if (id == pool.pool[i].task_TCB_id) {
+ return &pool.pool[i];
+ }
+ }
+ struct task_prof_data* p = &pool.pool[pool._pos];
+ pool._pos++;
+ return p;
+}
+
+
+
+void prof_pool_init(struct prof_pool_init_data init)
+{
+ pool.data = init;
+ pool.clean = _pool_clean;
+ pool.handle_overflow = _pool_overflow;
+ pool.get = _pool_get;
+
+ pool.pool = (struct task_prof_data *)(malloc(sizeof(struct task_prof_data)*pool.data.size));
+ pool.clean();
+}
+
+void prof_pool_deinit()
+{
+ free(pool.pool);
+ pool.pool = NULL;
+}
+
+
+struct prof_pool_init_data prof_pool_get_data()
+{
+ return pool.data;
+}
+
+void prof_pool_data_set(uint8_t ts, uint32_t id)
+{
+ struct task_prof_data *what = pool.get(id);
+ if ( what == NULL) {
+ return;
+ }
+ what->task_TCB_id=id;
+ what->exec_time += ts;
+ ++(what->switches);
+}
+
+unsigned int prof_pool_overflow()
+{
+ return pool._overflow_counter;
+}
+
+unsigned int prof_pool_flush(struct task_prof_data *mem, size_t cap)
+{
+ unsigned int to_ret = pool._overflow_counter;
+ memcpy(mem, pool.pool, cap * (sizeof(struct task_prof_data)));
+ pool.clean();
+ return to_ret;
+}
A module-os/FreeRTOS/prof.h => module-os/FreeRTOS/prof.h +57 -0
@@ 0,0 1,57 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+
+/// just store what's interesting
+/// 1. do not store TaskHandle_t, id is better - we normally have up to 32 id's as we do not
+/// as we tend to keep up to ~30 threads alive
+/// 2. execution time, the better granulation, the better result
+struct task_prof_data {
+ uint32_t task_TCB_id; /// task TCB id
+ uint32_t exec_time; /// single task switch execution time summed up in TS
+ uint32_t switches; /// count how many times it was switched out
+};
+
+/// initialization structure
+struct prof_pool_init_data
+{
+ size_t size; /// size of the pool, use should have linear eficiency
+};
+
+#if PROF_ON
+
+/// initialization of pool to store switch data
+void prof_pool_init(struct prof_pool_init_data init);
+void prof_pool_deinit();
+struct prof_pool_init_data prof_pool_get_data();
+
+/// get next available slot from the pool
+/// struct task_prof_data* prof_pool_get_next();
+/// set the element
+void prof_pool_data_set(uint8_t ts, uint32_t id);
+
+/// mark if overflow happened
+unsigned int prof_pool_overflow();
+
+/// to `mem` flush up to `cap` data - then clean
+/// if passed:
+/// - set used count: how much data was used
+/// - returns overflow count
+/// requires sched lock before running
+unsigned int prof_pool_flush(struct task_prof_data *mem, size_t cap);
+
+#else
+#define prof_pool_data_set(...)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
M module-os/FreeRTOS/tasks.c => module-os/FreeRTOS/tasks.c +109 -3
@@ 26,6 26,7 @@
*/
/* Standard includes. */
+#include "prof.h"
#include <stdlib.h>
#include <string.h>
@@ 2353,8 2354,6 @@ TCB_t *pxTCB;
TCB_t *pxNextTCB, *pxFirstTCB, *pxReturn = NULL;
UBaseType_t x;
char cNextChar;
- BaseType_t xBreakLoop;
-
/* This function is called with the scheduler suspended. */
if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
@@ 2412,6 2411,32 @@ TCB_t *pxTCB;
}
#endif /* INCLUDE_xTaskGetHandle */
+
+ static TCB_t *prvSearchForTCBNumberWithinSingleList( List_t *pxList, UBaseType_t TCBNumber)
+ {
+ TCB_t *pxNextTCB, *pxFirstTCB, *pxReturn = NULL;
+ /* This function is called with the scheduler suspended. */
+ if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
+ do
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
+ if (pxNextTCB->uxTCBNumber == TCBNumber) {
+ pxReturn = pxNextTCB;
+ break;
+ }
+ } while( pxNextTCB != pxFirstTCB );
+ }
+ else
+ {
+ mtCOVERAGE_TEST_MARKER();
+ }
+
+ return pxReturn;
+ }
+
+
/*-----------------------------------------------------------*/
#if ( INCLUDE_xTaskGetHandle == 1 )
@@ 2475,8 2500,64 @@ TCB_t *pxTCB;
return pxTCB;
}
-
#endif /* INCLUDE_xTaskGetHandle */
+
+ TaskHandle_t xTaskGetByTCBNumber(UBaseType_t TCBNumber ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
+ {
+ UBaseType_t uxQueue = configMAX_PRIORITIES;
+ TCB_t* pxTCB;
+
+ vTaskSuspendAll();
+ {
+ /* Search the ready lists. */
+ do
+ {
+ uxQueue--;
+ pxTCB = prvSearchForTCBNumberWithinSingleList( ( List_t * ) &( pxReadyTasksLists[ uxQueue ] ), TCBNumber);
+ if( pxTCB != NULL )
+ {
+ /* Found the handle. */
+ break;
+ }
+
+ } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
+
+ /* Search the delayed lists. */
+ if( pxTCB == NULL )
+ {
+ pxTCB = prvSearchForTCBNumberWithinSingleList( ( List_t * ) pxDelayedTaskList, TCBNumber );
+ }
+
+ if( pxTCB == NULL )
+ {
+ pxTCB = prvSearchForTCBNumberWithinSingleList( ( List_t * ) pxOverflowDelayedTaskList, TCBNumber );
+ }
+
+ #if ( INCLUDE_vTaskSuspend == 1 )
+ {
+ if( pxTCB == NULL )
+ {
+ /* Search the suspended list. */
+ pxTCB = prvSearchForTCBNumberWithinSingleList( &xSuspendedTaskList, TCBNumber );
+ }
+ }
+ #endif
+
+ #if( INCLUDE_vTaskDelete == 1 )
+ {
+ if( pxTCB == NULL )
+ {
+ /* Search the deleted list. */
+ pxTCB = prvSearchForTCBNumberWithinSingleList( &xTasksWaitingTermination, TCBNumber );
+ }
+ }
+ #endif
+ }
+ ( void ) xTaskResumeAll();
+
+ return pxTCB;
+ }
+
/*-----------------------------------------------------------*/
#if ( configUSE_TRACE_FACILITY == 1 )
@@ 2978,6 3059,7 @@ void vTaskSwitchContext( void )
if( ulTotalRunTime > ulTaskSwitchedInTime )
{
pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );
+ prof_pool_data_set(ulTotalRunTime - ulTaskSwitchedInTime, pxCurrentTCB->uxTCBNumber);
}
else
{
@@ 3305,6 3387,25 @@ void vTaskMissedYield( void )
return uxReturn;
}
+ UBaseType_t uxTaskGetTCBNumber( TaskHandle_t xTask )
+ {
+ UBaseType_t uxReturn;
+ TCB_t const *pxTCB;
+
+ if( xTask != NULL )
+ {
+ pxTCB = xTask;
+ uxReturn = pxTCB->uxTCBNumber;
+ }
+ else
+ {
+ uxReturn = 0U;
+ }
+
+ return uxReturn;
+ }
+
+
#endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/
@@ 5215,3 5316,8 @@ when performing module tests). */
#endif
+
+int isOSRunning()
+{
+ return pdTRUE == xSchedulerRunning;
+}
M module-os/LockGuard.cpp => module-os/LockGuard.cpp +9 -0
@@ 8,6 8,11 @@
LockGuard::LockGuard(cpp_freertos::MutexStandard& mutex) : mutex(mutex)
{
+
+ if (isOSRunning() == 0)
+ {
+ return;
+ }
if (isIRQ()) {
savedInterruptStatus = cpp_freertos::CriticalSection::EnterFromISR();
}
@@ 18,6 23,10 @@ LockGuard::LockGuard(cpp_freertos::MutexStandard& mutex) : mutex(mutex)
LockGuard::~LockGuard()
{
+ if (isOSRunning() == 0)
+ {
+ return;
+ }
if (isIRQ()) {
cpp_freertos::CriticalSection::ExitFromISR(savedInterruptStatus);
}
M module-os/board/linux/fsl_runtimestat_gpt.c => module-os/board/linux/fsl_runtimestat_gpt.c +47 -1
@@ 2,12 2,58 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <stdint.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/times.h>
+#include <signal.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static uint32_t prof_tick = 0;
+
+static void TickSignalHandler( int sig )
+{
+ ++prof_tick;
+}
void vConfigureTimerForRunTimeStats(void)
{
+ struct sigaction tick;
+ sigemptyset(&tick.sa_mask);
+ tick.sa_flags = 0;
+ tick.sa_handler = TickSignalHandler;
+
+ if (sigaction( SIGPROF, &tick, NULL )!=0)
+ //if (sigaction( SIGVTALRM, &tick, NULL )!=0)
+ {
+ printf("cant profile\n");
+ exit(1);
+ }
+
+ struct itimerval itimer;
+ if( getitimer(ITIMER_PROF , &itimer) != 0 ){
+ printf("cant get profile\n");
+ exit(1);
+ }
+ /// timer set to 1kHz, not 1MHz like timer in the other gpt
+ /// freq is the same as freq of rtos
+ itimer.it_interval.tv_sec = 0;
+ itimer.it_interval.tv_usec = 1000;
+ itimer.it_value.tv_sec = 0;
+ itimer.it_value.tv_usec = 1000;
+
+ /* Set-up the timer interrupt. */
+ if (setitimer( ITIMER_PROF, &itimer, NULL) != 0 )
+ {
+ printf("cant set profile\n");
+ exit(1);
+ }
}
uint32_t ulHighFrequencyTimerTicks(void)
{
- return 0;
+ return prof_tick;
}
M module-os/board/linux/macros.h => module-os/board/linux/macros.h +8 -0
@@ 73,4 73,12 @@ static inline bool isIRQ()
}
+#ifdef __cplusplus
+extern "C" {
+#endif
+ int isOSRunning();
+#ifdef __cplusplus
+};
+#endif
+
#endif /* MACROS_H_ */
M module-os/board/linux/port.c => module-os/board/linux/port.c +5 -0
@@ 921,3 921,8 @@ BaseType_t xPortIsInsideInterrupt(void)
{
return pdFALSE;
}
+
+uint32_t CLOCK_GetFreq(int clock) {
+ (void)clock;
+ return 0;
+}
M module-os/board/rt1051/include/macros.h => module-os/board/rt1051/include/macros.h +8 -0
@@ 71,3 71,11 @@ static inline void haltIfDebugging()
__asm("bkpt 1");
}
}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ int isOSRunning();
+#ifdef __cplusplus
+};
+#endif
A module-os/test/CMakeLists.txt => module-os/test/CMakeLists.txt +9 -0
@@ 0,0 1,9 @@
+if(${PROF_ON})
+add_catch2_executable(
+ NAME performance
+ SRCS
+ performance-monitor.cpp
+ LIBS
+ module-os
+)
+endif()
A module-os/test/performance-monitor.cpp => module-os/test/performance-monitor.cpp +49 -0
@@ 0,0 1,49 @@
+#include <limits>
+#define CATCH_CONFIG_MAIN
+
+#include <catch2/catch.hpp>
+#include "prof.h"
+
+TEST_CASE("prof api test")
+{
+ struct prof_pool_init_data init{0};
+
+ prof_pool_init(init);
+ auto pp = prof_pool_get_data();
+ REQUIRE(pp.size == 0);
+ prof_pool_deinit();
+}
+
+TEST_CASE("overflow")
+{
+ struct prof_pool_init_data init
+ {
+ 0
+ };
+ prof_pool_init(init);
+ prof_pool_data_set(0,-1);
+ REQUIRE(prof_pool_overflow() == 1);
+ prof_pool_deinit();
+}
+
+TEST_CASE("prof api sum")
+{
+ struct prof_pool_init_data init{1};
+
+ prof_pool_init(init);
+ auto pp = prof_pool_get_data();
+ REQUIRE(pp.size == 1);
+ const auto switches = 10;
+ const auto ts = 10;
+ for (auto i =0; i < switches ; ++i)
+ {
+ prof_pool_data_set(0,ts);
+ }
+
+ task_prof_data mem[1];
+ prof_pool_flush(mem, 1);
+ REQUIRE(mem->switches == switches);
+ REQUIRE(mem->exec_time == switches*ts);
+
+ prof_pool_deinit();
+}
M module-sys/Service/Service.cpp => module-sys/Service/Service.cpp +6 -0
@@ 112,6 112,7 @@ namespace sys
staleUniqueMsg.end());
const bool respond = msg->type != Message::Type::Response && GetName() != msg->sender;
+ currentlyProcessing = msg;
auto response = msg->Execute(this);
if (response == nullptr || !respond) {
continue;
@@ 268,6 269,11 @@ namespace sys
service->bus.sendUnicast(std::move(msg), service::name::system_manager);
}
+ std::string Service::getCurrentProcessing()
+ {
+ return currentlyProcessing ? std::string(typeid(*currentlyProcessing).name()) : "nothing in progress";
+ }
+
auto Proxy::handleMessage(Service *service, Message *message, ResponseMessage *response) -> MessagePointer
{
if (service->isReady) {
M module-sys/Service/include/Service/Service.hpp => module-sys/Service/include/Service/Service.hpp +3 -0
@@ 100,6 100,7 @@ namespace sys
bool disconnect(const std::type_info &type);
void sendCloseReadyMessage(Service *service);
+ std::string getCurrentProcessing();
protected:
bool enableRunLoop;
@@ 138,6 139,8 @@ namespace sys
[[nodiscard]] auto get(timer::SystemTimer *timer) noexcept -> timer::SystemTimer *;
} timers;
+ MessagePointer currentlyProcessing = nullptr;
+
public:
auto getTimers() -> auto &
{
M module-sys/SystemManager/CMakeLists.txt => module-sys/SystemManager/CMakeLists.txt +3 -0
@@ 14,6 14,8 @@ target_sources(sys-manager
CpuGovernor.cpp
CpuSentinel.cpp
CpuStatistics.cpp
+ CpuLogPrinter.cpp
+ CpuPackPrinter.cpp
data/SystemManagerActionsParams.hpp
DependencyGraph.cpp
DeviceManager.cpp
@@ 37,6 39,7 @@ target_link_libraries(sys-manager
sys-common
PRIVATE
service-desktop
+ msgpack11
)
if (${ENABLE_TESTS})
M module-sys/SystemManager/CpuGovernor.cpp => module-sys/SystemManager/CpuGovernor.cpp +22 -8
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <SystemManager/CpuGovernor.hpp>
@@ 113,19 113,33 @@ namespace sys
SetCpuFrequencyRequest(sentinelName, bsp::CpuFrequencyMHz::Level_0);
}
- [[nodiscard]] auto CpuGovernor::GetMinimumFrequencyRequested() const noexcept -> bsp::CpuFrequencyMHz
+ [[nodiscard]] auto CpuGovernor::GetMinimumFrequencyRequested() const noexcept -> sentinel::Data
{
- bsp::CpuFrequencyMHz minFrequency = bsp::CpuFrequencyMHz::Level_0;
+ sentinel::Data d;
+ if (sentinels.empty()) {
+ d.reason = "empty";
+ return d;
+ }
- for (auto &sentinel : sentinels) {
- const auto sentinelFrequency = sentinel->GetRequestedFrequency();
+ auto minSentinel = sentinels.begin();
+ for (auto iter = sentinels.begin(); iter != std::end(sentinels); ++iter) {
+ const auto sentinelFrequency = (*iter)->GetRequestedFrequency();
- if (sentinelFrequency > minFrequency) {
- minFrequency = sentinelFrequency;
+ if (sentinelFrequency > (*minSentinel)->GetRequestedFrequency()) {
+ minSentinel = iter;
}
}
- return minFrequency;
+ d.frequency = (*minSentinel)->GetRequestedFrequency();
+ if (auto p = (*minSentinel)->GetSentinel().lock()) {
+ d.name = p->GetName();
+ d.task = p->getTask();
+ d.reason = p->getReason();
+ }
+ else {
+ d.reason = "cant lock";
+ }
+ return d;
}
void CpuGovernor::InformSentinelsAboutCpuFrequencyChange(bsp::CpuFrequencyMHz newFrequency) const noexcept
A module-sys/SystemManager/CpuLogPrinter.cpp => module-sys/SystemManager/CpuLogPrinter.cpp +47 -0
@@ 0,0 1,47 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "SystemManager/CpuPrinter.hpp"
+#include "SystemManager/SysCpuUpdateResult.hpp"
+#include <SystemManager/SystemManagerCommon.hpp>
+
+extern "C"
+{
+ uint32_t CLOCK_GetFreq(int);
+}
+
+namespace sys::cpu::stats
+{
+
+ void LogPrinter::printSysUsage(struct task_prof_data *data, size_t size)
+ {
+ vTaskSuspendAll();
+ {
+ for (size_t i = 0; i < size; ++i) {
+ if (data[i].exec_time == 0 && data[i].switches == 0) {
+ continue;
+ }
+
+ LOG_PRINTF("%s,%" PRIu32 ",%" PRIu32 ",%" PRIu32 "\n",
+ SystemManagerCommon::ServiceProcessor(i).c_str(),
+ data[i].task_TCB_id,
+ data[i].exec_time,
+ data[i].switches);
+ /// NOTE: version below is much lighter and doesn't need system suspend, it requires GDB to show what
+ /// were the
+ // task names LOG_PRINTF("%d,%" PRIu32 "\n", data[i].task_TCB_id, data[i].exec_time);
+ }
+ }
+ xTaskResumeAll();
+ }
+
+ void LogPrinter::printCPUChange(const cpu::UpdateResult &ret)
+ {
+ LOG_PRINTF("CPU freq changed to: %d by: %s reason: %s for freq: %d curent: %" PRIu32 "\n",
+ int(ret.frequencySet),
+ ret.data.name.c_str(),
+ ret.data.reason.c_str(),
+ int(ret.data.frequency),
+ CLOCK_GetFreq(0));
+ }
+} // namespace sys::cpu::stats
A module-sys/SystemManager/CpuPackPrinter.cpp => module-sys/SystemManager/CpuPackPrinter.cpp +46 -0
@@ 0,0 1,46 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "SystemManager/CpuPrinter.hpp"
+#include "SystemManager/SysCpuUpdateResult.hpp"
+#include <SystemManager/SystemManagerCommon.hpp>
+#include "third-party/msgpack11/msgpack11/msgpack11.hpp"
+
+namespace sys::cpu::stats
+{
+
+ using namespace msgpack11;
+ enum class PackID
+ {
+ Proc,
+ Usage,
+ };
+
+ void PackPrinter::printSysUsage(struct task_prof_data *data, size_t size)
+ {
+ vTaskSuspendAll();
+ {
+ for (size_t i = 0; i < size; ++i) {
+ if (data[i].exec_time == 0 && data[i].switches == 0) {
+ continue;
+ }
+ MsgPack obj = MsgPack::object{{"id", uint32_t(PackID::Proc)},
+ {"name", SystemManagerCommon::ServiceProcessor(i)},
+ {"tcb", uint32_t(data[i].task_TCB_id)},
+ {"t", data[i].exec_time}};
+ LOG_PRINTF("%c%s\n", 2, obj.dump().c_str());
+ }
+ }
+ xTaskResumeAll();
+ }
+
+ void PackPrinter::printCPUChange(const cpu::UpdateResult &ret)
+ {
+ MsgPack obj = MsgPack::object{{"id", uint32_t(PackID::Usage)},
+ {"freq", uint32_t(ret.frequencySet)},
+ {"name", ret.data.name},
+ {"reason", ret.data.reason},
+ {"requested", uint32_t(ret.data.frequency)}};
+ LOG_PRINTF("%c%s\n", 2, obj.dump().c_str());
+ }
+} // namespace sys::cpu::stats
M module-sys/SystemManager/CpuSentinel.cpp => module-sys/SystemManager/CpuSentinel.cpp +17 -4
@@ 31,6 31,8 @@ namespace sys
auto msg = std::make_shared<sys::HoldCpuFrequencyMessage>(GetName(), frequencyToHold);
owner->bus.sendUnicast(std::move(msg), service::name::system_manager);
currentFrequencyToHold = frequencyToHold;
+ currentReason = std::string("up: ") + owner->getCurrentProcessing() + std::string(" req: ") +
+ std::to_string(int(frequencyToHold));
}
}
@@ 40,6 42,7 @@ namespace sys
auto msg = std::make_shared<sys::ReleaseCpuFrequencyMessage>(GetName());
owner->bus.sendUnicast(std::move(msg), service::name::system_manager);
currentFrequencyToHold = bsp::CpuFrequencyMHz::Level_0;
+ currentReason = std::string("down: ") + owner->getCurrentProcessing();
}
}
@@ 82,9 85,9 @@ namespace sys
if (callback) {
callback(newFrequency);
}
- if (taskHandle != nullptr && newFrequency >= currentFrequencyToHold) {
- xTaskNotifyGive(taskHandle);
- taskHandle = nullptr;
+ if (taskWaitingForFrequency != nullptr && newFrequency >= currentFrequencyToHold) {
+ xTaskNotifyGive(taskWaitingForFrequency);
+ taskWaitingForFrequency = nullptr;
}
}
@@ 92,10 95,11 @@ namespace sys
TaskHandle_t taskToNotify,
uint32_t timeout)
{
+ currentReason = std::string("h+w: ") + owner->getCurrentProcessing();
HoldMinimumFrequency(frequencyToHold);
if (currentFrequencyToHold < frequencyToHold) {
- taskHandle = taskToNotify;
+ taskWaitingForFrequency = taskToNotify;
return ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(timeout)) == 0;
}
@@ 135,4 139,13 @@ namespace sys
}
}
+ TaskHandle_t CpuSentinel::getTask()
+ {
+ return owner->GetHandle();
+ }
+
+ std::string CpuSentinel::getReason()
+ {
+ return currentReason;
+ }
} // namespace sys
M module-sys/SystemManager/CpuStatistics.cpp => module-sys/SystemManager/CpuStatistics.cpp +52 -8
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <SystemManager/CpuStatistics.hpp>
@@ 7,25 7,69 @@
#include <task.h>
#include <limits>
+extern "C"
+{
+#include "prof.h"
+}
+
namespace sys
{
- void CpuStatistics::Update()
+
+ CpuStatistics::CpuStatistics()
+ {
+
+#if PROF_ON
+ data_size = prof_pool_get_data().size;
+ data = new task_prof_data[data_size];
+#endif
+ printer = std::make_unique<cpu::stats::LogPrinter>();
+ }
+
+ CpuStatistics::~CpuStatistics()
+ {
+#if PROF_ON
+ delete[] data;
+#endif
+ }
+
+ void CpuStatistics::StoreSysUsage()
+ {
+#if PROF_ON
+ vTaskSuspendAll();
+ {
+ if (auto ovf = prof_pool_flush(data, data_size); ovf != 0) {
+ LOG_FATAL("prof pool flush overflow: %d", int(ovf));
+ }
+ }
+ xTaskResumeAll();
+#endif
+ }
+
+ void CpuStatistics::TrackChange(const cpu::UpdateResult &ret)
+ {
+ if (ret.changed) {
+ printer->printCPUChange(ret);
+#if PROF_ON
+ printer->printSysUsage(data, data_size);
+#endif
+ }
+ StoreSysUsage();
+ }
+
+ void CpuStatistics::UpdatePercentageCpuLoad()
{
uint32_t idleTickCount = xTaskGetIdleRunTimeCounter();
uint32_t totalTickCount = ulHighFrequencyTimerTicks();
-
uint32_t idleTickIncrease = ComputeIncrease(idleTickCount, lastIdleTickCount);
uint32_t totalTickIncrease = ComputeIncrease(totalTickCount, lastTotalTickCount);
-
- if (totalTickIncrease) {
+ lastIdleTickCount = idleTickCount;
+ lastTotalTickCount = totalTickCount;
+ if (totalTickIncrease != 0u) {
cpuLoad = 100 - ((idleTickIncrease * 100) / totalTickIncrease);
}
else {
cpuLoad = 0;
}
-
- lastIdleTickCount = idleTickCount;
- lastTotalTickCount = totalTickCount;
}
uint32_t CpuStatistics::GetPercentageCpuLoad() const noexcept
M module-sys/SystemManager/PowerManager.cpp => module-sys/SystemManager/PowerManager.cpp +24 -9
@@ 1,6 1,7 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+#include <gsl/util>
#include <log/log.hpp>
#include <SystemManager/PowerManager.hpp>
@@ 76,14 77,27 @@ namespace sys
}
}
- void PowerManager::UpdateCpuFrequency(uint32_t cpuLoad)
+ [[nodiscard]] cpu::UpdateResult PowerManager::UpdateCpuFrequency(uint32_t cpuLoad)
{
+ cpu::UpdateResult result;
+
const auto currentCpuFreq = lowPowerControl->GetCurrentFrequencyLevel();
- const auto minFrequencyRequested = cpuGovernor->GetMinimumFrequencyRequested();
- const auto permanentFrequencyToHold = cpuGovernor->GetPermanentFrequencyRequested();
+ const auto min = cpuGovernor->GetMinimumFrequencyRequested();
+ const auto permanent = cpuGovernor->GetPermanentFrequencyRequested();
+
+ auto _ = gsl::finally([&result, this, ¤tCpuFreq, min, permanent] {
+ result.frequencySet = lowPowerControl->GetCurrentFrequencyLevel();
+ result.changed = result.frequencySet != currentCpuFreq;
+ if (not permanent.isActive) {
+ result.data = min;
+ }
+ else {
+ result.data.reason = "perm";
+ }
+ });
- if (permanentFrequencyToHold.isActive) {
- auto frequencyToHold = std::max(permanentFrequencyToHold.frequencyToHold, powerProfile.minimalFrequency);
+ if (permanent.isActive) {
+ auto frequencyToHold = std::max(permanent.frequencyToHold, powerProfile.minimalFrequency);
if (currentCpuFreq < frequencyToHold) {
IncreaseCpuFrequency(frequencyToHold);
@@ 94,7 108,7 @@ namespace sys
} while (lowPowerControl->GetCurrentFrequencyLevel() > frequencyToHold);
}
ResetFrequencyShiftCounter();
- return;
+ return result;
}
if (cpuLoad > powerProfile.frequencyShiftUpperThreshold && currentCpuFreq < bsp::CpuFrequencyMHz::Level_6) {
@@ 114,9 128,9 @@ namespace sys
isFrequencyLoweringInProgress = false;
}
- if (minFrequencyRequested > currentCpuFreq) {
+ if (min.frequency > currentCpuFreq) {
ResetFrequencyShiftCounter();
- IncreaseCpuFrequency(minFrequencyRequested);
+ IncreaseCpuFrequency(min.frequency);
}
else if (aboveThresholdCounter >= powerProfile.maxAboveThresholdCount) {
if (powerProfile.frequencyIncreaseIntermediateStep && currentCpuFreq < bsp::CpuFrequencyMHz::Level_4) {
@@ 131,11 145,12 @@ namespace sys
else {
if (belowThresholdCounter >= (isFrequencyLoweringInProgress ? powerProfile.maxBelowThresholdInRowCount
: powerProfile.maxBelowThresholdCount) &&
- currentCpuFreq > minFrequencyRequested) {
+ currentCpuFreq > min.frequency) {
ResetFrequencyShiftCounter();
DecreaseCpuFrequency();
}
}
+ return result;
}
void PowerManager::IncreaseCpuFrequency(bsp::CpuFrequencyMHz newFrequency)
M module-sys/SystemManager/SystemManagerCommon.cpp => module-sys/SystemManager/SystemManagerCommon.cpp +40 -11
@@ 256,12 256,12 @@ namespace sys
// Start System manager
StartService();
- cpuStatisticsTimer = sys::TimerFactory::createPeriodicTimer(
- this, "cpuStatistics", constants::timerInitInterval, [this](sys::Timer &) { CpuStatisticsTimerHandler(); });
- cpuStatisticsTimer.start();
+ freqTimer = sys::TimerFactory::createPeriodicTimer(
+ this, "cpuTick", constants::timerInitInterval, [this](sys::Timer &) { FreqUpdateTick(); });
+ freqTimer.start();
powerManagerEfficiencyTimer = sys::TimerFactory::createPeriodicTimer(
- this, "logPowerManagerEfficiency", constants::powerManagerLogsTimerInterval, [this](sys::Timer &) {
+ this, "logPowerManagerEfficiency", constants::powerManagerLogsTimerInterval, [](sys::Timer &) {
powerManager->LogPowerManagerEfficiency();
});
powerManagerEfficiencyTimer.start();
@@ 437,6 437,36 @@ namespace sys
return false;
}
+ std::string SystemManagerCommon::ServiceProcessor(const uint32_t &t)
+ {
+ if (t == 0) {
+ return "Idle";
+ }
+
+ auto foo = [](auto &l, const uint32_t &t) {
+ auto found = std::find_if(l.begin(), l.end(), [&t](auto &r) {
+ auto right = uxTaskGetTCBNumber(r->GetHandle());
+ auto left = t;
+ return left == right;
+ });
+ return found;
+ };
+
+ if (auto found = foo(applicationsList, t); found != std::end(applicationsList)) {
+ return (*found)->GetName() + "::" + (*found)->getCurrentProcessing();
+ }
+ if (auto found = foo(servicesList, t); found != std::end(servicesList)) {
+ return (*found)->GetName() + "::" + (*found)->getCurrentProcessing();
+ }
+
+ auto handle = xTaskGetByTCBNumber(t);
+ if (handle != nullptr) {
+ return pcTaskGetTaskName(handle);
+ }
+
+ return "none";
+ }
+
void SystemManagerCommon::preCloseRoutine(CloseReason closeReason)
{
for (const auto &service : servicesList) {
@@ 678,9 708,7 @@ namespace sys
// In case if other power down request arrive in the meantime
lowBatteryShutdownDelay.stop();
-
- // We stop the timers
- cpuStatisticsTimer.stop();
+ freqTimer.stop();
powerManagerEfficiencyTimer.stop();
// We are going to remove services in reversed order of creation
@@ 744,15 772,16 @@ namespace sys
set(newState);
}
- void SystemManagerCommon::CpuStatisticsTimerHandler()
+ void SystemManagerCommon::FreqUpdateTick()
{
if (!cpuStatisticsTimerInit) {
cpuStatisticsTimerInit = true;
- cpuStatisticsTimer.restart(constants::timerPeriodInterval);
+ freqTimer.restart(constants::timerPeriodInterval);
}
- cpuStatistics->Update();
- powerManager->UpdateCpuFrequency(cpuStatistics->GetPercentageCpuLoad());
+ cpuStatistics->UpdatePercentageCpuLoad();
+ auto ret = powerManager->UpdateCpuFrequency(cpuStatistics->GetPercentageCpuLoad());
+ cpuStatistics->TrackChange(ret);
}
void SystemManagerCommon::UpdateResourcesAfterCpuFrequencyChange(bsp::CpuFrequencyMHz newFrequency)
A module-sys/SystemManager/doc/CpuStatistics.md => module-sys/SystemManager/doc/CpuStatistics.md +65 -0
@@ 0,0 1,65 @@
+CPU statistics
+==============
+
+We are able to gather CPU statistics and dump them wherever we want via printer.
+Current CPU statistics gathering:
+- measures each task in profiling pool data
+- prints last 100ms CPU usage data after frequency was changed
+
+# preface
+
+Our processor usage is limited to:
+- Applications
+- Services
+- Workers
+- Threads
+- IRQ's
+
+Applications and Services are registered on bus and are processing data on demand.
+Workers should also process data on demand, but do not have bus - but communicate via custom bindings. Workers are bound to Services.
+Threads are naked FreeRTOS threads, for our needs its: Idle task, Timer task - these do not have any rule how should be implemented.
+IRQ's are very processing specific.
+
+For Applications and Services we can measure:
+- What request was approximately was handled and how long
+For Workers and threads we can measure:
+- How long was it processing.
+For IRQs we do not have measuring capabilities right now.
+
+# data gathering
+
+defined in: `module-os/FreeRTOS/perf.h`, on each context switch saves data in memory pool for each task.
+used in:
+- CpuStatistics.cpp
+- tasks.c
+
+Two approaches were tested:
+1. approach where profiling data was stored separately on each context switch
+2. approach where profiling data is a sum of time for all context switches
+profiling gathering is meant to have O0 complexity to not add load to the core processing
+
+The first approach resulted in quite a lot of data, especially in the moments when the processor was fully loaded.
+With filtering out useless information it resulted in ~60 samples per 100ms when in idle, while having thousands when
+actual processing was happening (i.e. rendering). This resulted in pretty graphing capabilities, but was not useable
+for storage, as we could easily gather thousands kB per 100ms
+The second approach sums time and context switches per task from the last request.
+This way we do not know what exact tasks fight for the CPU attention, but have overall **smoothened** characteristics.
+
+The second approach is more convenient to both:
+- storage: with samples limiting we can save data only when frequency is changed, which depending on time span should take up to hundreds of bytes. normally tens right now.
+- ram usage: we can limit buffer to predicted count od threads, therefore whole performance gathering buffer shall take around 600 bytes.
+
+# data printing
+
+There is `sys::cpu::Printer` class in CpuStatistics for use. Depending of needs curently it can either:
+- not print at all
+- print CPU usage as formatted csv string to std::out
+- print CPU usage as message pack csv to std::out
+Formatted message pack can be modified to store data in file to minimize it's size. This way we will have small footprint, easily accessible statistics without logging.
+Any other printing capabilities could be added.
+
+# IRQ time
+
+Currently we do not measure time spent in IRQs, this could be easily achieved by:
+- funneling all IVT calls to single IRQ receptor function
+- calling IVT calls on demand form them, while saving GPT time before and after the call
M module-sys/SystemManager/doc/PowerManagement.md => module-sys/SystemManager/doc/PowerManagement.md +3 -0
@@ 75,3 75,6 @@ and requesting resources from `service_cellular` to make a phone call:

+# CpuStatistics
+
+CpuStatistics measurement is described in: [link](./module-sys/SystemManager/doc/CpuStatistics.md)
M module-sys/SystemManager/include/SystemManager/CpuGovernor.hpp => module-sys/SystemManager/include/SystemManager/CpuGovernor.hpp +20 -2
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 9,6 9,23 @@
namespace sys
{
+
+ namespace sentinel
+ {
+ struct Data
+ {
+ UBaseType_t ownerTCBNumber = 0;
+ /// name of sentinel thread responsible for curent minimum load
+ std::string name;
+ /// curent minimum frequency set in sentinel
+ bsp::CpuFrequencyMHz frequency = bsp::CpuFrequencyMHz::Level_0;
+ /// please do not use this task handle to perform actions, it's just for reference sake
+ TaskHandle_t task;
+ /// textual information on what actually happens
+ std::string reason;
+ };
+ }; // namespace sentinel
+
using SentinelPointer = std::weak_ptr<CpuSentinel>;
class GovernorSentinel
@@ 43,7 60,7 @@ namespace sys
bool permanentBlock = false);
void ResetCpuFrequencyRequest(std::string sentinelName, bool permanentBlock = false);
- [[nodiscard]] auto GetMinimumFrequencyRequested() const noexcept -> bsp::CpuFrequencyMHz;
+ [[nodiscard]] auto GetMinimumFrequencyRequested() const noexcept -> sentinel::Data;
void InformSentinelsAboutCpuFrequencyChange(bsp::CpuFrequencyMHz newFrequency) const noexcept;
[[nodiscard]] auto GetPermanentFrequencyRequested() const noexcept -> PermanentFrequencyToHold;
@@ 51,6 68,7 @@ namespace sys
private:
static void PrintName(const GovernorSentinelPointer &element);
+ /// this could be set - set is sorted :)
GovernorSentinelsVector sentinels;
PermanentFrequencyToHold permanentFrequencyToHold{false, bsp::CpuFrequencyMHz::Level_0};
};
A module-sys/SystemManager/include/SystemManager/CpuPrinter.hpp => module-sys/SystemManager/include/SystemManager/CpuPrinter.hpp +44 -0
@@ 0,0 1,44 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <cstddef>
+struct task_prof_data;
+namespace sys::cpu
+{
+ struct UpdateResult;
+
+ namespace stats
+ {
+
+ class Printer
+ {
+ public:
+ virtual void printSysUsage(struct task_prof_data *data, size_t size) = 0;
+ virtual void printCPUChange(const cpu::UpdateResult &ret) = 0;
+ };
+
+ class NullPrinter : public Printer
+ {
+ void printSysUsage(struct task_prof_data *data, size_t size)
+ {}
+ void printCPUChange(const cpu::UpdateResult &ret)
+ {}
+ };
+
+ class LogPrinter : public Printer
+ {
+ public:
+ void printSysUsage(struct task_prof_data *data, size_t size) override;
+ void printCPUChange(const cpu::UpdateResult &ret) override;
+ };
+
+ class PackPrinter : public Printer
+ {
+ public:
+ void printSysUsage(struct task_prof_data *data, size_t size) override;
+ void printCPUChange(const cpu::UpdateResult &ret) override;
+ };
+ }; // namespace stats
+}; // namespace sys::cpu
M module-sys/SystemManager/include/SystemManager/CpuSentinel.hpp => module-sys/SystemManager/include/SystemManager/CpuSentinel.hpp +4 -1
@@ 46,6 46,8 @@ namespace sys
void CpuFrequencyHasChanged(bsp::CpuFrequencyMHz newFrequency);
void ReadRegistrationData(bsp::CpuFrequencyMHz frequencyHz, bool permanentFrequency);
+ TaskHandle_t getTask();
+ std::string getReason();
protected:
const std::string name;
@@ 59,7 61,8 @@ namespace sys
/// critical section or mutex support necessary
std::function<void(bsp::CpuFrequencyMHz)> callback;
- TaskHandle_t taskHandle = nullptr;
+ TaskHandle_t taskWaitingForFrequency = nullptr;
+ std::string currentReason;
};
/// Sentinel releases the frequency lock automatically after the time specified in the parameter - timeout
M module-sys/SystemManager/include/SystemManager/CpuStatistics.hpp => module-sys/SystemManager/include/SystemManager/CpuStatistics.hpp +22 -2
@@ 1,10 1,17 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
+#include "SystemManager/PowerManager.hpp"
+#include "SystemManager/CpuPrinter.hpp"
#include <cstdint>
+extern "C"
+{
+#include "prof.h"
+}
+
namespace sys
{
@@ 12,15 19,28 @@ namespace sys
{
public:
- void Update();
+ CpuStatistics();
+ ~CpuStatistics();
+ /// stores system usage, should be called before any CPU frequency change
+ /// this way we know what services were in use and for how long before it happened
+ void StoreSysUsage();
[[nodiscard]] uint32_t GetPercentageCpuLoad() const noexcept;
+ void UpdatePercentageCpuLoad();
+ void TrackChange(const cpu::UpdateResult &ret);
private:
+ /// used to print stored data in CpuStatistics on change
+ std::unique_ptr<cpu::stats::Printer> printer;
uint32_t ComputeIncrease(uint32_t currentCount, uint32_t lastCount) const;
uint32_t lastIdleTickCount{0};
uint32_t lastTotalTickCount{0};
uint32_t cpuLoad{0};
+
+#if PROF_ON
+ size_t data_size{0};
+ struct task_prof_data *data = nullptr;
+#endif
};
} // namespace sys
M module-sys/SystemManager/include/SystemManager/PowerManager.hpp => module-sys/SystemManager/include/SystemManager/PowerManager.hpp +2 -1
@@ 8,6 8,7 @@
#include "bsp/lpm/bsp_lpm.hpp"
#include "drivers/semc/DriverSEMC.hpp"
+#include "SysCpuUpdateResult.hpp"
#include "CpuGovernor.hpp"
#include <bsp/lpm/PowerProfile.hpp>
#include <vector>
@@ 47,7 48,7 @@ namespace sys
/// periods the current CPU usage was below the lower limit (frequencyShiftLowerThreshold), CPU frequency is
/// reduced frequency
/// @param current cpu load
- void UpdateCpuFrequency(uint32_t cpuLoad);
+ [[nodiscard]] cpu::UpdateResult UpdateCpuFrequency(uint32_t cpuLoad);
[[nodiscard]] auto getExternalRamDevice() const noexcept -> std::shared_ptr<devices::Device>;
A module-sys/SystemManager/include/SystemManager/SysCpuUpdateResult.hpp => module-sys/SystemManager/include/SystemManager/SysCpuUpdateResult.hpp +15 -0
@@ 0,0 1,15 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "SystemManager/CpuGovernor.hpp"
+namespace sys::cpu
+{
+ struct UpdateResult
+ {
+ bool changed = false;
+ bsp::CpuFrequencyMHz frequencySet = bsp::CpuFrequencyMHz::Level_0;
+ sentinel::Data data{};
+ };
+}; // namespace sys::cpu
M module-sys/SystemManager/include/SystemManager/SystemManagerCommon.hpp => module-sys/SystemManager/include/SystemManager/SystemManagerCommon.hpp +4 -3
@@ 121,6 121,8 @@ namespace sys
/// Destroy existing application
static bool DestroyApplication(const std::string &name, Service *caller);
+ static std::string ServiceProcessor(const uint32_t &t);
+
/// Kill service
/// @note - this is final, it straight takes service, calls it's close callback and it's gone
/// please mind that services & apps not registered in SystemManager cant be killed - these should be handled by
@@ 185,8 187,7 @@ namespace sys
void RebootToUsbMscModeHandler(State newState);
- /// periodic update of cpu statistics
- void CpuStatisticsTimerHandler();
+ void FreqUpdateTick();
/// used for power management control for the filesystem
void UpdateResourcesAfterCpuFrequencyChange(bsp::CpuFrequencyMHz newFrequency);
@@ 195,7 196,7 @@ namespace sys
UpdateReason updateReason{UpdateReason::Update};
std::vector<std::unique_ptr<BaseServiceCreator>> systemServiceCreators;
- sys::TimerHandle cpuStatisticsTimer;
+ sys::TimerHandle freqTimer;
sys::TimerHandle servicesPreShutdownRoutineTimeout;
sys::TimerHandle lowBatteryShutdownDelay;
sys::TimerHandle powerManagerEfficiencyTimer;
M module-sys/SystemManager/tests/unittest_CpuSentinelsGovernor.cpp => module-sys/SystemManager/tests/unittest_CpuSentinelsGovernor.cpp +9 -9
@@ 68,27 68,27 @@ TEST_CASE("Power Manager CPU sentinels governor test")
governor->RegisterNewSentinel(testSentinel_1);
governor->RegisterNewSentinel(testSentinel_2);
- REQUIRE(governor->GetMinimumFrequencyRequested() == bsp::CpuFrequencyMHz::Level_0);
+ REQUIRE(governor->GetMinimumFrequencyRequested().frequency == bsp::CpuFrequencyMHz::Level_0);
governor->SetCpuFrequencyRequest("testSentinel_1", bsp::CpuFrequencyMHz::Level_4);
- REQUIRE(governor->GetMinimumFrequencyRequested() == bsp::CpuFrequencyMHz::Level_4);
+ REQUIRE(governor->GetMinimumFrequencyRequested().frequency == bsp::CpuFrequencyMHz::Level_4);
governor->SetCpuFrequencyRequest("testSentinel_2", bsp::CpuFrequencyMHz::Level_6);
- REQUIRE(governor->GetMinimumFrequencyRequested() == bsp::CpuFrequencyMHz::Level_6);
+ REQUIRE(governor->GetMinimumFrequencyRequested().frequency == bsp::CpuFrequencyMHz::Level_6);
governor->SetCpuFrequencyRequest("testSentinel_1", bsp::CpuFrequencyMHz::Level_2);
- REQUIRE(governor->GetMinimumFrequencyRequested() == bsp::CpuFrequencyMHz::Level_6);
+ REQUIRE(governor->GetMinimumFrequencyRequested().frequency == bsp::CpuFrequencyMHz::Level_6);
governor->ResetCpuFrequencyRequest("testSentinel_2");
- REQUIRE(governor->GetMinimumFrequencyRequested() == bsp::CpuFrequencyMHz::Level_2);
+ REQUIRE(governor->GetMinimumFrequencyRequested().frequency == bsp::CpuFrequencyMHz::Level_2);
- governor->SetCpuFrequencyRequest("bedNameSentinel", bsp::CpuFrequencyMHz::Level_6);
- REQUIRE(governor->GetMinimumFrequencyRequested() == bsp::CpuFrequencyMHz::Level_2);
+ governor->SetCpuFrequencyRequest("badNameSentinel", bsp::CpuFrequencyMHz::Level_6);
+ REQUIRE(governor->GetMinimumFrequencyRequested().frequency == bsp::CpuFrequencyMHz::Level_2);
governor->SetCpuFrequencyRequest("testSentinel_1", bsp::CpuFrequencyMHz::Level_1);
- REQUIRE(governor->GetMinimumFrequencyRequested() == bsp::CpuFrequencyMHz::Level_1);
+ REQUIRE(governor->GetMinimumFrequencyRequested().frequency == bsp::CpuFrequencyMHz::Level_1);
governor->ResetCpuFrequencyRequest("testSentinel_1");
- REQUIRE(governor->GetMinimumFrequencyRequested() == bsp::CpuFrequencyMHz::Level_0);
+ REQUIRE(governor->GetMinimumFrequencyRequested().frequency == bsp::CpuFrequencyMHz::Level_0);
}
}
M module-utils/log/api/log/log.hpp => module-utils/log/api/log/log.hpp +16 -1
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
/*
@@ 62,6 62,10 @@ extern "C"
*/
int log_Log(logger_level level, const char *file, int line, const char *function, const char *fmt, ...)
__attribute__((format(printf, 5, 6)));
+#ifdef LOG_IGNORE_ALL
+ int log_ignore(logger_level level, const char *file, int line, const char *function, const char *fmt, ...)
+ __attribute__((format(printf, 5, 6)));
+#endif
int log_Printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
void log_WriteToDevice(const uint8_t *pBuffer, unsigned NumBytes);
@@ 69,6 73,7 @@ extern "C"
* Log functions (one per level).
*/
#define LOG_PRINTF(...) log_Printf(__VA_ARGS__)
+#ifndef LOG_IGNORE_ALL
#define LOG_TRACE(...) log_Log(LOGTRACE, __FILENAME__, __LINE__, __func__, __VA_ARGS__)
#define LOG_DEBUG(...) log_Log(LOGDEBUG, __FILENAME__, __LINE__, __func__, __VA_ARGS__)
#define LOG_INFO(...) log_Log(LOGINFO, __FILENAME__, __LINE__, __func__, __VA_ARGS__)
@@ 76,6 81,16 @@ extern "C"
#define LOG_ERROR(...) log_Log(LOGERROR, __FILENAME__, __LINE__, __func__, __VA_ARGS__)
#define LOG_FATAL(...) log_Log(LOGFATAL, __FILENAME__, __LINE__, __func__, __VA_ARGS__)
#define LOG_CUSTOM(loggerLevel, ...) log_Log(loggerLevel, __FILENAME__, __LINE__, __func__, __VA_ARGS__)
+#else
+#define LOG_TRACE(...) log_ignore(LOGTRACE, __FILENAME__, __LINE__, __func__, __VA_ARGS__)
+#define LOG_DEBUG(...) log_ignore(LOGDEBUG, __FILENAME__, __LINE__, __func__, __VA_ARGS__)
+#define LOG_INFO(...) log_ignore(LOGINFO, __FILENAME__, __LINE__, __func__, __VA_ARGS__)
+#define LOG_WARN(...) log_ignore(LOGWARN, __FILENAME__, __LINE__, __func__, __VA_ARGS__)
+#define LOG_ERROR(...) log_ignore(LOGERROR, __FILENAME__, __LINE__, __func__, __VA_ARGS__)
+#define LOG_FATAL(...) log_ignore(LOGFATAL, __FILENAME__, __LINE__, __func__, __VA_ARGS__)
+#define LOG_CUSTOM(loggerLevel, ...) log_ignore(loggerLevel, __FILENAME__, __LINE__, __func__, __VA_ARGS__)
+#endif
+
#if LOG_SENSITIVE_DATA_ENABLED
#define LOG_SENSITIVE(loggerLevel, ...) log_Log(loggerLevel, __FILENAME__, __LINE__, __func__, __VA_ARGS__)
#else
M module-utils/log/log.cpp => module-utils/log/log.cpp +9 -1
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <log/log.hpp>
@@ 23,6 23,14 @@ int log_Printf(const char *fmt, ...)
return result;
}
+int log_ignore(logger_level level, const char *file, int line, const char *function, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ va_end(args);
+ return 0;
+}
+
int log_Log(logger_level level, const char *file, int line, const char *function, const char *fmt, ...)
{
va_list args;
M products/PurePhone/CMakeLists.txt => products/PurePhone/CMakeLists.txt +1 -0
@@ 28,6 28,7 @@ target_sources(PurePhone
PurePhoneMain.cpp
PlatformFactory.cpp
EinkSentinelPure.cpp
+ init_prof.cpp
)
target_include_directories(PurePhone
M products/PurePhone/EinkSentinelPure.cpp => products/PurePhone/EinkSentinelPure.cpp +3 -1
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "EinkSentinel.hpp"
@@ 27,6 27,8 @@ namespace service::eink
void EinkSentinel::HoldMinimumFrequency()
{
+ currentReason = std::string("up: ") + owner->getCurrentProcessing() + std::string(" req: ") +
+ std::to_string(static_cast<int>((GetFrequency())));
CpuSentinel::HoldMinimumFrequency(isScreenLocked ? RedrawLockedEinkCpuFrequency
: RedrawUnlockedEinkCpuFrequency);
}
M products/PurePhone/PurePhoneMain.cpp => products/PurePhone/PurePhoneMain.cpp +3 -0
@@ 71,6 71,7 @@
#include <memory>
#include <vector>
#include <cstdlib>
+#include "init_prof.hpp"
void atexit_cleanup_handler()
{
@@ 95,6 96,8 @@ int main()
const std::vector<std::string> fileIndexerAudioPaths = {{purefs::dir::getUserDiskPath() / "music"}};
+ prof::init();
+
#if SYSTEM_VIEW_ENABLED
SEGGER_SYSVIEW_Conf();
SEGGER_SYSVIEW_DisableEvents(SYSVIEW_EVTMASK_ISR_ENTER);
A products/PurePhone/init_prof.cpp => products/PurePhone/init_prof.cpp +26 -0
@@ 0,0 1,26 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "init_prof.hpp"
+#include "FreeRTOS.h"
+#include <cstdint>
+#include <bsp/common.hpp>
+
+extern "C"
+{
+#include "prof.h"
+}
+
+namespace prof
+{
+ void init()
+ {
+#if PROF_ON
+ struct prof_pool_init_data init
+ {
+ 32
+ };
+ prof_pool_init(init);
+#endif
+ }
+} // namespace prof
A products/PurePhone/init_prof.hpp => products/PurePhone/init_prof.hpp +9 -0
@@ 0,0 1,9 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+namespace prof
+{
+ void init();
+}
M third-party/CMakeLists.txt => third-party/CMakeLists.txt +2 -0
@@ 25,6 25,8 @@ add_subdirectory(taglib)
add_subdirectory(tinyexpr)
add_subdirectory(utz)
add_subdirectory(dr_libs)
+add_subdirectory(msgpack11)
+
if (${PROJECT_TARGET} STREQUAL "TARGET_RT1051")
add_subdirectory(CrashDebug)
A third-party/msgpack11/CMakeLists.txt => third-party/msgpack11/CMakeLists.txt +6 -0
@@ 0,0 1,6 @@
+add_library(msgpack11 msgpack11/msgpack11.cpp)
+
+target_include_directories(msgpack11
+ INTERFACE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}
+)
A third-party/msgpack11/msgpack11 => third-party/msgpack11/msgpack11 +1 -0
@@ 0,0 1,1 @@
+Subproject commit e15f1d33f3b06b9552f4e8b24d83f8c89fb31c35