Added SchedulerTask

This commit is contained in:
2021-08-09 16:38:13 +02:00
parent a6deb67f6d
commit 3195a3e590
6 changed files with 206 additions and 3 deletions

View File

@ -7,6 +7,7 @@ set(headers
src/lockhelper.h
src/lockingqueue.h
src/recursivelockhelper.h
src/schedulertask.h
src/taskutils.h
src/tickchrono.h
src/wrappers/binary_semaphore.h
@ -22,6 +23,7 @@ set(headers
set(sources
src/espstrutils.cpp
src/schedulertask.cpp
src/taskutils.cpp
)

40
Kconfig.projbuild Normal file
View File

@ -0,0 +1,40 @@
menu "espcpputils settings"
choice ESPCPPUTILS_LOG_LOCAL_LEVEL
bool "espcpputils log verbosity"
default ESPCPPUTILS_LOG_LOCAL_LEVEL_INFO
help
Specify how much output to compile into the binary.
You can set lower verbosity level at runtime using
esp_log_level_set function.
Note that this setting limits which log statements
are compiled into the program in go-e sources. So
setting this to, say, "Warning" would mean that
changing log level to "Debug" at runtime will not
be possible.
config ESPCPPUTILS_LOG_LOCAL_LEVEL_NONE
bool "No output"
config ESPCPPUTILS_LOG_LOCAL_LEVEL_ERROR
bool "Error"
config ESPCPPUTILS_LOG_LOCAL_LEVEL_WARN
bool "Warning"
config ESPCPPUTILS_LOG_LOCAL_LEVEL_INFO
bool "Info"
config ESPCPPUTILS_LOG_LOCAL_LEVEL_DEBUG
bool "Debug"
config ESPCPPUTILS_LOG_LOCAL_LEVEL_VERBOSE
bool "Verbose"
endchoice
config ESPCPPUTILS_LOG_LOCAL_LEVEL
int
default 0 if ESPCPPUTILS_LOG_LOCAL_LEVEL_NONE
default 1 if ESPCPPUTILS_LOG_LOCAL_LEVEL_ERROR
default 2 if ESPCPPUTILS_LOG_LOCAL_LEVEL_WARN
default 3 if ESPCPPUTILS_LOG_LOCAL_LEVEL_INFO
default 4 if ESPCPPUTILS_LOG_LOCAL_LEVEL_DEBUG
default 5 if ESPCPPUTILS_LOG_LOCAL_LEVEL_VERBOSE
endmenu

View File

@ -1,5 +1,8 @@
#include "espstrutils.h"
#include "sdkconfig.h"
#define LOG_LOCAL_LEVEL CONFIG_ESPCPPUTILS_LOG_LOCAL_LEVEL
// esp-idf includes
#include <esp_log.h>

83
src/schedulertask.cpp Normal file
View File

@ -0,0 +1,83 @@
#include "schedulertask.h"
#include "sdkconfig.h"
#define LOG_LOCAL_LEVEL CONFIG_ESPCPPUTILS_LOG_LOCAL_LEVEL
// esp-idf includes
#include <esp_log.h>
#include <esp_heap_caps.h>
using namespace std::chrono_literals;
namespace espcpputils {
namespace {
constexpr const char * const TAG = "ESPCPPUTILS";
} // namespace
SchedulerTask::SchedulerTask(const char *name, void (&setupCallback)(), void (&loopCallback)(), std::chrono::milliseconds loopInterval, bool intervalImportant, std::string (*perfInfo)()) :
m_name{name}, m_setupCallback{setupCallback}, m_loopCallback{loopCallback}, m_loopInterval{loopInterval}, m_intervalImportant{intervalImportant}, m_perfInfo{perfInfo}
{
}
void SchedulerTask::loop()
{
if (m_lastUpdate && espchrono::ago(*m_lastUpdate) < m_loopInterval)
return;
ESP_LOGV(TAG, "start %s", m_name);
if (m_intervalImportant)
{
if (!m_lastUpdate)
goto trotzdem;
*m_lastUpdate += m_loopInterval;
if (espchrono::ago(*m_lastUpdate) > m_loopInterval/2)
goto trotzdem;
}
else
trotzdem:
m_lastUpdate = espchrono::millis_clock::now();
const auto timeBefore = espchrono::millis_clock::now();
m_loopCallback();
const auto timeAfter = espchrono::millis_clock::now();
ESP_LOGV(TAG, "end %s", m_name);
m_callCountTemp++;
m_lastElapsed = timeAfter-timeBefore;
m_totalElapsedTemp += m_lastElapsed;
if (m_lastElapsed > m_maxElapsedTemp)
m_maxElapsedTemp = m_lastElapsed;
if (m_lastElapsed < 100ms)
ESP_LOGV(TAG, "task %s hang for %lldms (heap8=%zd)",
m_name, std::chrono::milliseconds{m_lastElapsed}.count(), heap_caps_get_free_size(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT));
else
ESP_LOGW(TAG, "task %s hang for %lldms (heap8=%zd) %s",
m_name, std::chrono::milliseconds{m_lastElapsed}.count(), heap_caps_get_free_size(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT),
m_perfInfo ? m_perfInfo().c_str() : "");
}
void SchedulerTask::pushStats(bool printTask)
{
m_callCount = m_callCountTemp;
m_totalElapsed = m_totalElapsedTemp;
m_averageElapsed = m_callCount > 0 ? (m_totalElapsed / m_callCount) : std::chrono::milliseconds{};
m_maxElapsed = m_maxElapsedTemp;
m_callCountTemp = 0;
m_totalElapsedTemp = {};
m_maxElapsedTemp = {};
if (printTask)
ESP_LOGI(TAG, "name=%s, count=%i, last=%lldms, total=%lldms, max=%lldms",
m_name, m_callCount,
std::chrono::milliseconds{m_lastElapsed}.count(),
std::chrono::milliseconds{m_totalElapsed}.count(),
std::chrono::milliseconds{m_maxElapsed}.count()
);
}
} // namespace espcpputils

51
src/schedulertask.h Normal file
View File

@ -0,0 +1,51 @@
#pragma once
// system includes
#include <optional>
#include <chrono>
#include <string>
// local includes
#include "espchrono.h"
#include "arrayview.h"
namespace espcpputils {
class SchedulerTask
{
public:
SchedulerTask(const char *name, void (&setupCallback)(), void (&loopCallback)(),
std::chrono::milliseconds loopInterval, bool intervalImportant = false,
std::string (*perfInfo)() = nullptr);
const char *name() const { return m_name; }
const std::chrono::milliseconds &lastElapsed() const { return m_lastElapsed; }
const std::chrono::milliseconds &averageElapsed() const { return m_averageElapsed; }
const std::chrono::milliseconds &maxElapsed() const { return m_maxElapsed; }
int callCount() const { return m_callCount; }
void setup() const { m_setupCallback(); }
void loop();
void pushStats(bool printTask);
private:
const char * const m_name;
void (&m_setupCallback)();
void (&m_loopCallback)();
const std::chrono::milliseconds m_loopInterval;
const bool m_intervalImportant;
std::string (* const m_perfInfo)();
std::optional<espchrono::millis_clock::time_point> m_lastUpdate;
std::chrono::milliseconds m_lastElapsed;
std::chrono::milliseconds m_totalElapsed;
std::chrono::milliseconds m_averageElapsed;
std::chrono::milliseconds m_maxElapsed;
int m_callCount{};
std::chrono::milliseconds m_totalElapsedTemp;
std::chrono::milliseconds m_maxElapsedTemp;
int m_callCountTemp{};
};
} // namespace espcpputils

View File

@ -1,6 +1,19 @@
#include "taskutils.h"
#include "sdkconfig.h"
#define LOG_LOCAL_LEVEL CONFIG_ESPCPPUTILS_LOG_LOCAL_LEVEL
// esp-idf includes
#include <esp_log.h>
// local includes
#include "futurecpp.h"
namespace espcpputils {
namespace {
constexpr const char * const TAG = "ESPCPPUTILS";
} // namespace
BaseType_t createTask(TaskFunction_t pvTaskCode,
const char * const pcName,
const uint32_t usStackDepth,
@ -13,11 +26,22 @@ BaseType_t createTask(TaskFunction_t pvTaskCode,
{
case CoreAffinity::Core0:
case CoreAffinity::Core1:
return xTaskCreatePinnedToCore(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask, int(coreAffinity));
{
const auto result = xTaskCreatePinnedToCore(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask, int(coreAffinity));
if (result != pdPASS)
ESP_LOGW(TAG, "xTaskCreatePinnedToCore() %s failed with %i", pcName, result);
return result;
}
case CoreAffinity::Both:
return xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask);
{
const auto result = xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask);
if (result != pdPASS)
ESP_LOGW(TAG, "xTaskCreate() %s failed with %i", pcName, result);
return result;
}
default:
__builtin_unreachable();
ESP_LOGE(TAG, "unknown coreAffinity %i", std::to_underlying(coreAffinity));
return pdFAIL;
}
}