diff --git a/doc/py_intro.rst b/doc/py_intro.rst index 7d0166568c3b35ee5d04b5912f65b92231e8e9f4..5b020f8052400cfb216a560dbc5cc66651efc6c6 100644 --- a/doc/py_intro.rst +++ b/doc/py_intro.rst @@ -2,7 +2,7 @@ Overview ========= -The Python frontend for Arbor is interface that the vast majority of users will use to interact with Arbor. +The Python frontend for Arbor is an interface that the vast majority of users will use to interact with Arbor. This section covers how to use the frontend with examples and detailed descriptions of features. .. _prerequisites: diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index e03878ecc0e83e2e99d79faa9f820c963c4cbdca..063c514686850990201c865c9854ac32eecb5733 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -23,6 +23,7 @@ add_library(pyarb MODULE event_generator.cpp identifiers.cpp mpi.cpp + profiler.cpp pyarb.cpp recipe.cpp schedule.cpp diff --git a/python/example/ring.py b/python/example/ring.py index 65a230d8cbd5b9815e186fede3f359505bafd42a..f5ba456e00d598796cb96d20192c6cf128c58c71 100644 --- a/python/example/ring.py +++ b/python/example/ring.py @@ -48,18 +48,31 @@ class ring_recipe (arbor.recipe): context = arbor.context(threads=4, gpu_id=None) print(context) +meters = arbor.meter_manager() +meters.start(context) + recipe = ring_recipe(100) -print(recipe) +print(f'{recipe}') + +meters.checkpoint('recipe-create', context) decomp = arbor.partition_load_balance(recipe, context) -print(decomp) +print(f'{decomp}') + +meters.checkpoint('load-balance', context) sim = arbor.simulation(recipe, decomp, context) -print(sim) +print(f'{sim}') + +meters.checkpoint('simulation-init', context) recorder = arbor.attach_spike_recorder(sim) sim.run(1000) +meters.checkpoint('simulation-run', context) + +print(f'{arbor.meter_report(meters, context)}') + for s in recorder.spikes: print(s) diff --git a/python/profiler.cpp b/python/profiler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b44a58c4b5601eaebe45fb4e33ab9aed86e34606 --- /dev/null +++ b/python/profiler.cpp @@ -0,0 +1,57 @@ +#include <sstream> + +#include <pybind11/pybind11.h> +#include <pybind11/stl.h> + +#include <arbor/profile/meter_manager.hpp> + +#include "context.hpp" +#include "strprintf.hpp" + +namespace pyarb { + +void register_profiler(pybind11::module& m) { + using namespace pybind11::literals; + + // meter manager + pybind11::class_<arb::profile::meter_manager> meter_manager(m, "meter_manager", + "Manage metering by setting checkpoints and starting the timing region."); + meter_manager + .def(pybind11::init<>()) + .def("start", + [](arb::profile::meter_manager& manager, const context_shim& ctx){ + manager.start(ctx.context); + }, + "context"_a, + "Start the metering. Records a time stamp,\ + that marks the start of the first checkpoint timing region.") + .def("checkpoint", + [](arb::profile::meter_manager& manager, std::string name, const context_shim& ctx){ + manager.checkpoint(name, ctx.context); + }, + "name"_a, "context"_a, + "Create a new checkpoint. Records the time since the last checkpoint\ + (or the call to start if no previous checkpoints),\ + and restarts the timer for the next checkpoint.") + .def_property_readonly("checkpoint_names", &arb::profile::meter_manager::checkpoint_names, + "A list of all metering checkpoint names.") + .def_property_readonly("times", &arb::profile::meter_manager::times, + "A list of all metering times.") + .def("__str__", [](const arb::profile::meter_manager&){return "<arbor.meter_manager>";}) + .def("__repr__", [](const arb::profile::meter_manager&){return "<arbor.meter_manager>";}); + + // meter report + pybind11::class_<arb::profile::meter_report> meter_report(m, "meter_report", + "Summarises the performance meter results, used to print a report to screen or file.\n" + "If a distributed context is used, the report will contain a summary of results from all MPI ranks."); + meter_report + .def(pybind11::init<>( + [](const arb::profile::meter_manager& manager, const context_shim& ctx){ + return arb::profile::make_meter_report(manager, ctx.context); + }), + "manager"_a, "context"_a) + .def("__str__", [](arb::profile::meter_report& r){return util::pprintf("{}", r);}) + .def("__repr__", [](arb::profile::meter_report& r){return "<arbor.meter_report>";}); +} + +} // namespace pyarb diff --git a/python/pyarb.cpp b/python/pyarb.cpp index c369c2ab2cc85345463a6ec98dd7fc42de9af997..7f5bdd71529c7f51243494b3619108f63c4002a8 100644 --- a/python/pyarb.cpp +++ b/python/pyarb.cpp @@ -12,6 +12,7 @@ void register_contexts(pybind11::module& m); void register_domain_decomposition(pybind11::module& m); void register_event_generators(pybind11::module& m); void register_identifiers(pybind11::module& m); +void register_profiler(pybind11::module& m); void register_recipe(pybind11::module& m); void register_schedules(pybind11::module& m); void register_simulation(pybind11::module& m); @@ -32,11 +33,13 @@ PYBIND11_MODULE(arbor, m) { pyarb::register_domain_decomposition(m); pyarb::register_event_generators(m); pyarb::register_identifiers(m); - #ifdef ARB_MPI_ENABLED - pyarb::register_mpi(m); - #endif + pyarb::register_profiler(m); pyarb::register_recipe(m); pyarb::register_schedules(m); pyarb::register_simulation(m); pyarb::register_spike_handling(m); + + #ifdef ARB_MPI_ENABLED + pyarb::register_mpi(m); + #endif }