219 lines
5.5 KiB
C++
219 lines
5.5 KiB
C++
/*
|
|
* 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 <cstdint>
|
|
#include <array>
|
|
|
|
#include <kernel/dpl/DebugP.h>
|
|
#include <kernel/dpl/CycleCounterP.h>
|
|
|
|
namespace free_rtos {
|
|
|
|
#define START_AUTO_PROFILER(name, size, id) static free_rtos::QuickProfiler<size> name##_profiler{#name}; \
|
|
QuickProfilerAutoItem<size> name##_profiler_item_##id = name##_profiler.makeProfilerAutoItem()
|
|
|
|
#define MAKE_AUTO_PROFILER(name, size) static free_rtos::QuickProfiler<size> name##_profiler{#name}
|
|
#define MAKE_STATIC_PROFILER(name, size) free_rtos::QuickProfiler<size> 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<size> name##_profiler
|
|
|
|
#define TRY_DUMP_PROFILER(name) name##_profiler.dumpTry();
|
|
|
|
#define MAKE_PROFILER_AUTO_ITEM(name, size, id) QuickProfilerAutoItem<size> name##_profiler_item_##id = name##_profiler.makeProfilerAutoItem()
|
|
|
|
#define MAKE_PROFILER_STATIC_ITEM(name, size, id) QuickProfilerStaticItem<size> name##_profiler_item_##id = name##_profiler.makeProfilerStaticItem()
|
|
#define EXTERN_PROFILER_STATIC_ITEM(name, size, id) extern QuickProfilerStaticItem<size> 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<size_t size>
|
|
class QuickProfilerAutoItem;
|
|
|
|
template<size_t size>
|
|
class QuickProfilerStaticItem;
|
|
|
|
template<size_t size>
|
|
class QuickProfiler {
|
|
public:
|
|
QuickProfiler(const char *name, bool auto_dump = false)
|
|
: name_{name}
|
|
, auto_dump_{auto_dump} { };
|
|
|
|
QuickProfilerAutoItem<size> makeProfilerAutoItem() {
|
|
return QuickProfilerAutoItem<size>{*this};
|
|
}
|
|
|
|
QuickProfilerStaticItem<size> makeProfilerStaticItem() {
|
|
return QuickProfilerStaticItem<size>{*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<uint64_t, size> 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<size_t size>
|
|
class QuickProfilerAutoItem {
|
|
public:
|
|
QuickProfilerAutoItem(QuickProfiler<size>& 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<size>& profiler_;
|
|
uint32_t start_cycle_;
|
|
};
|
|
|
|
template<size_t size>
|
|
class QuickProfilerStaticItem {
|
|
public:
|
|
QuickProfilerStaticItem(QuickProfiler<size>& 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<size>& profiler_;
|
|
uint32_t start_cycle_;
|
|
};
|
|
|
|
} // namespace free_rtos
|
|
|
|
#endif /* FREE_RTOS_PROFILER_QUICK_PROFILER_HPP_ */
|