Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic function profiler #848

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions micropython/modules/profiler/micropython.cmake
Original file line number Diff line number Diff line change
@@ -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"
)
24 changes: 24 additions & 0 deletions micropython/modules/profiler/profiler.c
Original file line number Diff line number Diff line change
@@ -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
116 changes: 116 additions & 0 deletions micropython/modules/profiler/profiler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#include "profiler.hpp"
#include <cstring>

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);
}

}
6 changes: 6 additions & 0 deletions micropython/modules/profiler/profiler.h
Original file line number Diff line number Diff line change
@@ -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();
37 changes: 37 additions & 0 deletions micropython/modules/profiler/profiler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <cstdint>
#include <vector>
#include <string>
#include <string_view>
#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();
};
}