X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/84402e8e2ee2a2d0bef25fdceb0a263ed8b471f6..d4e5297feb8df40f3ccb3782f7cb326a69d58cad:/include/simgrid/s4u/Actor.hpp diff --git a/include/simgrid/s4u/Actor.hpp b/include/simgrid/s4u/Actor.hpp index 9d46edac88..84d93453fd 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-2022. 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. */ @@ -10,20 +10,161 @@ #include #include -#include #include #include #include -#include // deprecated wrappers #include namespace simgrid { + +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); + +/** 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. * - * \beginrst + * @beginrst * It is located on a (simulated) :cpp:class:`host `, but can interact * with the whole simulated platform. * @@ -36,18 +177,21 @@ 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 void this_actor::sleep_for(double); + friend void this_actor::suspend(); kernel::actor::ActorImpl* const pimpl_; #endif - explicit Actor(smx_actor_t pimpl) : pimpl_(pimpl) {} + explicit Actor(kernel::actor::ActorImpl* pimpl) : pimpl_(pimpl) {} public: #ifndef DOXYGEN @@ -60,50 +204,79 @@ public: friend XBT_PUBLIC void intrusive_ptr_release(const Actor* actor); #endif /** Retrieve the amount of references on that object. Useful to debug the automatic refcounting */ - int get_refcount(); + int get_refcount() const; // ***** Actor creation ***** /** 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; - /** Signal indicating that an actor terminated its code. +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); + } + + /** 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 Actor::on_destruction. - * If you want to register to the termination of a given actor, use this_actor::on_exit() instead.*/ - static xbt::signal on_termination; - /** Signal indicating that an actor is about to disappear (its destructor was called). + * If you want to free extra data when the actor's destructor is called, use :cpp:var:`Actor::on_destruction`. + * If you want to register to the termination of a given actor, use :cpp:func:`this_actor::on_exit()` instead. + * @endrst + */ + 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. */ static ActorPtr create(const std::string& name, s4u::Host* host, const std::function& code); /** Create an actor, but don't start it yet. * - * This is usefull to set some properties or extension before actually starting it */ + * This is useful to set some properties or extension before actually starting it */ static ActorPtr init(const std::string& name, s4u::Host* host); + ActorPtr set_stacksize(unsigned stacksize); /** Start a previously initialized actor */ ActorPtr start(const std::function& code); + 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. */ template static ActorPtr create(const std::string& name, s4u::Host* host, F code) { @@ -113,9 +286,13 @@ public: /** Create an actor using a callable thing and its arguments. * * Note that the arguments will be copied, so move-only parameters are forbidden */ + 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)...)); @@ -131,6 +308,7 @@ public: /** 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; @@ -150,7 +328,7 @@ public: void resume(); /** Returns true if the actor is suspended. */ - bool 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); @@ -171,7 +349,7 @@ public: /** Sets the time at which that actor should be killed */ void set_kill_time(double time); /** Retrieves the time at which that actor will be killed (or -1 if not set) */ - double get_kill_time(); + double get_kill_time() const; /** @brief Moves the actor to another host * @@ -183,9 +361,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. * @@ -202,14 +377,14 @@ public: * Blocks the calling actor until the joined actor is terminated. If actor alice executes bob.join(), then alice is * blocked until bob terminates. */ - void join(); + void join() const; /** Wait for the actor to finish, or for the timeout to elapse. * * Blocks the calling actor until the joined actor is terminated. If actor alice executes bob.join(), then alice is * blocked until bob terminates. */ - void join(double timeout); + void join(double timeout) const; /** Kill that actor and restart it from start. */ Actor* restart(); @@ -219,165 +394,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 \\ to | host0 | host1| - * +===========+=======+======+ - * |host0 | 0 | 1 | - * +-----------+-------+------+ - * |host1 | 2 | 3 | - * +-----------+-------+------+ - * - * - 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 Resume the current actor, that was suspend()ed previously. */ -XBT_PUBLIC void resume(); - -/** @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, - * 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