From a33903f0993a2bd3e7a426314de93fb20b0a6172 Mon Sep 17 00:00:00 2001 From: Martin Quinson Date: Sun, 17 Mar 2019 19:34:36 +0100 Subject: [PATCH] python: exec-async and exec-remote examples --- examples/python/CMakeLists.txt | 2 +- examples/python/exec-async/exec-async.py | 64 ++++++++++++++++++++ examples/python/exec-async/exec-async.tesh | 14 +++++ examples/python/exec-remote/exec-remote.py | 61 +++++++++++++++++++ examples/python/exec-remote/exec-remote.tesh | 11 ++++ examples/s4u/README.rst | 8 ++- include/simgrid/forward.h | 2 + src/bindings/python/simgrid_python.cpp | 26 ++++++++ 8 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 examples/python/exec-async/exec-async.py create mode 100644 examples/python/exec-async/exec-async.tesh create mode 100644 examples/python/exec-remote/exec-remote.py create mode 100644 examples/python/exec-remote/exec-remote.tesh diff --git a/examples/python/CMakeLists.txt b/examples/python/CMakeLists.txt index d58c801227..c1b8b0eea0 100644 --- a/examples/python/CMakeLists.txt +++ b/examples/python/CMakeLists.txt @@ -1,6 +1,6 @@ foreach(example actor-create actor-daemon actor-join actor-kill actor-migrate actor-suspend actor-yield # actor-lifetime async-wait async-waitall async-waitany - exec-basic) + exec-basic exec-async exec-remote) set(tesh_files ${tesh_files} ${CMAKE_CURRENT_SOURCE_DIR}/${example}/${example}.tesh) set(examples_src ${examples_src} ${CMAKE_CURRENT_SOURCE_DIR}/${example}/${example}.py) diff --git a/examples/python/exec-async/exec-async.py b/examples/python/exec-async/exec-async.py new file mode 100644 index 0000000000..1f74851dd5 --- /dev/null +++ b/examples/python/exec-async/exec-async.py @@ -0,0 +1,64 @@ +# Copyright (c) 2018-2019. 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. + +import sys +from simgrid import * + + +class Waiter: + """ This actor simply waits for its task completion after starting it. That's exactly equivalent to synchronous execution. """ + + def __call__(self): + computation_amount = this_actor.get_host().speed + this_actor.info("Execute {:.0f} flops, should take 1 second.".format(computation_amount)) + activity = this_actor.exec_init(computation_amount) + activity.start() + activity.wait() + + this_actor.info("Goodbye now!") + + +class Monitor: + """This actor tests the ongoing execution until its completion, and don't wait before it's terminated.""" + + def __call__(self): + computation_amount = this_actor.get_host().speed + this_actor.info("Execute {:.0f} flops, should take 1 second.".format(computation_amount)) + activity = this_actor.exec_init(computation_amount).start() + + while not activity.test(): + this_actor.info("Remaining amount of flops: {:.0f} ({:.0f}%)".format( + activity.remaining, 100 * activity.remaining_ratio)) + this_actor.sleep_for(0.3) + activity.wait() + + this_actor.info("Goodbye now!") + + +class Canceller: + """This actor cancels the ongoing execution after a while.""" + + def __call__(self): + computation_amount = this_actor.get_host().speed + this_actor.info("Execute {:.0f} flops, should take 1 second.".format(computation_amount)) + activity = this_actor.exec_init(computation_amount).start() + + this_actor.sleep_for(0.5) + this_actor.info("I changed my mind, cancel!") + activity.cancel() + + this_actor.info("Goodbye now!") + + +if __name__ == '__main__': + e = Engine(sys.argv) + + e.load_platform(sys.argv[1]) + + Actor.create("wait", Host.by_name("Fafard"), Waiter()) + Actor.create("monitor", Host.by_name("Ginette"), Monitor()) + Actor.create("cancel", Host.by_name("Boivin"), Canceller()) + + e.run() diff --git a/examples/python/exec-async/exec-async.tesh b/examples/python/exec-async/exec-async.tesh new file mode 100644 index 0000000000..d18f11c454 --- /dev/null +++ b/examples/python/exec-async/exec-async.tesh @@ -0,0 +1,14 @@ +#!/usr/bin/env tesh + +$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${srcdir:=.}/exec-async.py ${platfdir}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" +> [ 0.000000] (1:wait@Fafard) Execute 76296000 flops, should take 1 second. +> [ 0.000000] (2:monitor@Ginette) Execute 48492000 flops, should take 1 second. +> [ 0.000000] (3:cancel@Boivin) Execute 98095000 flops, should take 1 second. +> [ 0.000000] (2:monitor@Ginette) Remaining amount of flops: 48492000 (100%) +> [ 0.300000] (2:monitor@Ginette) Remaining amount of flops: 33944400 (70%) +> [ 0.500000] (3:cancel@Boivin) I changed my mind, cancel! +> [ 0.500000] (3:cancel@Boivin) Goodbye now! +> [ 0.600000] (2:monitor@Ginette) Remaining amount of flops: 19396800 (40%) +> [ 0.900000] (2:monitor@Ginette) Remaining amount of flops: 4849200 (10%) +> [ 1.000000] (1:wait@Fafard) Goodbye now! +> [ 1.200000] (2:monitor@Ginette) Goodbye now! diff --git a/examples/python/exec-remote/exec-remote.py b/examples/python/exec-remote/exec-remote.py new file mode 100644 index 0000000000..356d741698 --- /dev/null +++ b/examples/python/exec-remote/exec-remote.py @@ -0,0 +1,61 @@ +# Copyright (c) 2018-2019. 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. + +import sys +from simgrid import * + + +class Wizard: + def __call__(self): + + fafard = Host.by_name("Fafard") + ginette = Host.by_name("Ginette") + boivin = Host.by_name("Boivin") + + this_actor.info("I'm a wizard! I can run a task on the Ginette host from the Fafard one! Look!") + exec = this_actor.exec_init(48.492e6) + exec.host = ginette + exec.start() + this_actor.info("It started. Running 48.492Mf takes exactly one second on Ginette (but not on Fafard).") + + this_actor.sleep_for(0.1) + this_actor.info("Loads in flops/s: Boivin={:.0f}; Fafard={:.0f}; Ginette={:.0f}".format(boivin.load, fafard.load, + ginette.load)) + exec.wait() + this_actor.info("Done!") + + this_actor.info("And now, harder. Start a remote task on Ginette and move it to Boivin after 0.5 sec") + exec = this_actor.exec_init(73293500) + exec.host = ginette + exec.start() + + this_actor.sleep_for(0.5) + this_actor.info( + "Loads before the move: Boivin={:.0f}; Fafard={:.0f}; Ginette={:.0f}".format( + boivin.load, + fafard.load, + ginette.load)) + + exec.host = boivin + + this_actor.sleep_for(0.1) + this_actor.info( + "Loads after the move: Boivin={:.0f}; Fafard={:.0f}; Ginette={:.0f}".format( + boivin.load, + fafard.load, + ginette.load)) + + exec.wait() + this_actor.info("Done!") + + +if __name__ == '__main__': + e = Engine(sys.argv) + + e.load_platform(sys.argv[1]) + + Actor.create("test", Host.by_name("Fafard"), Wizard()) + + e.run() diff --git a/examples/python/exec-remote/exec-remote.tesh b/examples/python/exec-remote/exec-remote.tesh new file mode 100644 index 0000000000..400b4ddaa3 --- /dev/null +++ b/examples/python/exec-remote/exec-remote.tesh @@ -0,0 +1,11 @@ +#!/usr/bin/env tesh + +$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/exec-remote.py ${platfdir}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" +> [ 0.000000] (1:test@Fafard) I'm a wizard! I can run a task on the Ginette host from the Fafard one! Look! +> [ 0.000000] (1:test@Fafard) It started. Running 48.492Mf takes exactly one second on Ginette (but not on Fafard). +> [ 0.100000] (1:test@Fafard) Loads in flops/s: Boivin=0; Fafard=0; Ginette=48492000 +> [ 1.000000] (1:test@Fafard) Done! +> [ 1.000000] (1:test@Fafard) And now, harder. Start a remote task on Ginette and move it to Boivin after 0.5 sec +> [ 1.500000] (1:test@Fafard) Loads before the move: Boivin=0; Fafard=0; Ginette=48492000 +> [ 1.600000] (1:test@Fafard) Loads after the move: Boivin=98095000; Fafard=0; Ginette=0 +> [ 2.000000] (1:test@Fafard) Done! diff --git a/examples/s4u/README.rst b/examples/s4u/README.rst index 8610665eb2..350d07361c 100644 --- a/examples/s4u/README.rst +++ b/examples/s4u/README.rst @@ -201,12 +201,16 @@ Executions on the CPU - **Asynchronous execution:** You can start asynchronous executions, just like you would fire background threads. - |br| `examples/s4u/exec-async/s4u-exec-async.cpp `_ + + - |cpp| `examples/s4u/exec-async/s4u-exec-async.cpp `_ + - |py| `examples/python/exec-async/exec-async.py `_ - **Remote execution:** You can start executions on remote hosts, or even change the host on which they occur during their execution. - |br| `examples/s4u/exec-remote/s4u-exec-remote.cpp `_ + + - |cpp| `examples/s4u/exec-remote/s4u-exec-remote.cpp `_ + - |py| `examples/python/exec-remote/exec-remote.py `_ - **Parallel executions:** These objects are convenient abstractions of parallel diff --git a/include/simgrid/forward.h b/include/simgrid/forward.h index e92b3a7d0c..9facab2ef4 100644 --- a/include/simgrid/forward.h +++ b/include/simgrid/forward.h @@ -49,7 +49,9 @@ typedef boost::intrusive_ptr ExecPtr; XBT_PUBLIC void intrusive_ptr_release(Exec* e); XBT_PUBLIC void intrusive_ptr_add_ref(Exec* e); class ExecSeq; +typedef boost::intrusive_ptr ExecSeqPtr; class ExecPar; +typedef boost::intrusive_ptr ExecParPtr; class Host; diff --git a/src/bindings/python/simgrid_python.cpp b/src/bindings/python/simgrid_python.cpp index 260dd8f3a2..0c42847448 100644 --- a/src/bindings/python/simgrid_python.cpp +++ b/src/bindings/python/simgrid_python.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,7 @@ PYBIND11_MODULE(simgrid, m) "Block the current actor, computing the given amount of flops at the given priority, see :cpp:func:`void " "simgrid::s4u::this_actor::execute(double, double)`", py::arg("flops"), py::arg("priority") = 1); + m2.def("exec_init", [](double flops){return simgrid::s4u::this_actor::exec_init(flops);}); m2.def("get_host", &simgrid::s4u::this_actor::get_host, "Retrieves host on which the current actor is located"); m2.def("migrate", &simgrid::s4u::this_actor::migrate, "Moves the current actor to another host, see :cpp:func:`void simgrid::s4u::this_actor::migrate()`", py::arg("dest")); @@ -151,6 +153,8 @@ PYBIND11_MODULE(simgrid, m) .def_property_readonly("name", [](Host* self) -> const std::string { return std::string(self->get_name().c_str()); // Convert from xbt::string because of MC }, "The name of this host") + .def_property_readonly("load", &Host::get_load, + "Returns the current computation load (in flops per second), see :cpp:func:`simgrid::s4u::Host::get_load()`") .def_property_readonly("speed", &Host::get_speed, "The peak computing speed in flops/s at the current pstate, taking the external load into account, see :cpp:func:`simgrid::s4u::Host::get_speed()`"); @@ -191,6 +195,28 @@ PYBIND11_MODULE(simgrid, m) "wait_any", [](std::vector* comms) { return simgrid::s4u::Comm::wait_any(comms); }, "Block until the completion of any communication in the list and return the index of the terminated one, see " ":cpp:func:`simgrid::s4u::Comm::wait_any()`"); + py::class_(m, "Exec", "Execution, see :ref:`class s4u::Exec `") + .def_property_readonly("remaining", [](simgrid::s4u::ExecPtr self) { return self->get_remaining(); }, + "Amount of flops that remain to be computed until completion, see :cpp:func:`simgrid::s4u::Exec::get_remaining()`") + .def_property_readonly("remaining_ratio", [](simgrid::s4u::ExecPtr self) { return self->get_remaining_ratio(); }, + "Amount of work remaining until completion from 0 (completely done) to 1 (nothing done yet). See :cpp:func:`simgrid::s4u::Exec::get_remaining_ratio()`") + .def_property("host", + [](simgrid::s4u::ExecPtr self) { + simgrid::s4u::ExecSeqPtr seq = boost::dynamic_pointer_cast(self); + if (seq != nullptr) + return seq->get_host(); + xbt_throw_unimplemented(__FILE__, __LINE__, "host of parallel executions is not implemented in python yet."); + }, + [](simgrid::s4u::ExecPtr self, simgrid::s4u::Host* host) { self->set_host(host); }, + "Host on which this execution runs. See :cpp:func:`simgrid::s4u::ExecSeq::get_host()`") + .def("test", [](simgrid::s4u::ExecPtr self) { return self->test(); }, + "Test whether the execution is terminated, see :cpp:func:`simgrid::s4u::Exec::test()`") + .def("cancel", [](simgrid::s4u::ExecPtr self) { self->cancel(); }, + "Cancel that execution, see :cpp:func:`simgrid::s4u::Exec::cancel()`") + .def("start", [](simgrid::s4u::ExecPtr self) { return self->start(); }, + "Start that execution, see :cpp:func:`simgrid::s4u::Exec::start()`") + .def("wait", [](simgrid::s4u::ExecPtr self) { return self->wait(); }, + "Block until the completion of that execution, see :cpp:func:`simgrid::s4u::Exec::wait()`"); /* Class Actor */ py::class_(m, "Actor", -- 2.20.1