/* * quick_profiler.hpp * * Created on: Aug 10, 2023 * Author: algin */ #ifndef FREE_RTOS_PROFILER_QUICK_PROFILER_HPP_ #define FREE_RTOS_PROFILER_QUICK_PROFILER_HPP_ #include #include #include #include namespace free_rtos { #define START_AUTO_PROFILER(name, size, id) static free_rtos::QuickProfiler name##_profiler{#name}; \ QuickProfilerAutoItem name##_profiler_item_##id = name##_profiler.makeProfilerAutoItem() #define MAKE_AUTO_PROFILER(name, size) static free_rtos::QuickProfiler name##_profiler{#name} #define MAKE_STATIC_PROFILER(name, size) free_rtos::QuickProfiler name##_profiler{#name} #define FORCE_DUMP_PROFILER(name) name##_profiler.forceDump() #define GET_LAST_PROFILER_ITEM(name) name##_profiler.getLast() #define EXTERN_PROFILER(name, size) extern QuickProfiler name##_profiler #define TRY_DUMP_PROFILER(name) name##_profiler.dumpTry(); #define MAKE_PROFILER_AUTO_ITEM(name, size, id) QuickProfilerAutoItem name##_profiler_item_##id = name##_profiler.makeProfilerAutoItem() #define MAKE_PROFILER_STATIC_ITEM(name, size, id) QuickProfilerStaticItem name##_profiler_item_##id = name##_profiler.makeProfilerStaticItem() #define EXTERN_PROFILER_STATIC_ITEM(name, size, id) extern QuickProfilerStaticItem name##_profiler_item_##id #define START_PROFILER_STATIC_ITEM(name, size, id) name##_profiler_item_##id.start() #define STOP_PROFILER_STATIC_ITEM(name, size, id) name##_profiler_item_##id.stop() static void QuickProfiler_init(const uint64_t cpuFreqHz) { CycleCounterP_init(cpuFreqHz); CycleCounterP_reset(); uint64_t nsToTicks = CycleCounterP_nsToTicks(1000); DebugP_log((char *)"%lld ticks in 1000 nanoseconds\r\n", nsToTicks); } template class QuickProfilerAutoItem; template class QuickProfilerStaticItem; template class QuickProfiler { public: QuickProfiler(const char *name, bool auto_dump = false) : name_{name} , auto_dump_{auto_dump} { }; QuickProfilerAutoItem makeProfilerAutoItem() { return QuickProfilerAutoItem{*this}; } QuickProfilerStaticItem makeProfilerStaticItem() { return QuickProfilerStaticItem{*this}; } void collect(uint64_t diff) { uint32_t counter = counter_; buffer_[counter] = diff; counter++; if(counter >= size) { counter = 0; if(auto_dump_ == true) { dump(); } } counter_ = counter; } void dumpTry() { uint32_t counter = counter_; if(counter == 0) { dump(); } counter_ = counter; } uint64_t getLast() { uint32_t counter = counter_; if(counter > 0) { counter = counter - 1; } else { counter = size - 1; } return buffer_[counter]; } void forceDump() { uint64_t average{0x0000000000000000}; uint32_t min{0xFFFFFFFF}; uint32_t max{0x00000000}; for(uint64_t value : buffer_) { average += value/size; if(value < min) { min = value; } if(value > max) { max = value; } DebugP_log((char *)"%lld ", value); } DebugP_log((char *)"\r\n"); DebugP_log((char *)"Profiler %s average: %lld min: %d max: %d\r\n", name_, average, min, max); } private: const char *name_; const bool auto_dump_{false}; size_t counter_{0}; std::array buffer_; void dump() { uint64_t average{0x0000000000000000}; uint32_t min{0xFFFFFFFF}; uint32_t max{0x00000000}; for(uint64_t value : buffer_) { average += value/size; if(value < min) { min = value; } if(value > max) { max = value; } } DebugP_log((char *)"Profiler %s average: %lld min: %d max: %d\r\n", name_, average, min, max); } }; template class QuickProfilerAutoItem { public: QuickProfilerAutoItem(QuickProfiler& profiler) : profiler_{profiler} { start_cycle_ = CycleCounterP_getCount32(); }; ~QuickProfilerAutoItem() { uint32_t end_cycle = CycleCounterP_getCount32(); uint32_t start_cycle = start_cycle_; uint64_t diff; if(end_cycle > start_cycle) { diff = end_cycle - start_cycle; } else { diff = (0xFFFFFFFFU - start_cycle) + end_cycle; } profiler_.collect(diff); } private: QuickProfiler& profiler_; uint32_t start_cycle_; }; template class QuickProfilerStaticItem { public: QuickProfilerStaticItem(QuickProfiler& profiler) : profiler_{profiler} { }; void start() { start_cycle_ = CycleCounterP_getCount32(); } void stop() { uint32_t end_cycle = CycleCounterP_getCount32(); uint32_t start_cycle = start_cycle_; uint64_t diff; if(end_cycle > start_cycle) { diff = end_cycle - start_cycle; } else { diff = (0xFFFFFFFFU - start_cycle) + end_cycle; } profiler_.collect(diff); } private: QuickProfiler& profiler_; uint32_t start_cycle_; }; } // namespace free_rtos #endif /* FREE_RTOS_PROFILER_QUICK_PROFILER_HPP_ */