#pragma once #include #include #include #include #include namespace roro { // One task as FreeRTOS reports it at one moment. struct TaskSample { uint32_t id = 0; // unique per task: a new task with an old name has another char name[17] = {}; uint32_t runtime = 0; // microseconds on a CPU since it started; 32 bits, so it wraps every 71 minutes uint16_t stackFree = 0; // the least it ever had left, bytes int8_t core = -1; // -1: not pinned uint8_t state = 0; // eTaskState uint8_t priority = 0; }; // What the System App and `tasks` show for a task (S1, Q119, Q122). struct TaskRow { std::string name; int core = -1; uint8_t state = 0, priority = 0; uint16_t stackFree = 0; uint16_t permille = 0; // share of one core over the interval, in tenths of a percent bool lowStack = false; bool idle = false; // a core's idle task: what's left over }; constexpr uint16_t kLowStackBytes = 512; // Shares from two samples: each task's run time between them over the time that passed. The // 32-bit counters may have wrapped once in between. The task that took the samples (the one // running) gets what's left of its core: see the .cpp. std::vector taskRows(const std::vector& before, uint32_t totalBefore, const std::vector& now, uint32_t totalNow); // A core's load in percent: what its idle task didn't use. -1 without that task in the rows. int coreLoad(const std::vector& rows, int core); enum class TaskSort : uint8_t { Share, Stack, Name }; void sortTasks(std::vector& rows, TaskSort by); // The last N samples, oldest first (Q120). template class History { public: void push(T value) { values_[(first_ + size_) % N] = value; if (size_ < N) size_++; else first_ = (first_ + 1) % N; } size_t size() const { return size_; } T at(size_t i) const { return values_[(first_ + i) % N]; } // 0: the oldest kept void clear() { first_ = size_ = 0; } private: T values_[N] = {}; size_t first_ = 0, size_ = 0; }; } // namespace roro