M module-bsp/board/linux/os/FreeRTOSConfig.h => module-bsp/board/linux/os/FreeRTOSConfig.h +7 -1
@@ 1,3 1,6 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
/*
* FreeRTOS Kernel V10.0.1
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
@@ 122,7 125,7 @@ extern "C"
#define INCLUDE_eTaskGetState 0
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskAbortDelay 1
-#define INCLUDE_xTaskGetHandle 0
+#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_xTaskResumeFromISR 1
#ifdef __NVIC_PRIO_BITS
@@ 172,4 175,7 @@ standard names. */
#define PROJECT_CONFIG_HEAP_INTEGRITY_CHECKS (1)
#endif
+extern void trace_deleteTask(const char *name);
+#define traceTASK_DELETE(pxTaskToDelete) trace_deleteTask(pxTaskToDelete->pcTaskName)
+
#endif /* FREERTOS_CONFIG_H */
M module-bsp/board/rt1051/os/include/FreeRTOSConfig.h => module-bsp/board/rt1051/os/include/FreeRTOSConfig.h +7 -1
@@ 1,3 1,6 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
/*
* FreeRTOS Kernel V10.0.1
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
@@ 122,7 125,7 @@ extern "C"
#define INCLUDE_eTaskGetState 0
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskAbortDelay 1
-#define INCLUDE_xTaskGetHandle 0
+#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_xTaskResumeFromISR 1
#ifdef __NVIC_PRIO_BITS
@@ 177,4 180,7 @@ extern uint32_t ulHighFrequencyTimerTicks(void);
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vConfigureTimerForRunTimeStats()
#define portGET_RUN_TIME_COUNTER_VALUE() ulHighFrequencyTimerTicks()
+extern void trace_deleteTask(const char *name);
+#define traceTASK_DELETE(pxTaskToDelete) trace_deleteTask(pxTaskToDelete->pcTaskName)
+
#endif /* FREERTOS_CONFIG_H */
M module-os/CMakeLists.txt => module-os/CMakeLists.txt +4 -1
@@ 22,6 22,8 @@ add_library(${PROJECT_NAME} STATIC
CriticalSectionGuard.cpp
$<$<BOOL:${PROF_ON}>:prof/prof.c>
+
+ trace/DeletedTasks.cpp
)
# Board specific compilation definitions,options,include directories and features
@@ 49,6 51,7 @@ target_include_directories(${PROJECT_NAME}
RTOSWrapper/include
prof
+ trace
)
@@ 60,7 63,7 @@ endif ()
target_link_libraries(${PROJECT_NAME} PUBLIC log-api board-config freertos_kernel)
-add_library(freertos-app application.c)
+add_library(freertos-app application.c trace/DeletedTasks.cpp)
target_link_libraries(freertos-app PRIVATE freertos_kernel log-api)
if (${ENABLE_TESTS})
A module-os/trace/DeletedTasks.cpp => module-os/trace/DeletedTasks.cpp +53 -0
@@ 0,0 1,53 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "DeletedTasks.hpp"
+#include <FreeRTOS.h>
+#include <mutex.hpp>
+#include <task.h>
+#include <cstdint>
+#include <algorithm>
+
+namespace
+{
+ std::vector<sys::DeletedTasks::DeletedTaskDetails_t> deletedTasks;
+ cpp_freertos::MutexStandard mutex;
+} // namespace
+
+// Function called from FreeRTOS when the task is deleted, works on static data therefore it is necessary to ensure
+// mutex synchronization
+void trace_deleteTask(const char *name)
+{
+ TaskHandle_t xHandle;
+ TaskStatus_t xTaskDetails;
+
+ cpp_freertos::LockGuard lock(mutex);
+
+ xHandle = xTaskGetHandle(name);
+ if (xHandle != NULL) {
+ vTaskGetInfo(xHandle, &xTaskDetails, pdFALSE, eInvalid);
+
+ auto taskIt = std::find_if(std::begin(deletedTasks), std::end(deletedTasks), [xTaskDetails](auto &el) {
+ return el.name == xTaskDetails.pcTaskName;
+ });
+
+ if (taskIt != std::end(deletedTasks)) {
+ taskIt->tickIncrements += xTaskDetails.ulRunTimeCounter;
+ }
+ else {
+ deletedTasks.push_back(
+ {.name = xTaskDetails.pcTaskName, .tickIncrements = xTaskDetails.ulRunTimeCounter});
+ }
+ }
+}
+
+namespace sys
+{
+ void DeletedTasks::MigrateDeletedTasks(std::vector<DeletedTaskDetails_t> &task)
+ {
+ cpp_freertos::LockGuard lock(mutex);
+
+ task.assign(deletedTasks.begin(), deletedTasks.end());
+ deletedTasks.clear();
+ }
+}
A module-os/trace/DeletedTasks.hpp => module-os/trace/DeletedTasks.hpp +27 -0
@@ 0,0 1,27 @@
+// 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 <vector>
+#include <cstdint>
+
+namespace sys
+{
+
+ class DeletedTasks
+ {
+
+ public:
+ struct DeletedTaskDetails_t
+ {
+ const char *name; // A pointer to the task's name
+ std::uint32_t tickIncrements; // The total run time allocated to the task so far, as defined by the run time
+ // stats clock.
+ };
+
+ void MigrateDeletedTasks(std::vector<DeletedTaskDetails_t> &task);
+ };
+
+} // namespace sys
+
M module-sys/SystemManager/CMakeLists.txt => module-sys/SystemManager/CMakeLists.txt +2 -0
@@ 9,12 9,14 @@ target_sources(sys-manager
include/SystemManager/CpuGovernor.hpp
include/SystemManager/PowerManager.hpp
include/SystemManager/DeviceManager.hpp
+ include/SystemManager/TaskStatistics.hpp
PRIVATE
CpuGovernor.cpp
CpuSentinel.cpp
GovernorSentinelOperations.cpp
CpuStatistics.cpp
+ TaskStatistics.cpp
CpuLogPrinter.cpp
CpuPackPrinter.cpp
data/SystemManagerActionsParams.hpp
M module-sys/SystemManager/CpuStatistics.cpp => module-sys/SystemManager/CpuStatistics.cpp +3 -12
@@ 5,7 5,7 @@
#include <log/log.hpp>
#include <FreeRTOS.h>
#include <task.h>
-#include <limits>
+#include <Utils.hpp>
extern "C"
{
@@ 65,8 65,8 @@ namespace sys
{
uint32_t idleTickCount = xTaskGetIdleRunTimeCounter();
uint32_t totalTickCount = ulHighFrequencyTimerTicks();
- uint32_t idleTickIncrease = ComputeIncrease(idleTickCount, lastIdleTickCount);
- uint32_t totalTickIncrease = ComputeIncrease(totalTickCount, lastTotalTickCount);
+ uint32_t idleTickIncrease = utils::computeIncrease(idleTickCount, lastIdleTickCount);
+ uint32_t totalTickIncrease = utils::computeIncrease(totalTickCount, lastTotalTickCount);
lastIdleTickCount = idleTickCount;
lastTotalTickCount = totalTickCount;
if (totalTickIncrease != 0u) {
@@ 83,13 83,4 @@ namespace sys
return cpuLoad;
}
- uint32_t CpuStatistics::ComputeIncrease(uint32_t currentCount, uint32_t lastCount) const
- {
- if (currentCount >= lastCount) {
- return currentCount - lastCount;
- }
- else {
- return std::numeric_limits<uint32_t>::max() - lastCount + currentCount;
- }
- }
} // namespace sys
M module-sys/SystemManager/PowerManager.cpp => module-sys/SystemManager/PowerManager.cpp +31 -8
@@ 10,6 10,7 @@
#include <SystemManager/PowerManager.hpp>
#include <gsl/util>
#include <log/log.hpp>
+#include <Utils.hpp>
namespace sys
{
@@ 28,10 29,19 @@ namespace sys
return levelName;
}
- [[nodiscard]] auto CpuFrequencyMonitor::GetRuntimePercentage() const noexcept -> std::uint32_t
+ [[nodiscard]] auto CpuFrequencyMonitor::GetTotalRuntimePercentage(
+ const TickType_t totalTicksIncrease) const noexcept -> std::uint32_t
{
- auto tickCount = xTaskGetTickCount();
- return tickCount == 0 ? 0 : ((totalTicksCount * 100) / tickCount);
+ return totalTicksIncrease == 0 ? 0 : ((totalTicksCount * 100) / totalTicksIncrease);
+ }
+
+ [[nodiscard]] auto CpuFrequencyMonitor::GetPeriodRuntimePercentage(
+ const TickType_t periodTicksIncrease) const noexcept -> std::uint32_t
+ {
+ return periodTicksIncrease == 0
+ ? 0
+ : ((static_cast<std::uint64_t>(utils::computeIncrease(totalTicksCount, lastTotalTicksCount)) * 100) /
+ periodTicksIncrease);
}
void CpuFrequencyMonitor::IncreaseTicks(TickType_t ticks)
@@ 39,7 49,13 @@ namespace sys
totalTicksCount += ticks;
}
- PowerManager::PowerManager(CpuStatistics &stats) : powerProfile{bsp::getPowerProfile()}, cpuStatistics(stats)
+ void CpuFrequencyMonitor::SavePeriodTicks()
+ {
+ lastTotalTicksCount = totalTicksCount;
+ }
+
+ PowerManager::PowerManager(CpuStatistics &cpuStats, TaskStatistics &taskStats)
+ : powerProfile{bsp::getPowerProfile()}, cpuStatistics(cpuStats), taskStatistics(taskStats)
{
driverSEMC = drivers::DriverSEMC::Create(drivers::name::ExternalRAM);
lowPowerControl = bsp::LowPowerMode::Create().value_or(nullptr);
@@ 184,16 200,23 @@ namespace sys
lastCpuFrequencyChangeTimestamp = ticks;
}
- void PowerManager::LogPowerManagerEfficiency()
+ void PowerManager::LogPowerManagerStatistics()
{
- std::string log{"PowerManager Efficiency: "};
+ const TickType_t tickCount = xTaskGetTickCount();
+ const TickType_t periodTickIncrease = tickCount - lastLogStatisticsTimestamp;
UpdateCpuFrequencyMonitor(lowPowerControl->GetCurrentFrequencyLevel());
+ std::string log{"last period (total): "};
for (auto &level : cpuFrequencyMonitor) {
- log.append(level.GetName() + ": " + std::to_string(level.GetRuntimePercentage()) + "% ");
+ log.append(level.GetName() + ": " + std::to_string(level.GetPeriodRuntimePercentage(periodTickIncrease)) +
+ "% (" + std::to_string(level.GetTotalRuntimePercentage(tickCount)) + "%) ");
+ level.SavePeriodTicks();
}
-
+ lastLogStatisticsTimestamp = tickCount;
LOG_INFO("%s", log.c_str());
+
+ taskStatistics.Update();
+ taskStatistics.LogCpuUsage();
}
void PowerManager::SetBootSuccess()
M module-sys/SystemManager/SystemManagerCommon.cpp => module-sys/SystemManager/SystemManagerCommon.cpp +7 -6
@@ 252,7 252,8 @@ namespace sys
void SystemManagerCommon::StartSystem(InitFunction sysInit, InitFunction appSpaceInit, DeinitFunction sysDeinit)
{
cpuStatistics = std::make_unique<CpuStatistics>();
- powerManager = std::make_unique<PowerManager>(*cpuStatistics);
+ taskStatistics = std::make_unique<TaskStatistics>();
+ powerManager = std::make_unique<PowerManager>(*cpuStatistics, *taskStatistics);
deviceManager = std::make_unique<DeviceManager>();
systemInit = std::move(sysInit);
@@ 265,11 266,11 @@ namespace sys
this, "cpuTick", constants::timerInitInterval, [this](sys::Timer &) { FreqUpdateTick(); });
freqTimer.start();
- powerManagerEfficiencyTimer = sys::TimerFactory::createPeriodicTimer(
- this, "logPowerManagerEfficiency", constants::powerManagerLogsTimerInterval, [this](sys::Timer &) {
- powerManager->LogPowerManagerEfficiency();
+ powerManagerStatisticsTimer = sys::TimerFactory::createPeriodicTimer(
+ this, "PowerManagerStatisticsTimer", constants::powerManagerLogsTimerInterval, [this](sys::Timer &) {
+ powerManager->LogPowerManagerStatistics();
});
- powerManagerEfficiencyTimer.start();
+ powerManagerStatisticsTimer.start();
}
bool SystemManagerCommon::Restore(Service *s)
@@ 705,7 706,7 @@ namespace sys
// In case if other power down request arrive in the meantime
lowBatteryShutdownDelay.stop();
freqTimer.stop();
- powerManagerEfficiencyTimer.stop();
+ powerManagerStatisticsTimer.stop();
// We are going to remove services in reversed order of creation
CriticalSection::Enter();
A module-sys/SystemManager/TaskStatistics.cpp => module-sys/SystemManager/TaskStatistics.cpp +117 -0
@@ 0,0 1,117 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <SystemManager/TaskStatistics.hpp>
+#include <log/log.hpp>
+#include <semphr.h>
+#include <Utils.hpp>
+#include <algorithm>
+#include <string>
+
+namespace constants
+{
+ inline constexpr std::uint32_t cpuUsageThreshold{10};
+ inline const std::string ignoredTaskName{"IDLE"};
+} // namespace constants
+
+namespace sys
+{
+
+ TaskStatistics::TaskStatistics() : totalSystemTick(0)
+ {}
+
+ void TaskStatistics::Update()
+ {
+ std::uint32_t currentSystemTick{0};
+ const auto currentNumberOfTasks = uxTaskGetNumberOfTasks();
+
+ TaskVector_t baseTasks;
+ DeletedTaskVector_t delTasks;
+ std::vector<TaskStatus_t> aliveTasks(currentNumberOfTasks);
+
+ deletedTasks.MigrateDeletedTasks(delTasks);
+ uxTaskGetSystemState(aliveTasks.data(), currentNumberOfTasks, ¤tSystemTick);
+
+ MergeDeletedTasks(baseTasks, delTasks);
+ MergeAliveTasks(baseTasks, aliveTasks);
+ MergeOldTasks(baseTasks, tasks);
+ UpdateCpuUsage(baseTasks, utils::computeIncrease(currentSystemTick, totalSystemTick));
+ ClearTasks(baseTasks);
+
+ totalSystemTick = currentSystemTick;
+ }
+
+ void TaskStatistics::LogCpuUsage() const
+ {
+ for (auto &task : tasks) {
+ if (!constants::ignoredTaskName.compare(task.name))
+ continue;
+ if (task.cpuUsage > constants::cpuUsageThreshold) {
+ LOG_INFO("Task %s had %" PRIu32 "%% CPU usage in the last period.", task.name, task.cpuUsage);
+ }
+ }
+ }
+
+ void TaskStatistics::UpdateCpuUsage(TaskVector_t &baseTasks, const std::uint32_t systemTickIncrease)
+ {
+ for (auto &task : baseTasks) {
+ task.cpuUsage = ComputePercentageCpuUsage(task.tickIncrements, systemTickIncrease);
+ }
+ }
+
+ void TaskStatistics::MergeDeletedTasks(TaskVector_t &baseTasks, const DeletedTaskVector_t &tasksToMerge)
+ {
+ for (auto &task : tasksToMerge) {
+ baseTasks.push_back({.name = task.name,
+ .isAlive = false,
+ .totalTick = 0,
+ .tickIncrements = task.tickIncrements,
+ .cpuUsage = 0});
+ }
+ }
+ void TaskStatistics::MergeAliveTasks(TaskVector_t &baseTasks, const std::vector<TaskStatus_t> &tasksToMerge)
+ {
+ for (auto &task : tasksToMerge) {
+ auto taskIt = std::find_if(
+ std::begin(baseTasks), std::end(baseTasks), [task](auto &el) { return el.name == task.pcTaskName; });
+
+ if (taskIt != std::end(baseTasks)) {
+ taskIt->tickIncrements += task.ulRunTimeCounter;
+ taskIt->totalTick = task.ulRunTimeCounter;
+ taskIt->isAlive = true;
+ }
+ else {
+ baseTasks.push_back({.name = task.pcTaskName,
+ .isAlive = true,
+ .totalTick = task.ulRunTimeCounter,
+ .tickIncrements = task.ulRunTimeCounter,
+ .cpuUsage = 0});
+ }
+ }
+ }
+ void TaskStatistics::MergeOldTasks(TaskVector_t &baseTasks, const TaskVector_t &tasksToMerge)
+ {
+ for (auto &task : tasksToMerge) {
+ if (!task.isAlive)
+ continue;
+ auto taskIt = std::find_if(
+ std::begin(baseTasks), std::end(baseTasks), [task](auto &el) { return el.name == task.name; });
+
+ if (taskIt != std::end(baseTasks)) {
+ taskIt->tickIncrements -= task.totalTick;
+ }
+ }
+ }
+ void TaskStatistics::ClearTasks(TaskVector_t &baseTasks)
+ {
+ tasks.assign(baseTasks.begin(), baseTasks.end());
+ baseTasks.clear();
+ }
+
+ [[nodiscard]] std::uint32_t TaskStatistics::ComputePercentageCpuUsage(const std::uint32_t taskTickIncrease,
+ const std::uint32_t totalTickIncrease) const
+ {
+ return totalTickIncrease == 0u ? 0 : ((static_cast<std::uint64_t>(taskTickIncrease) * 100) / totalTickIncrease);
+ }
+
+} // namespace sys
M module-sys/SystemManager/include/SystemManager/CpuStatistics.hpp => module-sys/SystemManager/include/SystemManager/CpuStatistics.hpp +0 -1
@@ 28,7 28,6 @@ namespace sys
void UpdatePercentageCpuLoad();
/// 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};
M module-sys/SystemManager/include/SystemManager/PowerManager.hpp => module-sys/SystemManager/include/SystemManager/PowerManager.hpp +12 -4
@@ 10,6 10,7 @@
#include "drivers/semc/DriverSEMC.hpp"
#include "SysCpuUpdateResult.hpp"
#include "CpuGovernor.hpp"
+#include "TaskStatistics.hpp"
#include <bsp/lpm/PowerProfile.hpp>
#include <vector>
@@ 28,18 29,23 @@ namespace sys
explicit CpuFrequencyMonitor(const std::string name);
[[nodiscard]] auto GetName() const noexcept -> std::string;
- [[nodiscard]] auto GetRuntimePercentage() const noexcept -> std::uint32_t;
+ [[nodiscard]] auto GetPeriodRuntimePercentage(const TickType_t periodTicksIncrease) const noexcept
+ -> std::uint32_t;
+ [[nodiscard]] auto GetTotalRuntimePercentage(const TickType_t totalTicksIncrease) const noexcept
+ -> std::uint32_t;
void IncreaseTicks(TickType_t ticks);
+ void SavePeriodTicks();
private:
std::string levelName;
- std::uint64_t totalTicksCount{0};
+ std::uint32_t totalTicksCount{0};
+ std::uint32_t lastTotalTicksCount{0};
};
class PowerManager
{
public:
- explicit PowerManager(CpuStatistics &stats);
+ explicit PowerManager(CpuStatistics &cpuStats, TaskStatistics &taskStats);
~PowerManager();
int32_t PowerOff();
@@ 65,7 71,7 @@ namespace sys
void SetPernamentFrequency(bsp::CpuFrequencyMHz freq);
void ResetPernamentFrequency();
- void LogPowerManagerEfficiency();
+ void LogPowerManagerStatistics();
void SetBootSuccess();
private:
@@ 75,6 81,7 @@ namespace sys
void UpdateCpuFrequencyMonitor(bsp::CpuFrequencyMHz currentFreq);
TickType_t lastCpuFrequencyChangeTimestamp{0};
+ TickType_t lastLogStatisticsTimestamp{0};
std::vector<CpuFrequencyMonitor> cpuFrequencyMonitor;
@@ 85,6 92,7 @@ namespace sys
std::unique_ptr<sys::cpu::AlgorithmFactory> cpuAlgorithms;
CpuStatistics &cpuStatistics;
+ TaskStatistics &taskStatistics;
};
} // namespace sys
M module-sys/SystemManager/include/SystemManager/SystemManagerCommon.hpp => module-sys/SystemManager/include/SystemManager/SystemManagerCommon.hpp +3 -1
@@ 16,6 16,7 @@
#include <hal/key_input/RawKey.hpp>
#include <system/Constants.hpp>
#include "CpuStatistics.hpp"
+#include "TaskStatistics.hpp"
#include "DeviceManager.hpp"
#include <chrono>
#include <vector>
@@ 201,7 202,7 @@ namespace sys
sys::TimerHandle freqTimer;
sys::TimerHandle serviceCloseTimer;
sys::TimerHandle lowBatteryShutdownDelay;
- sys::TimerHandle powerManagerEfficiencyTimer;
+ sys::TimerHandle powerManagerStatisticsTimer;
InitFunction userInit;
InitFunction systemInit;
DeinitFunction systemDeinit;
@@ 214,6 215,7 @@ namespace sys
static cpp_freertos::MutexStandard serviceDestroyMutex;
static cpp_freertos::MutexStandard appDestroyMutex;
std::unique_ptr<CpuStatistics> cpuStatistics;
+ std::unique_ptr<TaskStatistics> taskStatistics;
std::unique_ptr<PowerManager> powerManager;
std::unique_ptr<DeviceManager> deviceManager;
};
A module-sys/SystemManager/include/SystemManager/TaskStatistics.hpp => module-sys/SystemManager/include/SystemManager/TaskStatistics.hpp +51 -0
@@ 0,0 1,51 @@
+// 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 <FreeRTOS.h>
+#include <task.h>
+#include <vector>
+#include <cstdint>
+#include <DeletedTasks.hpp>
+
+namespace sys
+{
+
+ class TaskStatistics
+ {
+
+ public:
+ TaskStatistics();
+
+ /// update the total running time allocated so far for all tasks
+ void Update();
+ /// print the percentage of CPU usage in the last period
+ void LogCpuUsage() const;
+
+ protected:
+ struct TaskDetails_t
+ {
+ const char *name; // A pointer to the task's name
+ bool isAlive; // Flag with information if task exists
+ std::uint32_t totalTick; // The total run time allocated to the task so far
+ std::uint32_t tickIncrements; // run time allocated to the task for the last period
+ std::uint32_t cpuUsage; // Percentage of CPU usage for the last period
+ };
+ using TaskVector_t = std::vector<TaskDetails_t>;
+ using DeletedTaskVector_t = std::vector<DeletedTasks::DeletedTaskDetails_t>;
+
+ TaskVector_t tasks;
+ std::uint32_t totalSystemTick;
+ DeletedTasks deletedTasks;
+
+ [[nodiscard]] std::uint32_t ComputePercentageCpuUsage(const std::uint32_t taskTickIncrease,
+ const std::uint32_t totalTickIncrease) const;
+ void UpdateCpuUsage(TaskVector_t &baseTasks, const std::uint32_t systemTickIncrease);
+ void MergeDeletedTasks(TaskVector_t &baseTasks, const DeletedTaskVector_t &tasksToMerge);
+ void MergeAliveTasks(TaskVector_t &baseTasks, const std::vector<TaskStatus_t> &tasksToMerge);
+ void MergeOldTasks(TaskVector_t &baseTasks, const TaskVector_t &tasksToMerge);
+ void ClearTasks(TaskVector_t &baseTasks);
+ };
+
+} // namespace sys
M module-sys/SystemManager/tests/CMakeLists.txt => module-sys/SystemManager/tests/CMakeLists.txt +9 -0
@@ 24,3 24,12 @@ add_catch2_executable(
LIBS
module-sys
)
+
+add_catch2_executable(
+ NAME
+ task-statistics
+ SRCS
+ test-taskStatistics.cpp
+ LIBS
+ module-sys
+)
A module-sys/SystemManager/tests/test-taskStatistics.cpp => module-sys/SystemManager/tests/test-taskStatistics.cpp +133 -0
@@ 0,0 1,133 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <catch2/catch.hpp>
+
+#include "SystemManager/TaskStatistics.hpp"
+
+namespace mockup
+{
+ class TaskStat : public sys::TaskStatistics
+ {
+ public:
+ using TaskVector_t = std::vector<TaskDetails_t>;
+ using DeletedTaskVector_t = std::vector<sys::DeletedTasks::DeletedTaskDetails_t>;
+
+ [[nodiscard]] auto GetData() const noexcept -> TaskVector_t
+ {
+ return sys::TaskStatistics::tasks;
+ }
+ [[nodiscard]] auto GetPercentageCpuUsage(const std::uint32_t taskTickIncrease,
+ const std::uint32_t totalTickIncrease) const noexcept -> std::uint32_t
+ {
+ return ComputePercentageCpuUsage(taskTickIncrease, totalTickIncrease);
+ }
+ void mergeDeletedTasks(TaskVector_t &baseTasks, const DeletedTaskVector_t &tasksToMerge)
+ {
+ MergeDeletedTasks(baseTasks, tasksToMerge);
+ }
+ void mergeAliveTasks(TaskVector_t &baseTasks, const std::vector<TaskStatus_t> &tasksToMerge)
+ {
+ MergeAliveTasks(baseTasks, tasksToMerge);
+ }
+ void mergeOldTasks(TaskVector_t &baseTasks, const TaskVector_t &tasksToMerge)
+ {
+ MergeOldTasks(baseTasks, tasksToMerge);
+ }
+ void clearTasks(TaskVector_t &baseTasks)
+ {
+ ClearTasks(baseTasks);
+ }
+ };
+} // namespace mockup
+
+TEST_CASE("CpuUsage")
+{
+ auto taskStat = std::make_unique<mockup::TaskStat>();
+ SECTION("positive")
+ {
+ const auto data = taskStat->GetPercentageCpuUsage(100, 1000);
+ REQUIRE(data == 10);
+ }
+ SECTION("null")
+ {
+ const auto data = taskStat->GetPercentageCpuUsage(100, 0);
+ REQUIRE(data == 0);
+ }
+ SECTION("overflow")
+ {
+ const auto data = taskStat->GetPercentageCpuUsage(50000000, 100000000);
+ REQUIRE(data == 50);
+ }
+}
+
+TEST_CASE("Tick Increments")
+{
+ auto taskStat = std::make_unique<mockup::TaskStat>();
+ mockup::TaskStat::TaskVector_t baseTasks;
+ mockup::TaskStat::DeletedTaskVector_t deletedTasks;
+ std::vector<TaskStatus_t> aliveTasks;
+ mockup::TaskStat::TaskVector_t oldTasks;
+
+ oldTasks.push_back({.name = "test_1", .isAlive = true, .totalTick = 1000, .tickIncrements = 100, .cpuUsage = 0});
+ oldTasks.push_back({.name = "test_2", .isAlive = true, .totalTick = 1100, .tickIncrements = 200, .cpuUsage = 0});
+ oldTasks.push_back({.name = "test_3", .isAlive = false, .totalTick = 1200, .tickIncrements = 300, .cpuUsage = 0});
+ oldTasks.push_back({.name = "test_4", .isAlive = false, .totalTick = 1300, .tickIncrements = 400, .cpuUsage = 0});
+ oldTasks.push_back({.name = "test_5", .isAlive = true, .totalTick = 1400, .tickIncrements = 500, .cpuUsage = 0});
+ oldTasks.push_back({.name = "test_6", .isAlive = false, .totalTick = 1500, .tickIncrements = 600, .cpuUsage = 0});
+
+ aliveTasks.push_back({.xHandle = NULL,
+ .pcTaskName = "test_2",
+ .xTaskNumber = 0,
+ .eCurrentState = eTaskState::eSuspended,
+ .uxCurrentPriority = 0,
+ .uxBasePriority = 0,
+ .ulRunTimeCounter = 1000,
+ .pxStackBase = nullptr,
+ .usStackHighWaterMark = 0});
+ aliveTasks.push_back({.xHandle = NULL,
+ .pcTaskName = "test_4",
+ .xTaskNumber = 0,
+ .eCurrentState = eTaskState::eSuspended,
+ .uxCurrentPriority = 0,
+ .uxBasePriority = 0,
+ .ulRunTimeCounter = 1500,
+ .pxStackBase = nullptr,
+ .usStackHighWaterMark = 0});
+ aliveTasks.push_back({.xHandle = NULL,
+ .pcTaskName = "test_5",
+ .xTaskNumber = 0,
+ .eCurrentState = eTaskState::eSuspended,
+ .uxCurrentPriority = 0,
+ .uxBasePriority = 0,
+ .ulRunTimeCounter = 2000,
+ .pxStackBase = nullptr,
+ .usStackHighWaterMark = 0});
+ aliveTasks.push_back({.xHandle = NULL,
+ .pcTaskName = "test_6",
+ .xTaskNumber = 0,
+ .eCurrentState = eTaskState::eSuspended,
+ .uxCurrentPriority = 0,
+ .uxBasePriority = 0,
+ .ulRunTimeCounter = 2500,
+ .pxStackBase = nullptr,
+ .usStackHighWaterMark = 0});
+
+ deletedTasks.push_back({.name = "test_1", .tickIncrements = 1200});
+ deletedTasks.push_back({.name = "test_2", .tickIncrements = 400});
+ deletedTasks.push_back({.name = "test_3", .tickIncrements = 600});
+ deletedTasks.push_back({.name = "test_4", .tickIncrements = 800});
+
+ taskStat->mergeDeletedTasks(baseTasks, deletedTasks);
+ taskStat->mergeAliveTasks(baseTasks, aliveTasks);
+ taskStat->mergeOldTasks(baseTasks, oldTasks);
+ taskStat->clearTasks(baseTasks);
+ auto data = taskStat->GetData();
+
+ REQUIRE(data[0].tickIncrements == 200);
+ REQUIRE(data[1].tickIncrements == 300);
+ REQUIRE(data[2].tickIncrements == 600);
+ REQUIRE(data[3].tickIncrements == 2300);
+ REQUIRE(data[4].tickIncrements == 600);
+ REQUIRE(data[5].tickIncrements == 2500);
+}
M module-utils/utility/Utils.hpp => module-utils/utility/Utils.hpp +11 -0
@@ 259,6 259,17 @@ namespace utils
}
}
+ template <class T>
+ [[nodiscard]] inline T computeIncrease(const T currentCount, const T lastCount)
+ {
+ if (currentCount >= lastCount) {
+ return currentCount - lastCount;
+ }
+ else {
+ return std::numeric_limits<T>::max() - lastCount + currentCount;
+ }
+ }
+
static inline void findAndReplaceAll(std::string &data,
const std::vector<std::pair<std::string, std::optional<std::string>>> &values,
std::function<std::string(int)> getReplaceString = nullptr)
M module-utils/utility/tests/unittest_utils.cpp => module-utils/utility/tests/unittest_utils.cpp +16 -0
@@ 625,3 625,19 @@ TEST_CASE("Generate random Id")
REQUIRE((ret.size() == expectedSize));
}
}
+
+TEST_CASE("Compute increase")
+{
+ SECTION("positive")
+ {
+ const std::uint64_t a{2500}, b{2000};
+ const auto data = utils::computeIncrease(a, b);
+ REQUIRE(data == 500);
+ }
+ SECTION("overfow")
+ {
+ const std::uint32_t a{500}, b{0xFFFFFFFF - 500};
+ const auto data = utils::computeIncrease(a, b);
+ REQUIRE(data == 1000);
+ }
+}
M pure_changelog.md => pure_changelog.md +1 -0
@@ 38,6 38,7 @@
### Added
* Added tethering information on the status bar
* Added basic MMS handling
+* Added run-time statistics for tasks
## [1.3.0 2022-08-04]