X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/7f960794190d563e58d57286c7401f0d4e2892d4..5ed37babb2fa9097abe82df299c0aa259ed84d5a:/include/simgrid/s4u/Actor.hpp diff --git a/include/simgrid/s4u/Actor.hpp b/include/simgrid/s4u/Actor.hpp index 0f8b058907..de7a22e978 100644 --- a/include/simgrid/s4u/Actor.hpp +++ b/include/simgrid/s4u/Actor.hpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2006-2020. The SimGrid Team. All rights reserved. */ +/* 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. */ @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -22,9 +21,152 @@ extern template class XBT_PUBLIC xbt::Extendable; namespace s4u { +/** @ingroup s4u_api + * @brief Static methods working on the current actor (see @ref s4u::Actor) */ +namespace this_actor { + +XBT_PUBLIC bool is_maestro(); + +/** Block the current actor sleeping for that amount of seconds */ +XBT_PUBLIC void sleep_for(double duration); +/** Block the current actor sleeping until the specified timestamp */ +XBT_PUBLIC void sleep_until(double wakeup_time); + +template inline void sleep_for(std::chrono::duration duration) +{ + auto seconds = std::chrono::duration_cast(duration); + this_actor::sleep_for(seconds.count()); +} + +template inline void sleep_until(const SimulationTimePoint& wakeup_time) +{ + auto timeout_native = std::chrono::time_point_cast(wakeup_time); + this_actor::sleep_until(timeout_native.time_since_epoch().count()); +} + +/** Block the current actor, computing the given amount of flops */ +XBT_PUBLIC void execute(double flop); + +/** Block the current actor, computing the given amount of flops at the given priority. + * An execution of priority 2 computes twice as fast as an execution at priority 1. */ +XBT_PUBLIC void execute(double flop, double priority); + +/** + * @example examples/cpp/exec-ptask/s4u-exec-ptask.cpp + */ + +/** Block the current actor until the built parallel execution terminates + * + * @beginrst + * .. _API_s4u_parallel_execute: + * + * **Example of use:** `examples/cpp/exec-ptask/s4u-exec-ptask.cpp + * `_ + * + * Parallel executions convenient abstractions of parallel computational kernels that span over several machines, + * such as a PDGEM and the other ScaLAPACK routines. If you are interested in the effects of such parallel kernel + * on the platform (e.g. to schedule them wisely), there is no need to model them in all details of their internal + * execution and communications. It is much more convenient to model them as a single execution activity that spans + * over several hosts. This is exactly what s4u's Parallel Executions are. + * + * To build such an object, you need to provide a list of hosts that are involved in the parallel kernel (the + * actor's own host may or may not be in this list) and specify the amount of computations that should be done by + * each host, using a vector of flops amount. Then, you should specify the amount of data exchanged between each + * hosts during the parallel kernel. For that, a matrix of values is expected. + * + * It is OK to build a parallel execution without any computation and/or without any communication. + * Just pass an empty vector to the corresponding parameter. + * + * For example, if your list of hosts is ``[host0, host1]``, passing a vector ``[1000, 2000]`` as a `flops_amount` + * vector means that `host0` should compute 1000 flops while `host1` will compute 2000 flops. A matrix of + * communications' sizes of ``[0, 1, 2, 3]`` specifies the following data exchanges: + * + * - from host0: [ to host0: 0 bytes; to host1: 1 byte ] + * + * - from host1: [ to host0: 2 bytes; to host1: 3 bytes ] + * + * Or, in other words: + * + * - From host0 to host0: 0 bytes are exchanged + * + * - From host0 to host1: 1 byte is exchanged + * + * - From host1 to host0: 2 bytes are exchanged + * + * - From host1 to host1: 3 bytes are exchanged + * + * In a parallel execution, all parts (all executions on each hosts, all communications) progress exactly at the + * same pace, so they all terminate at the exact same pace. If one part is slow because of a slow resource or + * because of contention, this slows down the parallel execution as a whole. + * + * These objects are somewhat surprising from a modeling point of view. For example, the unit of their speed is + * somewhere between flop/sec and byte/sec. Arbitrary parallel executions will simply not work with the usual platform + * models, and you must :ref:`use the ptask_L07 host model ` for that. Note that you can mix + * regular executions and communications with parallel executions, provided that the host model is ptask_L07. + * + * @endrst + */ +/** Block the current actor until the built parallel execution completes */ +XBT_PUBLIC void parallel_execute(const std::vector& hosts, const std::vector& flops_amounts, + const std::vector& bytes_amounts); + +/** Block the current actor until the built multi-thread execution completes */ +XBT_PUBLIC void thread_execute(s4u::Host* host, double flop_amounts, int thread_count); + +/** Initialize a sequential execution that must then be started manually */ +XBT_PUBLIC ExecPtr exec_init(double flops_amounts); +/** Initialize a parallel execution that must then be started manually */ +XBT_PUBLIC ExecPtr exec_init(const std::vector& hosts, const std::vector& flops_amounts, + const std::vector& bytes_amounts); + +XBT_PUBLIC ExecPtr exec_async(double flops_amounts); + +/** @brief Returns the actor ID of the current actor. */ +XBT_PUBLIC aid_t get_pid(); + +/** @brief Returns the ancestor's actor ID of the current actor. */ +XBT_PUBLIC aid_t get_ppid(); + +/** @brief Returns the name of the current actor. */ +XBT_PUBLIC std::string get_name(); +/** @brief Returns the name of the current actor as a C string. */ +XBT_PUBLIC const char* get_cname(); + +/** @brief Returns the name of the host on which the current actor is running. */ +XBT_PUBLIC Host* get_host(); + +/** @brief Suspend the current actor, that is blocked until resume()ed by another actor. */ +XBT_PUBLIC void suspend(); + +/** @brief Yield the current actor. */ +XBT_PUBLIC void yield(); + +/** @brief kill the current actor. */ +XBT_ATTRIB_NORETURN XBT_PUBLIC void exit(); + +/** @brief Add a function to the list of "on_exit" functions of the current actor. + * + * The on_exit functions are the functions executed when your actor is killed. You should use them to free the data used + * by your actor. + * + * Please note that functions registered in this signal cannot do any simcall themselves. It means that they cannot + * send or receive messages, acquire or release mutexes, nor even modify a host property or something. Not only are + * blocking functions forbidden in this setting, but also modifications to the global state. + * + * The parameter of on_exit's callbacks denotes whether or not the actor's execution failed. + * It will be set to true if the actor was killed or failed because of an exception or if the simulation deadlocked, + * while it will remain to false if the actor terminated gracefully. + */ + +XBT_PUBLIC void on_exit(const std::function& fun); + +/** @brief Migrate the current actor to a new host. */ +XBT_PUBLIC void set_host(Host* new_host); +} // namespace this_actor + /** An actor is an independent stream of execution in your distributed application. * - * \rst + * @beginrst * It is located on a (simulated) :cpp:class:`host `, but can interact * with the whole simulated platform. * @@ -37,13 +179,16 @@ namespace s4u { * The `documentation of this standard `_ * may help to understand the philosophy of the SimGrid actors. * - * \endrst */ + * @endrst + */ class XBT_PUBLIC Actor : public xbt::Extendable { #ifndef DOXYGEN friend Exec; friend Mailbox; friend kernel::actor::ActorImpl; friend kernel::activity::MailboxImpl; + friend XBT_PUBLIC void this_actor::sleep_for(double); + friend XBT_PUBLIC void this_actor::suspend(); kernel::actor::ActorImpl* const pimpl_; #endif @@ -67,39 +212,50 @@ public: /** Retrieve a reference to myself */ static Actor* self(); - /** Fired when a new actor has been created **/ +private: static xbt::signal on_creation; - /** Signal to others that an actor has been suspended**/ static xbt::signal on_suspend; - /** Signal to others that an actor has been resumed **/ static xbt::signal on_resume; - /** Signal to others that an actor is sleeping **/ static xbt::signal on_sleep; - /** Signal to others that an actor wakes up for a sleep **/ static xbt::signal on_wake_up; - /** Signal to others that an actor is has been migrated to another host **/ - static xbt::signal on_host_change; -#ifndef DOXYGEN - static xbt::signal on_migration_start; // XBT_ATTRIB_DEPRECATED_v329 - static xbt::signal on_migration_end; // XBT_ATTRIB_DEPRECATED_v329 -#endif + static xbt::signal on_host_change; + static xbt::signal on_termination; + static xbt::signal on_destruction; + +public: + /** Add a callback fired when a new actor has been created **/ + static void on_creation_cb(const std::function& cb) { on_creation.connect(cb); } + /** Add a callback fired when an actor has been suspended**/ + static void on_suspend_cb(const std::function& cb) { on_suspend.connect(cb); } + /** Add a callback fired when an actor has been resumed **/ + static void on_resume_cb(const std::function& cb) { on_resume.connect(cb); } + /** Add a callback fired when an actor starts sleeping **/ + static void on_sleep_cb(const std::function& cb) { on_sleep.connect(cb); } + /** Add a callback fired when an actor wakes up from a sleep **/ + static void on_wake_up_cb(const std::function& cb) { on_wake_up.connect(cb); } + /** Add a callback fired when an actor is has been migrated to another host **/ + static void on_host_change_cb(const std::function& cb) + { + on_host_change.connect(cb); + } - /** Signal indicating that an actor terminated its code. + /** Add a callback fired when an actor terminates its code. * @beginrst * The actor may continue to exist if it is still referenced in the simulation, but it's not active anymore. - * If you want to free extra data when the actor's destructor is called, use :cpp:var:`Actor::on_destruction`. + * If you want to free extra data when the actor's destructor is called, use :cpp:func:`Actor::on_destruction_cb`. * If you want to register to the termination of a given actor, use :cpp:func:`this_actor::on_exit()` instead. * @endrst */ - static xbt::signal on_termination; - /** Signal indicating that an actor is about to disappear (its destructor was called). + static void on_termination_cb(const std::function& cb) { on_termination.connect(cb); } + /** Add a callback fired when an actor is about to disappear (its destructor was called). * This signal is fired for any destructed actor, which is mostly useful when designing plugins and extensions. * If you want to react to the end of the actor's code, use Actor::on_termination instead. * If you want to register to the termination of a given actor, use this_actor::on_exit() instead.*/ - static xbt::signal on_destruction; + static void on_destruction_cb(const std::function& cb) { on_destruction.connect(cb); } - /** Create an actor from a std::function. - * If the actor is restarted, it gets a fresh copy of the function. */ + /** Create an actor from a @c std::function. + * If the actor is restarted, it gets a fresh copy of the function. + * @verbatim embed:rst:inline See the :ref:`example `. @endverbatim */ static ActorPtr create(const std::string& name, s4u::Host* host, const std::function& code); /** Create an actor, but don't start it yet. * @@ -109,7 +265,23 @@ public: /** Start a previously initialized actor */ ActorPtr start(const std::function& code); - /** Create an actor from a callable thing. */ + template ActorPtr start(F code) { return start(std::function(std::move(code))); } + + template +#endif + > + ActorPtr start(F code, Args... args) + { + return start(std::bind(std::move(code), std::move(args)...)); + } + + ActorPtr start(const std::function& code, std::vector args); + + /** Create an actor from a callable thing. + * @verbatim embed:rst:inline See the :ref:`example `. @endverbatim */ template static ActorPtr create(const std::string& name, s4u::Host* host, F code) { return create(name, host, std::function(std::move(code))); @@ -117,28 +289,39 @@ public: /** Create an actor using a callable thing and its arguments. * - * Note that the arguments will be copied, so move-only parameters are forbidden */ + * Note that the arguments will be copied, so move-only parameters are forbidden. + * @verbatim embed:rst:inline See the :ref:`example `. @endverbatim */ + template ::type> +#ifndef DOXYGEN /* breathe seem to choke on function signatures in template parameter, see breathe#611 */ + typename = typename std::result_of_t +#endif + > static ActorPtr create(const std::string& name, s4u::Host* host, F code, Args... args) { return create(name, host, std::bind(std::move(code), std::move(args)...)); } - /** Create actor from function name and a vector of strings as arguments. */ + /** Create actor from function name and a vector of strings as arguments. + * @verbatim embed:rst:inline See the :ref:`example `. @endverbatim */ static ActorPtr create(const std::string& name, s4u::Host* host, const std::string& function, std::vector args); // ***** Methods ***** - /** This actor will be automatically terminated when the last non-daemon actor finishes **/ - void daemonize(); + /** This actor will be automatically terminated when the last non-daemon actor finishes. + * + * Daemons are killed as soon as the last regular actor disappears. If another regular actor + * gets restarted later on by a timer or when its host reboots, the daemons do not get restarted. + **/ + Actor* daemonize(); /** Returns whether or not this actor has been daemonized or not **/ bool is_daemon() const; + static bool is_maestro(); /** Retrieves the name of that actor as a C++ string */ - const simgrid::xbt::string& get_name() const; + const std::string& get_name() const; /** Retrieves the name of that actor as a C string */ const char* get_cname() const; /** Retrieves the host on which that actor is running */ @@ -148,7 +331,7 @@ public: /** Retrieves the actor ID of that actor's creator */ aid_t get_ppid() const; - /** Suspend an actor, that is blocked until resumeed by another actor */ + /** Suspend an actor, that is blocked until resumed by another actor. */ void suspend(); /** Resume an actor that was previously suspended */ @@ -157,8 +340,20 @@ public: /** Returns true if the actor is suspended. */ bool is_suspended() const; - /** If set to true, the actor will automatically restart when its host reboots */ - void set_auto_restart(bool autorestart); + /** If set to true, the actor will automatically restart when its host reboots. + * + * Some elements of the actor are remembered over reboots: name, host, properties, the on_exit functions, whether it + * is daemonized and whether it should automatically restart when its host reboots. Note that the state after reboot + * is the one when set_auto_restart() is called. + * + * If you daemonize your actor after marking it auto_restart, then the new actor after rebooot will not be a daemon. + * + * The on_exit functions are the one defined when the actor dies, not the ones given when it was marked auto_restart + * (sorry for the inconsistency -- speak to us if it's too hard to bear). + */ + Actor* set_auto_restart(bool autorestart = true); + /** Returns the number of reboots that this actor did. Before the first reboot, this function returns 0. */ + int get_restart_count() const; /** Add a function to the list of "on_exit" functions for the current actor. The on_exit functions are the functions * executed when your actor is killed. You should use them to free the data used by your actor. @@ -188,9 +383,6 @@ public: * to take care of this yourself (only you knows which ones should be migrated). */ void set_host(Host* new_host); -#ifndef DOXYGEN - XBT_ATTRIB_DEPRECATED_v329("Please use set_host() instead") void migrate(Host* new_host) { set_host(new_host); } -#endif /** Ask the actor to die. * @@ -224,161 +416,17 @@ public: /** Returns the internal implementation of this actor */ kernel::actor::ActorImpl* get_impl() const { return pimpl_; } - /** Retrieve the property value (or nullptr if not set) */ + /** Retrieve the list of properties for that actor */ const std::unordered_map* get_properties() const; // FIXME: do not export the map, but only the keys or something + + /** Retrieve the property value (or nullptr if not set) */ const char* get_property(const std::string& key) const; + + /** Set a property (old values will be overwritten) */ void set_property(const std::string& key, const std::string& value); }; -/** @ingroup s4u_api - * @brief Static methods working on the current actor (see @ref s4u::Actor) */ -namespace this_actor { - -XBT_PUBLIC bool is_maestro(); - -/** Block the current actor sleeping for that amount of seconds */ -XBT_PUBLIC void sleep_for(double duration); -/** Block the current actor sleeping until the specified timestamp */ -XBT_PUBLIC void sleep_until(double wakeup_time); - -template inline void sleep_for(std::chrono::duration duration) -{ - auto seconds = std::chrono::duration_cast(duration); - this_actor::sleep_for(seconds.count()); -} - -template inline void sleep_until(const SimulationTimePoint& wakeup_time) -{ - auto timeout_native = std::chrono::time_point_cast(wakeup_time); - this_actor::sleep_until(timeout_native.time_since_epoch().count()); -} - -/** Block the current actor, computing the given amount of flops */ -XBT_PUBLIC void execute(double flop); - -/** Block the current actor, computing the given amount of flops at the given priority. - * An execution of priority 2 computes twice as fast as an execution at priority 1. */ -XBT_PUBLIC void execute(double flop, double priority); - -/** - * @example examples/s4u/exec-ptask/s4u-exec-ptask.cpp - */ - -/** Block the current actor until the built parallel execution terminates - * - * \rst - * .. _API_s4u_parallel_execute: - * - * **Example of use:** `examples/s4u/exec-ptask/s4u-exec-ptask.cpp - * `_ - * - * Parallel executions convenient abstractions of parallel computational kernels that span over several machines, - * such as a PDGEM and the other ScaLAPACK routines. If you are interested in the effects of such parallel kernel - * on the platform (e.g. to schedule them wisely), there is no need to model them in all details of their internal - * execution and communications. It is much more convenient to model them as a single execution activity that spans - * over several hosts. This is exactly what s4u's Parallel Executions are. - * - * To build such an object, you need to provide a list of hosts that are involved in the parallel kernel (the - * actor's own host may or may not be in this list) and specify the amount of computations that should be done by - * each host, using a vector of flops amount. Then, you should specify the amount of data exchanged between each - * hosts during the parallel kernel. For that, a matrix of values is expected. - * - * It is OK to build a parallel execution without any computation and/or without any communication. - * Just pass an empty vector to the corresponding parameter. - * - * For example, if your list of hosts is ``[host0, host1]``, passing a vector ``[1000, 2000]`` as a `flops_amount` - * vector means that `host0` should compute 1000 flops while `host1` will compute 2000 flops. A matrix of - * communications' sizes of ``[0, 1, 2, 3]`` specifies the following data exchanges: - * - * - from host0: [ to host0: 0 bytes; to host1: 1 byte ] - * - * - from host1: [ to host0: 2 bytes; to host1: 3 bytes ] - * - * Or, in other words: - * - * - From host0 to host0: 0 bytes are exchanged - * - * - From host0 to host1: 1 byte is exchanged - * - * - From host1 to host0: 2 bytes are exchanged - * - * - From host1 to host1: 3 bytes are exchanged - * - * In a parallel execution, all parts (all executions on each hosts, all communications) progress exactly at the - * same pace, so they all terminate at the exact same pace. If one part is slow because of a slow resource or - * because of contention, this slows down the parallel execution as a whole. - * - * These objects are somewhat surprising from a modeling point of view. For example, the unit of their speed is - * somewhere between flop/sec and byte/sec. Arbitrary parallel executions will simply not work with the usual platform - * models, and you must :ref:`use the ptask_L07 host model ` for that. Note that you can mix - * regular executions and communications with parallel executions, provided that the host model is ptask_L07. - * - * \endrst - */ -/** Block the current actor until the built parallel execution completes */ -XBT_PUBLIC void parallel_execute(const std::vector& hosts, const std::vector& flops_amounts, - const std::vector& bytes_amounts); - -XBT_ATTRIB_DEPRECATED_v329("Please use exec_init(...)->wait_for(timeout)") XBT_PUBLIC - void parallel_execute(const std::vector& hosts, const std::vector& flops_amounts, - const std::vector& bytes_amounts, double timeout); - -/** Initialize a sequential execution that must then be started manually */ -XBT_PUBLIC ExecPtr exec_init(double flops_amounts); -/** Initialize a parallel execution that must then be started manually */ -XBT_PUBLIC ExecPtr exec_init(const std::vector& hosts, const std::vector& flops_amounts, - const std::vector& bytes_amounts); - -XBT_PUBLIC ExecPtr exec_async(double flops_amounts); - -/** @brief Returns the actor ID of the current actor. */ -XBT_PUBLIC aid_t get_pid(); - -/** @brief Returns the ancestor's actor ID of the current actor. */ -XBT_PUBLIC aid_t get_ppid(); - -/** @brief Returns the name of the current actor. */ -XBT_PUBLIC std::string get_name(); -/** @brief Returns the name of the current actor as a C string. */ -XBT_PUBLIC const char* get_cname(); - -/** @brief Returns the name of the host on which the current actor is running. */ -XBT_PUBLIC Host* get_host(); - -/** @brief Suspend the current actor, that is blocked until resume()ed by another actor. */ -XBT_PUBLIC void suspend(); - -/** @brief Yield the current actor. */ -XBT_PUBLIC void yield(); - -/** @brief kill the current actor. */ -XBT_PUBLIC void exit(); - -/** @brief Add a function to the list of "on_exit" functions of the current actor. - * - * The on_exit functions are the functions executed when your actor is killed. You should use them to free the data used - * by your actor. - * - * Please note that functions registered in this signal cannot do any simcall themselves. It means that they cannot - * send or receive messages, acquire or release mutexes, nor even modify a host property or something. Not only are - * blocking functions forbidden in this setting, but also modifications to the global state. - * - * The parameter of on_exit's callbacks denotes whether or not the actor's execution failed. - * It will be set to true if the actor was killed or failed because of an exception or if the simulation deadlocked, - * while it will remain to false if the actor terminated gracefully. - */ - -XBT_PUBLIC void on_exit(const std::function& fun); - -/** @brief Migrate the current actor to a new host. */ -XBT_PUBLIC void set_host(Host* new_host); -#ifndef DOXYGEN -XBT_ATTRIB_DEPRECATED_v329("Please use set_host() instead") XBT_PUBLIC void migrate(Host* new_host); -#endif -} - - }} // namespace simgrid::s4u