Added SchedulerTask
This commit is contained in:
@ -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
40
Kconfig.projbuild
Normal 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
|
@ -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
83
src/schedulertask.cpp
Normal 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
51
src/schedulertask.h
Normal 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
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user