diff --git a/micropython/modules/profiler/micropython.cmake b/micropython/modules/profiler/micropython.cmake new file mode 100644 index 00000000..8a710d24 --- /dev/null +++ b/micropython/modules/profiler/micropython.cmake @@ -0,0 +1,24 @@ +set(MOD_NAME profiler) +string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER) +add_library(usermod_${MOD_NAME} INTERFACE) + +target_sources(usermod_${MOD_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c +) + +target_include_directories(usermod_${MOD_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +target_compile_definitions(usermod_${MOD_NAME} INTERFACE + MODULE_${MOD_NAME_UPPER}_ENABLED=1 +) + +target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) + +set_source_files_properties( + ${CMAKE_CURRENT_LIST_DIR}/profiler.c + PROPERTIES COMPILE_FLAGS + "-Wno-discarded-qualifiers" +) \ No newline at end of file diff --git a/micropython/modules/profiler/profiler.c b/micropython/modules/profiler/profiler.c new file mode 100644 index 00000000..eb758906 --- /dev/null +++ b/micropython/modules/profiler/profiler.c @@ -0,0 +1,24 @@ +#include "profiler.h" + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(profiler_get_probes_obj, profiler_get_probes); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(profiler_reset_obj, profiler_reset); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(profiler_get_probe_obj, profiler_get_probe); + +STATIC const mp_map_elem_t profiler_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_profiler) }, + { MP_ROM_QSTR(MP_QSTR_get_probes), MP_ROM_PTR(&profiler_get_probes_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_probe), MP_ROM_PTR(&profiler_get_probe_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&profiler_reset_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_profiler_globals, profiler_globals_table); + +const mp_obj_module_t profiler_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_profiler_globals, +}; + +#if MICROPY_VERSION <= 70144 +MP_REGISTER_MODULE(MP_QSTR_profiler, profiler_user_cmodule, MODULE_PROFILER_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_profiler, profiler_user_cmodule); +#endif \ No newline at end of file diff --git a/micropython/modules/profiler/profiler.cpp b/micropython/modules/profiler/profiler.cpp new file mode 100644 index 00000000..26808291 --- /dev/null +++ b/micropython/modules/profiler/profiler.cpp @@ -0,0 +1,116 @@ +#include "profiler.hpp" +#include + +namespace pimoroni { + void Probe::reset() { + total_us = 0; + exec_count = 0; + } + + uint32_t Probe::get_avg_runtime() { + return total_us / exec_count; + } + + uint32_t Probe::get_exec_count() { + return exec_count; + } + + void Probe::enter() { + t_start = get_absolute_time(); + } + + void Probe::exit() { + total_us += absolute_time_diff_us(t_start, get_absolute_time()); + exec_count++; + } + + namespace Profiler { + Probe* probes[255]; + uint16_t probe_count = 0; + + Probe* add_probe(const char *name) { + if(probe_count >= 256) return nullptr; + Probe *new_probe = new Probe(name); + probes[probe_count] = new_probe; + probe_count++; + return new_probe; + } + + void reset() { + Probe *p = probes[0]; + for(auto x = 0u; x < probe_count; x++) { + p->reset(); + p++; + } + } + + Probe* get_probe(const char *name) { + Probe *p = probes[0]; + for(auto x = 0u; x < probe_count; x++) { + if (strncmp(name, p->name.data(), p->name.length()) == 0) { + return p; + } + p++; + } + return nullptr; + } + + Probe** get_probes() { + return probes; + } + + uint16_t count() { + return probe_count; + } + } +} + +extern "C" { +#include "profiler.h" + +mp_obj_t profiler_reset() { + pimoroni::Profiler::reset(); + + return mp_const_none; +} + +mp_obj_t profiler_get_probe(mp_obj_t name) { + if(mp_obj_is_str_or_bytes(name)) { + GET_STR_DATA_LEN(name, str, str_len); + pimoroni::Probe *probe = pimoroni::Profiler::get_probe((const char *)str); + + mp_obj_t tuple_probe[3] = { + mp_obj_new_str(probe->name.data(), probe->name.length()), + mp_obj_new_int(probe->get_avg_runtime()), + mp_obj_new_int(probe->get_exec_count()) + }; + + return mp_obj_new_tuple(3, tuple_probe); + } + return mp_const_none; +} + +mp_obj_t profiler_get_probes() { + pimoroni::Probe* probe = pimoroni::Profiler::get_probes()[0]; + uint16_t count = pimoroni::Profiler::count(); + + mp_obj_t list_probes[count]; + + for(auto x = 0u; x < count; x++){ + //mp_printf(&mp_plat_print, "Probe: %s\n", probe->name.data()); + //mp_printf(&mp_plat_print, " Avg (us): %lu\n", probe->get_avg_runtime()); + //mp_printf(&mp_plat_print, " Runs: %lu\n", probe->get_exec_count()); + + mp_obj_t tuple_probe[3] = { + mp_obj_new_str(probe->name.data(), probe->name.length()), + mp_obj_new_int(probe->get_avg_runtime()), + mp_obj_new_int(probe->get_exec_count()) + }; + + list_probes[x] = mp_obj_new_tuple(3, tuple_probe); + probe++; + } + return mp_obj_new_list(count, list_probes); +} + +} \ No newline at end of file diff --git a/micropython/modules/profiler/profiler.h b/micropython/modules/profiler/profiler.h new file mode 100644 index 00000000..5b4a1ec1 --- /dev/null +++ b/micropython/modules/profiler/profiler.h @@ -0,0 +1,6 @@ +#include "py/runtime.h" +#include "py/objstr.h" + +extern mp_obj_t profiler_get_probes(); +extern mp_obj_t profiler_get_probe(mp_obj_t name); +extern mp_obj_t profiler_reset(); \ No newline at end of file diff --git a/micropython/modules/profiler/profiler.hpp b/micropython/modules/profiler/profiler.hpp new file mode 100644 index 00000000..598c6496 --- /dev/null +++ b/micropython/modules/profiler/profiler.hpp @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include "pico/stdlib.h" + +namespace pimoroni { + + class Probe { + private: + uint64_t total_us; + uint32_t exec_count; + absolute_time_t t_start; + + public: + std::string_view name; + + Probe(const char* name) : total_us(0), exec_count(0), name(name) { + } + + void reset(); + + uint32_t get_avg_runtime(); + + uint32_t get_exec_count(); + + void __not_in_flash_func(enter)(); + + void __not_in_flash_func(exit)(); + }; + + namespace Profiler { + Probe *add_probe(const char *name); + uint16_t count(); + Probe** get_probes(); + }; +} \ No newline at end of file