Added SchedulerTask
This commit is contained in:
@ -7,6 +7,7 @@ set(headers
|
|||||||
src/lockhelper.h
|
src/lockhelper.h
|
||||||
src/lockingqueue.h
|
src/lockingqueue.h
|
||||||
src/recursivelockhelper.h
|
src/recursivelockhelper.h
|
||||||
|
src/schedulertask.h
|
||||||
src/taskutils.h
|
src/taskutils.h
|
||||||
src/tickchrono.h
|
src/tickchrono.h
|
||||||
src/wrappers/binary_semaphore.h
|
src/wrappers/binary_semaphore.h
|
||||||
@ -22,6 +23,7 @@ set(headers
|
|||||||
|
|
||||||
set(sources
|
set(sources
|
||||||
src/espstrutils.cpp
|
src/espstrutils.cpp
|
||||||
|
src/schedulertask.cpp
|
||||||
src/taskutils.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 "espstrutils.h"
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#define LOG_LOCAL_LEVEL CONFIG_ESPCPPUTILS_LOG_LOCAL_LEVEL
|
||||||
|
|
||||||
// esp-idf includes
|
// esp-idf includes
|
||||||
#include <esp_log.h>
|
#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 "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 espcpputils {
|
||||||
|
namespace {
|
||||||
|
constexpr const char * const TAG = "ESPCPPUTILS";
|
||||||
|
} // namespace
|
||||||
|
|
||||||
BaseType_t createTask(TaskFunction_t pvTaskCode,
|
BaseType_t createTask(TaskFunction_t pvTaskCode,
|
||||||
const char * const pcName,
|
const char * const pcName,
|
||||||
const uint32_t usStackDepth,
|
const uint32_t usStackDepth,
|
||||||
@ -13,11 +26,22 @@ BaseType_t createTask(TaskFunction_t pvTaskCode,
|
|||||||
{
|
{
|
||||||
case CoreAffinity::Core0:
|
case CoreAffinity::Core0:
|
||||||
case CoreAffinity::Core1:
|
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:
|
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:
|
default:
|
||||||
__builtin_unreachable();
|
ESP_LOGE(TAG, "unknown coreAffinity %i", std::to_underlying(coreAffinity));
|
||||||
|
return pdFAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user