Monitoring APIs

Task Monitor

The task monitor provides the ability to use the FreeRTOS trace facility to output information about the CPU utilization (%), stack high water mark (bytes), and priority of all the tasks running on the system.

There is an associated task-monitor python gui which can parse the output of this component and render it as a chart or into a table for visualization.

Code examples for the monitor API are provided in the monitor example folder.

API Reference

Header File

Classes

class TaskMonitor : public espp::BaseComponent

Class which monitors the currently running tasks in the system and periodically logs their states. See also FreeRTOS::vTaskGetInfo().

Basic Task Monitor Example

    // create the monitor
    espp::TaskMonitor tm({.period = 500ms});
    // create threads
    auto start = std::chrono::high_resolution_clock::now();
    auto task_fn = [&start](int task_id, auto &, auto &, auto &) {
      auto now = std::chrono::high_resolution_clock::now();
      auto seconds_since_start = std::chrono::duration<float>(now - start).count();
      // do some work
      float x = 2.0f * M_PI * sin(exp(task_id) * seconds_since_start);
      // sleep
      std::this_thread::sleep_for((10ms * std::abs(x)) + 1ms);
      // don't want to stop the task
      return false;
    };
    std::vector<std::unique_ptr<espp::Task>> tasks;
    size_t num_tasks = 10;
    tasks.resize(num_tasks);
    for (size_t i = 0; i < num_tasks; i++) {
      std::string task_name = fmt::format("Task {}", i);
      auto task = espp::Task::make_unique(
          {.callback = std::bind(task_fn, i, _1, _2, _3),
           .task_config = {.name = task_name, .stack_size_bytes = 5 * 1024}});
      tasks[i] = std::move(task);
      tasks[i]->start();
    }
    // now sleep for a while to let the monitor do its thing
    std::this_thread::sleep_for(5s);

get_latest_info_vector() Example

    // create threads
    auto start = std::chrono::high_resolution_clock::now();
    auto task_fn = [&start](int task_id, auto &, auto &, auto &) {
      auto now = std::chrono::high_resolution_clock::now();
      auto seconds_since_start = std::chrono::duration<float>(now - start).count();
      // do some work
      float x = 2.0f * M_PI * sin(exp(task_id) * seconds_since_start);
      // sleep
      std::this_thread::sleep_for((10ms * std::abs(x)) + 1ms);
      // don't want to stop the task
      return false;
    };
    std::vector<std::unique_ptr<espp::Task>> tasks;
    size_t num_tasks = 10;
    tasks.resize(num_tasks);
    for (size_t i = 0; i < num_tasks; i++) {
      std::string task_name = fmt::format("Task {}", i);
      auto task = espp::Task::make_unique(
          {.callback = std::bind(task_fn, i, _1, _2, _3),
           .task_config = {.name = task_name, .stack_size_bytes = 5 * 1024}});
      tasks[i] = std::move(task);
      tasks[i]->start();
    }
    // now sleep for a while to let the monitor do its thing
    std::this_thread::sleep_for(1s);
    auto task_info = espp::TaskMonitor::get_latest_info_vector();
    for (const auto &info : task_info) {
      fmt::print("{}\n", info);
    }

get_latest_info_*() Example

    // create threads
    auto start = std::chrono::high_resolution_clock::now();
    auto task_fn = [&start](int task_id, auto &, auto &, auto &) {
      auto now = std::chrono::high_resolution_clock::now();
      auto seconds_since_start = std::chrono::duration<float>(now - start).count();
      // do some work
      float x = 2.0f * M_PI * sin(exp(task_id) * seconds_since_start);
      // sleep
      std::this_thread::sleep_for((10ms * std::abs(x)) + 1ms);
      // don't want to stop the task
      return false;
    };
    std::vector<std::unique_ptr<espp::Task>> tasks;
    size_t num_tasks = 10;
    tasks.resize(num_tasks);
    for (size_t i = 0; i < num_tasks; i++) {
      std::string task_name = fmt::format("Task {}", i);
      auto task = espp::Task::make_unique(
          {.callback = std::bind(task_fn, i, _1, _2, _3),
           .task_config = {.name = task_name, .stack_size_bytes = 5 * 1024}});
      tasks[i] = std::move(task);
      tasks[i]->start();
    }
    // now sleep for a while to let the monitor do its thing
    std::this_thread::sleep_for(1s);
    // single line string
    fmt::print("Task Monitor Info (single line):\n");
    fmt::print("{}\n", espp::TaskMonitor::get_latest_info_string());
    // pretty table
    fmt::print("Task Monitor Info (pretty table):\n");
    auto task_table = espp::TaskMonitor::get_latest_info_table();
    std::cout << task_table << std::endl;

Note

you must enable CONFIG_FREERTOS_USE_TRACE_FACILITY and CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS for this class to do anything. This means that you can always instantiate this class in your app_main, and then based on those two config settings it will either do nothing (default) or print out the stats for you to analyze. Finally, the monitoring period can be configured as well.

Note

If you wish to also get the core id of the task, you must enable CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID. If you do not enable this option, the core id will be -2.

Public Functions

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters

rate_limit – The rate limit to use for the logger

Public Static Functions

static inline std::vector<TaskInfo> get_latest_info_vector()

Get information about all the tasks running. Will provide for each task the following information:

  • name

  • % CPU run time the task has used

  • stack high water mark (bytes)

  • current priority of the task

Returns

std::vector<TaskInfo> vector containing info for each task.

static inline std::string get_latest_info_string()

Get information about all the tasks running. Will provide for each task the following information:

  • name

  • % CPU run time the task has used

  • stack high water mark (bytes)

  • current priority of the task

  • core the task is running on

Where each entry is separated by ‘,’ and each set of task data is separated by ‘;’.

This is a static function, so it can be called without having to instantiate a TaskMonitor object.

Note

There is no newline returned.

Note

This function calls TaskMonitor::get_latest_info_vector() and then formats the data into a single line string separated by , and ;.

Returns

std::string containing sequence of entries, formatted:

name, cpu%, high_water_mark, priority, core_id;;

static inline auto get_latest_info_table()

Print the latest task information in a nice table format. This is a static function, so it can be called without having to instantiate a TaskMonitor object.

Note

This function calls TaskMonitor::get_latest_info_vector() and then formats the data into a table using the libfmt library.

Returns

A string containing the information in a table format.

struct Config

Config structure for TaskMonitor object.

Public Members

std::chrono::duration<float> period

Period (s) the TaskMonitor::task_callback runs at.

size_t task_stack_size_bytes{8 * 1024}

Stack size (B) allocated to the TaskMonitor::task_callback.

struct TaskInfo

Info structure for each task monitored.

Public Members

std::string name

Name of the task.

uint32_t cpu_percent

% CPU run time the task has used.

uint32_t high_water_mark

Stack high water mark (bytes).

uint32_t priority

Current priority of the task.

int core_id

Core the task is running on. Will be 0,1, or -1 if task is not pinned to a core. Only valid if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID is set to y, otherwise will be -2.