From 505d827ccafbb31eb15cfbd72bdc6079e50525e2 Mon Sep 17 00:00:00 2001 From: Adrien Gougeon Date: Thu, 8 Jun 2023 16:28:08 +0200 Subject: [PATCH] add python bindings for plugin host load --- MANIFEST.in | 2 + examples/python/CMakeLists.txt | 1 + .../plugin-host-load/plugin-host-load.py | 86 +++++++++++++++++++ .../plugin-host-load/plugin-host-load.tesh | 21 +++++ src/bindings/python/simgrid_python.cpp | 22 ++++- 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 examples/python/plugin-host-load/plugin-host-load.py create mode 100644 examples/python/plugin-host-load/plugin-host-load.tesh diff --git a/MANIFEST.in b/MANIFEST.in index 5fac1c74f3..453c595898 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -482,6 +482,8 @@ include examples/python/platform-failures/platform-failures.py include examples/python/platform-failures/platform-failures.tesh include examples/python/platform-profile/platform-profile.py include examples/python/platform-profile/platform-profile.tesh +include examples/python/plugin-host-load/plugin-host-load.py +include examples/python/plugin-host-load/plugin-host-load.tesh include examples/python/synchro-barrier/synchro-barrier.py include examples/python/synchro-barrier/synchro-barrier.tesh include examples/python/synchro-mutex/synchro-mutex.py diff --git a/examples/python/CMakeLists.txt b/examples/python/CMakeLists.txt index f4afe5bbd7..555cfc15f6 100644 --- a/examples/python/CMakeLists.txt +++ b/examples/python/CMakeLists.txt @@ -5,6 +5,7 @@ foreach(example actor-create actor-daemon actor-join actor-kill actor-migrate ac exec-async exec-basic exec-dvfs exec-remote exec-ptask task-io task-simple task-switch-host task-variable-load platform-comm-serialize platform-profile platform-failures + plugin-host-load network-nonlinear clusters-multicpu io-degradation exec-cpu-nonlinear synchro-barrier synchro-mutex synchro-semaphore) set(tesh_files ${tesh_files} ${CMAKE_CURRENT_SOURCE_DIR}/${example}/${example}.tesh) diff --git a/examples/python/plugin-host-load/plugin-host-load.py b/examples/python/plugin-host-load/plugin-host-load.py new file mode 100644 index 0000000000..3b6156caa3 --- /dev/null +++ b/examples/python/plugin-host-load/plugin-host-load.py @@ -0,0 +1,86 @@ +# Copyright (c) 2006-2023. The SimGrid Team. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the license (GNU LGPL) which comes with this package. + + +from argparse import ArgumentParser +import sys +from simgrid import Engine, Host, this_actor, Actor + +def parse(): + parser = ArgumentParser() + parser.add_argument( + '--platform', + type=str, + required=True, + help='path to the platform description' + ) + return parser.parse_args() + +def execute_load_test(): + host = Host.by_name('MyHost1') + this_actor.info(f'Initial peak speed: {host.speed:.0E} flop/s; number of flops computed so far: {host.computed_flops:.0E} (should be 0) and current average load: {host.avg_load} (should be 0)') + + start = Engine.clock + this_actor.info('Sleep for 10 seconds') + this_actor.sleep_for(10) + + speed = host.speed + this_actor.info(f'Done sleeping {Engine.clock - start}s; peak speed: {host.speed:.0E} flop/s; number of flops computed so far: {host.computed_flops:.0E} (nothing should have changed)') + + # Run an activity + start = e.clock + this_actor.info(f'Run an activity of {200E6:.0E} flops at current speed of {host.speed:.0E} flop/s') + this_actor.execute(200E6) + + this_actor.info(f'Done working on my activity; this took {Engine.clock - start}s; current peak speed: {host.speed:.0E} flop/s (when I started the computation, \ +the speed was set to {speed:.0E} flop/s); number of flops computed so \ +far: {host.computed_flops:.0E}, average load as reported by the HostLoad plugin: {host.avg_load:.5f} (should be {200E6 / (10.5 * speed * host.core_count + (Engine.clock - start - 0.5) * host.speed * host.core_count):.5f})') + + # ========= Change power peak ========= + pstate = 1 + host.pstate = pstate + this_actor.info(f'========= Requesting pstate {pstate} (speed should be of {host.pstate_speed(pstate):.0E} flop/s and is of {host.speed:.0E} flop/s, average load is {host.avg_load:.5f})') + + # Run a second activity + start = Engine.clock + this_actor.info(f'Run an activity of {100E6:.0E} flops') + this_actor.execute(100E6) + this_actor.info(f'Done working on my activity; this took {Engine.clock - start}s; current peak speed: {host.speed:.0E} flop/s; number of flops computed so far: {host.computed_flops:.0E}') + Engine + start = Engine.clock + this_actor.info("========= Requesting a reset of the computation and load counters") + host.reset_load() + this_actor.info(f'After reset: {host.computed_flops:.0E} flops computed; load is {host.avg_load}') + this_actor.info('Sleep for 4 seconds') + this_actor.sleep_for(4) + this_actor.info(f'Done sleeping {Engine.clock - start}s; peak speed: {host.speed:.0E} flop/s; number of flops computed so far: {host.computed_flops:.0E}') + + # =========== Turn the other host off ========== + host2 = Host.by_name('MyHost2') + this_actor.info(f'Turning MyHost2 off, and sleeping another 10 seconds. MyHost2 computed {host2.computed_flops:.0E} flops so far and has an average load of {host2.avg_load}') + host2.turn_off() + start = Engine.clock + this_actor.sleep_for(10) + this_actor.info(f'Done sleeping {Engine.clock - start}s; peak speed: {host.speed:.0E} flop/s; number of flops computed so far: {host.computed_flops:.0E}') + +def change_speed(): + host = Host.by_name('MyHost1') + this_actor.sleep_for(10.5) + this_actor.info("I slept until now, but now I'll change the speed of this host while the other actor is still computing! This should slow the computation down.") + host.pstate = 2 + +if __name__ == '__main__': + args = parse() + Host.sg_host_load_plugin_init() + e = Engine(sys.argv) + e.load_platform(args.platform) + + Actor.create('load_test', e.host_by_name('MyHost1'), execute_load_test) + Actor.create('change_speed', e.host_by_name('MyHost1'), change_speed) + + e.run() + + this_actor.info(f'Total simulation time: {Engine.clock}') + diff --git a/examples/python/plugin-host-load/plugin-host-load.tesh b/examples/python/plugin-host-load/plugin-host-load.tesh new file mode 100644 index 0000000000..ad14d1915e --- /dev/null +++ b/examples/python/plugin-host-load/plugin-host-load.tesh @@ -0,0 +1,21 @@ +#!/usr/bin/env tesh + +p This tests the Host Load plugin (that allows the user to get the current load of a host and the computed flops) + +$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${srcdir:=.}/plugin-host-load.py --platform ${platfdir}/energy_platform.xml +> [MyHost1:load_test:(1) 0.000000] [python/INFO] Initial peak speed: 1E+08 flop/s; number of flops computed so far: 0E+00 (should be 0) and current average load: 0.0 (should be 0) +> [MyHost1:load_test:(1) 0.000000] [python/INFO] Sleep for 10 seconds +> [MyHost1:load_test:(1) 10.000000] [python/INFO] Done sleeping 10.0s; peak speed: 1E+08 flop/s; number of flops computed so far: 0E+00 (nothing should have changed) +> [MyHost1:load_test:(1) 10.000000] [python/INFO] Run an activity of 2E+08 flops at current speed of 1E+08 flop/s +> [MyHost1:change_speed:(2) 10.500000] [python/INFO] I slept until now, but now I'll change the speed of this host while the other actor is still computing! This should slow the computation down. +> [MyHost1:load_test:(1) 18.000000] [python/INFO] Done working on my activity; this took 8.0s; current peak speed: 2E+07 flop/s (when I started the computation, the speed was set to 1E+08 flop/s); number of flops computed so far: 2E+08, average load as reported by the HostLoad plugin: 0.04167 (should be 0.04167) +> [MyHost1:load_test:(1) 18.000000] [python/INFO] ========= Requesting pstate 1 (speed should be of 5E+07 flop/s and is of 5E+07 flop/s, average load is 0.04167) +> [MyHost1:load_test:(1) 18.000000] [python/INFO] Run an activity of 1E+08 flops +> [MyHost1:load_test:(1) 20.000000] [python/INFO] Done working on my activity; this took 2.0s; current peak speed: 5E+07 flop/s; number of flops computed so far: 3E+08 +> [MyHost1:load_test:(1) 20.000000] [python/INFO] ========= Requesting a reset of the computation and load counters +> [MyHost1:load_test:(1) 20.000000] [python/INFO] After reset: 0E+00 flops computed; load is 0.0 +> [MyHost1:load_test:(1) 20.000000] [python/INFO] Sleep for 4 seconds +> [MyHost1:load_test:(1) 24.000000] [python/INFO] Done sleeping 4.0s; peak speed: 5E+07 flop/s; number of flops computed so far: 0E+00 +> [MyHost1:load_test:(1) 24.000000] [python/INFO] Turning MyHost2 off, and sleeping another 10 seconds. MyHost2 computed 0E+00 flops so far and has an average load of 0.0 +> [MyHost1:load_test:(1) 34.000000] [python/INFO] Done sleeping 10.0s; peak speed: 5E+07 flop/s; number of flops computed so far: 0E+00 +> [34.000000] [python/INFO] Total simulation time: 34.0 diff --git a/src/bindings/python/simgrid_python.cpp b/src/bindings/python/simgrid_python.cpp index 5f0f33599c..f9fcf3c15f 100644 --- a/src/bindings/python/simgrid_python.cpp +++ b/src/bindings/python/simgrid_python.cpp @@ -11,6 +11,7 @@ #include "simgrid/kernel/ProfileBuilder.hpp" #include "simgrid/kernel/routing/NetPoint.hpp" #include +#include #include #include #include @@ -441,6 +442,8 @@ PYBIND11_MODULE(simgrid, m) py::overload_cast(&Host::create_disk), py::call_guard(), "Create a disk") .def("seal", &Host::seal, py::call_guard(), "Seal this host") + .def("turn_off", &Host::turn_off, py::call_guard(), "Turn off this host") + .def("turn_on", &Host::turn_on, py::call_guard(), "Turn on this host") .def_property("pstate", &Host::get_pstate, py::cpp_function(&Host::set_pstate, py::call_guard()), "The current pstate (read/write property).") @@ -476,7 +479,24 @@ PYBIND11_MODULE(simgrid, m) "") .def( "__repr__", [](const Host* h) { return "Host(" + h->get_name() + ")"; }, - "Textual representation of the Host"); + "Textual representation of the Host.") + .def_static( + "sg_host_load_plugin_init", []() { sg_host_load_plugin_init(); }, py::call_guard(), + "Initialize host load plugin.") + .def( + "reset_load", [](const Host* h) { sg_host_load_reset(h); }, py::call_guard(), + "Reset counters of the host load plugin for this host.") + .def_property_readonly( + "current_load", [](const Host* h) { return sg_host_get_current_load(h); }, "Current load of the host.") + .def_property_readonly( + "avg_load", [](const Host* h) { return sg_host_get_avg_load(h); }, "Average load of the host.") + .def_property_readonly( + "idle_time", [](const Host* h) { return sg_host_get_idle_time(h); }, "Idle time of the host") + .def_property_readonly( + "total_idle_time", [](const Host* h) { return sg_host_get_total_idle_time(h); }, + "Total idle time of the host.") + .def_property_readonly( + "computed_flops", [](const Host* h) { return sg_host_get_computed_flops(h); }, "Computed flops of the host."); py::enum_(host, "SharingPolicy") .value("NONLINEAR", simgrid::s4u::Host::SharingPolicy::NONLINEAR) -- 2.20.1