Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
python: exec-async and exec-remote examples
authorMartin Quinson <martin.quinson@ens-rennes.fr>
Sun, 17 Mar 2019 18:34:36 +0000 (19:34 +0100)
committerMartin Quinson <martin.quinson@ens-rennes.fr>
Sun, 17 Mar 2019 18:50:53 +0000 (19:50 +0100)
examples/python/CMakeLists.txt
examples/python/exec-async/exec-async.py [new file with mode: 0644]
examples/python/exec-async/exec-async.tesh [new file with mode: 0644]
examples/python/exec-remote/exec-remote.py [new file with mode: 0644]
examples/python/exec-remote/exec-remote.tesh [new file with mode: 0644]
examples/s4u/README.rst
include/simgrid/forward.h
src/bindings/python/simgrid_python.cpp

index d58c801..c1b8b0e 100644 (file)
@@ -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 (file)
index 0000000..1f74851
--- /dev/null
@@ -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 (file)
index 0000000..d18f11c
--- /dev/null
@@ -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 (file)
index 0000000..356d741
--- /dev/null
@@ -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 (file)
index 0000000..400b4dd
--- /dev/null
@@ -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!
index 8610665..350d073 100644 (file)
@@ -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 <https://framagit.org/simgrid/simgrid/tree/master/examples/s4u/exec-async/s4u-exec-async.cpp>`_
+    
+    - |cpp| `examples/s4u/exec-async/s4u-exec-async.cpp <https://framagit.org/simgrid/simgrid/tree/master/examples/s4u/exec-async/s4u-exec-async.cpp>`_
+    - |py|  `examples/python/exec-async/exec-async.py <https://framagit.org/simgrid/simgrid/tree/master/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 <https://framagit.org/simgrid/simgrid/tree/master/examples/s4u/exec-remote/s4u-exec-remote.cpp>`_
+    
+    - |cpp| `examples/s4u/exec-remote/s4u-exec-remote.cpp <https://framagit.org/simgrid/simgrid/tree/master/examples/s4u/exec-remote/s4u-exec-remote.cpp>`_
+    - |py| `examples/python/exec-remote/exec-remote.py <https://framagit.org/simgrid/simgrid/tree/master/examples/python/exec-remote/exec-remote.py>`_
 
   - **Parallel executions:**
     These objects are convenient abstractions of parallel
index e92b3a7..9facab2 100644 (file)
@@ -49,7 +49,9 @@ typedef boost::intrusive_ptr<Exec> ExecPtr;
 XBT_PUBLIC void intrusive_ptr_release(Exec* e);
 XBT_PUBLIC void intrusive_ptr_add_ref(Exec* e);
 class ExecSeq;
+typedef boost::intrusive_ptr<ExecSeq> ExecSeqPtr;
 class ExecPar;
+typedef boost::intrusive_ptr<ExecPar> ExecParPtr;
 
 class Host;
 
index 260dd8f..0c42847 100644 (file)
@@ -16,6 +16,7 @@
 #include <simgrid/Exception.hpp>
 #include <simgrid/s4u/Actor.hpp>
 #include <simgrid/s4u/Comm.hpp>
+#include <simgrid/s4u/Exec.hpp>
 #include <simgrid/s4u/Engine.hpp>
 #include <simgrid/s4u/Host.hpp>
 #include <simgrid/s4u/Mailbox.hpp>
@@ -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<simgrid::s4u::CommPtr>* 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_<simgrid::s4u::Exec, simgrid::s4u::ExecPtr>(m, "Exec", "Execution, see :ref:`class s4u::Exec <API_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<simgrid::s4u::ExecSeq>(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_<simgrid::s4u::Actor, ActorPtr>(m, "Actor",