S4U Examples
SimGrid comes with an extensive set of examples, documented on this page. Most of them only demonstrate one single feature, with some larger exemplars listed below.
The C++ examples can be found under examples/cpp while python examples are in examples/python. Each such directory contains the source code (also listed from this page), and the so-called tesh file containing how to call the binary obtained by compiling this example and also the expected output. Tesh files are used to turn each of our examples into an integration test. Some examples also contain other files, on need.
A good way to bootstrap your own project is to copy and combine some of the provided examples to constitute the skeleton of what you plan to simulate.
Actors: the Active Entities
Starting and Stopping Actors
Creating actors
Most actors are started from the deployment XML file because this is a better scientific habit, but you can also create them directly from your code.
You create actors either:
Directly with
simgrid::s4u::Actor::create()
From XML with
simgrid::s4u::Engine::register_actor()
(if your actor is a class) orsimgrid::s4u::Engine::register_function()
(if your actor is a function) and thensimgrid::s4u::Engine::load_deployment()
View examples/cpp/actor-create/s4u-actor-create.cpp
/* 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. */
/* This example shows how to declare and start your actors.
*
* The first step is to declare the code of your actors (what they do exactly does not matter to this example) and then
* you ask SimGrid to start your actors. There is three ways of doing so:
* - Directly, by instantiating your actor as parameter to Actor::create()
* - By first registering your actors before instantiating it
* - Through the deployment file.
*
* This example shows all these solutions, even if you obviously should use only one of these solutions to start your
* actors. The most advised solution is to use a deployment file, as it creates a clear separation between your
* application and the settings to test it. This is a better scientific methodology. Actually, starting an actor with
* Actor::create() is mostly useful to start an actor from another actor.
*/
#include <simgrid/s4u.hpp>
#include <string>
namespace sg4 = simgrid::s4u;
// This declares a logging channel so that XBT_INFO can be used later
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_actor_create, "The logging channel used in this example");
/* Our first class of actors is simply implemented with a function, that takes a single string as parameter.
*
* Later, this actor class is instantiated within the simulation.
*/
static void receiver(const std::string& mailbox_name)
{
sg4::Mailbox* mailbox = sg4::Mailbox::by_name(mailbox_name);
XBT_INFO("Hello s4u, I'm ready to get any message you'd want on %s", mailbox->get_cname());
auto msg1 = mailbox->get_unique<std::string>();
auto msg2 = mailbox->get_unique<std::string>();
auto msg3 = mailbox->get_unique<std::string>();
XBT_INFO("I received '%s', '%s' and '%s'", msg1->c_str(), msg2->c_str(), msg3->c_str());
XBT_INFO("I'm done. See you.");
}
/* Our second class of actors is also a function */
static void forwarder(int argc, char** argv)
{
xbt_assert(argc >= 3, "Actor forwarder requires 2 parameters, but got only %d", argc - 1);
sg4::Mailbox* in = sg4::Mailbox::by_name(argv[1]);
sg4::Mailbox* out = sg4::Mailbox::by_name(argv[2]);
auto* msg = in->get<std::string>();
XBT_INFO("Forward '%s'.", msg->c_str());
out->put(msg, msg->size());
}
/* Declares a third class of actors which sends a message to the mailbox 'mb42'.
* The sent message is what was passed as parameter on creation (or 'GaBuZoMeu' by default)
*
* Later, this actor class is instantiated twice in the simulation.
*/
class Sender {
public:
std::string mbox = "mb42";
std::string msg = "GaBuZoMeu";
explicit Sender() = default; /* Sending the default message */
explicit Sender(const std::string& arg) : msg(arg) { /* Sending the specified message */}
explicit Sender(std::vector<std::string> args)
{
/* This constructor is used when we start the actor from the deployment file */
/* args[0] is the actor's name, so the first parameter is args[1] */
xbt_assert(args.size() >= 3, "The sender is expecting 2 parameters from the deployment file but got %zu",
args.size() - 1);
msg = args[1];
mbox = args[2];
}
void operator()() const /* This is the main code of the actor */
{
XBT_INFO("Hello s4u, I have something to send");
sg4::Mailbox* mailbox = sg4::Mailbox::by_name(mbox);
mailbox->put(new std::string(msg), msg.size());
XBT_INFO("I'm done. See you.");
}
};
/* Here comes the main function of your program */
int main(int argc, char** argv)
{
/* When your program starts, you have to first start a new simulation engine, as follows */
sg4::Engine e(&argc, argv);
/* Then you should load a platform file, describing your simulated platform */
e.load_platform(argc > 1 ? argv[1] : "../../platforms/small_platform.xml");
/* And now you have to ask SimGrid to actually start your actors.
*
* The easiest way to do so is to implement the behavior of your actor in a single function,
* as we do here for the receiver actors. This function can take any kind of parameters, as
* long as the last parameters of Actor::create() match what your function expects.
*/
sg4::Actor::create("receiver", e.host_by_name("Fafard"), &receiver, "mb42");
/* If your actor is getting more complex, you probably want to implement it as a class instead,
* as we do here for the sender actors. The main behavior goes into operator()() of the class.
*
* You can then directly start your actor, as follows: */
sg4::Actor::create("sender1", e.host_by_name("Tremblay"), Sender());
/* If you want to pass parameters to your class, that's very easy: just use your constructors */
sg4::Actor::create("sender2", e.host_by_name("Jupiter"), Sender("GloubiBoulga"));
/* But starting actors directly is considered as a bad experimental habit, since it ties the code
* you want to test with the experimental scenario. Starting your actors from an external deployment
* file in XML ensures that you can test your code in several scenarios without changing the code itself.
*
* For that, you first need to register your function or your actor as follows.
* Actor classes must have a (std::vector<std::string>) constructor,
* and actor functions must be of type int(*)(int argc, char**argv). */
e.register_actor<Sender>("sender"); // The sender class is passed as a template parameter here
e.register_function("forwarder", &forwarder);
/* Once actors and functions are registered, just load the deployment file */
e.load_deployment(argc > 2 ? argv[2] : "s4u-actor-create_d.xml");
/* Once every actors are started in the engine, the simulation can start */
e.run();
/* Once the simulation is done, the program is ended */
return 0;
}
You create actors either:
Directly with
simgrid.Actor.create()
From XML with
simgrid.Engine.register_actor()
and thensimgrid.Engine.load_deployment()
View examples/python/actor-create/actor-create.py
# 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.
"""
This example shows how to declare and start your actors.
The first step is to declare the code of your actors (what they do exactly does not matter to this example) and then
you ask SimGrid to start your actors. There is three ways of doing so:
- Directly, by instantiating your actor as parameter to Actor::create()
- By first registering your actors before instantiating it;
- Through the deployment file.
This example shows all these solutions, even if you obviously should use only one of these solutions to start your
actors. The most advised solution is to use a deployment file, as it creates a clear separation between your
application and the settings to test it. This is a better scientific methodology. Actually, starting an actor with
Actor.create() is mostly useful to start an actor from another actor.
"""
import sys
from simgrid import Actor, Engine, Host, Mailbox, this_actor
def receiver(mailbox_name):
"""
Our first class of actors is simply implemented with a function, that takes a single string as parameter.
Later, this actor class is instantiated within the simulation.
"""
mailbox = Mailbox.by_name(mailbox_name)
this_actor.info(
"Hello s4u, I'm ready to get any message you'd want on {:s}".format(mailbox.name))
msg1 = mailbox.get()
msg2 = mailbox.get()
msg3 = mailbox.get()
this_actor.info(
"I received '{:s}', '{:s}' and '{:s}'".format(msg1, msg2, msg3))
this_actor.info("I'm done. See you.")
def forwarder(*args):
"""Our second class of actors is also a function"""
if len(args) < 2:
raise AssertionError(
"Actor forwarder requires 2 parameters, but got only {:d}".format(len(args)))
mb_in = Mailbox.by_name(args[0])
mb_out = Mailbox.by_name(args[1])
msg = mb_in.get()
this_actor.info("Forward '{:s}'.".format(msg))
mb_out.put(msg, len(msg))
class Sender:
"""
Declares a third class of actors which sends a message to the mailbox 'mb42'.
The sent message is what was passed as parameter on creation (or 'GaBuZoMeu' by default)
Later, this actor class is instantiated twice in the simulation.
"""
def __init__(self, msg="GaBuZoMeu", mbox="mb42"):
self.msg = msg
self.mbox = mbox
# Actors that are created as object will execute their __call__ method.
# So, the following constitutes the main function of the Sender actor.
def __call__(self):
this_actor.info("Hello s4u, I have something to send")
mailbox = Mailbox.by_name(self.mbox)
mailbox.put(self.msg, len(self.msg))
this_actor.info("I'm done. See you.")
if __name__ == '__main__':
# Here comes the main function of your program
# When your program starts, you have to first start a new simulation engine, as follows
e = Engine(sys.argv)
# Then you should load a platform file, describing your simulated platform
e.load_platform("../../platforms/small_platform.xml")
# And now you have to ask SimGrid to actually start your actors.
#
# The easiest way to do so is to implement the behavior of your actor in a single function,
# as we do here for the receiver actors. This function can take any kind of parameters, as
# long as the last parameters of Actor::create() match what your function expects.
Actor.create("receiver", Host.by_name("Fafard"), receiver, "mb42")
# If your actor is getting more complex, you probably want to implement it as a class instead,
# as we do here for the sender actors. The main behavior goes into operator()() of the class.
#
# You can then directly start your actor, as follows:
Actor.create("sender1", Host.by_name("Tremblay"), Sender())
# If you want to pass parameters to your class, that's very easy: just use your constructors
Actor.create("sender2", Host.by_name("Jupiter"), Sender("GloubiBoulga"))
# But starting actors directly is considered as a bad experimental habit, since it ties the code
# you want to test with the experimental scenario. Starting your actors from an external deployment
# file in XML ensures that you can test your code in several scenarios without changing the code itself.
#
# For that, you first need to register your function or your actor as follows.
e.register_actor("sender", Sender)
e.register_actor("forwarder", forwarder)
# Once actors and functions are registered, just load the deployment file
e.load_deployment("actor-create_d.xml")
# Once every actors are started in the engine, the simulation can start
e.run()
# Once the simulation is done, the program is ended
You create actors either:
Directly with
sg_actor_create()
followed bysg_actor_start()
.From XML with
simgrid_register_function()
and thensimgrid_load_deployment()
.
View examples/c/actor-create/actor-create.c
/* 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. */
/* This example shows how to declare and start your actors.
*
* The first step is to declare the code of your actors (what they do exactly does not matter to this example) and then
* you ask SimGrid to start your actors. There is three ways of doing so:
* - Directly, by instantiating your actor as parameter to Actor::create()
* - By first registering your actors before instantiating it;
* - Through the deployment file.
*
* This example shows all these solutions, even if you obviously should use only one of these solutions to start your
* actors. The most advised solution is to use a deployment file, as it creates a clear separation between your
* application and the settings to test it. This is a better scientific methodology. Actually, starting an actor with
* Actor::create() is mostly useful to start an actor from another actor.
*/
#include <simgrid/actor.h>
#include <simgrid/engine.h>
#include <simgrid/host.h>
#include <simgrid/mailbox.h>
#include <xbt/log.h>
#include <xbt/sysdep.h>
// This declares a logging channel so that XBT_INFO can be used later
XBT_LOG_NEW_DEFAULT_CATEGORY(actor_create, "The logging channel used in this example");
/* Our first class of actors is simply implemented with a function.
* As every CSG actors, its parameters are in a vector of string (argc/argv), and it does not return anything.
*
* One 'receiver' actor is instantiated within the simulation later in this file.
*/
static void receiver(int argc, char** argv)
{
xbt_assert(argc == 2, "This actor expects a single argument: the mailbox on which to get messages");
sg_mailbox_t mailbox = sg_mailbox_by_name(argv[1]);
XBT_INFO("Hello, I'm ready to get any message you'd want on %s", argv[1]);
char* msg1 = sg_mailbox_get(mailbox);
char* msg2 = sg_mailbox_get(mailbox);
char* msg3 = sg_mailbox_get(mailbox);
XBT_INFO("I received '%s', '%s' and '%s'", msg1, msg2, msg3);
xbt_free(msg1);
xbt_free(msg2);
xbt_free(msg3);
XBT_INFO("I'm done. See you.");
}
/* Our second class of actors, in charge of sending stuff */
static void sender(int argc, char** argv)
{
xbt_assert(argc == 3, "Actor 'sender' requires 2 parameters (mailbox and data to send), but got only %d", argc - 1);
XBT_INFO("Hello, I have something to send");
const char* sent_data = argv[1];
sg_mailbox_t mailbox = sg_mailbox_by_name(argv[2]);
sg_mailbox_put(mailbox, xbt_strdup(sent_data), strlen(sent_data));
XBT_INFO("I'm done. See you.");
}
static void forwarder(int argc, char** argv)
{
xbt_assert(argc >= 3, "Actor forwarder requires 2 parameters, but got only %d", argc - 1);
sg_mailbox_t mailbox_in = sg_mailbox_by_name(argv[1]);
sg_mailbox_t mailbox_out = sg_mailbox_by_name(argv[2]);
char* msg = sg_mailbox_get(mailbox_in);
XBT_INFO("Forward '%s'.", msg);
sg_mailbox_put(mailbox_out, msg, strlen(msg));
}
/* Here comes the main function of your program */
int main(int argc, char** argv)
{
/* When your program starts, you have to first start a new simulation engine, as follows */
simgrid_init(&argc, argv);
/* Then you should load a platform file, describing your simulated platform */
simgrid_load_platform("../../platforms/small_platform.xml");
/* And now you have to ask SimGrid to actually start your actors.
*
* The easiest way to do so is to implement the behavior of your actor in a single function,
* as we do here for the receiver actors. This function can take any kind of parameters, as
* long as the last parameters of sg_actor_create() or sg_actor_start() match what your function expects.
*/
int recv_argc = 2;
const char* recv_argv[] = {"receiver", "mb42", NULL};
sg_actor_create_("receiver", sg_host_by_name("Fafard"), receiver, recv_argc, recv_argv);
int sender1_argc = 3;
const char* sender1_argv[] = {"sender", "GaBuZoMeu", "mb42", NULL};
sg_actor_create_("sender1", sg_host_by_name("Tremblay"), sender, sender1_argc, sender1_argv);
int sender2_argc = 3;
const char* sender2_argv[] = {"sender", "GloubiBoulga", "mb42", NULL};
sg_actor_t sender2 = sg_actor_init("sender2", sg_host_by_name("Jupiter"));
sg_actor_start_(sender2, sender, sender2_argc, sender2_argv);
/* But starting actors directly is considered as a bad experimental habit, since it ties the code
* you want to test with the experimental scenario. Starting your actors from an external deployment
* file in XML ensures that you can test your code in several scenarios without changing the code itself.
*
* For that, you first need to register your function or your actor as follows.
* actor functions must be of type void(*)(int argc, char**argv). */
simgrid_register_function("sender", sender);
simgrid_register_function("forwarder", forwarder);
/* Once actors and functions are registered, just load the deployment file */
simgrid_load_deployment("actor-create_d.xml");
/* Once every actors are started in the engine, the simulation can start */
simgrid_run();
/* Once the simulation is done, the program is ended */
return 0;
}
The following file is used in both C++ and Python.
View examples/python/actor-create/actor-create_d.xml
<?xml version='1.0'?>
<!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
<platform version="4.1">
<!-- This a weird deployment file: we only start one actor from here and the others from the main().
-
- This is only for the example, but don't do that at home.
- Instead, you want to start all your actors from the deployment file.
-->
<actor host="Fafard" function="sender">
<argument value="PopPop!"/> <!-- msg as argv[1] -->
<argument value="other mb"/> <!-- mbox as argv[2] -->
</actor>
<actor host="Ginette" function="forwarder">
<argument value="other mb"/>
<argument value="mb42"/>
</actor>
</platform>
Reacting to actors’ end
You can attach callbacks to the end of actors. There are several ways of doing so, depending on whether you want to attach your callback to a given actor and on how you define the end of a given actor. User code probably wants to react to the termination of an actor while some plugins want to react to the destruction (memory collection) of actors.
This example shows how to attach a callback to:
the end of a specific actor:
simgrid::s4u::Actor::on_exit()
the end of any actor:
simgrid::s4u::Actor::on_termination_cb()
the destruction of any actor:
simgrid::s4u::Actor::on_destruction_cb()
View examples/cpp/actor-exiting/s4u-actor-exiting.cpp
Download s4u-actor-exiting.cpp
/* Copyright (c) 2017-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. */
/* There is two very different ways of being informed when an actor exits.
*
* The this_actor::on_exit() function allows one to register a function to be
* executed when this very actor exits. The registered function will run
* when this actor terminates (either because its main function returns, or
* because it's killed in any way). No simcall are allowed here: your actor
* is dead already, so it cannot interact with its environment in any way
* (network, executions, disks, etc).
*
* Usually, the functions registered in this_actor::on_exit() are in charge
* of releasing any memory allocated by the actor during its execution.
*
* The other way of getting informed when an actor terminates is to connect a
* function in the Actor::on_termination signal, that is shared between
* all actors. Callbacks to this signal are executed for each terminating
* actors, no matter what. This is useful in many cases, in particular
* when developing SimGrid plugins.
*
* Finally, you can attach callbacks to the Actor::on_destruction signal.
* It is also shared between all actors, and gets fired when the actors
* are destroyed. A delay is possible between the termination of an actor
* (ie, when it terminates executing its code) and its destruction (ie,
* when it is not referenced anywhere in the simulation and can be collected).
*
* In both cases, you can stack more than one callback in the signal.
* They will all be executed in the registration order.
*/
#include <simgrid/s4u.hpp>
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_actor_exiting, "Messages specific for this s4u example");
static void actor_a()
{
// Register a lambda function to be executed once it stops
sg4::this_actor::on_exit([](bool /*failed*/) { XBT_INFO("I stop now"); });
sg4::this_actor::sleep_for(1);
}
static void actor_b()
{
sg4::this_actor::sleep_for(2);
}
static void actor_c()
{
// Register a lambda function to be executed once it stops
sg4::this_actor::on_exit([](bool failed) {
if (failed) {
XBT_INFO("I was killed!");
if (xbt_log_no_loc)
XBT_INFO("The backtrace would be displayed here if --log=no_loc would not have been passed");
else
xbt_backtrace_display_current();
} else
XBT_INFO("Exiting gracefully.");
});
sg4::this_actor::sleep_for(3);
XBT_INFO("And now, induce a deadlock by waiting for a message that will never come\n\n");
sg4::Mailbox::by_name("nobody")->get<void>();
xbt_die("Receiving is not supposed to succeed when nobody is sending");
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
xbt_assert(argc == 2, "Usage: %s platform_file\n\tExample: %s ../platforms/small_platform.xml\n", argv[0], argv[0]);
e.load_platform(argv[1]); /* - Load the platform description */
/* Register a callback in the Actor::on_termination signal. It will be called for every terminated actors */
sg4::Actor::on_termination_cb(
[](sg4::Actor const& actor) { XBT_INFO("Actor %s terminates now", actor.get_cname()); });
/* Register a callback in the Actor::on_destruction signal. It will be called for every destructed actors */
sg4::Actor::on_destruction_cb(
[](sg4::Actor const& actor) { XBT_INFO("Actor %s gets destroyed now", actor.get_cname()); });
/* Create some actors */
sg4::Actor::create("A", e.host_by_name("Tremblay"), actor_a);
sg4::Actor::create("B", e.host_by_name("Fafard"), actor_b);
sg4::Actor::create("C", e.host_by_name("Ginette"), actor_c);
e.run(); /* - Run the simulation */
return 0;
}
This example shows how to attach a callback to the end of a specific actor with
sg_actor_on_exit()
.
View examples/c/actor-exiting/actor-exiting.c
/* Copyright (c) 2017-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. */
/* In C, there is a single way of being informed when an actor exits.
*
* The sg_actor_on_exit() function allows one to register a function to be
* executed when this very actor exits. The registered function will run
* when this actor terminates (either because its main function returns, or
* because it's killed in any way). No simcall are allowed here: your actor
* is dead already, so it cannot interact with its environment in any way
* (network, executions, disks, etc).
*
* Usually, the functions registered in sg_actor_on_exit() are in charge
* of releasing any memory allocated by the actor during its execution.
*/
#include <simgrid/actor.h>
#include <simgrid/engine.h>
#include <simgrid/host.h>
#include <simgrid/mailbox.h>
#include <xbt/asserts.h>
#include <xbt/log.h>
XBT_LOG_NEW_DEFAULT_CATEGORY(actor_exiting, "Messages specific for this example");
static void A_on_exit(int ignored1, void* ignored2)
{
XBT_INFO("I stop now");
}
static void actorA_fun(int argc, char* argv[])
{
// Register a lambda function to be executed once it stops
sg_actor_on_exit(&A_on_exit, NULL);
sg_actor_sleep_for(1);
}
static void actorB_fun(int argc, char* argv[])
{
sg_actor_sleep_for(2);
}
static void C_on_exit(int failed, void* ignored2)
{
if (failed) {
XBT_INFO("I was killed!");
if (xbt_log_no_loc)
XBT_INFO("The backtrace would be displayed here if --log=no_loc would not have been passed");
else
xbt_backtrace_display_current();
} else
XBT_INFO("Exiting gracefully.");
}
static void actorC_fun(int argc, char* argv[])
{
// Register a lambda function to be executed once it stops
sg_actor_on_exit(&C_on_exit, NULL);
sg_actor_sleep_for(3);
XBT_INFO("And now, induce a deadlock by waiting for a message that will never come\n\n");
sg_mailbox_get(sg_mailbox_by_name("nobody"));
xbt_die("Receiving is not supposed to succeed when nobody is sending");
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
xbt_assert(argc == 2, "Usage: %s platform_file\n\tExample: %s ../platforms/small_platform.xml\n", argv[0], argv[0]);
simgrid_load_platform(argv[1]); /* - Load the platform description */
sg_actor_create("A", sg_host_by_name("Tremblay"), actorA_fun, 0, NULL);
sg_actor_create("B", sg_host_by_name("Fafard"), actorB_fun, 0, NULL);
sg_actor_create("C", sg_host_by_name("Ginette"), actorC_fun, 0, NULL);
simgrid_run();
return 0;
}
Killing actors
Actors can forcefully stop other actors.
See also void simgrid::s4u::Actor::kill(void)
, void simgrid::s4u::Actor::kill_all()
,
simgrid::s4u::this_actor::exit()
, simgrid::s4u::Actor::on_exit()
.
View examples/cpp/actor-kill/s4u-actor-kill.cpp
/* Copyright (c) 2017-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. */
#include <simgrid/s4u.hpp>
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_actor_kill, "Messages specific for this s4u example");
static void victimA_fun()
{
sg4::this_actor::on_exit([](bool /*failed*/) { XBT_INFO("I have been killed!"); });
XBT_INFO("Hello!");
XBT_INFO("Suspending myself");
sg4::this_actor::suspend(); /* - Start by suspending itself */
XBT_INFO("OK, OK. Let's work"); /* - Then is resumed and start to execute some flops */
sg4::this_actor::execute(1e9);
XBT_INFO("Bye!"); /* - But will never reach the end of it */
}
static void victimB_fun()
{
XBT_INFO("Terminate before being killed");
}
static void killer()
{
XBT_INFO("Hello!"); /* - First start a victim actor */
sg4::ActorPtr victimA = sg4::Actor::create("victim A", sg4::Host::by_name("Fafard"), victimA_fun);
sg4::ActorPtr victimB = sg4::Actor::create("victim B", sg4::Host::by_name("Jupiter"), victimB_fun);
sg4::this_actor::sleep_for(10); /* - Wait for 10 seconds */
XBT_INFO("Resume the victim A"); /* - Resume it from its suspended state */
victimA->resume();
sg4::this_actor::sleep_for(2);
XBT_INFO("Kill the victim A"); /* - and then kill it */
sg4::Actor::by_pid(victimA->get_pid())->kill(); // You can retrieve an actor from its PID (and then kill it)
sg4::this_actor::sleep_for(1);
XBT_INFO("Kill victimB, even if it's already dead"); /* that's a no-op, there is no zombies in SimGrid */
victimB->kill(); // the actor is automatically garbage-collected after this last reference
sg4::this_actor::sleep_for(1);
XBT_INFO("Start a new actor, and kill it right away");
sg4::ActorPtr victimC = sg4::Actor::create("victim C", sg4::Host::by_name("Jupiter"), victimA_fun);
victimC->kill();
sg4::this_actor::sleep_for(1);
XBT_INFO("Killing everybody but myself");
sg4::Actor::kill_all();
XBT_INFO("OK, goodbye now. I commit a suicide.");
sg4::this_actor::exit();
XBT_INFO("This line never gets displayed: I'm already dead since the previous line.");
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
xbt_assert(argc == 2, "Usage: %s platform_file\n\tExample: %s ../platforms/small_platform.xml\n", argv[0], argv[0]);
e.load_platform(argv[1]); /* - Load the platform description */
/* - Create and deploy killer actor, that will create the victim actors */
sg4::Actor::create("killer", e.host_by_name("Tremblay"), killer);
e.run(); /* - Run the simulation */
return 0;
}
See also simgrid.Actor.kill()
, simgrid.Actor.kill_all()
, simgrid.this_actor.exit()
,
simgrid.this_actor.on_exit()
.
View examples/python/actor-kill/actor-kill.py
# Copyright (c) 2017-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.
"""
Usage: actor-kill.py platform_file [other parameters]
"""
import sys
from simgrid import Actor, Engine, Host, this_actor
def victim_a_fun():
this_actor.on_exit(lambda forcefully: this_actor.info("I have been killed!" if forcefully else "I finish now."))
this_actor.info("Hello!")
this_actor.info("Suspending myself")
this_actor.suspend() # - Start by suspending itself
# - Then is resumed and start to execute a task
this_actor.info("OK, OK. Let's work")
this_actor.execute(1e9)
# - But will never reach the end of it
this_actor.info("Bye!")
def victim_b_fun():
this_actor.info("Terminate before being killed")
def killer():
this_actor.info("Hello!") # - First start a victim actor
victim_a = Actor.create("victim A", Host.by_name("Fafard"), victim_a_fun)
victim_b = Actor.create("victim B", Host.by_name("Jupiter"), victim_b_fun)
this_actor.sleep_for(10) # - Wait for 10 seconds
# - Resume it from its suspended state
this_actor.info("Resume the victim A")
victim_a.resume()
this_actor.sleep_for(2)
this_actor.info("Kill the victim A") # - and then kill it
Actor.by_pid(victim_a.pid).kill() # You can retrieve an actor from its PID (and then kill it)
this_actor.sleep_for(1)
# that's a no-op, there is no zombies in SimGrid
this_actor.info("Kill victim B, even if it's already dead")
victim_b.kill()
this_actor.sleep_for(1)
this_actor.info("Start a new actor, and kill it right away")
victim_c = Actor.create("victim C", Host.by_name("Jupiter"), victim_a_fun)
victim_c.kill()
this_actor.sleep_for(1)
this_actor.info("Killing everybody but myself")
Actor.kill_all()
this_actor.info("OK, goodbye now. I commit a suicide.")
this_actor.exit()
this_actor.info(
"This line never gets displayed: I'm already dead since the previous line.")
if __name__ == '__main__':
e = Engine(sys.argv)
if len(sys.argv) < 2:
raise AssertionError(
"Usage: actor-kill.py platform_file [other parameters]")
e.load_platform(sys.argv[1]) # Load the platform description
# Create and deploy killer actor, that will create the victim actors
Actor.create("killer", Host.by_name("Tremblay"), killer)
e.run()
See also sg_actor_kill()
, sg_actor_kill_all()
, sg_actor_exit()
, sg_actor_on_exit()
.
View examples/c/actor-kill/actor-kill.c
/* Copyright (c) 2007-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. */
#include "simgrid/actor.h"
#include "simgrid/engine.h"
#include "simgrid/host.h"
#include "xbt/log.h"
#include "xbt/sysdep.h"
XBT_LOG_NEW_DEFAULT_CATEGORY(actor_kill, "Messages specific for this example");
static void victim_on_exit(int ignored1, void* ignored2)
{
XBT_INFO("I have been killed!");
}
static void victimA_fun(int argc, char* argv[])
{
sg_actor_on_exit(&victim_on_exit, NULL);
XBT_INFO("Hello!");
XBT_INFO("Suspending myself");
sg_actor_suspend(sg_actor_self()); /* - First suspend itself */
XBT_INFO("OK, OK. Let's work"); /* - Then is resumed and start to execute a task */
sg_actor_execute(1e9);
XBT_INFO("Bye!"); /* - But will never reach the end of it */
}
static void victimB_fun(int argc, char* argv[])
{
XBT_INFO("Terminate before being killed");
}
static void killer_fun(int argc, char* argv[])
{
XBT_INFO("Hello!"); /* - First start a victim actor */
sg_actor_t victimA = sg_actor_create("victim A", sg_host_by_name("Fafard"), victimA_fun, 0, NULL);
sg_actor_t victimB = sg_actor_create("victim B", sg_host_by_name("Jupiter"), victimB_fun, 0, NULL);
sg_actor_ref(victimB); // We have to take that ref because victimB will end before we try to kill it
sg_actor_sleep_for(10.0);
XBT_INFO("Resume the victim A"); /* - Resume it from its suspended state */
sg_actor_resume(victimA);
sg_actor_sleep_for(2.0);
XBT_INFO("Kill the victim A"); /* - and then kill it */
sg_actor_kill(victimA);
sg_actor_sleep_for(1.0);
XBT_INFO("Kill victimB, even if it's already dead"); /* that's a no-op, there is no zombies in SimGrid */
sg_actor_kill(victimB); // the actor is automatically garbage-collected after this last reference
sg_actor_unref(victimB); // Release the ref taken on victimB to avoid to leak memory
sg_actor_sleep_for(1.0);
XBT_INFO("Start a new actor, and kill it right away");
sg_actor_t victimC = sg_actor_create("victim C", sg_host_by_name("Jupiter"), victimA_fun, 0, NULL);
sg_actor_kill(victimC);
sg_actor_sleep_for(1.0);
XBT_INFO("Killing everybody but myself");
sg_actor_kill_all();
XBT_INFO("OK, goodbye now. I commit a suicide.");
sg_actor_exit();
XBT_INFO("This line will never get displayed: I'm already dead since the previous line.");
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
xbt_assert(argc == 2, "Usage: %s platform_file\n\tExample: %s platform.xml\n", argv[0], argv[0]);
simgrid_load_platform(argv[1]);
/* - Create and deploy killer actor, that will create the victim actor */
sg_actor_create("killer", sg_host_by_name("Tremblay"), killer_fun, 0, NULL);
simgrid_run();
return 0;
}
Actors’ life cycle from XML_reference
You can specify a start time and a kill time in the deployment file.
This file is not really interesting: the important matter is in the XML file.
View examples/cpp/actor-lifetime/s4u-actor-lifetime.cpp
Download s4u-actor-lifetime.cpp
/* Copyright (c) 2007-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. */
/* This C++ file acts as the foil to the corresponding XML file, where the
action takes place: Actors are started and stopped at predefined time. */
#include "simgrid/s4u.hpp"
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(test, "Messages specific for this s4u example");
/* This actor just sleeps until termination */
class sleeper {
public:
explicit sleeper(std::vector<std::string> /*args*/)
{
sg4::this_actor::on_exit([](bool /*failed*/) {
/* Executed on actor termination, to display a message helping to understand the output */
XBT_INFO("Exiting now (done sleeping or got killed).");
});
}
void operator()() const
{
XBT_INFO("Hello! I go to sleep.");
sg4::this_actor::sleep_for(10);
XBT_INFO("Done sleeping.");
}
};
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
xbt_assert(argc > 2,
"Usage: %s platform_file deployment_file\n"
"\tExample: %s ../platforms/cluster_backbone.xml ./s4u_actor_lifetime_d.xml\n",
argv[0], argv[0]);
e.load_platform(argv[1]); /* Load the platform description */
e.register_actor<sleeper>("sleeper");
e.load_deployment(argv[2]); /* Deploy the sleeper actors with explicit start/kill times */
e.run(); /* - Run the simulation */
return 0;
}
This demonstrates the start_time
and kill_time
attribute of the <actor> tag.
View examples/cpp/actor-lifetime/s4u-actor-lifetime_d.xml
Download s4u-actor-lifetime_d.xml
<?xml version='1.0'?>
<!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
<!-- This shows how to use the start_time and kill_time attributes of <actors> -->
<platform version="4.1">
<actor host="node-0.simgrid.org" function="sleeper" />
<actor host="node-0.simgrid.org" function="sleeper" start_time="2" />
<actor host="node-1.simgrid.org" function="sleeper" kill_time="3" />
<actor host="node-2.simgrid.org" function="sleeper" start_time="4" kill_time="7" />
</platform>
This file is not really interesting: the important matter is in the XML file.
View examples/python/actor-lifetime/actor-lifetime.py
# Copyright (c) 2007-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.
"""
This Python file acts as the foil to the corresponding XML file, where the
action takes place: Actors are started and stopped at predefined time
"""
import sys
from simgrid import Engine, this_actor
class Sleeper:
"""This actor just sleeps until termination"""
def __init__(self):
this_actor.on_exit(lambda killed: this_actor.info("Exiting now (killed)." if killed else "Exiting now (finishing)."))
def __call__(self):
this_actor.info("Hello! I go to sleep.")
this_actor.sleep_for(10)
this_actor.info("Done sleeping.")
if __name__ == '__main__':
e = Engine(sys.argv)
if len(sys.argv) < 2:
raise AssertionError(
"Usage: actor-lifetime.py platform_file actor-lifetime_d.xml [other parameters]")
e.load_platform(sys.argv[1]) # Load the platform description
e.register_actor("sleeper", Sleeper)
# Deploy the sleeper actors with explicit start/kill times
e.load_deployment(sys.argv[2])
e.run()
This file is not really interesting: the important matter is in the XML file.
View examples/c/actor-lifetime/actor-lifetime.c
/* Copyright (c) 2007-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. */
#include "simgrid/actor.h"
#include "simgrid/engine.h"
#include "xbt/asserts.h"
#include "xbt/log.h"
#include <stdio.h> /* snprintf */
XBT_LOG_NEW_DEFAULT_CATEGORY(test, "Messages specific for this example");
/* Executed on actor termination*/
static void my_onexit(int ignored1, void* ignored2)
{
XBT_INFO("Exiting now (done sleeping or got killed)."); /* - Just display an informative message (see tesh file) */
}
/* Just sleep until termination */
static void sleeper(int argc, char* argv[])
{
sg_actor_on_exit(my_onexit, NULL);
XBT_INFO("Hello! I go to sleep.");
sg_actor_sleep_for(10);
XBT_INFO("Done sleeping.");
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
xbt_assert(argc > 2,
"Usage: %s platform_file deployment_file\n"
"\tExample: %s platform.xml deployment.xml\n",
argv[0], argv[0]);
simgrid_load_platform(argv[1]); /* - Load the platform description */
simgrid_register_function("sleeper", sleeper);
simgrid_load_deployment(argv[2]); /* - Deploy the sleeper actors with explicit start/kill times */
simgrid_run(); /* - Run the simulation */
return 0;
}
Daemon actors
Some actors may be intended to simulate daemons that run in the background. This example shows how to transform a regular actor into a daemon that will be automatically killed once the simulation is over.
See also simgrid::s4u::Actor::daemonize()
and simgrid::s4u::Actor::is_daemon()
.
View examples/cpp/actor-daemon/s4u-actor-daemon.cpp
/* Copyright (c) 2017-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. */
#include "simgrid/s4u.hpp"
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_actor_daemon, "Messages specific for this s4u example");
/* The worker actor, working for a while before leaving */
static void worker()
{
XBT_INFO("Let's do some work (for 10 sec on Boivin).");
sg4::this_actor::execute(980.95e6);
XBT_INFO("I'm done now. I leave even if it makes the daemon die.");
}
/* The daemon, displaying a message every 3 seconds until all other actors stop */
static void my_daemon()
{
sg4::Actor::self()->daemonize();
while (sg4::this_actor::get_host()->is_on()) {
XBT_INFO("Hello from the infinite loop");
sg4::this_actor::sleep_for(3.0);
}
XBT_INFO("I will never reach that point: daemons are killed when regular actors are done");
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
e.load_platform(argv[1]);
sg4::Actor::create("worker", e.host_by_name("Boivin"), worker);
sg4::Actor::create("daemon", e.host_by_name("Tremblay"), my_daemon);
e.run();
return 0;
}
See also simgrid.Actor.daemonize()
and simgrid.Actor.is_daemon()
.
View examples/python/actor-daemon/actor-daemon.py
# Copyright (c) 2017-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.
"""
Usage: actor-daemon.py platform_file [other parameters]
"""
import sys
from simgrid import Actor, Engine, Host, this_actor
def worker():
"""The worker actor, working for a while before leaving"""
this_actor.info("Let's do some work (for 10 sec on Boivin).")
this_actor.execute(980.95e6)
this_actor.info("I'm done now. I leave even if it makes the daemon die.")
def my_daemon():
"""The daemon, displaying a message every 3 seconds until all other actors stop"""
Actor.self().daemonize()
while True:
this_actor.info("Hello from the infinite loop")
this_actor.sleep_for(3.0)
this_actor.info(
"I will never reach that point: daemons are killed when regular actors are done")
if __name__ == '__main__':
e = Engine(sys.argv)
if len(sys.argv) < 2:
raise AssertionError(
"Usage: actor-daemon.py platform_file [other parameters]")
e.load_platform(sys.argv[1])
Actor.create("worker", Host.by_name("Boivin"), worker)
Actor.create("daemon", Host.by_name("Tremblay"), my_daemon)
e.run()
See also sg_actor_daemonize()
and sg_actor_is_daemon()
.
View examples/c/actor-daemon/actor-daemon.c
/* Copyright (c) 2017-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. */
#include "simgrid/actor.h"
#include "simgrid/engine.h"
#include "simgrid/host.h"
#include "xbt/asserts.h"
#include "xbt/log.h"
XBT_LOG_NEW_DEFAULT_CATEGORY(actor_daemon, "Messages specific for this example");
/* The worker actor, working for a while before leaving */
static void worker(int argc, char* argv[])
{
XBT_INFO("Let's do some work (for 10 sec on Boivin).");
sg_actor_execute(980.95e6);
XBT_INFO("I'm done now. I leave even if it makes the daemon die.");
}
/* The daemon, displaying a message every 3 seconds until all other actors stop */
static void my_daemon(int argc, char* argv[])
{
sg_actor_daemonize(sg_actor_self());
while (1) {
XBT_INFO("Hello from the infinite loop");
sg_actor_sleep_for(3.0);
}
XBT_INFO("I will never reach that point: daemons are killed when regular actors are done");
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
xbt_assert(argc > 1, "Usage: %s platform.xml\n", argv[0]);
simgrid_load_platform(argv[1]);
sg_actor_create("worker", sg_host_by_name("Boivin"), worker, 0, NULL);
sg_actor_create("daemon", sg_host_by_name("Tremblay"), my_daemon, 0, NULL);
simgrid_run();
}
Specifying the stack size
The stack size can be specified by default on the command line,
globally by changing the configuration with simgrid::s4u::Engine::set_config()
,
or for a specific actor using simgrid::s4u::Actor::set_stacksize()
before its start.
View examples/cpp/actor-stacksize/s4u-actor-stacksize.cpp
Download s4u-actor-stacksize.cpp
/* Copyright (c) 2010-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. */
/* This code tests that we can change the stack-size between the actors creation. */
#include <simgrid/s4u.hpp>
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_test, "Messages specific for this s4u example");
static void actor()
{
XBT_INFO("Hello");
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
e.load_platform(argv[1]);
// If you don't specify anything, you get the default size (8Mb) or the one passed on the command line
sg4::Actor::create("actor", e.host_by_name("Tremblay"), actor);
// You can use set_config(string) to pass a size that will be parsed. That value will be used for any subsequent
// actors
sg4::Engine::set_config("contexts/stack-size:16384");
sg4::Actor::create("actor", e.host_by_name("Tremblay"), actor);
sg4::Actor::create("actor", e.host_by_name("Tremblay"), actor);
// You can use set_config(key, value) for the same effect.
sg4::Engine::set_config("contexts/stack-size", 32 * 1024);
sg4::Actor::create("actor", e.host_by_name("Tremblay"), actor);
sg4::Actor::create("actor", e.host_by_name("Tremblay"), actor);
// Or you can use set_stacksize() before starting the actor to modify only this one
sg4::Actor::init("actor", e.host_by_name("Tremblay"))->set_stacksize(64 * 1024)->start(actor);
sg4::Actor::create("actor", e.host_by_name("Tremblay"), actor);
e.run();
XBT_INFO("Simulation time %g", sg4::Engine::get_clock());
return 0;
}
View examples/c/actor-stacksize/actor-stacksize.c
/* Copyright (c) 2010-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. */
/* This code tests that we can change the stack-size between the actors creation. */
#include "simgrid/actor.h"
#include "simgrid/engine.h"
#include "simgrid/host.h"
#include "xbt/config.h"
#include "xbt/log.h"
XBT_LOG_NEW_DEFAULT_CATEGORY(actor_stacksize, "Messages specific for this example");
static void actor(int argc, char* argv[])
{
XBT_INFO("Hello");
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
simgrid_load_platform(argv[1]);
// If you don't specify anything, you get the default size (8Mb) or the one passed on the command line
sg_actor_create("actor", sg_host_by_name("Tremblay"), actor, 0, NULL);
// You can use sg_cfg_set_int(key, value) to pass a size that will be parsed. That value will be used for any
// subsequent actors
sg_cfg_set_int("contexts/stack-size", 16384);
sg_actor_create("actor", sg_host_by_name("Tremblay"), actor, 0, NULL);
sg_actor_create("actor", sg_host_by_name("Tremblay"), actor, 0, NULL);
sg_cfg_set_int("contexts/stack-size", 32 * 1024);
sg_actor_create("actor", sg_host_by_name("Tremblay"), actor, 0, NULL);
sg_actor_create("actor", sg_host_by_name("Tremblay"), actor, 0, NULL);
// Or you can use set_stacksize() before starting the actor to modify only this one
sg_actor_t a = sg_actor_init("actor", sg_host_by_name("Tremblay"));
sg_actor_set_stacksize(a, 64 * 1024);
sg_actor_start(a, actor, 0, NULL);
sg_actor_create("actor", sg_host_by_name("Tremblay"), actor, 0, NULL);
simgrid_run();
XBT_INFO("Simulation time %g", simgrid_get_clock());
return 0;
}
Inter-Actors Interactions
See also the examples on inter-actors communications and the ones on classical synchronization objects.
Suspending/resuming Actors
Actors can be suspended and resumed during their executions.
See also simgrid::s4u::this_actor::suspend()
,
simgrid::s4u::Actor::suspend()
, simgrid::s4u::Actor::resume()
, and
simgrid::s4u::Actor::is_suspended()
.
View examples/cpp/actor-suspend/s4u-actor-suspend.cpp
Download s4u-actor-suspend.cpp
/* Copyright (c) 2017-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. */
#include <simgrid/s4u.hpp>
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_actor_suspend, "Messages specific for this s4u example");
/* The Lazy guy only wants to sleep, but can be awaken by the dream_master actor. */
static void lazy_guy()
{
XBT_INFO("Nobody's watching me ? Let's go to sleep.");
sg4::this_actor::suspend(); /* - Start by suspending itself */
XBT_INFO("Uuuh ? Did somebody call me ?");
XBT_INFO("Going to sleep..."); /* - Then repetitively go to sleep, but got awaken */
sg4::this_actor::sleep_for(10);
XBT_INFO("Mmm... waking up.");
XBT_INFO("Going to sleep one more time (for 10 sec)...");
sg4::this_actor::sleep_for(10);
XBT_INFO("Waking up once for all!");
XBT_INFO("Ok, let's do some work, then (for 10 sec on Boivin).");
sg4::this_actor::execute(980.95e6);
XBT_INFO("Mmmh, I'm done now. Goodbye.");
}
/* The Dream master: */
static void dream_master()
{
XBT_INFO("Let's create a lazy guy."); /* - Create a lazy_guy actor */
sg4::ActorPtr lazy = sg4::Actor::create("Lazy", sg4::this_actor::get_host(), lazy_guy);
XBT_INFO("Let's wait a little bit...");
sg4::this_actor::sleep_for(10); /* - Wait for 10 seconds */
XBT_INFO("Let's wake the lazy guy up! >:) BOOOOOUUUHHH!!!!");
if (lazy->is_suspended())
lazy->resume(); /* - Then wake up the lazy_guy */
else
XBT_ERROR("I was thinking that the lazy guy would be suspended now");
sg4::this_actor::sleep_for(5); /* Repeat two times: */
XBT_INFO("Suspend the lazy guy while he's sleeping...");
lazy->suspend(); /* - Suspend the lazy_guy while he's asleep */
XBT_INFO("Let him finish his siesta.");
sg4::this_actor::sleep_for(10); /* - Wait for 10 seconds */
XBT_INFO("Wake up, lazy guy!");
lazy->resume(); /* - Then wake up the lazy_guy again */
sg4::this_actor::sleep_for(5);
XBT_INFO("Suspend again the lazy guy while he's sleeping...");
lazy->suspend();
XBT_INFO("This time, don't let him finish his siesta.");
sg4::this_actor::sleep_for(2);
XBT_INFO("Wake up, lazy guy!");
lazy->resume();
sg4::this_actor::sleep_for(5);
XBT_INFO("Give a 2 seconds break to the lazy guy while he's working...");
lazy->suspend();
sg4::this_actor::sleep_for(2);
XBT_INFO("Back to work, lazy guy!");
lazy->resume();
XBT_INFO("OK, I'm done here.");
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
xbt_assert(argc == 2, "Usage: %s platform_file\n\tExample: %s ../platforms/small_platform.xml\n", argv[0], argv[0]);
e.load_platform(argv[1]); /* - Load the platform description */
std::vector<sg4::Host*> list = e.get_all_hosts();
sg4::Actor::create("dream_master", list.front(), dream_master);
e.run(); /* - Run the simulation */
return 0;
}
See also simgrid.this_actor.suspend()
,
simgrid.Actor.suspend()
, simgrid.Actor.resume()
, and
simgrid.Actor.is_suspended()
.
View examples/python/actor-suspend/actor-suspend.py
# Copyright (c) 2017-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.
"""
Usage: actor-suspend.py platform_file [other parameters]
"""
import sys
from simgrid import Actor, Engine, this_actor
def lazy_guy():
"""The Lazy guy only wants to sleep, but can be awaken by the dream_master actor"""
this_actor.info("Nobody's watching me ? Let's go to sleep.")
this_actor.suspend() # - Start by suspending itself
this_actor.info("Uuuh ? Did somebody call me ?")
# - Then repetitively go to sleep, but get awaken
this_actor.info("Going to sleep...")
this_actor.sleep_for(10)
this_actor.info("Mmm... waking up.")
this_actor.info("Going to sleep one more time (for 10 sec)...")
this_actor.sleep_for(10)
this_actor.info("Waking up once for all!")
this_actor.info("Ok, let's do some work, then (for 10 sec on Boivin).")
this_actor.execute(980.95e6)
this_actor.info("Mmmh, I'm done now. Goodbye.")
def dream_master():
"""The Dream master"""
this_actor.info("Let's create a lazy guy.") # Create a lazy_guy actor
lazy = Actor.create("Lazy", this_actor.get_host(), lazy_guy)
this_actor.info("Let's wait a little bit...")
this_actor.sleep_for(10) # Wait for 10 seconds
this_actor.info("Let's wake the lazy guy up! >:) BOOOOOUUUHHH!!!!")
if lazy.is_suspended():
lazy.resume() # Then wake up the lazy_guy
else:
this_actor.error(
"I was thinking that the lazy guy would be suspended now")
this_actor.sleep_for(5) # Repeat two times:
this_actor.info("Suspend the lazy guy while he's sleeping...")
lazy.suspend() # Suspend the lazy_guy while he's asleep
this_actor.info("Let him finish his siesta.")
this_actor.sleep_for(10) # Wait for 10 seconds
this_actor.info("Wake up, lazy guy!")
lazy.resume() # Then wake up the lazy_guy again
this_actor.sleep_for(5)
this_actor.info("Suspend again the lazy guy while he's sleeping...")
lazy.suspend()
this_actor.info("This time, don't let him finish his siesta.")
this_actor.sleep_for(2)
this_actor.info("Wake up, lazy guy!")
lazy.resume()
this_actor.sleep_for(5)
this_actor.info(
"Give a 2 seconds break to the lazy guy while he's working...")
lazy.suspend()
this_actor.sleep_for(2)
this_actor.info("Back to work, lazy guy!")
lazy.resume()
this_actor.info("OK, I'm done here.")
if __name__ == '__main__':
e = Engine(sys.argv)
if len(sys.argv) < 2:
raise AssertionError(
"Usage: actor-suspend.py platform_file [other parameters]")
e.load_platform(sys.argv[1]) # Load the platform description
hosts = e.all_hosts
Actor.create("dream_master", hosts[0], dream_master)
e.run() # Run the simulation
See also sg_actor_suspend()
, sg_actor_resume()
, and
sg_actor_is_suspended()
.
View examples/c/actor-suspend/actor-suspend.c
/* Copyright (c) 2007-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. */
#include "simgrid/actor.h"
#include "simgrid/engine.h"
#include "simgrid/host.h"
#include "xbt/asserts.h"
#include "xbt/log.h"
XBT_LOG_NEW_DEFAULT_CATEGORY(actor_suspend, "Messages specific for this example");
/* The Lazy guy only wants to sleep, but can be awaken by the dream_master actor. */
static void lazy_guy(int argc, char* argv[])
{
XBT_INFO("Nobody's watching me ? Let's go to sleep.");
sg_actor_suspend(sg_actor_self()); /* - Start by suspending itself */
XBT_INFO("Uuuh ? Did somebody call me ?");
XBT_INFO("Going to sleep..."); /* - Then repetitively go to sleep, but got awaken */
sg_actor_sleep_for(10.0);
XBT_INFO("Mmm... waking up.");
XBT_INFO("Going to sleep one more time (for 10 sec)...");
sg_actor_sleep_for(10.0);
XBT_INFO("Waking up once for all!");
XBT_INFO("Ok, let's do some work, then (for 10 sec on Boivin).");
sg_actor_execute(980.95e6);
XBT_INFO("Mmmh, I'm done now. Goodbye.");
}
/* The Dream master: */
static void dream_master(int argc, char* argv[])
{
XBT_INFO("Let's create a lazy guy."); /* - Create a lazy_guy actor */
sg_actor_t lazy = sg_actor_create("Lazy", sg_host_self(), lazy_guy, 0, NULL);
XBT_INFO("Let's wait a little bit...");
sg_actor_sleep_for(10.0); /* - Wait for 10 seconds */
XBT_INFO("Let's wake the lazy guy up! >:) BOOOOOUUUHHH!!!!");
sg_actor_resume(lazy); /* - Then wake up the lazy_guy */
sg_actor_sleep_for(5.0); /* Repeat two times: */
XBT_INFO("Suspend the lazy guy while he's sleeping...");
sg_actor_suspend(lazy); /* - Suspend the lazy_guy while he's asleep */
XBT_INFO("Let him finish his siesta.");
sg_actor_sleep_for(10.0); /* - Wait for 10 seconds */
XBT_INFO("Wake up, lazy guy!");
sg_actor_resume(lazy); /* - Then wake up the lazy_guy again */
sg_actor_sleep_for(5.0);
XBT_INFO("Suspend again the lazy guy while he's sleeping...");
sg_actor_suspend(lazy);
XBT_INFO("This time, don't let him finish his siesta.");
sg_actor_sleep_for(2.0);
XBT_INFO("Wake up, lazy guy!");
sg_actor_resume(lazy);
sg_actor_sleep_for(5.0);
XBT_INFO("Give a 2 seconds break to the lazy guy while he's working...");
sg_actor_suspend(lazy);
sg_actor_sleep_for(2.0);
XBT_INFO("Back to work, lazy guy!");
sg_actor_resume(lazy);
XBT_INFO("OK, I'm done here.");
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
xbt_assert(argc > 1, "Usage: %s platform_file\n\tExample: %s platform.xml\n", argv[0], argv[0]);
simgrid_load_platform(argv[1]);
simgrid_register_function("dream_master", dream_master);
sg_actor_create("dream_master", sg_host_by_name("Boivin"), dream_master, 0, NULL);
simgrid_run();
return 0;
}
Migrating Actors
Actors can move or be moved from a host to another very easily. It amounts to setting them on a new host.
See also simgrid::s4u::this_actor::set_host()
and simgrid::s4u::Actor::set_host()
.
View examples/cpp/actor-migrate/s4u-actor-migrate.cpp
Download s4u-actor-migrate.cpp
/* Copyright (c) 2017-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. */
/* This example demonstrate the actor migrations.
*
* The worker actor first move by itself, and then start an execution.
* During that execution, the monitor migrates the worker, that wakes up on another host.
* The execution was of the right amount of flops to take exactly 5 seconds on the first host
* and 5 other seconds on the second one, so it stops after 10 seconds.
*
* Then another migration is done by the monitor while the worker is suspended.
*
* Note that worker() takes an uncommon set of parameters,
* and that this is perfectly accepted by create().
*/
#include <simgrid/s4u.hpp>
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_actor_migration, "Messages specific for this s4u example");
static void worker(sg4::Host* first, const sg4::Host* second)
{
double flopAmount = first->get_speed() * 5 + second->get_speed() * 5;
XBT_INFO("Let's move to %s to execute %.2f Mflops (5sec on %s and 5sec on %s)", first->get_cname(), flopAmount / 1e6,
first->get_cname(), second->get_cname());
sg4::this_actor::set_host(first);
sg4::this_actor::execute(flopAmount);
XBT_INFO("I wake up on %s. Let's suspend a bit", sg4::this_actor::get_host()->get_cname());
sg4::this_actor::suspend();
XBT_INFO("I wake up on %s", sg4::this_actor::get_host()->get_cname());
XBT_INFO("Done");
}
static void monitor()
{
sg4::Host* boivin = sg4::Host::by_name("Boivin");
sg4::Host* jacquelin = sg4::Host::by_name("Jacquelin");
sg4::Host* fafard = sg4::Host::by_name("Fafard");
sg4::ActorPtr actor = sg4::Actor::create("worker", fafard, worker, boivin, jacquelin);
sg4::this_actor::sleep_for(5);
XBT_INFO("After 5 seconds, move the actor to %s", jacquelin->get_cname());
actor->set_host(jacquelin);
sg4::this_actor::sleep_until(15);
XBT_INFO("At t=15, move the actor to %s and resume it.", fafard->get_cname());
actor->set_host(fafard);
actor->resume();
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
xbt_assert(argc == 2, "Usage: %s platform_file\n\tExample: %s ../platforms/small_platform.xml\n", argv[0], argv[0]);
e.load_platform(argv[1]);
sg4::Actor::create("monitor", e.host_by_name("Boivin"), monitor);
e.run();
return 0;
}
See also simgrid.Actor.host
.
View examples/python/actor-migrate/actor-migrate.py
# Copyright (c) 2017-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.
"""
This example demonstrate the actor migrations.
The worker actor first move by itself, and then start an execution.
During that execution, the monitor migrates the worker, that wakes up on another host.
The execution was of the right amount of flops to take exactly 5 seconds on the first host
and 5 other seconds on the second one, so it stops after 10 seconds.
Then another migration is done by the monitor while the worker is suspended.
Note that worker() takes an uncommon set of parameters,
and that this is perfectly accepted by create().
"""
import sys
from simgrid import Actor, Engine, Host, this_actor
def worker(first_host, second_host):
flop_amount = first_host.speed * 5 + second_host.speed * 5
this_actor.info("Let's move to {:s} to execute {:.2f} Mflops (5sec on {:s} and 5sec on {:s})".format(
first_host.name, flop_amount / 1e6, first_host.name, second_host.name))
this_actor.set_host(first_host)
this_actor.execute(flop_amount)
this_actor.info("I wake up on {:s}. Let's suspend a bit".format(
this_actor.get_host().name))
this_actor.suspend()
this_actor.info("I wake up on {:s}".format(this_actor.get_host().name))
this_actor.info("Done")
def monitor():
boivin = Host.by_name("Boivin")
jacquelin = Host.by_name("Jacquelin")
fafard = Host.by_name("Fafard")
actor = Actor.create("worker", fafard, worker, boivin, jacquelin)
this_actor.sleep_for(5)
this_actor.info(
"After 5 seconds, move the actor to {:s}".format(jacquelin.name))
actor.host = jacquelin
this_actor.sleep_until(15)
this_actor.info(
"At t=15, move the actor to {:s} and resume it.".format(fafard.name))
actor.host = fafard
actor.resume()
if __name__ == '__main__':
e = Engine(sys.argv)
if len(sys.argv) < 2:
raise AssertionError(
"Usage: actor-migration.py platform_file [other parameters]")
e.load_platform(sys.argv[1])
Actor.create("monitor", Host.by_name("Boivin"), monitor)
e.run()
See also sg_actor_set_host()
.
View examples/c/actor-migrate/actor-migrate.c
/* Copyright (c) 2009-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. */
#include "simgrid/actor.h"
#include "simgrid/barrier.h"
#include "simgrid/engine.h"
#include "simgrid/host.h"
#include "xbt/asserts.h"
#include "xbt/log.h"
XBT_LOG_NEW_DEFAULT_CATEGORY(actor_migrate, "Messages specific for this example");
static void worker(int argc, char* argv[])
{
xbt_assert(argc > 2);
sg_host_t first = sg_host_by_name(argv[1]);
const_sg_host_t second = sg_host_by_name(argv[2]);
double flopAmount = sg_host_get_speed(first) * 5 + sg_host_get_speed(second) * 5;
XBT_INFO("Let's move to %s to execute %.2f Mflops (5sec on %s and 5sec on %s)", argv[1], flopAmount / 1e6, argv[1],
argv[2]);
sg_actor_set_host(sg_actor_self(), first);
sg_actor_execute(flopAmount);
XBT_INFO("I wake up on %s. Let's suspend a bit", sg_host_get_name(sg_host_self()));
sg_actor_suspend(sg_actor_self());
XBT_INFO("I wake up on %s", sg_host_get_name(sg_host_self()));
XBT_INFO("Done");
}
static void monitor(int argc, char* argv[])
{
sg_host_t jacquelin = sg_host_by_name("Jacquelin");
sg_host_t fafard = sg_host_by_name("Fafard");
int actor_argc = 3;
const char* actor_argv[] = {"worker", "Boivin", "Jacquelin", NULL};
sg_actor_t actor = sg_actor_create_("worker", sg_host_by_name("Fafard"), worker, actor_argc, actor_argv);
sg_actor_sleep_for(5);
XBT_INFO("After 5 seconds, move the actor to %s", sg_host_get_name(jacquelin));
sg_actor_set_host(actor, jacquelin);
sg_actor_sleep_until(15);
XBT_INFO("At t=15, move the actor to %s and resume it.", sg_host_get_name(fafard));
sg_actor_set_host(actor, fafard);
sg_actor_resume(actor);
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
xbt_assert(argc == 2, "Usage: %s platform_file\n\tExample: %s platform.xml\n", argv[0], argv[0]);
simgrid_load_platform(argv[1]); /* - Load the platform description */
sg_actor_create("monitor", sg_host_by_name("Boivin"), monitor, 0, NULL);
simgrid_run();
return 0;
}
Waiting for the termination of an actor (joining on it)
You can block the current actor until the end of another actor.
See also simgrid::s4u::Actor::join()
.
View examples/cpp/actor-join/s4u-actor-join.cpp
/* Copyright (c) 2017-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. */
#include "simgrid/s4u.hpp"
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_test, "Messages specific for this s4u example");
static void sleeper()
{
XBT_INFO("Sleeper started");
sg4::this_actor::sleep_for(3);
XBT_INFO("I'm done. See you!");
}
static void master()
{
sg4::ActorPtr actor;
XBT_INFO("Start sleeper");
actor = sg4::Actor::create("sleeper from master", sg4::Host::current(), sleeper);
XBT_INFO("Join the sleeper (timeout 2)");
actor->join(2);
XBT_INFO("Start sleeper");
actor = sg4::Actor::create("sleeper from master", sg4::Host::current(), sleeper);
XBT_INFO("Join the sleeper (timeout 4)");
actor->join(4);
XBT_INFO("Start sleeper");
actor = sg4::Actor::create("sleeper from master", sg4::Host::current(), sleeper);
XBT_INFO("Join the sleeper (timeout 2)");
actor->join(2);
XBT_INFO("Start sleeper");
actor = sg4::Actor::create("sleeper from master", sg4::Host::current(), sleeper);
XBT_INFO("Waiting 4");
sg4::this_actor::sleep_for(4);
XBT_INFO("Join the sleeper after its end (timeout 1)");
actor->join(1);
XBT_INFO("Goodbye now!");
sg4::this_actor::sleep_for(1);
XBT_INFO("Goodbye now!");
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
xbt_assert(argc == 2, "Usage: %s platform_file\n\tExample: %s ../platforms/small_platform.xml\n", argv[0], argv[0]);
e.load_platform(argv[1]);
sg4::Actor::create("master", e.host_by_name("Tremblay"), master);
e.run();
XBT_INFO("Simulation time %g", sg4::Engine::get_clock());
return 0;
}
See also simgrid.Actor.join()
.
View examples/python/actor-join/actor-join.py
# Copyright (c) 2017-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.
"""
Usage: actor-join.py platform_file [other parameters]
"""
import sys
from simgrid import Actor, Engine, Host, this_actor
def sleeper():
this_actor.info("Sleeper started")
this_actor.sleep_for(3)
this_actor.info("I'm done. See you!")
def master():
this_actor.info("Start 1st sleeper")
actor = Actor.create("1st sleeper from master", Host.current(), sleeper)
this_actor.info("Join the 1st sleeper (timeout 2)")
actor.join(2)
this_actor.info("Start 2nd sleeper")
actor = Actor.create("2nd sleeper from master", Host.current(), sleeper)
this_actor.info("Join the 2nd sleeper (timeout 4)")
actor.join(4)
this_actor.info("Start 3rd sleeper")
actor = Actor.create("3rd sleeper from master", Host.current(), sleeper)
this_actor.info("Join the 3rd sleeper (timeout 2)")
actor.join(2)
this_actor.info("Start 4th sleeper")
actor = Actor.create("4th sleeper from master", Host.current(), sleeper)
this_actor.info("Waiting 4")
this_actor.sleep_for(4)
this_actor.info("Join the 4th sleeper after its end (timeout 1)")
actor.join(1)
this_actor.info("Goodbye now!")
this_actor.sleep_for(1)
this_actor.info("Goodbye now!")
if __name__ == '__main__':
e = Engine(sys.argv)
if len(sys.argv) < 2:
raise AssertionError(
"Usage: actor-join.py platform_file [other parameters]")
e.load_platform(sys.argv[1])
Actor.create("master", Host.by_name("Tremblay"), master)
e.run()
this_actor.info("Simulation time {}".format(e.clock))
See also sg_actor_join()
.
View examples/c/actor-join/actor-join.c
/* Copyright (c) 2010-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. */
#include "simgrid/actor.h"
#include "simgrid/engine.h"
#include "simgrid/host.h"
#include "xbt/log.h"
#include "xbt/sysdep.h"
XBT_LOG_NEW_DEFAULT_CATEGORY(actor_join, "Messages specific for this example");
static void sleeper(int argc, char* argv[])
{
XBT_INFO("Sleeper started");
sg_actor_sleep_for(3);
XBT_INFO("I'm done. See you!");
}
static void master(int argc, char* argv[])
{
const_sg_actor_t actor;
XBT_INFO("Start sleeper");
actor = sg_actor_create("sleeper from master", sg_host_self(), sleeper, 0, NULL);
XBT_INFO("Join the sleeper (timeout 2)");
sg_actor_join(actor, 2);
XBT_INFO("Start sleeper");
actor = sg_actor_create("sleeper from master", sg_host_self(), sleeper, 0, NULL);
XBT_INFO("Join the sleeper (timeout 4)");
sg_actor_join(actor, 4);
XBT_INFO("Start sleeper");
actor = sg_actor_create("sleeper from master", sg_host_self(), sleeper, 0, NULL);
XBT_INFO("Join the sleeper (timeout 2)");
sg_actor_join(actor, 2);
XBT_INFO("Start sleeper");
actor = sg_actor_create("sleeper from master", sg_host_self(), sleeper, 0, NULL);
sg_actor_ref(actor); // We have to take that ref because the actor will stop before we join it
XBT_INFO("Waiting 4");
sg_actor_sleep_for(4);
XBT_INFO("Join the sleeper after its end (timeout 1)");
sg_actor_join(actor, 1);
sg_actor_unref(actor); // Avoid to leak memory
XBT_INFO("Goodbye now!");
sg_actor_sleep_for(1);
XBT_INFO("Goodbye now!");
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
xbt_assert(argc == 2, "Usage: %s platform_file\n\tExample: %s platform.xml\n", argv[0], argv[0]);
simgrid_load_platform(argv[1]);
sg_actor_create("master", sg_host_by_name("Tremblay"), master, 0, NULL);
simgrid_run();
XBT_INFO("Simulation time %g", simgrid_get_clock());
return 0;
}
Yielding to other actors
The `yield()`
function interrupts the execution of the current
actor, leaving a chance to the other actors that are ready to run
at this timestamp.
See also simgrid::s4u::this_actor::yield()
.
View examples/cpp/actor-yield/s4u-actor-yield.cpp
/* Copyright (c) 2017-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. */
#include <simgrid/s4u.hpp>
namespace sg4 = simgrid::s4u;
/* This example does not much: It just spans over-polite actor that yield a large amount
* of time before ending.
*
* This serves as an example for the sg4::this_actor::yield() function, with which an actor can request
* to be rescheduled after the other actor that are ready at the current timestamp.
*
* It can also be used to benchmark our context-switching mechanism.
*/
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_actor_yield, "Messages specific for this s4u example");
static void yielder(long number_of_yields)
{
for (int i = 0; i < number_of_yields; i++)
sg4::this_actor::yield();
XBT_INFO("I yielded %ld times. Goodbye now!", number_of_yields);
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
e.load_platform(argv[1]); /* Load the platform description */
sg4::Actor::create("yielder", e.host_by_name("Tremblay"), yielder, 10);
sg4::Actor::create("yielder", e.host_by_name("Ruby"), yielder, 15);
e.run(); /* - Run the simulation */
return 0;
}
See also simgrid.this_actor.yield_()
.
View examples/python/actor-yield/actor-yield.py
# Copyright (c) 2017-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.
"""
This example does not much: It just spans over-polite actor that yield a large amount
of time before ending.
This serves as an example for the simgrid.yield() function, with which an actor can request
to be rescheduled after the other actor that are ready at the current timestamp.
It can also be used to benchmark our context-switching mechanism.
"""
import sys
from simgrid import Actor, Engine, Host, this_actor
def yielder(number_of_yields):
for _ in range(number_of_yields):
this_actor.yield_()
this_actor.info("I yielded {:d} times. Goodbye now!".format(number_of_yields))
if __name__ == '__main__':
e = Engine(sys.argv)
e.load_platform(sys.argv[1]) # Load the platform description
Actor.create("yielder", Host.by_name("Tremblay"), yielder, 10)
Actor.create("yielder", Host.by_name("Ruby"), yielder, 15)
e.run() # - Run the simulation
See also sg_actor_yield()
.
View examples/c/actor-yield/actor-yield.c
/* Copyright (c) 2017-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. */
#include "simgrid/actor.h"
#include "simgrid/engine.h"
#include "xbt/asserts.h"
#include "xbt/log.h"
#include "xbt/str.h"
/* This example does not much: It just spans over-polite actors that yield a large amount
* of time before ending.
*
* This serves as an example for the sg_actor_yield() function, with which an actor can request
* to be rescheduled after the other actors that are ready at the current timestamp.
*
* It can also be used to benchmark our context-switching mechanism.
*/
XBT_LOG_NEW_DEFAULT_CATEGORY(actor_yield, "Messages specific for this example");
/* Main function of the Yielder actor */
static void yielder(int argc, char* argv[])
{
xbt_assert(argc == 2, "The sender function expects 1 arguments from the XML deployment file");
long number_of_yields = xbt_str_parse_int(argv[1], "Invalid amount of yields");
for (int i = 0; i < number_of_yields; i++)
sg_actor_yield();
XBT_INFO("I yielded %ld times. Goodbye now!", number_of_yields);
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
xbt_assert(argc > 2,
"Usage: %s platform_file deployment_file\n"
"\tExample: %s platform.xml deployment.xml\n",
argv[0], argv[0]);
simgrid_load_platform(argv[1]); /* - Load the platform description */
simgrid_register_function("yielder", yielder);
simgrid_load_deployment(argv[2]); /* - Deploy the sender and receiver actors */
simgrid_run();
return 0;
}
Traces Replay as a Workload
This section details how to run trace-driven simulations. It is very handy when you want to test an algorithm or protocol that only reacts to external events. For example, many P2P protocols react to user requests, but do nothing if there is no such event.
In such situations, you should write your protocol in C++, and separate
the workload that you want to play onto your protocol in a separate
text file. Declare a function handling each type of the events in your
trace, register them using xbt_replay_action_register()
in
your main, and then run the simulation.
Then, you can either have one trace file containing all your events, or a file per simulated process: the former may be easier to work with, but the second is more efficient on very large traces. Check also the tesh files in the example directories for details.
Communication replay
Presents a set of event handlers reproducing classical communication primitives (asynchronous send/receive at the moment).
View examples/cpp/replay-comm/s4u-replay-comm.cpp
/* Copyright (c) 2009-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. */
#include "simgrid/s4u.hpp"
#include "xbt/replay.hpp"
#include "xbt/str.h"
#include <boost/algorithm/string/join.hpp>
#include <cinttypes>
#include <string>
XBT_LOG_NEW_DEFAULT_CATEGORY(replay_comm, "Messages specific for this example");
namespace sg4 = simgrid::s4u;
#define ACT_DEBUG(...) \
if (XBT_LOG_ISENABLED(replay_comm, xbt_log_priority_verbose)) { \
std::string NAME = boost::algorithm::join(action, " "); \
XBT_DEBUG(__VA_ARGS__); \
} else \
((void)0)
static void log_action(const simgrid::xbt::ReplayAction& action, double date)
{
if (XBT_LOG_ISENABLED(replay_comm, xbt_log_priority_verbose)) {
std::string s = boost::algorithm::join(action, " ");
XBT_VERB("%s %f", s.c_str(), date);
}
}
class Replayer {
public:
explicit Replayer(std::vector<std::string> args)
{
const char* actor_name = args.at(0).c_str();
if (args.size() > 1) { // split mode, the trace file was provided in the deployment file
const char* trace_filename = args[1].c_str();
simgrid::xbt::replay_runner(actor_name, trace_filename);
} else { // Merged mode
simgrid::xbt::replay_runner(actor_name);
}
}
void operator()() const
{
// Nothing to do here
}
/* My actions */
static void compute(simgrid::xbt::ReplayAction& action)
{
double amount = std::stod(action[2]);
double clock = sg4::Engine::get_clock();
ACT_DEBUG("Entering %s", NAME.c_str());
sg4::this_actor::execute(amount);
log_action(action, sg4::Engine::get_clock() - clock);
}
static void send(simgrid::xbt::ReplayAction& action)
{
auto size = static_cast<uint64_t>(std::stod(action[3]));
auto* payload = new std::string(action[3]);
double clock = sg4::Engine::get_clock();
sg4::Mailbox* to = sg4::Mailbox::by_name(sg4::this_actor::get_name() + "_" + action[2]);
ACT_DEBUG("Entering Send: %s (size: %" PRIu64 ") -- Actor %s on mailbox %s", NAME.c_str(), size,
sg4::this_actor::get_cname(), to->get_cname());
to->put(payload, size);
log_action(action, sg4::Engine::get_clock() - clock);
}
static void recv(simgrid::xbt::ReplayAction& action)
{
double clock = sg4::Engine::get_clock();
sg4::Mailbox* from = sg4::Mailbox::by_name(action[2] + "_" + sg4::this_actor::get_name());
ACT_DEBUG("Receiving: %s -- Actor %s on mailbox %s", NAME.c_str(), sg4::this_actor::get_cname(), from->get_cname());
from->get_unique<std::string>();
log_action(action, sg4::Engine::get_clock() - clock);
}
};
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
xbt_assert(argc > 2,
"Usage: %s platform_file deployment_file [action_files]\n"
"\t# if all actions are in the same file\n"
"\tExample: %s platform.xml deployment.xml actions\n"
"\t# if actions are in separate files, specified in deployment\n"
"\tExample: %s platform.xml deployment.xml ",
argv[0], argv[0], argv[0]);
e.load_platform(argv[1]);
e.register_actor<Replayer>("p0");
e.register_actor<Replayer>("p1");
e.load_deployment(argv[2]);
if (argv[3] != nullptr)
xbt_replay_set_tracefile(argv[3]);
/* Action registration */
xbt_replay_action_register("compute", Replayer::compute);
xbt_replay_action_register("send", Replayer::send);
xbt_replay_action_register("recv", Replayer::recv);
e.run();
XBT_INFO("Simulation time %g", sg4::Engine::get_clock());
return 0;
}
I/O replay
Presents a set of event handlers reproducing classical I/O primitives (open, read, close).
View examples/cpp/replay-io/s4u-replay-io.cpp
/* Copyright (c) 2017-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. */
#include <simgrid/plugins/file_system.h>
#include <simgrid/s4u.hpp>
#include <xbt/replay.hpp>
#include <xbt/str.h>
#include <boost/algorithm/string/join.hpp>
XBT_LOG_NEW_DEFAULT_CATEGORY(replay_io, "Messages specific for this example");
namespace sg4 = simgrid::s4u;
#define ACT_DEBUG(...) \
if (XBT_LOG_ISENABLED(replay_io, xbt_log_priority_verbose)) { \
std::string NAME = boost::algorithm::join(action, " "); \
XBT_DEBUG(__VA_ARGS__); \
} else \
((void)0)
class Replayer {
static std::unordered_map<std::string, sg4::File*> opened_files;
static void log_action(const simgrid::xbt::ReplayAction& action, double date)
{
if (XBT_LOG_ISENABLED(replay_io, xbt_log_priority_verbose)) {
std::string s = boost::algorithm::join(action, " ");
XBT_VERB("%s %f", s.c_str(), date);
}
}
static sg4::File* get_file_descriptor(const std::string& file_name)
{
std::string full_name = sg4::this_actor::get_name() + ":" + file_name;
return opened_files.at(full_name);
}
public:
explicit Replayer(std::vector<std::string> args)
{
const char* actor_name = args[0].c_str();
if (args.size() > 1) { // split mode, the trace file was provided in the deployment file
const char* trace_filename = args[1].c_str();
simgrid::xbt::replay_runner(actor_name, trace_filename);
} else { // Merged mode
simgrid::xbt::replay_runner(actor_name);
}
}
void operator()() const
{
// Nothing to do here
}
/* My actions */
static void open(simgrid::xbt::ReplayAction& action)
{
std::string file_name = action[2];
double clock = sg4::Engine::get_clock();
std::string full_name = sg4::this_actor::get_name() + ":" + file_name;
ACT_DEBUG("Entering Open: %s (filename: %s)", NAME.c_str(), file_name.c_str());
auto* file = sg4::File::open(file_name, nullptr);
opened_files.try_emplace(full_name, file);
log_action(action, sg4::Engine::get_clock() - clock);
}
static void read(simgrid::xbt::ReplayAction& action)
{
std::string file_name = action[2];
sg_size_t size = std::stoul(action[3]);
double clock = sg4::Engine::get_clock();
sg4::File* file = get_file_descriptor(file_name);
ACT_DEBUG("Entering Read: %s (size: %llu)", NAME.c_str(), size);
file->read(size);
log_action(action, sg4::Engine::get_clock() - clock);
}
static void close(simgrid::xbt::ReplayAction& action)
{
std::string file_name = action[2];
std::string full_name = sg4::this_actor::get_name() + ":" + file_name;
double clock = sg4::Engine::get_clock();
ACT_DEBUG("Entering Close: %s (filename: %s)", NAME.c_str(), file_name.c_str());
auto entry = opened_files.find(full_name);
xbt_assert(entry != opened_files.end(), "File not found in opened files: %s", full_name.c_str());
entry->second->close();
opened_files.erase(entry);
log_action(action, sg4::Engine::get_clock() - clock);
}
};
std::unordered_map<std::string, sg4::File*> Replayer::opened_files;
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
sg_storage_file_system_init();
xbt_assert(argc > 3,
"Usage: %s platform_file deployment_file [action_files]\n"
"\texample: %s platform.xml deployment.xml actions # if all actions are in the same file\n"
"\t# if actions are in separate files, specified in deployment\n"
"\texample: %s platform.xml deployment.xml",
argv[0], argv[0], argv[0]);
e.load_platform(argv[1]);
e.register_actor<Replayer>("p0");
e.load_deployment(argv[2]);
if (argv[3] != nullptr)
xbt_replay_set_tracefile(argv[3]);
/* Action registration */
xbt_replay_action_register("open", Replayer::open);
xbt_replay_action_register("read", Replayer::read);
xbt_replay_action_register("close", Replayer::close);
e.run();
XBT_INFO("Simulation time %g", sg4::Engine::get_clock());
return 0;
}
Activities: what Actors do
Communications on the Network
Basic communications
This simple example just sends one message back and forth. The tesh file laying in the directory shows how to start the simulator binary, highlighting how to pass options to the simulators (as detailed in Section Configuring SimGrid).
View examples/cpp/comm-pingpong/s4u-comm-pingpong.cpp
Download s4u-comm-pingpong.cpp
/* Copyright (c) 2007-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. */
#include <simgrid/s4u.hpp>
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_app_pingpong, "Messages specific for this s4u example");
static void pinger(sg4::Mailbox* mailbox_in, sg4::Mailbox* mailbox_out)
{
XBT_INFO("Ping from mailbox %s to mailbox %s", mailbox_in->get_name().c_str(), mailbox_out->get_name().c_str());
/* - Do the ping with a 1-Byte payload (latency bound) ... */
auto* payload = new double(sg4::Engine::get_clock());
mailbox_out->put(payload, 1);
/* - ... then wait for the (large) pong */
auto sender_time = mailbox_in->get_unique<double>();
double communication_time = sg4::Engine::get_clock() - *sender_time;
XBT_INFO("Payload received : large communication (bandwidth bound)");
XBT_INFO("Pong time (bandwidth bound): %.3f", communication_time);
}
static void ponger(sg4::Mailbox* mailbox_in, sg4::Mailbox* mailbox_out)
{
XBT_INFO("Pong from mailbox %s to mailbox %s", mailbox_in->get_name().c_str(), mailbox_out->get_name().c_str());
/* - Receive the (small) ping first ....*/
auto sender_time = mailbox_in->get_unique<double>();
double communication_time = sg4::Engine::get_clock() - *sender_time;
XBT_INFO("Payload received : small communication (latency bound)");
XBT_INFO("Ping time (latency bound) %f", communication_time);
/* - ... Then send a 1GB pong back (bandwidth bound) */
auto* payload = new double(sg4::Engine::get_clock());
XBT_INFO("payload = %.3f", *payload);
mailbox_out->put(payload, 1e9);
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
e.load_platform(argv[1]);
sg4::Mailbox* mb1 = e.mailbox_by_name_or_create("Mailbox 1");
sg4::Mailbox* mb2 = e.mailbox_by_name_or_create("Mailbox 2");
sg4::Actor::create("pinger", e.host_by_name("Tremblay"), pinger, mb1, mb2);
sg4::Actor::create("ponger", e.host_by_name("Jupiter"), ponger, mb2, mb1);
e.run();
XBT_INFO("Total simulation time: %.3f", sg4::Engine::get_clock());
return 0;
}
View examples/python/comm-pingpong/comm-pingpong.py
# Copyright (c) 2010-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, Actor, Mailbox, this_actor
def create_parser() -> ArgumentParser:
parser = ArgumentParser()
parser.add_argument(
'--platform',
type=str,
required=True,
help='path to the platform description'
)
return parser
def pinger(mailbox_in: Mailbox, mailbox_out: Mailbox):
this_actor.info(f"Ping from mailbox {mailbox_in.name} to mailbox {mailbox_out.name}")
# Do the ping with a 1-Byte payload (latency bound) ...
payload = Engine.clock
mailbox_out.put(payload, 1)
# ... then wait for the (large) pong
sender_time: float = mailbox_in.get()
communication_time = Engine.clock - sender_time
this_actor.info("Payload received : large communication (bandwidth bound)")
this_actor.info(f"Pong time (bandwidth bound): {communication_time:.3f}")
def ponger(mailbox_in: Mailbox, mailbox_out: Mailbox):
this_actor.info(f"Pong from mailbox {mailbox_in.name} to mailbox {mailbox_out.name}")
# Receive the (small) ping first ...
sender_time: float = mailbox_in.get()
communication_time = Engine.clock - sender_time
this_actor.info("Payload received : small communication (latency bound)")
this_actor.info(f"Ping time (latency bound) {communication_time:.3f}")
# ... Then send a 1GB pong back (bandwidth bound)
payload = Engine.clock
this_actor.info(f"payload = {payload:.3f}")
mailbox_out.put(payload, int(1e9))
def main():
settings = create_parser().parse_known_args()[0]
e = Engine(sys.argv)
e.load_platform(settings.platform)
mb1: Mailbox = e.mailbox_by_name_or_create("Mailbox 1")
mb2: Mailbox = e.mailbox_by_name_or_create("Mailbox 2")
Actor.create("pinger", e.host_by_name("Tremblay"), pinger, mb1, mb2)
Actor.create("ponger", e.host_by_name("Jupiter"), ponger, mb2, mb1)
e.run()
this_actor.info(f"Total simulation time: {e.clock:.3f}")
if __name__ == "__main__":
main()
View examples/c/comm-pingpong/comm-pingpong.c
/* Copyright (c) 2007-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. */
#include "simgrid/actor.h"
#include "simgrid/comm.h"
#include "simgrid/engine.h"
#include "simgrid/forward.h"
#include "simgrid/mailbox.h"
#include "xbt/log.h"
#include "xbt/str.h"
#include "xbt/sysdep.h"
#include <stdio.h> /* snprintf */
XBT_LOG_NEW_DEFAULT_CATEGORY(app_pingpong, "Messages specific for this example");
static void pinger(int argc, char* argv[])
{
sg_mailbox_t mailbox_in = sg_mailbox_by_name("Mailbox 1");
sg_mailbox_t mailbox_out = sg_mailbox_by_name("Mailbox 2");
XBT_INFO("Ping from mailbox %s to mailbox %s", sg_mailbox_get_name(mailbox_in), sg_mailbox_get_name(mailbox_out));
/* - Do the ping with a 1-Byte task (latency bound) ... */
double* now = (double*)xbt_malloc(sizeof(double));
*now = simgrid_get_clock();
sg_mailbox_put(mailbox_out, now, 1);
/* - ... then wait for the (large) pong */
double* sender_time = (double*)sg_mailbox_get(mailbox_in);
double communication_time = simgrid_get_clock() - *sender_time;
XBT_INFO("Task received : large communication (bandwidth bound)");
XBT_INFO("Pong time (bandwidth bound): %.3f", communication_time);
xbt_free(sender_time);
}
static void ponger(int argc, char* argv[])
{
sg_mailbox_t mailbox_in = sg_mailbox_by_name("Mailbox 2");
sg_mailbox_t mailbox_out = sg_mailbox_by_name("Mailbox 1");
XBT_INFO("Pong from mailbox %s to mailbox %s", sg_mailbox_get_name(mailbox_in), sg_mailbox_get_name(mailbox_out));
/* - Receive the (small) ping first ....*/
double* sender_time = (double*)sg_mailbox_get(mailbox_in);
double communication_time = simgrid_get_clock() - *sender_time;
XBT_INFO("Task received : small communication (latency bound)");
XBT_INFO(" Ping time (latency bound) %f", communication_time);
xbt_free(sender_time);
/* - ... Then send a 1GB pong back (bandwidth bound) */
double* payload = (double*)xbt_malloc(sizeof(double));
*payload = simgrid_get_clock();
XBT_INFO("task_bw->data = %.3f", *payload);
sg_mailbox_put(mailbox_out, payload, 1e9);
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
xbt_assert(argc > 2,
"Usage: %s platform_file deployment_file\n"
"\tExample: %s ../../platforms/small_platform.xml app-pingpong_d.xml\n",
argv[0], argv[0]);
simgrid_load_platform(argv[1]);
simgrid_register_function("pinger", pinger);
simgrid_register_function("ponger", ponger);
simgrid_load_deployment(argv[2]);
simgrid_run();
XBT_INFO("Total simulation time: %.3f", simgrid_get_clock());
return 0;
}
Basic asynchronous communications
Illustrates how to have non-blocking communications, that are communications running in the background leaving the process free to do something else during their completion.
See also simgrid::s4u::Mailbox::put_async()
and simgrid::s4u::Comm::wait()
.
View examples/cpp/comm-wait/s4u-comm-wait.cpp
/* Copyright (c) 2010-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. */
/* This example shows how to use simgrid::s4u::this_actor::wait() to wait for a given communication.
*
* As for the other asynchronous examples, the sender initiate all the messages it wants to send and
* pack the resulting simgrid::s4u::CommPtr objects in a vector. All messages thus occurs concurrently.
*
* The sender then loops until there is no ongoing communication.
*/
#include "simgrid/s4u.hpp"
#include <cstdlib>
#include <iostream>
#include <string>
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_comm_wait, "Messages specific for this s4u example");
static void sender(int messages_count, size_t payload_size)
{
double sleep_start_time = 5.0;
double sleep_test_time = 0;
sg4::Mailbox* mbox = sg4::Mailbox::by_name("receiver");
XBT_INFO("sleep_start_time : %f , sleep_test_time : %f", sleep_start_time, sleep_test_time);
sg4::this_actor::sleep_for(sleep_start_time);
for (int i = 0; i < messages_count; i++) {
std::string msg_content = "Message " + std::to_string(i);
// Copy the data we send: the 'msg_content' variable is not a stable storage location.
// It will be destroyed when this actor leaves the loop, ie before the receiver gets the data
auto* payload = new std::string(msg_content);
/* Create a communication representing the ongoing communication and then */
sg4::CommPtr comm = mbox->put_async(payload, payload_size);
XBT_INFO("Send '%s' to '%s'", msg_content.c_str(), mbox->get_cname());
if (sleep_test_time > 0) { /* - "test_time" is set to 0, wait */
while (not comm->test()) { /* - Call test() every "sleep_test_time" otherwise */
sg4::this_actor::sleep_for(sleep_test_time);
}
} else {
comm->wait();
}
}
/* Send message to let the receiver know that it should stop */
XBT_INFO("Send 'finalize' to 'receiver'");
mbox->put(new std::string("finalize"), 0);
}
/* Receiver actor expects 1 argument: its ID */
static void receiver()
{
double sleep_start_time = 1.0;
double sleep_test_time = 0.1;
sg4::Mailbox* mbox = sg4::Mailbox::by_name("receiver");
XBT_INFO("sleep_start_time : %f , sleep_test_time : %f", sleep_start_time, sleep_test_time);
sg4::this_actor::sleep_for(sleep_start_time);
XBT_INFO("Wait for my first message");
for (bool cont = true; cont;) {
std::string* received;
sg4::CommPtr comm = mbox->get_async<std::string>(&received);
if (sleep_test_time > 0) { /* - "test_time" is set to 0, wait */
while (not comm->test()) { /* - Call test() every "sleep_test_time" otherwise */
sg4::this_actor::sleep_for(sleep_test_time);
}
} else {
comm->wait();
}
XBT_INFO("I got a '%s'.", received->c_str());
if (*received == "finalize")
cont = false; // If it's a finalize message, we're done.
delete received;
}
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
e.load_platform(argv[1]);
sg4::Actor::create("sender", e.host_by_name("Tremblay"), sender, 3, 482117300);
sg4::Actor::create("receiver", e.host_by_name("Ruby"), receiver);
e.run();
return 0;
}
See also simgrid.Mailbox.put_async()
and simgrid.Comm.wait()
.
View examples/python/comm-wait/comm-wait.py
# Copyright (c) 2010-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.
"""
This example shows how to use simgrid::s4u::this_actor::wait() to wait for a given communication.
As for the other asynchronous examples, the sender initiate all the messages it wants to send and
pack the resulting simgrid::s4u::CommPtr objects in a vector. All messages thus occurs concurrently.
The sender then loops until there is no ongoing communication.
"""
import sys
from simgrid import Actor, Engine, Host, Mailbox, this_actor
def sender(messages_count, msg_size, receivers_count):
# List in which we store all ongoing communications
pending_comms = []
# Vector of the used mailboxes
mboxes = [Mailbox.by_name("receiver-{:d}".format(i)) for i in range(0, receivers_count)]
# Start dispatching all messages to receivers, in a round robin fashion
for i in range(0, messages_count):
content = "Message {:d}".format(i)
mbox = mboxes[i % receivers_count]
this_actor.info("Send '{:s}' to '{:s}'".format(content, str(mbox)))
# Create a communication representing the ongoing communication, and store it in pending_comms
comm = mbox.put_async(content, msg_size)
pending_comms.append(comm)
# Start sending messages to let the workers know that they should stop
for i in range(0, receivers_count):
mbox = mboxes[i]
this_actor.info("Send 'finalize' to '{:s}'".format(str(mbox)))
comm = mbox.put_async("finalize", 0)
pending_comms.append(comm)
this_actor.info("Done dispatching all messages")
# Now that all message exchanges were initiated, wait for their completion, in order of creation.
for comm in pending_comms:
comm.wait()
this_actor.info("Goodbye now!")
def receiver(my_id):
mbox = Mailbox.by_name("receiver-{:d}".format(my_id))
this_actor.info("Wait for my first message")
while True:
received = mbox.get()
this_actor.info("I got a '{:s}'.".format(received))
if received == "finalize":
break # If it's a finalize message, we're done.
if __name__ == '__main__':
e = Engine(sys.argv)
e.load_platform(sys.argv[1]) # Load the platform description
Actor.create("sender", Host.by_name("Tremblay"), sender, 3, 50000000, 1)
Actor.create("receiver", Host.by_name("Ruby"), receiver, 0)
e.run()
See also sg_mailbox_put_async()
and sg_comm_wait()
.
View examples/c/comm-wait/comm-wait.c
/* Copyright (c) 2010-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. */
#include "simgrid/actor.h"
#include "simgrid/comm.h"
#include "simgrid/engine.h"
#include "simgrid/mailbox.h"
#include "xbt/log.h"
#include "xbt/str.h"
#include "xbt/sysdep.h"
#include <stdio.h>
XBT_LOG_NEW_DEFAULT_CATEGORY(comm_wait, "Messages specific for this example");
/* Main function of the Sender actor */
static void sender(int argc, char* argv[])
{
xbt_assert(argc == 5, "The sender function expects 4 arguments from the XML deployment file");
long messages_count = xbt_str_parse_int(argv[1], "Invalid amount of messages"); /* - number of messages */
long message_size = xbt_str_parse_int(argv[2], "Invalid message size"); /* - communication cost */
double sleep_start_time = xbt_str_parse_double(argv[3], "Invalid sleep start time"); /* - start time */
double sleep_test_time = xbt_str_parse_double(argv[4], "Invalid test time"); /* - test time */
XBT_INFO("sleep_start_time : %f , sleep_test_time : %f", sleep_start_time, sleep_test_time);
sg_mailbox_t mailbox = sg_mailbox_by_name("receiver");
sg_actor_sleep_for(sleep_start_time);
for (int i = 0; i < messages_count; i++) {
char* payload = bprintf("Message %d", i);
/* This actor first sends a message asynchronously with @ref sg_mailbox_put_async. Then, if: */
sg_comm_t comm = sg_mailbox_put_async(mailbox, payload, message_size);
XBT_INFO("Send '%s' to 'receiver'", payload);
if (sleep_test_time > 0) { /* - "test_time" is set to 0, wait on @ref sg_comm_wait */
while (sg_comm_test(comm) == 0) { /* - Call @ref sg_comm_test every "sleep_test_time" otherwise */
sg_actor_sleep_for(sleep_test_time);
}
} else {
sg_comm_wait(comm);
}
}
XBT_INFO("Send 'finalize' to 'receiver'");
sg_mailbox_put(mailbox, xbt_strdup("finalize"), 0);
}
/* Receiver actor expects 3 arguments: */
static void receiver(int argc, char* argv[])
{
xbt_assert(argc == 3, "The relay_runner function does not accept any parameter from the XML deployment file");
double sleep_start_time = xbt_str_parse_double(argv[1], "Invalid sleep start parameter"); /* - start time */
double sleep_test_time = xbt_str_parse_double(argv[2], "Invalid sleep test parameter"); /* - test time */
XBT_INFO("sleep_start_time : %f , sleep_test_time : %f", sleep_start_time, sleep_test_time);
sg_actor_sleep_for(sleep_start_time); /* This actor first sleeps for "start time" seconds. */
sg_mailbox_t mailbox = sg_mailbox_by_name("receiver");
void* received = NULL;
XBT_INFO("Wait for my first message");
while (1) {
/* Then it posts asynchronous receives (@ref sg_mailbox_get_async) and*/
sg_comm_t comm = sg_mailbox_get_async(mailbox, &received);
if (sleep_test_time > 0) { /* - if "test_time" is set to 0, wait on @ref sg_comm_wait */
while (sg_comm_test(comm) == 0) { /* - Call @ref sg_comm_test every "sleep_test_time" otherwise */
sg_actor_sleep_for(sleep_test_time);
}
} else {
sg_comm_wait(comm);
}
XBT_INFO("I got a '%s'.", (char*)received);
if (strcmp((char*)received, "finalize") == 0) { /* If the received task is "finalize", the actor ends */
free(received);
break;
}
free(received);
}
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
xbt_assert(argc > 2,
"Usage: %s platform_file deployment_file\n"
"\tExample: %s platform.xml deployment.xml\n",
argv[0], argv[0]);
simgrid_load_platform(argv[1]); /* - Load the platform description */
simgrid_register_function("sender", sender);
simgrid_register_function("receiver", receiver);
simgrid_load_deployment(argv[2]); /* - Deploy the sender and receiver actors */
simgrid_run(); /* - Run the simulation */
return 0;
}
Waiting for communications with timeouts
There is two ways of declaring timeouts in SimGrid. waituntil
let you specify the deadline until when you want to wait, while
waitfor
expects the maximal wait duration.
This example is very similar to the previous one, simply adding how to declare timeouts when waiting on asynchronous communication.
See also simgrid::s4u::Activity::wait_until()
and simgrid::s4u::Comm::wait_for()
.
View examples/cpp/comm-waituntil/s4u-comm-waituntil.cpp
Download s4u-comm-waituntil.cpp
/* Copyright (c) 2010-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. */
/* This example shows how to use simgrid::s4u::Activity::wait_until() and
* simgrid::s4u::Activity::wait_for() on a given communication.
*
* It is very similar to the comm-wait example, but the sender initially
* does some waits that are too short before doing an infinite wait.
*/
#include "simgrid/s4u.hpp"
#include <cstdlib>
#include <iostream>
#include <string>
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_comm_waituntil, "Messages specific for this s4u example");
static void sender(int messages_count, size_t payload_size)
{
std::vector<sg4::CommPtr> pending_comms;
sg4::Mailbox* mbox = sg4::Mailbox::by_name("receiver-0");
/* Start dispatching all messages to the receiver */
for (int i = 0; i < messages_count; i++) {
std::string message = "Message " + std::to_string(i);
auto* payload = new std::string(message); // copy the data we send:
// 'msgName' is not a stable storage location
XBT_INFO("Send '%s' to '%s'", message.c_str(), mbox->get_cname());
/* Create a communication representing the ongoing communication */
sg4::CommPtr comm = mbox->put_async(payload, payload_size);
/* Add this comm to the vector of all known comms */
pending_comms.push_back(comm);
}
/* Start the finalize signal to the receiver*/
auto* payload = new std::string("finalize"); // Make a copy of the data we will send
sg4::CommPtr final_comm = mbox->put_async(payload, 0);
pending_comms.push_back(final_comm);
XBT_INFO("Send 'finalize' to 'receiver-0'");
XBT_INFO("Done dispatching all messages");
/* Now that all message exchanges were initiated, wait for their completion, in order of creation. */
while (not pending_comms.empty()) {
sg4::CommPtr comm = pending_comms.back();
comm->wait_for(1);
pending_comms.pop_back(); // remove it from the list
}
XBT_INFO("Goodbye now!");
}
static void receiver()
{
sg4::Mailbox* mbox = sg4::Mailbox::by_name("receiver-0");
XBT_INFO("Wait for my first message");
for (bool cont = true; cont;) {
auto received = mbox->get_unique<std::string>();
XBT_INFO("I got a '%s'.", received->c_str());
if (*received == "finalize")
cont = false; // If it's a finalize message, we're done.
}
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
e.load_platform(argv[1]);
sg4::Actor::create("sender", e.host_by_name("Tremblay"), sender, 3, 5e7);
sg4::Actor::create("receiver", e.host_by_name("Ruby"), receiver);
e.run();
return 0;
}
See also simgrid.Comm.wait_until()
View examples/python/comm-waituntil/comm-waituntil.py
# Copyright (c) 2010-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.
""" This example demonstrates Comm.wait_for() and Comm.wait_until to set timeouts on waits.
"""
from argparse import ArgumentParser
from typing import List
import sys
from simgrid import Actor, Comm, Engine, Mailbox, this_actor
FINALIZE_MESSAGE = "finalize"
def create_parser() -> ArgumentParser:
parser = ArgumentParser()
parser.add_argument(
'--platform',
type=str,
required=True,
help='path to the platform description'
)
return parser
def sender(receiver_mailbox: Mailbox, messages_count: int, payload_size: int):
pending_comms: List[Comm] = []
# Start dispatching all messages to the receiver
for i in range(messages_count):
payload = f"Message {i}"
this_actor.info(f"Send '{payload}' to '{receiver_mailbox.name}'")
# Create a communication representing the ongoing communication
comm = receiver_mailbox.put_async(payload, payload_size)
# Add this comm to the vector of all known comms
pending_comms.append(comm)
# Start the finalize signal to the receiver
final_comm = receiver_mailbox.put_async(FINALIZE_MESSAGE, 0)
pending_comms.append(final_comm)
this_actor.info(f"Send '{FINALIZE_MESSAGE}' to '{receiver_mailbox.name}'")
this_actor.info("Done dispatching all messages")
# Now that all message exchanges were initiated, wait for their completion, in order of creation
while pending_comms:
comm = pending_comms[-1]
comm.wait_until(Engine.clock + 1) # same as: current_comm.wait_for(1.0)
pending_comms.pop() # remove it from the list
this_actor.info("Goodbye now!")
def receiver(mailbox: Mailbox):
this_actor.info("Wait for my first message")
finalized = False
while not finalized:
received: str = mailbox.get()
this_actor.info(f"I got a '{received}'.")
# If it's a finalize message, we're done.
if received == FINALIZE_MESSAGE:
finalized = True
def main():
settings = create_parser().parse_known_args()[0]
e = Engine(sys.argv)
e.load_platform(settings.platform)
receiver_mailbox: Mailbox = Mailbox.by_name("receiver")
Actor.create("sender", e.host_by_name("Tremblay"), sender, receiver_mailbox, 3, int(5e7))
Actor.create("receiver", e.host_by_name("Ruby"), receiver, receiver_mailbox)
e.run()
if __name__ == "__main__":
main()
Checking for incoming communications
This example uses Mailbox.ready()
to check for completed communications. When this function returns true, then at least a message
is arrived, so you know that Mailbox.get()
will complete immediately. This is thus another way toward asynchronous communications.
See also simgrid::s4u::Mailbox::ready()
.
View examples/cpp/comm-ready/s4u-comm-ready.cpp
/* Copyright (c) 2010-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. */
/* This example shows how to use simgrid::s4u::Mailbox::ready() to check for completed communications.
*
* We have a number of peers which send and receive messages in two phases:
* -> sending phase: each one of them sends a number of messages to the others followed
* by a single "finalize" message.
* -> receiving phase: each one of them receives all the available messages that reached
* their corresponding mailbox until it has all the needed "finalize"
* messages to know that no more work needs to be done.
*
* To avoid doing a wait() over the ongoing communications, each peer makes use of the
* simgrid::s4u::Mailbox::ready() method. If it returns true then a following get() will fetch the
* message immediately, if not the peer will sleep for a fixed amount of time before checking again.
*
*/
#include "simgrid/s4u.hpp"
#include <cstdlib>
#include <iostream>
#include <string>
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_async_ready, "Messages specific for this s4u example");
static void peer(int my_id, int messages_count, size_t payload_size, int peers_count)
{
/* Set myself as the persistent receiver of my mailbox so that messages start flowing to me as soon as they are put
* into it */
sg4::Mailbox* my_mbox = sg4::Mailbox::by_name("peer-" + std::to_string(my_id));
my_mbox->set_receiver(sg4::Actor::self());
std::vector<sg4::CommPtr> pending_comms;
/* Start dispatching all messages to peers others that myself */
for (int i = 0; i < messages_count; i++) {
for (int peer_id = 0; peer_id < peers_count; peer_id++) {
if (peer_id != my_id) {
sg4::Mailbox* mbox = sg4::Mailbox::by_name("peer-" + std::to_string(peer_id));
std::string message = "Message " + std::to_string(i) + " from peer " + std::to_string(my_id);
auto* payload = new std::string(message); // copy the data we send:
// 'message' is not a stable storage location
XBT_INFO("Send '%s' to '%s'", message.c_str(), mbox->get_cname());
/* Create a communication representing the ongoing communication */
pending_comms.push_back(mbox->put_async(payload, payload_size));
}
}
}
/* Start sending messages to let peers know that they should stop */
for (int peer_id = 0; peer_id < peers_count; peer_id++) {
if (peer_id != my_id) {
sg4::Mailbox* mbox = sg4::Mailbox::by_name("peer-" + std::to_string(peer_id));
auto* payload = new std::string("finalize"); // Make a copy of the data we will send
pending_comms.push_back(mbox->put_async(payload, payload_size));
XBT_INFO("Send 'finalize' to 'peer-%d'", peer_id);
}
}
XBT_INFO("Done dispatching all messages");
/* Retrieve all the messages other peers have been sending to me until I receive all the corresponding "Finalize"
* messages */
long pending_finalize_messages = peers_count - 1;
while (pending_finalize_messages > 0) {
if (my_mbox->ready()) {
double start = sg4::Engine::get_clock();
auto received = my_mbox->get_unique<std::string>();
double waiting_time = sg4::Engine::get_clock() - start;
xbt_assert(
waiting_time == 0,
"Expecting the waiting time to be 0 because the communication was supposedly ready, but got %f instead",
waiting_time);
XBT_INFO("I got a '%s'.", received->c_str());
if (*received == "finalize") {
pending_finalize_messages--;
}
} else {
XBT_INFO("Nothing ready to consume yet, I better sleep for a while");
sg4::this_actor::sleep_for(.01);
}
}
XBT_INFO("I'm done, just waiting for my peers to receive the messages before exiting");
sg4::Comm::wait_all(pending_comms);
XBT_INFO("Goodbye now!");
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
e.load_platform(argv[1]);
sg4::Actor::create("peer", e.host_by_name("Tremblay"), peer, 0, 2, 5e7, 3);
sg4::Actor::create("peer", e.host_by_name("Ruby"), peer, 1, 6, 2.5e5, 3);
sg4::Actor::create("peer", e.host_by_name("Perl"), peer, 2, 0, 5e7, 3);
e.run();
return 0;
}
See also simgrid.Mailbox.ready()
View examples/python/comm-ready/comm-ready.py
# Copyright (c) 2010-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
from typing import List
import sys
from simgrid import Actor, Comm, Engine, Mailbox, this_actor
FINALIZE_MESSAGE = "finalize"
def create_parser() -> ArgumentParser:
parser = ArgumentParser()
parser.add_argument(
'--platform',
type=str,
required=True,
help='path to the platform description'
)
return parser
def get_peer_mailbox(peer_id: int) -> Mailbox:
return Mailbox.by_name(f"peer-{peer_id}")
def peer(my_id: int, message_count: int, payload_size: int, peers_count: int):
my_mailbox: Mailbox = get_peer_mailbox(my_id)
my_mailbox.set_receiver(Actor.self())
pending_comms: List[Comm] = []
# Start dispatching all messages to peers others that myself
for i in range(message_count):
for peer_id in range(peers_count):
if peer_id != my_id:
peer_mailbox = get_peer_mailbox(peer_id)
message = f"Message {i} from peer {my_id}"
this_actor.info(f"Send '{message}' to '{peer_mailbox.name}'")
pending_comms.append(peer_mailbox.put_async(message, payload_size))
# Start sending messages to let peers know that they should stop
for peer_id in range(peers_count):
if peer_id != my_id:
peer_mailbox = get_peer_mailbox(peer_id)
payload = str(FINALIZE_MESSAGE)
pending_comms.append(peer_mailbox.put_async(payload, payload_size))
this_actor.info(f"Send '{payload}' to '{peer_mailbox.name}'")
this_actor.info("Done dispatching all messages")
# Retrieve all the messages other peers have been sending to me until I receive all the corresponding "Finalize"
# messages
pending_finalize_messages = peers_count - 1
while pending_finalize_messages > 0:
if my_mailbox.ready:
start = Engine.clock
received: str = my_mailbox.get()
waiting_time = Engine.clock - start
if waiting_time != 0.0:
raise AssertionError(f"Expecting the waiting time to be 0.0 because the communication was supposedly "
f"ready, but got {waiting_time} instead")
this_actor.info(f"I got a '{received}'.")
if received == FINALIZE_MESSAGE:
pending_finalize_messages -= 1
else:
this_actor.info("Nothing ready to consume yet, I better sleep for a while")
this_actor.sleep_for(0.01)
this_actor.info("I'm done, just waiting for my peers to receive the messages before exiting")
Comm.wait_all(pending_comms)
this_actor.info("Goodbye now!")
def main():
settings = create_parser().parse_known_args()[0]
e = Engine(sys.argv)
e.load_platform(settings.platform)
Actor.create("peer", e.host_by_name("Tremblay"), peer, 0, 2, int(5e7), 3)
Actor.create("peer", e.host_by_name("Ruby"), peer, 1, 6, int(2.5e5), 3)
Actor.create("peer", e.host_by_name("Perl"), peer, 2, 0, int(5e7), 3)
e.run()
if __name__ == "__main__":
main()
Suspending communications
The suspend()
and resume()
functions block the progression of a given communication for a while and then unblock it.
is_suspended()
returns whether that activity is currently blocked or not.
See also simgrid::s4u::Activity::suspend()
simgrid::s4u::Activity::resume()
and
simgrid::s4u::Activity::is_suspended()
.
View examples/cpp/comm-suspend/s4u-comm-suspend.cpp
/* Copyright (c) 2010-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. */
/* This example shows how to suspend and resume an asynchronous communication. */
#include "simgrid/s4u.hpp"
#include <cstdlib>
#include <iostream>
#include <string>
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_comm_wait, "Messages specific for this s4u example");
static void sender()
{
sg4::Mailbox* mbox = sg4::Mailbox::by_name("receiver");
// Copy the data we send: the 'msg_content' variable is not a stable storage location.
// It will be destroyed when this actor leaves the loop, ie before the receiver gets the data
auto* payload = new std::string("Sent message");
/* Create a communication representing the ongoing communication and then */
sg4::CommPtr comm = mbox->put_init(payload, 13194230);
XBT_INFO("Suspend the communication before it starts (remaining: %.0f bytes) and wait a second.",
comm->get_remaining());
sg4::this_actor::sleep_for(1);
XBT_INFO("Now, start the communication (remaining: %.0f bytes) and wait another second.", comm->get_remaining());
comm->start();
sg4::this_actor::sleep_for(1);
XBT_INFO("There is still %.0f bytes to transfer in this communication. Suspend it for one second.",
comm->get_remaining());
comm->suspend();
XBT_INFO("Now there is %.0f bytes to transfer. Resume it and wait for its completion.", comm->get_remaining());
comm->resume();
comm->wait();
XBT_INFO("There is %f bytes to transfer after the communication completion.", comm->get_remaining());
XBT_INFO("Suspending a completed activity is a no-op.");
comm->suspend();
}
static void receiver()
{
sg4::Mailbox* mbox = sg4::Mailbox::by_name("receiver");
XBT_INFO("Wait for the message.");
auto received = mbox->get_unique<std::string>();
XBT_INFO("I got '%s'.", received->c_str());
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
e.load_platform(argv[1]);
sg4::Actor::create("sender", e.host_by_name("Tremblay"), sender);
sg4::Actor::create("receiver", e.host_by_name("Jupiter"), receiver);
e.run();
return 0;
}
See also simgrid.Comm.suspend()
and
simgrid.Comm.resume()
.
View examples/python/comm-suspend/comm-suspend.py
# Copyright (c) 2010-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.
""" This example shows how to suspend and resume an asynchronous communication.
"""
from argparse import ArgumentParser
import sys
from simgrid import Actor, Comm, Engine, Mailbox, this_actor
def create_parser() -> ArgumentParser:
parser = ArgumentParser()
parser.add_argument(
'--platform',
type=str,
required=True,
help='path to the platform description'
)
return parser
def sender():
mailbox: Mailbox = Mailbox.by_name("receiver")
payload = "Sent message"
# Create a communication representing the ongoing communication and then
simulated_size_in_bytes = 13194230
comm: Comm = mailbox.put_init(payload, simulated_size_in_bytes)
this_actor.info(f"Suspend the communication before it starts (remaining: {comm.remaining:.0f} bytes)"
f" and wait a second.")
this_actor.sleep_for(1)
this_actor.info(f"Now, start the communication (remaining: {comm.remaining:.0f} bytes) and wait another second.")
comm.start()
this_actor.sleep_for(1)
this_actor.info(f"There is still {comm.remaining:.0f} bytes to transfer in this communication."
" Suspend it for one second.")
comm.suspend()
this_actor.info(f"Now there is {comm.remaining:.0f} bytes to transfer. Resume it and wait for its completion.")
comm.resume()
comm.wait()
this_actor.info(f"There is {comm.remaining:.0f} bytes to transfer after the communication completion.")
this_actor.info("Suspending a completed activity is a no-op.")
comm.suspend()
def receiver():
mailbox: Mailbox = Mailbox.by_name("receiver")
this_actor.info("Wait for the message.")
received: str = mailbox.get()
this_actor.info(f"I got '{received}'.")
def main():
settings = create_parser().parse_known_args()[0]
e = Engine(sys.argv)
e.load_platform(settings.platform)
Actor.create("sender", e.host_by_name("Tremblay"), sender)
Actor.create("receiver", e.host_by_name("Jupiter"), receiver)
e.run()
if __name__ == "__main__":
main()
Waiting for all communications in a set
The wait_all()
function is useful when you want to block until all activities in a given set have been completed.
See also simgrid::s4u::Comm::wait_all()
.
View examples/cpp/comm-waitall/s4u-comm-waitall.cpp
/* Copyright (c) 2010-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. */
/* This example shows how to block on the completion of a set of communications.
*
* As for the other asynchronous examples, the sender initiate all the messages it wants to send and
* pack the resulting simgrid::s4u::CommPtr objects in a vector. All messages thus occur concurrently.
*
* The sender then blocks until all ongoing communication terminate, using simgrid::s4u::Comm::wait_all()
*
*/
#include "simgrid/s4u.hpp"
#include <cstdlib>
#include <iostream>
#include <string>
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_async_waitall, "Messages specific for this s4u example");
static void sender(unsigned int messages_count, unsigned int receivers_count, long msg_size)
{
if (messages_count == 0 || receivers_count == 0) {
XBT_WARN("Sender has nothing to do. Bail out!");
return;
}
// sphinx-doc: init-begin (this line helps the doc to build; ignore it)
/* Vector in which we store all ongoing communications */
std::vector<sg4::CommPtr> pending_comms;
/* Make a vector of the mailboxes to use */
std::vector<sg4::Mailbox*> mboxes;
for (unsigned int i = 0; i < receivers_count; i++)
mboxes.push_back(sg4::Mailbox::by_name("receiver-" + std::to_string(i)));
// sphinx-doc: init-end
/* Start dispatching all messages to receivers, in a round robin fashion */
for (unsigned int i = 0; i < messages_count; i++) {
std::string msg_content = "Message " + std::to_string(i);
// Copy the data we send: the 'msg_content' variable is not a stable storage location.
// It will be destroyed when this actor leaves the loop, ie before the receiver gets it
auto* payload = new std::string(msg_content);
XBT_INFO("Send '%s' to '%s'", msg_content.c_str(), mboxes[i % receivers_count]->get_cname());
/* Create a communication representing the ongoing communication, and store it in pending_comms */
sg4::CommPtr comm = mboxes[i % receivers_count]->put_async(payload, msg_size);
pending_comms.push_back(comm);
}
/* Start sending messages to let the workers know that they should stop */ // sphinx-doc: put-begin
for (unsigned int i = 0; i < receivers_count; i++) {
XBT_INFO("Send 'finalize' to 'receiver-%u'", i);
sg4::CommPtr comm = mboxes[i]->put_async(new std::string("finalize"), 0);
pending_comms.push_back(comm);
}
XBT_INFO("Done dispatching all messages");
/* Now that all message exchanges were initiated, wait for their completion in one single call */
sg4::Comm::wait_all(pending_comms);
// sphinx-doc: put-end
XBT_INFO("Goodbye now!");
}
/* Receiver actor expects 1 argument: its ID */
static void receiver(int id)
{
sg4::Mailbox* mbox = sg4::Mailbox::by_name("receiver-" + std::to_string(id));
XBT_INFO("Wait for my first message");
for (bool cont = true; cont;) {
auto received = mbox->get_unique<std::string>();
XBT_INFO("I got a '%s'.", received->c_str());
cont = (*received != "finalize"); // If it's a finalize message, we're done
// Receiving the message was all we were supposed to do
}
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
e.load_platform(argv[1]);
sg4::Actor::create("sender", e.host_by_name("Tremblay"), sender, 5, 2, 1e6);
sg4::Actor::create("receiver", e.host_by_name("Ruby"), receiver, 0);
sg4::Actor::create("receiver", e.host_by_name("Perl"), receiver, 1);
e.run();
return 0;
}
See also simgrid.Comm.wait_all()
.
View examples/python/comm-waitall/comm-waitall.py
# Copyright (c) 2010-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.
"""
This example shows how to block on the completion of a set of communications.
As for the other asynchronous examples, the sender initiate all the messages it wants to send and
pack the resulting simgrid.Comm objects in a list. All messages thus occur concurrently.
The sender then blocks until all ongoing communication terminate, using simgrid.Comm.wait_all()
"""
import sys
from simgrid import Actor, Comm, Engine, Host, Mailbox, this_actor
def sender(messages_count, msg_size, receivers_count):
# List in which we store all ongoing communications
pending_comms = []
# Vector of the used mailboxes
mboxes = [Mailbox.by_name("receiver-{:d}".format(i))
for i in range(0, receivers_count)]
# Start dispatching all messages to receivers, in a round robin fashion
for i in range(0, messages_count):
content = "Message {:d}".format(i)
mbox = mboxes[i % receivers_count]
this_actor.info("Send '{:s}' to '{:s}'".format(content, str(mbox)))
# Create a communication representing the ongoing communication, and store it in pending_comms
comm = mbox.put_async(content, msg_size)
pending_comms.append(comm)
# Start sending messages to let the workers know that they should stop
for i in range(0, receivers_count):
mbox = mboxes[i]
this_actor.info("Send 'finalize' to '{:s}'".format(str(mbox)))
comm = mbox.put_async("finalize", 0)
pending_comms.append(comm)
this_actor.info("Done dispatching all messages")
# Now that all message exchanges were initiated, wait for their completion in one single call
Comm.wait_all(pending_comms)
this_actor.info("Goodbye now!")
def receiver(my_id):
mbox = Mailbox.by_name("receiver-{:d}".format(my_id))
this_actor.info("Wait for my first message")
while True:
received = mbox.get()
this_actor.info("I got a '{:s}'.".format(received))
if received == "finalize":
break # If it's a finalize message, we're done.
if __name__ == '__main__':
e = Engine(sys.argv)
# Load the platform description
e.load_platform(sys.argv[1])
Actor.create("sender", Host.by_name("Tremblay"), sender, 5, 1000000, 2)
Actor.create("receiver", Host.by_name("Ruby"), receiver, 0)
Actor.create("receiver", Host.by_name("Perl"), receiver, 1)
e.run()
See also sg_comm_wait_all()
.
View examples/c/comm-waitall/comm-waitall.c
/* Copyright (c) 2010-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. */
#include "simgrid/actor.h"
#include "simgrid/comm.h"
#include "simgrid/engine.h"
#include "simgrid/host.h"
#include "simgrid/mailbox.h"
#include "xbt/log.h"
#include "xbt/str.h"
#include "xbt/sysdep.h"
#include <stdio.h> /* snprintf */
XBT_LOG_NEW_DEFAULT_CATEGORY(comm_waitall, "Messages specific for this example");
static void sender(int argc, char* argv[])
{
xbt_assert(argc == 4, "This function expects 3 parameters from the XML deployment file");
long messages_count = xbt_str_parse_int(argv[1], "Invalid message count");
long message_size = xbt_str_parse_int(argv[2], "Invalid message size");
long receivers_count = xbt_str_parse_int(argv[3], "Invalid amount of receivers");
xbt_assert(receivers_count > 0);
/* Array in which we store all ongoing communications */
sg_comm_t* pending_comms = xbt_malloc(sizeof(sg_comm_t) * (messages_count + receivers_count));
int pending_comms_count = 0;
/* Make an array of the mailboxes to use */
sg_mailbox_t* mboxes = xbt_malloc(sizeof(sg_mailbox_t) * receivers_count);
for (long i = 0; i < receivers_count; i++) {
char mailbox_name[80];
snprintf(mailbox_name, 79, "receiver-%ld", i);
sg_mailbox_t mbox = sg_mailbox_by_name(mailbox_name);
mboxes[i] = mbox;
}
/* Start dispatching all messages to receivers, in a round robin fashion */
for (long i = 0; i < messages_count; i++) {
char msg_content[80];
snprintf(msg_content, 79, "Message %ld", i);
sg_mailbox_t mbox = mboxes[i % receivers_count];
XBT_INFO("Send '%s' to '%s'", msg_content, sg_mailbox_get_name(mbox));
/* Create a communication representing the ongoing communication, and store it in pending_comms */
pending_comms[pending_comms_count++] = sg_mailbox_put_async(mbox, xbt_strdup(msg_content), message_size);
}
/* Start sending messages to let the workers know that they should stop */
for (long i = 0; i < receivers_count; i++) {
XBT_INFO("Send 'finalize' to 'receiver-%ld'", i);
char* end_msg = xbt_strdup("finalize");
sg_mailbox_t mbox = mboxes[i % receivers_count];
pending_comms[pending_comms_count++] = sg_mailbox_put_async(mbox, end_msg, 0);
}
XBT_INFO("Done dispatching all messages");
/* Now that all message exchanges were initiated, wait for their completion in one single call */
sg_comm_wait_all(pending_comms, pending_comms_count);
xbt_free(pending_comms);
xbt_free(mboxes);
XBT_INFO("Goodbye now!");
}
static void receiver(int argc, char* argv[])
{
xbt_assert(argc == 2, "Expecting one parameter from the XML deployment file but got %d", argc);
int id = (int)xbt_str_parse_int(argv[1], "ID should be numerical");
char mailbox_name[80];
snprintf(mailbox_name, 79, "receiver-%d", id);
sg_mailbox_t mbox = sg_mailbox_by_name(mailbox_name);
XBT_INFO("Wait for my first message");
while (1) {
char* received = (char*)sg_mailbox_get(mbox);
XBT_INFO("I got a '%s'.", received);
if (!strcmp(received, "finalize")) { // If it's a finalize message, we're done
xbt_free(received);
break;
}
xbt_free(received);
}
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
xbt_assert(argc > 2,
"Usage: %s platform_file deployment_file\n"
"\tExample: %s platform.xml deployment.xml\n",
argv[0], argv[0]);
simgrid_load_platform(argv[1]);
simgrid_register_function("sender", sender);
simgrid_register_function("receiver", receiver);
simgrid_load_deployment(argv[2]);
simgrid_run();
return 0;
}
Waiting for the first completed communication in a set
The wait_any()
blocks until one activity of the set completes, no matter which terminates first.
See also simgrid::s4u::Comm::wait_any()
.
View examples/cpp/comm-waitany/s4u-comm-waitany.cpp
/* Copyright (c) 2010-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. */
/* This example shows how to use simgrid::s4u::this_actor::wait_any() to wait for the first occurring event.
*
* As for the other asynchronous examples, the sender initiate all the messages it wants to send and
* pack the resulting simgrid::s4u::CommPtr objects in a vector. All messages thus occur concurrently.
*
* The sender then loops until there is no ongoing communication. Using wait_any() ensures that the sender
* will notice events as soon as they occur even if it does not follow the order of the container.
*
* Here, finalize messages will terminate earlier because their size is 0, so they travel faster than the
* other messages of this application. As expected, the trace shows that the finalize of worker 1 is
* processed before 'Message 5' that is sent to worker 0.
*
*/
#include "simgrid/s4u.hpp"
#include <cstdlib>
#include <iostream>
#include <string>
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_comm_waitall, "Messages specific for this s4u example");
static void sender(unsigned int messages_count, unsigned int receivers_count, long msg_size)
{
if (messages_count == 0 || receivers_count == 0) {
XBT_WARN("Sender has nothing to do. Bail out!");
return;
}
/* Vector in which we store all ongoing communications */
std::vector<sg4::CommPtr> pending_comms;
/* Make a vector of the mailboxes to use */
std::vector<sg4::Mailbox*> mboxes;
for (unsigned int i = 0; i < receivers_count; i++)
mboxes.push_back(sg4::Mailbox::by_name("receiver-" + std::to_string(i)));
/* Start dispatching all messages to receivers, in a round robin fashion */
for (unsigned int i = 0; i < messages_count; i++) {
std::string msg_content = "Message " + std::to_string(i);
// Copy the data we send: the 'msg_content' variable is not a stable storage location.
// It will be destroyed when this actor leaves the loop, ie before the receiver gets it
auto* payload = new std::string(msg_content);
XBT_INFO("Send '%s' to '%s'", msg_content.c_str(), mboxes[i % receivers_count]->get_cname());
/* Create a communication representing the ongoing communication, and store it in pending_comms */
sg4::CommPtr comm = mboxes[i % receivers_count]->put_async(payload, msg_size);
pending_comms.push_back(comm);
}
/* Start sending messages to let the workers know that they should stop */
for (unsigned int i = 0; i < receivers_count; i++) {
XBT_INFO("Send 'finalize' to 'receiver-%u'", i);
sg4::CommPtr comm = mboxes[i]->put_async(new std::string("finalize"), 0);
pending_comms.push_back(comm);
}
XBT_INFO("Done dispatching all messages");
/* Now that all message exchanges were initiated, wait for their completion, in order of termination.
*
* This loop waits for first terminating message with wait_any() and remove it with erase(), until all comms are
* terminated
* Even in this simple example, the pending comms do not terminate in the exact same order of creation.
*/
while (not pending_comms.empty()) {
ssize_t changed_pos = sg4::Comm::wait_any(pending_comms);
pending_comms.erase(pending_comms.begin() + changed_pos);
if (changed_pos != 0)
XBT_INFO("Remove the %zdth pending comm: it terminated earlier than another comm that was initiated first.",
changed_pos);
}
XBT_INFO("Goodbye now!");
}
/* Receiver actor expects 1 argument: its ID */
static void receiver(int id)
{
sg4::Mailbox* mbox = sg4::Mailbox::by_name("receiver-" + std::to_string(id));
XBT_INFO("Wait for my first message");
for (bool cont = true; cont;) {
auto received = mbox->get_unique<std::string>();
XBT_INFO("I got a '%s'.", received->c_str());
cont = (*received != "finalize"); // If it's a finalize message, we're done
// Receiving the message was all we were supposed to do
}
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
e.load_platform(argv[1]);
sg4::Actor::create("sender", e.host_by_name("Tremblay"), sender, 6, 2, 1e6);
sg4::Actor::create("receiver", e.host_by_name("Fafard"), receiver, 0);
sg4::Actor::create("receiver", e.host_by_name("Jupiter"), receiver, 1);
e.run();
return 0;
}
See also simgrid.Comm.wait_any()
.
View examples/python/comm-waitany/comm-waitany.py
# Copyright (c) 2010-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.
"""
This example shows how to block on the completion of a set of communications.
As for the other asynchronous examples, the sender initiate all the messages it wants to send and
pack the resulting simgrid.Comm objects in a list. All messages thus occur concurrently.
The sender then loops until there is no ongoing communication. Using wait_any() ensures that the sender
will notice events as soon as they occur even if it does not follow the order of the container.
Here, finalize messages will terminate earlier because their size is 0, so they travel faster than the
other messages of this application. As expected, the trace shows that the finalize of worker 1 is
processed before 'Message 5' that is sent to worker 0.
"""
import sys
from simgrid import Actor, Comm, Engine, Host, Mailbox, this_actor
def sender(messages_count, msg_size, receivers_count):
# List in which we store all ongoing communications
pending_comms = []
# Vector of the used mailboxes
mboxes = [Mailbox.by_name("receiver-{:d}".format(i))
for i in range(0, receivers_count)]
# Start dispatching all messages to receivers, in a round robin fashion
for i in range(0, messages_count):
content = "Message {:d}".format(i)
mbox = mboxes[i % receivers_count]
this_actor.info("Send '{:s}' to '{:s}'".format(content, str(mbox)))
# Create a communication representing the ongoing communication, and store it in pending_comms
comm = mbox.put_async(content, msg_size)
pending_comms.append(comm)
# Start sending messages to let the workers know that they should stop
for i in range(0, receivers_count):
mbox = mboxes[i]
this_actor.info("Send 'finalize' to '{:s}'".format(str(mbox)))
comm = mbox.put_async("finalize", 0)
pending_comms.append(comm)
this_actor.info("Done dispatching all messages")
# Now that all message exchanges were initiated, wait for their completion, in order of completion.
#
# This loop waits for first terminating message with wait_any() and remove it with del, until all comms are
# terminated.
# Even in this simple example, the pending comms do not terminate in the exact same order of creation.
while pending_comms:
changed_pos = Comm.wait_any(pending_comms)
del pending_comms[changed_pos]
if changed_pos != 0:
this_actor.info(
"Remove the {:d}th pending comm: it terminated earlier than another comm that was initiated first."
.format(changed_pos))
this_actor.info("Goodbye now!")
def receiver(my_id):
mbox = Mailbox.by_name("receiver-{:d}".format(my_id))
this_actor.info("Wait for my first message")
while True:
received = mbox.get()
this_actor.info("I got a '{:s}'.".format(received))
if received == "finalize":
break # If it's a finalize message, we're done.
if __name__ == '__main__':
e = Engine(sys.argv)
# Load the platform description
e.load_platform(sys.argv[1])
Actor.create("sender", Host.by_name("Tremblay"), sender, 6, 1000000, 2)
Actor.create("receiver", Host.by_name("Fafard"), receiver, 0)
Actor.create("receiver", Host.by_name("Jupiter"), receiver, 1)
e.run()
See also sg_comm_wait_any()
.
View examples/c/comm-waitany/comm-waitany.c
/* Copyright (c) 2010-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. */
#include "simgrid/actor.h"
#include "simgrid/comm.h"
#include "simgrid/engine.h"
#include "simgrid/forward.h"
#include "simgrid/mailbox.h"
#include "xbt/log.h"
#include "xbt/str.h"
#include "xbt/sysdep.h"
#include <stdio.h> /* snprintf */
XBT_LOG_NEW_DEFAULT_CATEGORY(comm_waitany, "Messages specific for this example");
static void sender(int argc, char* argv[])
{
xbt_assert(argc == 4, "Expecting 3 parameters from the XML deployment file but got %d", argc);
long messages_count = xbt_str_parse_int(argv[1], "Invalid message count");
long msg_size = xbt_str_parse_int(argv[2], "Invalid message size");
long receivers_count = xbt_str_parse_int(argv[3], "Invalid amount of receivers");
xbt_assert(receivers_count > 0);
/* Array in which we store all ongoing communications */
sg_comm_t* pending_comms = xbt_malloc(sizeof(sg_comm_t) * (messages_count + receivers_count));
int pending_comms_count = 0;
/* Make an array of the mailboxes to use */
sg_mailbox_t* mboxes = xbt_malloc(sizeof(sg_mailbox_t) * receivers_count);
for (long i = 0; i < receivers_count; i++) {
char mailbox_name[80];
snprintf(mailbox_name, 79, "receiver-%ld", i);
sg_mailbox_t mbox = sg_mailbox_by_name(mailbox_name);
mboxes[i] = mbox;
}
/* Start dispatching all messages to receivers, in a round robin fashion */
for (long i = 0; i < messages_count; i++) {
char msg_content[80];
snprintf(msg_content, 79, "Message %ld", i);
sg_mailbox_t mbox = mboxes[i % receivers_count];
XBT_INFO("Send '%s' to '%s'", msg_content, sg_mailbox_get_name(mbox));
/* Create a communication representing the ongoing communication, and store it in pending_comms */
pending_comms[pending_comms_count++] = sg_mailbox_put_async(mbox, xbt_strdup(msg_content), msg_size);
}
/* Start sending messages to let the workers know that they should stop */
for (long i = 0; i < receivers_count; i++) {
XBT_INFO("Send 'finalize' to 'receiver-%ld'", i);
char* end_msg = xbt_strdup("finalize");
sg_mailbox_t mbox = mboxes[i % receivers_count];
pending_comms[pending_comms_count++] = sg_mailbox_put_async(mbox, end_msg, 0);
}
XBT_INFO("Done dispatching all messages");
/* Now that all message exchanges were initiated, wait for their completion, in order of termination.
*
* This loop waits for first terminating message with wait_any() and remove it from the array (with a memmove),
* until all comms are terminated.
* Even in this simple example, the pending comms do not terminate in the exact same order of creation.
*/
while (pending_comms_count != 0) {
ssize_t changed_pos = sg_comm_wait_any(pending_comms, pending_comms_count);
memmove(pending_comms + changed_pos, pending_comms + changed_pos + 1,
sizeof(sg_comm_t) * (pending_comms_count - changed_pos - 1));
pending_comms_count--;
if (changed_pos != 0)
XBT_INFO("Remove the %zdth pending comm: it terminated earlier than another comm that was initiated first.",
changed_pos);
}
xbt_free(pending_comms);
xbt_free(mboxes);
XBT_INFO("Goodbye now!");
}
static void receiver(int argc, char* argv[])
{
xbt_assert(argc == 2, "Expecting one parameter from the XML deployment file but got %d", argc);
int id = (int)xbt_str_parse_int(argv[1], "ID should be numerical");
char mailbox_name[80];
snprintf(mailbox_name, 79, "receiver-%d", id);
sg_mailbox_t mbox = sg_mailbox_by_name(mailbox_name);
XBT_INFO("Wait for my first message on '%s'", mailbox_name);
while (1) {
char* received = (char*)sg_mailbox_get(mbox);
XBT_INFO("I got a '%s'.", received);
if (!strcmp(received, "finalize")) { // If it's a finalize message, we're done
xbt_free(received);
break;
}
xbt_free(received);
}
XBT_INFO("I'm done. See you!");
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
xbt_assert(argc > 2,
"Usage: %s platform_file deployment_file\n"
"\tExample: %s platform.xml deployment.xml\n",
argv[0], argv[0]);
simgrid_load_platform(argv[1]);
simgrid_register_function("sender", sender);
simgrid_register_function("receiver", receiver);
simgrid_load_deployment(argv[2]);
simgrid_run();
XBT_INFO("Simulation time %g", simgrid_get_clock());
return 0;
}
Testing whether at least one communication completed
The test_any()
returns whether at least one activity of the set has completed, or -1.
See also simgrid::s4u::Comm::test_any()
.
View examples/cpp/comm-testany/s4u-comm-testany.cpp
/* Copyright (c) 2010-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. */
#include "simgrid/s4u.hpp"
#include <cstdlib>
#include <iostream>
#include <string>
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_comm_testany, "Messages specific for this s4u example");
static void rank0()
{
sg4::Mailbox* mbox = sg4::Mailbox::by_name("rank0");
std::string* msg1;
std::string* msg2;
std::string* msg3;
XBT_INFO("Post my asynchronous receives");
auto comm1 = mbox->get_async(&msg1);
auto comm2 = mbox->get_async(&msg2);
auto comm3 = mbox->get_async(&msg3);
std::vector<sg4::CommPtr> pending_comms = {comm1, comm2, comm3};
XBT_INFO("Send some data to rank-1");
for (int i = 0; i < 3; i++)
sg4::Mailbox::by_name("rank1")->put(new int(i), 1);
XBT_INFO("Test for completed comms");
while (not pending_comms.empty()) {
ssize_t flag = sg4::Comm::test_any(pending_comms);
if (flag != -1) {
pending_comms.erase(pending_comms.begin() + flag);
XBT_INFO("Remove a pending comm.");
} else // nothing matches, wait for a little bit
sg4::this_actor::sleep_for(0.1);
}
XBT_INFO("Last comm is complete");
delete msg1;
delete msg2;
delete msg3;
}
static void rank1()
{
sg4::Mailbox* rank0_mbox = sg4::Mailbox::by_name("rank0");
sg4::Mailbox* rank1_mbox = sg4::Mailbox::by_name("rank1");
for (int i = 0; i < 3; i++) {
auto res = rank1_mbox->get_unique<int>();
XBT_INFO("Received %d", *res);
std::string msg_content = "Message " + std::to_string(i);
auto* payload = new std::string(msg_content);
XBT_INFO("Send '%s'", msg_content.c_str());
rank0_mbox->put(payload, 1e6);
}
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
e.load_platform(argv[1]);
sg4::Actor::create("rank-0", e.host_by_name("Tremblay"), rank0);
sg4::Actor::create("rank-1", e.host_by_name("Fafard"), rank1);
e.run();
return 0;
}
See also simgrid.Comm.test_any()
.
View examples/python/comm-testany/comm-testany.py
# Copyright (c) 2010-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
from typing import List
import sys
from simgrid import Engine, Actor, Comm, Mailbox, this_actor
def create_parser() -> ArgumentParser:
parser = ArgumentParser()
parser.add_argument(
'--platform',
type=str,
required=True,
help='path to the platform description'
)
return parser
def rank0():
rank0_mailbox: Mailbox = Mailbox.by_name("rank0")
this_actor.info("Post my asynchronous receives")
comm1, a1 = rank0_mailbox.get_async()
comm2, a2 = rank0_mailbox.get_async()
comm3, a3 = rank0_mailbox.get_async()
pending_comms: List[Comm] = [comm1, comm2, comm3]
this_actor.info("Send some data to rank-1")
rank1_mailbox: Mailbox = Mailbox.by_name("rank1")
for i in range(3):
rank1_mailbox.put(i, 1)
this_actor.info("Test for completed comms")
while pending_comms:
flag = Comm.test_any(pending_comms)
if flag != -1:
pending_comms.pop(flag)
this_actor.info("Remove a pending comm.")
else:
# Nothing matches, wait for a little bit
this_actor.sleep_for(0.1)
this_actor.info("Last comm is complete")
def rank1():
rank0_mailbox: Mailbox = Mailbox.by_name("rank0")
rank1_mailbox: Mailbox = Mailbox.by_name("rank1")
for i in range(3):
data: int = rank1_mailbox.get()
this_actor.info(f"Received {data}")
msg_content = f"Message {i}"
this_actor.info(f"Send '{msg_content}'")
rank0_mailbox.put(msg_content, int(1e6))
def main():
settings = create_parser().parse_known_args()[0]
e = Engine(sys.argv)
e.load_platform(settings.platform)
Actor.create("rank0", e.host_by_name("Tremblay"), rank0)
Actor.create("rank1", e.host_by_name("Fafard"), rank1)
e.run()
if __name__ == "__main__":
main()
Dealing with network failures
This examples shows how to survive to network exceptions that occurs when a link is turned off, or when the actor with whom
you communicate fails because its host is turned off. In this case, any blocking operation such as put
, get
or
wait
will raise an exception that you can catch and react to. See also Modeling churn (e.g., in P2P),
this example on how to attach a state profile to hosts and
that example on how to react to host failures.
View examples/cpp/comm-failure/s4u-comm-failure.cpp
/* Copyright (c) 2021-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. */
/* This example shows how to react to a failed communication, which occurs when a link is turned off,
* or when the actor with whom you communicate fails because its host is turned off.
*/
#include <simgrid/s4u.hpp>
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_comm_failure, "Messages specific for this s4u example");
namespace sg4 = simgrid::s4u;
class Sender {
std::string mailbox1_name;
std::string mailbox2_name;
public:
Sender(const std::string& mailbox1_name, const std::string& mailbox2_name)
: mailbox1_name(mailbox1_name), mailbox2_name(mailbox2_name)
{
}
void operator()() const
{
auto* mailbox1 = sg4::Mailbox::by_name(mailbox1_name);
auto* mailbox2 = sg4::Mailbox::by_name(mailbox2_name);
XBT_INFO("Initiating asynchronous send to %s", mailbox1->get_cname());
auto comm1 = mailbox1->put_async((void*)666, 5);
XBT_INFO("Initiating asynchronous send to %s", mailbox2->get_cname());
auto comm2 = mailbox2->put_async((void*)666, 2);
XBT_INFO("Calling wait_any..");
std::vector<sg4::CommPtr> pending_comms;
pending_comms.push_back(comm1);
pending_comms.push_back(comm2);
try {
long index = sg4::Comm::wait_any(pending_comms);
XBT_INFO("Wait any returned index %ld (comm to %s)", index, pending_comms.at(index)->get_mailbox()->get_cname());
} catch (const simgrid::NetworkFailureException&) {
XBT_INFO("Sender has experienced a network failure exception, so it knows that something went wrong");
XBT_INFO("Now it needs to figure out which of the two comms failed by looking at their state:");
XBT_INFO(" Comm to %s has state: %s", comm1->get_mailbox()->get_cname(), comm1->get_state_str());
XBT_INFO(" Comm to %s has state: %s", comm2->get_mailbox()->get_cname(), comm2->get_state_str());
}
try {
comm1->wait();
} catch (const simgrid::NetworkFailureException& e) {
XBT_INFO("Waiting on a FAILED comm raises an exception: '%s'", e.what());
}
XBT_INFO("Wait for remaining comm, just to be nice");
pending_comms.erase(pending_comms.begin());
sg4::Comm::wait_any(pending_comms);
}
};
class Receiver {
sg4::Mailbox* mailbox;
public:
explicit Receiver(const std::string& mailbox_name) : mailbox(sg4::Mailbox::by_name(mailbox_name)) {}
void operator()() const
{
XBT_INFO("Receiver posting a receive...");
try {
mailbox->get<void*>();
XBT_INFO("Receiver has received successfully!");
} catch (const simgrid::NetworkFailureException&) {
XBT_INFO("Receiver has experience a network failure exception");
}
}
};
int main(int argc, char** argv)
{
sg4::Engine engine(&argc, argv);
auto* zone = sg4::create_full_zone("AS0");
auto* host1 = zone->create_host("Host1", "1f");
auto* host2 = zone->create_host("Host2", "1f");
auto* host3 = zone->create_host("Host3", "1f");
sg4::LinkInRoute linkto2{zone->create_link("linkto2", "1bps")->seal()};
sg4::LinkInRoute linkto3{zone->create_link("linkto3", "1bps")->seal()};
zone->add_route(host1->get_netpoint(), host2->get_netpoint(), nullptr, nullptr, {linkto2}, false);
zone->add_route(host1->get_netpoint(), host3->get_netpoint(), nullptr, nullptr, {linkto3}, false);
zone->seal();
sg4::Actor::create("Sender", host1, Sender("mailbox2", "mailbox3"));
sg4::Actor::create("Receiver", host2, Receiver("mailbox2"));
sg4::Actor::create("Receiver", host3, Receiver("mailbox3"));
sg4::Actor::create("LinkKiller", host1, [](){
sg4::this_actor::sleep_for(10.0);
XBT_INFO("Turning off link 'linkto2'");
sg4::Link::by_name("linkto2")->turn_off();
});
engine.run();
return 0;
}
View examples/python/comm-failure/comm-failure.py
# Copyright (c) 2010-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.
import sys
from simgrid import Engine, Actor, Comm, NetZone, Link, LinkInRoute, Mailbox, this_actor, NetworkFailureException
def sender(mailbox1_name: str, mailbox2_name: str) -> None:
mailbox1: Mailbox = Mailbox.by_name(mailbox1_name)
mailbox2: Mailbox = Mailbox.by_name(mailbox2_name)
this_actor.info(f"Initiating asynchronous send to {mailbox1.name}")
comm1: Comm = mailbox1.put_async(666, 5)
this_actor.info(f"Initiating asynchronous send to {mailbox2.name}")
comm2: Comm = mailbox2.put_async(666, 2)
this_actor.info("Calling wait_any..")
pending_comms = [comm1, comm2]
try:
index = Comm.wait_any([comm1, comm2])
this_actor.info(f"Wait any returned index {index} (comm to {pending_comms[index].mailbox.name})")
except NetworkFailureException:
this_actor.info("Sender has experienced a network failure exception, so it knows that something went wrong")
this_actor.info("Now it needs to figure out which of the two comms failed by looking at their state:")
this_actor.info(f" Comm to {comm1.mailbox.name} has state: {comm1.state_str}")
this_actor.info(f" Comm to {comm2.mailbox.name} has state: {comm2.state_str}")
try:
comm1.wait()
except NetworkFailureException as err:
this_actor.info(f"Waiting on a FAILED comm raises an exception: '{err}'")
this_actor.info("Wait for remaining comm, just to be nice")
pending_comms.pop(0)
try:
Comm.wait_any(pending_comms)
except Exception as e:
this_actor.warning(str(e))
def receiver(mailbox_name: str) -> None:
mailbox: Mailbox = Mailbox.by_name(mailbox_name)
this_actor.info(f"Receiver posting a receive ({mailbox_name})...")
try:
mailbox.get()
this_actor.info(f"Receiver has received successfully ({mailbox_name})!")
except NetworkFailureException:
this_actor.info(f"Receiver has experience a network failure exception ({mailbox_name})")
def link_killer(link_name: str) -> None:
link_to_kill = Link.by_name(link_name)
this_actor.sleep_for(10.0)
this_actor.info(f"Turning off link '{link_to_kill.name}'")
link_to_kill.turn_off()
def main():
e = Engine(sys.argv)
zone: NetZone = NetZone.create_full_zone("AS0")
host1 = zone.create_host("Host1", "1f")
host2 = zone.create_host("Host2", "1f")
host3 = zone.create_host("Host3", "1f")
link_to_2 = LinkInRoute(zone.create_link("link_to_2", "1bps").seal())
link_to_3 = LinkInRoute(zone.create_link("link_to_3", "1bps").seal())
zone.add_route(host1.netpoint, host2.netpoint, None, None, [link_to_2], False)
zone.add_route(host1.netpoint, host3.netpoint, None, None, [link_to_3], False)
zone.seal()
Actor.create("Sender", host1, sender, "mailbox2", "mailbox3")
Actor.create("Receiver-1", host2, receiver, "mailbox2").daemonize()
Actor.create("Receiver-2", host3, receiver, "mailbox3").daemonize()
Actor.create("LinkKiller", host2, link_killer, "link_to_2").daemonize()
e.run()
if __name__ == "__main__":
main()
Direct host-to-host communication
This example demonstrates the direct communication mechanism, that allows to send data from one host to another without relying on the mailbox mechanism.
See also simgrid::s4u::Comm::sendto_init()
and simgrid::s4u::Comm::sendto_async()
.
View examples/cpp/comm-host2host/s4u-comm-host2host.cpp
Download s4u-comm-host2host.cpp
/* Copyright (c) 2007-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. */
/* This simple example demonstrates the Comm::sento_init() Comm::sento_async() functions,
that can be used to create a direct communication from one host to another without
relying on the mailbox mechanism.
There is not much to say, actually: The _init variant creates the communication and
leaves it unstarted (in case you want to modify this communication before it starts),
while the _async variant creates and start it. In both cases, you need to wait() it.
It is mostly useful when you want to have a centralized simulation of your settings,
with a central actor declaring all communications occurring on your distributed system.
*/
#include <simgrid/s4u.hpp>
namespace sg4 = simgrid::s4u;
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_comm_host2host, "Messages specific for this s4u example");
static void sender(sg4::Host* h1, sg4::Host* h2, sg4::Host* h3, sg4::Host* h4)
{
XBT_INFO("Send c12 with sendto_async(%s -> %s), and c34 with sendto_init(%s -> %s)", h1->get_cname(), h2->get_cname(),
h3->get_cname(), h4->get_cname());
auto c12 = sg4::Comm::sendto_async(h1, h2, 1.5e7); // Creates and start a direct communication
auto c34 = sg4::Comm::sendto_init(h3, h4); // Creates but do not start another direct communication
c34->set_payload_size(1e7); // Specify the amount of bytes to exchange in this comm
// You can also detach() communications that you never plan to test() or wait().
// Here we create a communication that only slows down the other ones
auto noise = sg4::Comm::sendto_init(h1, h2);
noise->set_payload_size(10000);
noise->detach();
XBT_INFO("After creation, c12 is %s (remaining: %.2e bytes); c34 is %s (remaining: %.2e bytes)",
c12->get_state_str(), c12->get_remaining(), c34->get_state_str(), c34->get_remaining());
sg4::this_actor::sleep_for(1);
XBT_INFO("One sec later, c12 is %s (remaining: %.2e bytes); c34 is %s (remaining: %.2e bytes)",
c12->get_state_str(), c12->get_remaining(), c34->get_state_str(), c34->get_remaining());
c34->start();
XBT_INFO("After c34->start,c12 is %s (remaining: %.2e bytes); c34 is %s (remaining: %.2e bytes)",
c12->get_state_str(), c12->get_remaining(), c34->get_state_str(), c34->get_remaining());
c12->wait();
XBT_INFO("After c12->wait, c12 is %s (remaining: %.2e bytes); c34 is %s (remaining: %.2e bytes)",
c12->get_state_str(), c12->get_remaining(), c34->get_state_str(), c34->get_remaining());
c34->wait();
XBT_INFO("After c34->wait, c12 is %s (remaining: %.2e bytes); c34 is %s (remaining: %.2e bytes)",
c12->get_state_str(), c12->get_remaining(), c34->get_state_str(), c34->get_remaining());
/* As usual, you don't have to explicitly start communications that were just init()ed.
The wait() will start it automatically. */
auto c14 = sg4::Comm::sendto_init(h1, h4);
c14->set_payload_size(100)->wait(); // Chaining 2 operations on this new communication
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
e.load_platform(argv[1]);
sg4::Actor::create("sender", e.host_by_name("Boivin"), sender, e.host_by_name("Tremblay"), e.host_by_name("Jupiter"),
e.host_by_name("Fafard"), e.host_by_name("Ginette"));
e.run();
XBT_INFO("Total simulation time: %.3f", sg4::Engine::get_clock());
return 0;
}
See also simgrid.Comm.sendto_init()
and simgrid.Comm.sendto_async()
.
View examples/python/comm-host2host/comm-host2host.py
# Copyright (c) 2010-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.
"""
This simple example demonstrates the Comm.sento_init() Comm.sento_async() functions,
that can be used to create a direct communication from one host to another without
relying on the mailbox mechanism.
There is not much to say, actually: The _init variant creates the communication and
leaves it unstarted (in case you want to modify this communication before it starts),
while the _async variant creates and start it. In both cases, you need to wait() it.
It is mostly useful when you want to have a centralized simulation of your settings,
with a central actor declaring all communications occurring on your distributed system.
"""
from argparse import ArgumentParser
import sys
from simgrid import Actor, Comm, Engine, Host, this_actor
def create_parser() -> ArgumentParser:
parser = ArgumentParser()
parser.add_argument(
'--platform',
type=str,
required=True,
help='path to the platform description'
)
return parser
def sender(h1: Host, h2: Host, h3: Host, h4: Host):
this_actor.info(f"Send c12 with sendto_async({h1.name} -> {h2.name}),"
f" and c34 with sendto_init({h3.name} -> {h4.name})")
c12: Comm = Comm.sendto_async(h1, h2, int(1.5e7))
c34: Comm = Comm.sendto_init(h3, h4)
c34.set_payload_size(int(1e7))
# You can also detach() communications that you never plan to test() or wait().
# Here we create a communication that only slows down the other ones
noise: Comm = Comm.sendto_init(h1, h2)
noise.set_payload_size(10000)
noise.detach()
this_actor.info(f"After creation, c12 is {c12.state_str} (remaining: {c12.remaining:.2e} bytes);"
f" c34 is {c34.state_str} (remaining: {c34.remaining:.2e} bytes)")
this_actor.sleep_for(1)
this_actor.info(f"One sec later, c12 is {c12.state_str} (remaining: {c12.remaining:.2e} bytes);"
f" c34 is {c34.state_str} (remaining: {c34.remaining:.2e} bytes)")
c34.start()
this_actor.info(f"After c34.start(), c12 is {c12.state_str} (remaining: {c12.remaining:.2e} bytes);"
f" c34 is {c34.state_str} (remaining: {c34.remaining:.2e} bytes)")
c12.wait()
this_actor.info(f"After c12.wait(), c12 is {c12.state_str} (remaining: {c12.remaining:.2e} bytes);"
f" c34 is {c34.state_str} (remaining: {c34.remaining:.2e} bytes)")
c34.wait()
this_actor.info(f"After c34.wait(), c12 is {c12.state_str} (remaining: {c12.remaining:.2e} bytes);"
f" c34 is {c34.state_str} (remaining: {c34.remaining:.2e} bytes)")
# As usual, you don't have to explicitly start communications that were just init()ed.
# The wait() will start it automatically.
c14: Comm = Comm.sendto_init(h1, h4)
c14.set_payload_size(100).wait()
def main():
settings = create_parser().parse_known_args()[0]
e = Engine(sys.argv)
e.load_platform(settings.platform)
Actor.create(
"sender", e.host_by_name("Boivin"), sender,
e.host_by_name("Tremblay"), # h1
e.host_by_name("Jupiter"), # h2
e.host_by_name("Fafard"), # h3
e.host_by_name("Ginette") # h4
)
e.run()
this_actor.info(f"Total simulation time: {e.clock:.3f}")
if __name__ == "__main__":
main()
Executions on the CPU
Basic execution
The computations done in your program are not reported to the simulated world unless you explicitly request the simulator to pause the actor until a given amount of flops gets computed on its simulated host. Some executions can be given a higher priority so that they get more resources.
See also void simgrid::s4u::this_actor::execute(double)
and void simgrid::s4u::this_actor::execute(double, double)
.
View examples/cpp/exec-basic/s4u-exec-basic.cpp
/* Copyright (c) 2010-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. */
#include "simgrid/s4u.hpp"
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_test, "Messages specific for this s4u example");
namespace sg4 = simgrid::s4u;
static void executor()
{
/* this_actor::execute() tells SimGrid to pause the calling actor
* until its host has computed the amount of flops passed as a parameter */
sg4::this_actor::execute(98095);
XBT_INFO("Done.");
/* This simple example does not do anything beyond that */
}
static void privileged()
{
/* This version of this_actor::execute() specifies that this execution gets a larger share of the resource.
*
* Since the priority is 2, it computes twice as fast as a regular one.
*
* So instead of a half/half sharing between the two executions, we get a 1/3 vs 2/3 sharing. */
sg4::this_actor::execute(98095, 2);
XBT_INFO("Done.");
/* Note that the timings printed when running this example are a bit misleading, because the uneven sharing only last
* until the privileged actor ends. After this point, the unprivileged one gets 100% of the CPU and finishes quite
* quickly. */
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
xbt_assert(argc > 1, "Usage: %s platform_file\n\tExample: %s platform.xml\n", argv[0], argv[0]);
e.load_platform(argv[1]);
sg4::Actor::create("executor", e.host_by_name("Tremblay"), executor);
sg4::Actor::create("privileged", e.host_by_name("Tremblay"), privileged);
e.run();
return 0;
}
See also simgrid.this_actor.execute()
.
View examples/python/exec-basic/exec-basic.py
# Copyright (c) 2018-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.
import sys
from simgrid import Actor, Engine, Host, this_actor
def executor():
# execute() tells SimGrid to pause the calling actor until
# its host has computed the amount of flops passed as a parameter
this_actor.execute(98095)
this_actor.info("Done.")
# This simple example does not do anything beyond that
def privileged():
# You can also specify the priority of your execution as follows.
# An execution of priority 2 computes twice as fast as a regular one.
#
# So instead of a half/half sharing between the two executions,
# we get a 1/3 vs 2/3 sharing.
this_actor.execute(98095, priority=2)
this_actor.info("Done.")
# Note that the timings printed when executing this example are a bit misleading,
# because the uneven sharing only last until the privileged actor ends.
# After this point, the unprivileged one gets 100% of the CPU and finishes
# quite quickly.
if __name__ == '__main__':
e = Engine(sys.argv)
e.load_platform(sys.argv[1])
Actor.create("executor", Host.by_name("Tremblay"), executor)
Actor.create("privileged", Host.by_name("Tremblay"), privileged)
e.run()
See also void sg_actor_execute(double)
and void sg_actor_execute_with_priority(double, double)
.
View examples/c/exec-basic/exec-basic.c
/* Copyright (c) 2010-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. */
#include "simgrid/actor.h"
#include "simgrid/engine.h"
#include "simgrid/host.h"
#include "xbt/asserts.h"
#include "xbt/log.h"
XBT_LOG_NEW_DEFAULT_CATEGORY(exec_basic, "Messages specific for this example");
static void executor(int argc, char* argv[])
{
/* sg_actor_execute() tells SimGrid to pause the calling actor
* until its host has computed the amount of flops passed as a parameter */
sg_actor_execute(98095);
XBT_INFO("Done.");
/* This simple example does not do anything beyond that */
}
static void privileged(int argc, char* argv[])
{
/* sg_actor_execute_with_priority() specifies that this execution gets a larger share of the resource.
*
* Since the priority is 2, it computes twice as fast as a regular one.
*
* So instead of a half/half sharing between the two executions,
* we get a 1/3 vs 2/3 sharing. */
sg_actor_execute_with_priority(98095, 2);
XBT_INFO("Done.");
/* Note that the timings printed when executing this example are a bit misleading,
* because the uneven sharing only last until the privileged actor ends.
* After this point, the unprivileged one gets 100% of the CPU and finishes
* quite quickly. */
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
xbt_assert(argc > 1, "Usage: %s platform_file\n\tExample: %s ../platforms/small_platform.xml\n", argv[0], argv[0]);
simgrid_load_platform(argv[1]);
sg_actor_create("executor", sg_host_by_name("Tremblay"), executor, 0, NULL);
sg_actor_create("privileged", sg_host_by_name("Tremblay"), privileged, 0, NULL);
simgrid_run();
return 0;
}
Asynchronous execution
You can start asynchronous executions, just like you would fire background threads.
See also simgrid::s4u::this_actor::exec_init()
,
simgrid::s4u::Activity::start()
,
simgrid::s4u::Activity::wait()
,
simgrid::s4u::Activity::get_remaining()
,
simgrid::s4u::Exec::get_remaining_ratio()
,
simgrid::s4u::this_actor::exec_async()
and
simgrid::s4u::Activity::cancel()
.
View examples/cpp/exec-async/s4u-exec-async.cpp
/* Copyright (c) 2007-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. */
#include "simgrid/s4u.hpp"
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_test, "Messages specific for this s4u example");
namespace sg4 = simgrid::s4u;
/* This actor simply waits for its activity completion after starting it.
* That's exactly equivalent to synchronous execution. */
static void waiter()
{
double computation_amount = sg4::this_actor::get_host()->get_speed();
XBT_INFO("Execute %g flops, should take 1 second.", computation_amount);
sg4::ExecPtr activity = sg4::this_actor::exec_init(computation_amount);
activity->start();
activity->wait();
XBT_INFO("Goodbye now!");
}
/* This actor tests the ongoing execution until its completion, and don't wait before it's terminated. */
static void monitor()
{
double computation_amount = sg4::this_actor::get_host()->get_speed();
XBT_INFO("Execute %g flops, should take 1 second.", computation_amount);
sg4::ExecPtr activity = sg4::this_actor::exec_init(computation_amount);
activity->start();
while (not activity->test()) {
XBT_INFO("Remaining amount of flops: %g (%.0f%%)", activity->get_remaining(),
100 * activity->get_remaining_ratio());
sg4::this_actor::sleep_for(0.3);
}
XBT_INFO("Goodbye now!");
}
/* This actor cancels the ongoing execution after a while. */
static void canceller()
{
double computation_amount = sg4::this_actor::get_host()->get_speed();
XBT_INFO("Execute %g flops, should take 1 second.", computation_amount);
sg4::ExecPtr activity = sg4::this_actor::exec_async(computation_amount);
sg4::this_actor::sleep_for(0.5);
XBT_INFO("I changed my mind, cancel!");
activity->cancel();
XBT_INFO("Goodbye now!");
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
e.load_platform(argv[1]);
sg4::Host* fafard = e.host_by_name("Fafard");
sg4::Host* ginette = e.host_by_name("Ginette");
sg4::Host* boivin = e.host_by_name("Boivin");
sg4::Actor::create("wait", fafard, waiter);
sg4::Actor::create("monitor", ginette, monitor);
sg4::Actor::create("cancel", boivin, canceller);
e.run();
XBT_INFO("Simulation time %g", sg4::Engine::get_clock());
return 0;
}
See also simgrid.this_actor.exec_init()
,
simgrid.Exec.start()
,
simgrid.Exec.wait()
,
simgrid.Exec.remaining
,
simgrid.Exec.remaining_ratio
,
simgrid.this_actor.exec_async()
and
simgrid.Exec.cancel()
.
View examples/python/exec-async/exec-async.py
# Copyright (c) 2018-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.
"""
Usage: exec-async.py platform_file [other parameters]
"""
import sys
from simgrid import Actor, Engine, Host, this_actor
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("Waiter executes {:.0f} flops, should take 1 second.".format(computation_amount))
activity = this_actor.exec_init(computation_amount)
activity.start()
activity.wait()
this_actor.info("Goodbye from waiter!")
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("Monitor executes {:.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 from monitor!")
class Canceller:
"""This actor cancels the ongoing execution after a while."""
def __call__(self):
computation_amount = this_actor.get_host().speed
this_actor.info("Canceller executes {:.0f} flops, should take 1 second.".format(computation_amount))
activity = this_actor.exec_async(computation_amount)
this_actor.sleep_for(0.5)
this_actor.info("I changed my mind, cancel!")
activity.cancel()
this_actor.info("Goodbye from canceller!")
if __name__ == '__main__':
e = Engine(sys.argv)
if len(sys.argv) < 2:
raise AssertionError("Usage: exec-async.py platform_file [other parameters]")
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()
See also sg_actor_exec_init()
,
sg_exec_start()
,
sg_exec_wait()
,
sg_exec_get_remaining()
,
sg_exec_get_remaining_ratio()
,
sg_actor_exec_async()
and
sg_exec_cancel()
,
View examples/c/exec-async/exec-async.c
/* Copyright (c) 2007-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. */
#include "simgrid/actor.h"
#include "simgrid/engine.h"
#include "simgrid/exec.h"
#include "simgrid/host.h"
#include "xbt/asserts.h"
#include "xbt/log.h"
XBT_LOG_NEW_DEFAULT_CATEGORY(exec_async, "Messages specific for this example");
/* This actor simply waits for its task completion after starting it.
* That's exactly equivalent to synchronous execution. */
static void waiter(int argc, char* argv[])
{
double computation_amount = sg_host_get_speed(sg_host_self());
XBT_INFO("Execute %g flops, should take 1 second.", computation_amount);
sg_exec_t activity = sg_actor_exec_init(computation_amount);
sg_exec_start(activity);
sg_exec_wait(activity);
XBT_INFO("Goodbye now!");
}
/* This actor tests the ongoing execution until its completion, and don't wait before it's terminated. */
static void monitor(int argc, char* argv[])
{
double computation_amount = sg_host_get_speed(sg_host_self());
XBT_INFO("Execute %g flops, should take 1 second.", computation_amount);
sg_exec_t activity = sg_actor_exec_init(computation_amount);
sg_exec_start(activity);
while (!sg_exec_test(activity)) {
XBT_INFO("Remaining amount of flops: %g (%.0f%%)", sg_exec_get_remaining(activity),
100 * sg_exec_get_remaining_ratio(activity));
sg_actor_sleep_for(0.3);
}
XBT_INFO("Goodbye now!");
}
/* This actor cancels the ongoing execution after a while. */
static void canceller(int argc, char* argv[])
{
double computation_amount = sg_host_get_speed(sg_host_self());
XBT_INFO("Execute %g flops, should take 1 second.", computation_amount);
sg_exec_t activity = sg_actor_exec_async(computation_amount);
sg_actor_sleep_for(0.5);
XBT_INFO("I changed my mind, cancel!");
sg_exec_cancel(activity);
XBT_INFO("Goodbye now!");
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
simgrid_load_platform(argv[1]);
sg_host_t fafard = sg_host_by_name("Fafard");
sg_host_t ginette = sg_host_by_name("Ginette");
sg_host_t boivin = sg_host_by_name("Boivin");
sg_actor_create("wait", fafard, waiter, 0, NULL);
sg_actor_create("monitor", ginette, monitor, 0, NULL);
sg_actor_create("cancel", boivin, canceller, 0, NULL);
simgrid_run();
XBT_INFO("Simulation time %g", simgrid_get_clock());
return 0;
}
Remote execution
You can start executions on remote hosts, or even change the host on which they occur during their execution. This is naturally not very realistic, but it’s something handy to have.
See also simgrid::s4u::Exec::set_host()
.
View examples/cpp/exec-remote/s4u-exec-remote.cpp
/* Copyright (c) 2007-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. */
#include "simgrid/s4u.hpp"
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_test, "Messages specific for this s4u example");
namespace sg4 = simgrid::s4u;
static void wizard()
{
const sg4::Host* fafard = sg4::Host::by_name("Fafard");
sg4::Host* ginette = sg4::Host::by_name("Ginette");
sg4::Host* boivin = sg4::Host::by_name("Boivin");
XBT_INFO("I'm a wizard! I can run an activity on the Ginette host from the Fafard one! Look!");
sg4::ExecPtr exec = sg4::this_actor::exec_init(48.492e6);
exec->set_host(ginette);
exec->start();
XBT_INFO("It started. Running 48.492Mf takes exactly one second on Ginette (but not on Fafard).");
sg4::this_actor::sleep_for(0.1);
XBT_INFO("Loads in flops/s: Boivin=%.0f; Fafard=%.0f; Ginette=%.0f", boivin->get_load(), fafard->get_load(),
ginette->get_load());
exec->wait();
XBT_INFO("Done!");
XBT_INFO("And now, harder. Start a remote activity on Ginette and move it to Boivin after 0.5 sec");
exec = sg4::this_actor::exec_init(73293500)->set_host(ginette);
exec->start();
sg4::this_actor::sleep_for(0.5);
XBT_INFO("Loads before the move: Boivin=%.0f; Fafard=%.0f; Ginette=%.0f", boivin->get_load(), fafard->get_load(),
ginette->get_load());
exec->set_host(boivin);
sg4::this_actor::sleep_for(0.1);
XBT_INFO("Loads after the move: Boivin=%.0f; Fafard=%.0f; Ginette=%.0f", boivin->get_load(), fafard->get_load(),
ginette->get_load());
exec->wait();
XBT_INFO("Done!");
XBT_INFO("And now, even harder. Start a remote activity on Ginette and turn off the host after 0.5 sec");
exec = sg4::this_actor::exec_init(48.492e6)->set_host(ginette);
exec->start();
sg4::this_actor::sleep_for(0.5);
ginette->turn_off();
try {
exec->wait();
} catch (const simgrid::HostFailureException&) {
XBT_INFO("Execution failed on %s", ginette->get_cname());
}
XBT_INFO("Done!");
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
e.load_platform(argv[1]);
sg4::Actor::create("test", e.host_by_name("Fafard"), wizard);
e.run();
return 0;
}
See also simgrid.Exec.host
.
View examples/python/exec-remote/exec-remote.py
# Copyright (c) 2018-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.
import sys
from simgrid import Actor, Engine, Host, this_actor
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!")
activity = this_actor.exec_init(48.492e6)
activity.host = ginette
activity.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))
activity.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")
activity = this_actor.exec_init(73293500)
activity.host = ginette
activity.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))
activity.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))
activity.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()
See also sg_exec_set_host()
.
View examples/c/exec-remote/exec-remote.c
/* Copyright (c) 2007-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. */
#include "simgrid/actor.h"
#include "simgrid/engine.h"
#include "simgrid/exec.h"
#include "simgrid/host.h"
#include "xbt/log.h"
XBT_LOG_NEW_DEFAULT_CATEGORY(exec_remote, "Messages specific for this example");
static void wizard(int argc, char* argv[])
{
const_sg_host_t fafard = sg_host_by_name("Fafard");
sg_host_t ginette = sg_host_by_name("Ginette");
sg_host_t boivin = sg_host_by_name("Boivin");
XBT_INFO("I'm a wizard! I can run a task on the Ginette host from the Fafard one! Look!");
sg_exec_t exec = sg_actor_exec_init(48.492e6);
sg_exec_set_host(exec, ginette);
sg_exec_start(exec);
XBT_INFO("It started. Running 48.492Mf takes exactly one second on Ginette (but not on Fafard).");
sg_actor_sleep_for(0.1);
XBT_INFO("Loads in flops/s: Boivin=%.0f; Fafard=%.0f; Ginette=%.0f", sg_host_get_load(boivin),
sg_host_get_load(fafard), sg_host_get_load(ginette));
sg_exec_wait(exec);
XBT_INFO("Done!");
XBT_INFO("And now, harder. Start a remote task on Ginette and move it to Boivin after 0.5 sec");
exec = sg_actor_exec_init(73293500);
sg_exec_set_host(exec, ginette);
sg_exec_start(exec);
sg_actor_sleep_for(0.5);
XBT_INFO("Loads before the move: Boivin=%.0f; Fafard=%.0f; Ginette=%.0f", sg_host_get_load(boivin),
sg_host_get_load(fafard), sg_host_get_load(ginette));
sg_exec_set_host(exec, boivin);
sg_actor_sleep_for(0.1);
XBT_INFO("Loads after the move: Boivin=%.0f; Fafard=%.0f; Ginette=%.0f", sg_host_get_load(boivin),
sg_host_get_load(fafard), sg_host_get_load(ginette));
sg_exec_wait(exec);
XBT_INFO("Done!");
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
simgrid_load_platform(argv[1]);
sg_actor_create("test", sg_host_by_name("Fafard"), wizard, 0, NULL);
simgrid_run();
return 0;
}
Parallel executions
These objects are convenient abstractions of parallel
computational kernels that span over several machines, such as a
PDGEM and the other ScaLAPACK routines. Note that this only works
with the “ptask_L07” host model (--cfg=host/model:ptask_L07
).
This example demonstrates several kinds of parallel tasks: regular ones, communication-only (without computation), computation-only (without communication), synchronization-only (neither communication nor computation). It also shows how to reconfigure a task after its start, to change the number of hosts it runs onto. This allows simulating malleable tasks.
See also simgrid::s4u::this_actor::parallel_execute()
.
View examples/cpp/exec-ptask/s4u-exec-ptask.cpp
/* Copyright (c) 2017-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. */
/* Parallel activities are convenient abstractions of parallel computational kernels that span over several machines.
* To create a new one, you have to provide several things:
* - a vector of hosts on which the activity will execute
* - a vector of values, the amount of computation for each of the hosts (in flops)
* - a matrix of values, the amount of communication between each pair of hosts (in bytes)
*
* Each of these operation will be processed at the same relative speed.
* This means that at some point in time, all sub-executions and all sub-communications will be at 20% of completion.
* Also, they will all complete at the exact same time.
*
* This is obviously a simplistic abstraction, but this is very handful in a large amount of situations.
*
* Please note that you must have the LV07 platform model enabled to use such constructs.
*/
#include <simgrid/s4u.hpp>
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_ptask, "Messages specific for this s4u example");
namespace sg4 = simgrid::s4u;
static void runner()
{
/* Retrieve the list of all hosts as an array of hosts */
auto hosts = sg4::Engine::get_instance()->get_all_hosts();
size_t hosts_count = hosts.size();
std::vector<double> computation_amounts;
std::vector<double> communication_amounts;
/* ------[ test 1 ]----------------- */
XBT_INFO("First, build a classical parallel activity, with 1 Gflop to execute on each node, "
"and 10MB to exchange between each pair");
computation_amounts.assign(hosts_count, 1e9 /*1Gflop*/);
communication_amounts.assign(hosts_count * hosts_count, 0);
for (size_t i = 0; i < hosts_count; i++)
for (size_t j = i + 1; j < hosts_count; j++)
communication_amounts[i * hosts_count + j] = 1e7; // 10 MB
sg4::this_actor::parallel_execute(hosts, computation_amounts, communication_amounts);
/* ------[ test 2 ]----------------- */
XBT_INFO("We can do the same with a timeout of 10 seconds enabled.");
computation_amounts.assign(hosts_count, 1e9 /*1Gflop*/);
communication_amounts.assign(hosts_count * hosts_count, 0);
for (size_t i = 0; i < hosts_count; i++)
for (size_t j = i + 1; j < hosts_count; j++)
communication_amounts[i * hosts_count + j] = 1e7; // 10 MB
sg4::ExecPtr activity = sg4::this_actor::exec_init(hosts, computation_amounts, communication_amounts);
try {
activity->wait_for(10.0 /* timeout (in seconds)*/);
xbt_die("Woops, this did not timeout as expected... Please report that bug.");
} catch (const simgrid::TimeoutException&) {
XBT_INFO("Caught the expected timeout exception.");
activity->cancel();
}
/* ------[ test 3 ]----------------- */
XBT_INFO("Then, build a parallel activity involving only computations (of different amounts) and no communication");
computation_amounts = {3e8, 6e8, 1e9}; // 300Mflop, 600Mflop, 1Gflop
communication_amounts.clear(); // no comm
sg4::this_actor::parallel_execute(hosts, computation_amounts, communication_amounts);
/* ------[ test 4 ]----------------- */
XBT_INFO("Then, build a parallel activity with no computation nor communication (synchro only)");
computation_amounts.clear();
communication_amounts.clear();
sg4::this_actor::parallel_execute(hosts, computation_amounts, communication_amounts);
/* ------[ test 5 ]----------------- */
XBT_INFO("Then, Monitor the execution of a parallel activity");
computation_amounts.assign(hosts_count, 1e6 /*1Mflop*/);
communication_amounts = {0, 1e6, 0, 0, 0, 1e6, 1e6, 0, 0};
activity = sg4::this_actor::exec_init(hosts, computation_amounts, communication_amounts);
activity->start();
while (not activity->test()) {
XBT_INFO("Remaining flop ratio: %.0f%%", 100 * activity->get_remaining_ratio());
sg4::this_actor::sleep_for(5);
}
activity->wait();
/* ------[ test 6 ]----------------- */
XBT_INFO("Finally, simulate a malleable task (a parallel execution that gets reconfigured after its start).");
XBT_INFO(" - Start a regular parallel execution, with both comm and computation");
computation_amounts.assign(hosts_count, 1e6 /*1Mflop*/);
communication_amounts = {0, 1e6, 0, 0, 1e6, 0, 1e6, 0, 0};
activity = sg4::this_actor::exec_init(hosts, computation_amounts, communication_amounts);
activity->start();
sg4::this_actor::sleep_for(10);
double remaining_ratio = activity->get_remaining_ratio();
XBT_INFO(" - After 10 seconds, %.2f%% remains to be done. Change it from 3 hosts to 2 hosts only.",
remaining_ratio * 100);
XBT_INFO(" Let's first suspend the task.");
activity->suspend();
XBT_INFO(" - Now, simulate the reconfiguration (modeled as a comm from the removed host to the remaining ones).");
std::vector<double> rescheduling_comp{0, 0, 0};
std::vector<double> rescheduling_comm{0, 0, 0, 0, 0, 0, 25000, 25000, 0};
sg4::this_actor::parallel_execute(hosts, rescheduling_comp, rescheduling_comm);
XBT_INFO(" - Now, let's cancel the old task and create a new task with modified comm and computation vectors:");
XBT_INFO(" What was already done is removed, and the load of the removed host is shared between remaining ones.");
for (int i = 0; i < 2; i++) {
// remove what we've done so far, for both comm and compute load
computation_amounts[i] *= remaining_ratio;
communication_amounts[i] *= remaining_ratio;
// The work from 1 must be shared between 2 remaining ones. 1/2=50% of extra work for each
computation_amounts[i] *= 1.5;
communication_amounts[i] *= 1.5;
}
hosts.resize(2);
computation_amounts.resize(2);
double remaining_comm = communication_amounts[1];
communication_amounts = {0, remaining_comm, remaining_comm, 0}; // Resizing a linearized matrix is hairly
activity->cancel();
activity = sg4::this_actor::exec_init(hosts, computation_amounts, communication_amounts);
XBT_INFO(" - Done, let's wait for the task completion");
activity->wait();
XBT_INFO("Goodbye now!");
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
xbt_assert(argc == 2, "Usage: %s <platform file>", argv[0]);
e.load_platform(argv[1]);
sg4::Actor::create("test", e.host_by_name("MyHost1"), runner);
e.run();
XBT_INFO("Simulation done.");
return 0;
}
See also simgrid.this_actor.parallel_execute()
View examples/python/exec-ptask/exec-ptask.py
# Copyright (c) 2018-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.
# This script does exactly the same thing as file s4u-exec-ptask.cpp
import sys
from simgrid import Actor, Engine, Host, this_actor, TimeoutException
def runner():
hosts = Engine.instance.all_hosts
hosts_count = len(hosts)
# Test 1
this_actor.info("First, build a classical parallel activity, with 1 Gflop to execute on each node, "
"and 10MB to exchange between each pair")
computation_amounts = [1e9]*hosts_count
communication_amounts = [0]*hosts_count*hosts_count
for i in range(hosts_count):
for j in range(i+1, hosts_count):
communication_amounts[i * hosts_count + j] = 1e7
this_actor.parallel_execute(hosts, computation_amounts, communication_amounts)
# Test 2
this_actor.info("We can do the same with a timeout of 10 seconds enabled.")
activity = this_actor.exec_init(hosts, computation_amounts, communication_amounts)
try:
activity.wait_for(10.0)
sys.exit("Woops, this did not timeout as expected... Please report that bug.")
except TimeoutException:
this_actor.info("Caught the expected timeout exception.")
activity.cancel()
# Test 3
this_actor.info("Then, build a parallel activity involving only computations (of different amounts) and no communication")
computation_amounts = [3e8, 6e8, 1e9]
communication_amounts = []
this_actor.parallel_execute(hosts, computation_amounts, communication_amounts)
# Test 4
this_actor.info("Then, build a parallel activity with no computation nor communication (synchro only)")
computation_amounts = []
this_actor.parallel_execute(hosts, computation_amounts, communication_amounts)
# Test 5
this_actor.info("Then, Monitor the execution of a parallel activity")
computation_amounts = [1e6]*hosts_count
communication_amounts = [0, 1e6, 0, 0, 0, 1e6, 1e6, 0, 0]
activity = this_actor.exec_init(hosts, computation_amounts, communication_amounts)
activity.start()
while not activity.test():
ratio = activity.remaining_ratio * 100
this_actor.info(f"Remaining flop ratio: {ratio:.0f}%")
this_actor.sleep_for(5)
activity.wait()
# Test 6
this_actor.info("Finally, simulate a malleable task (a parallel execution that gets reconfigured after its start).")
this_actor.info(" - Start a regular parallel execution, with both comm and computation")
computation_amounts = [1e6]*hosts_count
communication_amounts = [0, 1e6, 0, 0, 1e6, 0, 1e6, 0, 0]
activity = this_actor.exec_init(hosts, computation_amounts, communication_amounts)
activity.start()
this_actor.sleep_for(10)
remaining_ratio = activity.remaining_ratio
this_actor.info(f" - After 10 seconds, {remaining_ratio*100:.2f}% remains to be done. Change it from 3 hosts to 2 hosts only.")
this_actor.info(" Let's first suspend the task.")
activity.suspend()
this_actor.info(" - Now, simulate the reconfiguration (modeled as a comm from the removed host to the remaining ones).")
rescheduling_comp = [0, 0, 0]
rescheduling_comm = [0, 0, 0, 0, 0, 0, 25000, 25000, 0]
this_actor.parallel_execute(hosts, rescheduling_comp, rescheduling_comm)
this_actor.info(" - Now, let's cancel the old task and create a new task with modified comm and computation vectors:")
this_actor.info(" What was already done is removed, and the load of the removed host is shared between remaining ones.")
for i in range(2):
# remove what we've done so far, for both comm and compute load
computation_amounts[i] *= remaining_ratio
communication_amounts[i] *= remaining_ratio
# The work from 1 must be shared between 2 remaining ones. 1/2=50% of extra work for each
computation_amounts[i] *= 1.5
communication_amounts[i] *= 1.5
hosts = hosts[:2]
computation_amounts = computation_amounts[:2]
remaining_comm = communication_amounts[1]
communication_amounts = [0, remaining_comm, remaining_comm, 0]
activity.cancel()
activity = this_actor.exec_init(hosts, computation_amounts, communication_amounts)
this_actor.info(" - Done, let's wait for the task completion")
activity.wait()
this_actor.info("Goodbye now!")
if __name__ == "__main__":
if len(sys.argv) != 2:
sys.exit(f"Syntax: {sys.argv[0]} <platform_file>")
platform = sys.argv[1]
engine = Engine.instance
Engine.set_config("host/model:ptask_L07") # /!\ this is required for running ptasks
engine.load_platform(platform)
Actor.create("foo", engine.host_by_name("MyHost1"), runner)
engine.run()
Ptasks play well with the host energy plugin, as shown in this example. There is not much new compared to the above ptask example or the examples about energy. It just works.
View examples/cpp/energy-exec-ptask/s4u-energy-exec-ptask.cpp
Download s4u-energy-exec-ptask.cpp
/* Copyright (c) 2007-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. */
#include "simgrid/s4u.hpp"
#include "simgrid/plugins/energy.h"
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_test, "Messages specific for this s4u example");
namespace sg4 = simgrid::s4u;
static void runner()
{
sg4::Host* host1 = sg4::Host::by_name("MyHost1");
sg4::Host* host2 = sg4::Host::by_name("MyHost2");
std::vector<sg4::Host*> hosts{host1, host2};
double old_energy_host1 = sg_host_get_consumed_energy(host1);
double old_energy_host2 = sg_host_get_consumed_energy(host2);
XBT_INFO("[%s] Energetic profile: %s", host1->get_cname(), host1->get_property("wattage_per_state"));
XBT_INFO("[%s] Initial peak speed=%.0E flop/s; Total energy dissipated =%.0E J", host1->get_cname(), host1->get_speed(),
old_energy_host1);
XBT_INFO("[%s] Energetic profile: %s", host2->get_cname(), host2->get_property("wattage_per_state"));
XBT_INFO("[%s] Initial peak speed=%.0E flop/s; Total energy dissipated =%.0E J", host2->get_cname(), host2->get_speed(),
old_energy_host2);
double start = sg4::Engine::get_clock();
XBT_INFO("Sleep for 10 seconds");
sg4::this_actor::sleep_for(10);
double new_energy_host1 = sg_host_get_consumed_energy(host1);
double new_energy_host2 = sg_host_get_consumed_energy(host2);
XBT_INFO("Done sleeping (duration: %.2f s).\n"
"[%s] Current peak speed=%.0E; Energy dissipated during this step=%.2f J; Total energy dissipated=%.2f J\n"
"[%s] Current peak speed=%.0E; Energy dissipated during this step=%.2f J; Total energy dissipated=%.2f J\n",
sg4::Engine::get_clock() - start, host1->get_cname(), host1->get_speed(),
(new_energy_host1 - old_energy_host1), sg_host_get_consumed_energy(host1), host2->get_cname(),
host2->get_speed(), (new_energy_host2 - old_energy_host2), sg_host_get_consumed_energy(host2));
old_energy_host1 = new_energy_host1;
old_energy_host2 = new_energy_host2;
// ========= Execute something =========
start = sg4::Engine::get_clock();
double flopAmount = 1E9;
std::vector<double> cpu_amounts{flopAmount, flopAmount};
std::vector<double> com_amounts{0, 0, 0, 0};
XBT_INFO("Run a task of %.0E flops on two hosts", flopAmount);
sg4::this_actor::parallel_execute(hosts, cpu_amounts, com_amounts);
new_energy_host1 = sg_host_get_consumed_energy(host1);
new_energy_host2 = sg_host_get_consumed_energy(host2);
XBT_INFO(
"Task done (duration: %.2f s).\n"
"[%s] Current peak speed=%.0E flop/s; Energy dissipated during this step=%.2f J; Total energy dissipated=%.0f J\n"
"[%s] Current peak speed=%.0E flop/s; Energy dissipated during this step=%.2f J; Total energy dissipated=%.0f "
"J\n",
sg4::Engine::get_clock() - start, host1->get_cname(), host1->get_speed(), (new_energy_host1 - old_energy_host1),
sg_host_get_consumed_energy(host1), host2->get_cname(), host2->get_speed(), (new_energy_host2 - old_energy_host2),
sg_host_get_consumed_energy(host2));
old_energy_host1 = new_energy_host1;
old_energy_host2 = new_energy_host2;
// ========= Change power peak =========
int pstate = 2;
host1->set_pstate(pstate);
host2->set_pstate(pstate);
XBT_INFO("========= Requesting pstate %d for both hosts (speed should be of %.0E flop/s and is of %.0E flop/s)", pstate,
host1->get_pstate_speed(pstate), host1->get_speed());
// ========= Run another ptask =========
start = sg4::Engine::get_clock();
std::vector<double> cpu_amounts2{flopAmount, flopAmount};
std::vector<double> com_amounts2{0, 0, 0, 0};
XBT_INFO("Run a task of %.0E flops on %s and %.0E flops on %s.", flopAmount, host1->get_cname(), flopAmount, host2->get_cname());
sg4::this_actor::parallel_execute(hosts, cpu_amounts2, com_amounts2);
new_energy_host1 = sg_host_get_consumed_energy(host1);
new_energy_host2 = sg_host_get_consumed_energy(host2);
XBT_INFO(
"Task done (duration: %.2f s).\n"
"[%s] Current peak speed=%.0E flop/s; Energy dissipated during this step=%.2f J; Total energy dissipated=%.0f J\n"
"[%s] Current peak speed=%.0E flop/s; Energy dissipated during this step=%.2f J; Total energy dissipated=%.0f "
"J\n",
sg4::Engine::get_clock() - start, host1->get_cname(), host1->get_speed(), (new_energy_host1 - old_energy_host1),
sg_host_get_consumed_energy(host1), host2->get_cname(), host2->get_speed(), (new_energy_host2 - old_energy_host2),
sg_host_get_consumed_energy(host2));
old_energy_host1 = new_energy_host1;
old_energy_host2 = new_energy_host2;
// ========= A new ptask with computation and communication =========
start = sg4::Engine::get_clock();
double comAmount = 1E7;
std::vector<double> cpu_amounts3{flopAmount, flopAmount};
std::vector<double> com_amounts3{0, comAmount, comAmount, 0};
XBT_INFO("Run a task with computation and communication on two hosts.");
sg4::this_actor::parallel_execute(hosts, cpu_amounts3, com_amounts3);
new_energy_host1 = sg_host_get_consumed_energy(host1);
new_energy_host2 = sg_host_get_consumed_energy(host2);
XBT_INFO(
"Task done (duration: %.2f s).\n"
"[%s] Current peak speed=%.0E flop/s; Energy dissipated during this step=%.2f J; Total energy dissipated=%.0f J\n"
"[%s] Current peak speed=%.0E flop/s; Energy dissipated during this step=%.2f J; Total energy dissipated=%.0f "
"J\n",
sg4::Engine::get_clock() - start, host1->get_cname(), host1->get_speed(), (new_energy_host1 - old_energy_host1),
sg_host_get_consumed_energy(host1), host2->get_cname(), host2->get_speed(), (new_energy_host2 - old_energy_host2),
sg_host_get_consumed_energy(host2));
old_energy_host1 = new_energy_host1;
old_energy_host2 = new_energy_host2;
// ========= A new ptask with communication only =========
start = sg4::Engine::get_clock();
std::vector<double> cpu_amounts4{0, 0};
std::vector<double> com_amounts4{0, comAmount, comAmount, 0};
XBT_INFO("Run a task with only communication on two hosts.");
sg4::this_actor::parallel_execute(hosts, cpu_amounts4, com_amounts4);
new_energy_host1 = sg_host_get_consumed_energy(host1);
new_energy_host2 = sg_host_get_consumed_energy(host2);
XBT_INFO(
"Task done (duration: %.2f s).\n"
"[%s] Current peak speed=%.0E flop/s; Energy dissipated during this step=%.2f J; Total energy dissipated=%.0f J\n"
"[%s] Current peak speed=%.0E flop/s; Energy dissipated during this step=%.2f J; Total energy dissipated=%.0f "
"J\n",
sg4::Engine::get_clock() - start, host1->get_cname(), host1->get_speed(), (new_energy_host1 - old_energy_host1),
sg_host_get_consumed_energy(host1), host2->get_cname(), host2->get_speed(), (new_energy_host2 - old_energy_host2),
sg_host_get_consumed_energy(host2));
old_energy_host1 = new_energy_host1;
old_energy_host2 = new_energy_host2;
// ========= A new ptask with computation and a timeout =========
start = sg4::Engine::get_clock();
XBT_INFO("Run a task with computation on two hosts and a timeout of 20s.");
try {
std::vector<double> cpu_amounts5{flopAmount, flopAmount};
std::vector<double> com_amounts5{0, 0, 0, 0};
sg4::this_actor::exec_init(hosts, cpu_amounts5, com_amounts5)->wait_for(20);
} catch (const simgrid::TimeoutException &){
XBT_INFO("Finished WITH timeout");
}
new_energy_host1 = sg_host_get_consumed_energy(host1);
new_energy_host2 = sg_host_get_consumed_energy(host2);
XBT_INFO(
"Task ended (duration: %.2f s).\n"
"[%s] Current peak speed=%.0E flop/s; Energy dissipated during this step=%.2f J; Total energy dissipated=%.0f J\n"
"[%s] Current peak speed=%.0E flop/s; Energy dissipated during this step=%.2f J; Total energy dissipated=%.0f "
"J\n",
sg4::Engine::get_clock() - start, host1->get_cname(), host1->get_speed(), (new_energy_host1 - old_energy_host1),
sg_host_get_consumed_energy(host1), host2->get_cname(), host2->get_speed(), (new_energy_host2 - old_energy_host2),
sg_host_get_consumed_energy(host2));
XBT_INFO("Now is time to quit!");
}
int main(int argc, char* argv[])
{
sg_host_energy_plugin_init();
sg4::Engine e(&argc, argv);
sg4::Engine::set_config("host/model:ptask_L07");
xbt_assert(argc == 2, "Usage: %s platform_file\n\tExample: %s ../platforms/energy_platform.xml\n", argv[0], argv[0]);
e.load_platform(argv[1]);
sg4::Actor::create("energy_ptask_test", e.host_by_name("MyHost1"), runner);
e.run();
XBT_INFO("End of simulation.");
return 0;
}
View examples/c/energy-exec-ptask/energy-exec-ptask.c
/* Copyright (c) 2007-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. */
#include "simgrid/actor.h"
#include "simgrid/engine.h"
#include "simgrid/exec.h"
#include "simgrid/host.h"
#include "simgrid/plugins/energy.h"
#include "xbt/config.h"
#include "xbt/log.h"
#include "xbt/sysdep.h"
XBT_LOG_NEW_DEFAULT_CATEGORY(energy_exec_ptask, "Messages specific for this example");
static void runner(int argc, char* argv[])
{
/* Retrieve the list of all hosts as an array of hosts */
int host_count = (int)sg_host_count();
sg_host_t* hosts = sg_host_list();
XBT_INFO("First, build a classical parallel task, with 1 Gflop to execute on each node, "
"and 10MB to exchange between each pair");
double* computation_amounts = xbt_new0(double, host_count);
double* communication_amounts = xbt_new0(double, host_count * host_count);
for (int i = 0; i < host_count; i++)
computation_amounts[i] = 1e9; // 1 Gflop
for (int i = 0; i < host_count; i++)
for (int j = i + 1; j < host_count; j++)
communication_amounts[i * host_count + j] = 1e7; // 10 MB
sg_actor_parallel_execute(host_count, hosts, computation_amounts, communication_amounts);
xbt_free(communication_amounts);
xbt_free(computation_amounts);
XBT_INFO("We can do the same with a timeout of one second enabled.");
computation_amounts = xbt_new0(double, host_count);
communication_amounts = xbt_new0(double, host_count * host_count);
for (int i = 0; i < host_count; i++)
computation_amounts[i] = 1e9; // 1 Gflop
for (int i = 0; i < host_count; i++)
for (int j = i + 1; j < host_count; j++)
communication_amounts[i * host_count + j] = 1e7; // 10 MB
sg_exec_t exec = sg_actor_parallel_exec_init(host_count, hosts, computation_amounts, communication_amounts);
if (sg_exec_wait_for(exec, 1 /* timeout (in seconds)*/) == SG_ERROR_TIMEOUT)
sg_exec_cancel(exec);
xbt_free(communication_amounts);
xbt_free(computation_amounts);
XBT_INFO("Then, build a parallel task involving only computations and no communication (1 Gflop per node)");
computation_amounts = xbt_new0(double, host_count);
for (int i = 0; i < host_count; i++)
computation_amounts[i] = 1e9; // 1 Gflop
sg_actor_parallel_execute(host_count, hosts, computation_amounts, NULL);
xbt_free(computation_amounts);
XBT_INFO("Then, build a parallel task with no computation nor communication (synchro only)");
computation_amounts = xbt_new0(double, host_count);
communication_amounts = xbt_new0(double, host_count * host_count);
sg_actor_parallel_execute(host_count, hosts, computation_amounts, communication_amounts);
xbt_free(communication_amounts);
xbt_free(computation_amounts);
XBT_INFO("Finally, trick the ptask to do a 'remote execution', on host %s", sg_host_get_name(hosts[1]));
computation_amounts = xbt_new0(double, 1);
computation_amounts[0] = 1e9; // 1 Gflop
sg_host_t remote[1];
remote[0] = hosts[1];
sg_actor_parallel_execute(1, remote, computation_amounts, NULL /* no comm */);
xbt_free(computation_amounts);
XBT_INFO("Goodbye now!");
xbt_free(hosts);
}
int main(int argc, char* argv[])
{
simgrid_init(&argc, argv);
sg_cfg_set_string("host/model", "ptask_L07");
xbt_assert(argc <= 3, "1Usage: %s <platform file> [--energy]", argv[0]);
xbt_assert(argc >= 2, "2Usage: %s <platform file> [--energy]", argv[0]);
if (argc == 3 && argv[2][2] == 'e')
sg_host_energy_plugin_init();
simgrid_load_platform(argv[1]);
/* Pick the first host from the platform file */
sg_host_t* all_hosts = sg_host_list();
sg_host_t first_host = all_hosts[0];
xbt_free(all_hosts);
sg_actor_create("test", first_host, runner, 0, NULL);
simgrid_run();
XBT_INFO("Simulation done.");
return 0;
}
Dealing with host failures
This examples shows how to survive to host failure exceptions that occur when an host is turned off. The actors do not get notified when the host
on which they run is turned off: they are just terminated in this case, and their on_exit()
callback gets executed. For remote executions on
failing hosts however, any blocking operation such as exec
or wait
will raise an exception that you can catch and react to. See also
Modeling churn (e.g., in P2P),
this example on how to attach a state profile to hosts, and
that example on how to react to network failures.
View examples/cpp/exec-failure/s4u-exec-failure.cpp
/* Copyright (c) 2021-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. */
/* This examples shows how to survive to host failure exceptions that occur when an host is turned off.
*
* The actors do not get notified when the host on which they run is turned off: they are just terminated
* in this case, and their ``on_exit()`` callback gets executed.
*
* For remote executions on failing hosts however, any blocking operation such as ``exec`` or ``wait`` will
* raise an exception that you can catch and react to, as illustrated in this example.
*/
#include <simgrid/s4u.hpp>
#include "simgrid/kernel/ProfileBuilder.hpp"
XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_exec_failure, "Messages specific for this s4u example");
namespace sg4 = simgrid::s4u;
static void dispatcher(std::vector<sg4::Host*> const& hosts)
{
std::vector<sg4::ExecPtr> pending_execs;
for (auto* host: hosts) {
XBT_INFO("Initiating asynchronous exec on %s", host->get_cname());
// Computing 20 flops on an host which speed is 1f takes 20 seconds (when it does not fail)
auto exec = sg4::this_actor::exec_init(20)->set_host(host);
pending_execs.push_back(exec);
exec->start();
}
XBT_INFO("---------------------------------");
XBT_INFO("Wait on the first exec, which host is turned off at t=10 by the another actor.");
try {
pending_execs[0]->wait();
xbt_assert("This wait was not supposed to succeed.");
} catch (const simgrid::HostFailureException&) {
XBT_INFO("Dispatcher has experienced a host failure exception, so it knows that something went wrong.");
}
XBT_INFO("State of each exec:");
for (auto const& exec : pending_execs)
XBT_INFO(" Exec on %s has state: %s", exec->get_host()->get_cname(), exec->get_state_str());
XBT_INFO("---------------------------------");
XBT_INFO("Wait on the second exec, which host is turned off at t=12 by the state profile.");
try {
pending_execs[1]->wait();
xbt_assert("This wait was not supposed to succeed.");
} catch (const simgrid::HostFailureException&) {
XBT_INFO("Dispatcher has experienced a host failure exception, so it knows that something went wrong.");
}
XBT_INFO("State of each exec:");
for (auto const& exec : pending_execs)
XBT_INFO(" Exec on %s has state: %s", exec->get_host()->get_cname(), exec->get_state_str());
XBT_INFO("---------------------------------");
XBT_INFO("Wait on the third exec, which should succeed.");
try {
pending_execs[2]->wait();
XBT_INFO("No exception occured.");
} catch (const simgrid::HostFailureException&) {
xbt_assert("This wait was not supposed to fail.");
}
XBT_INFO("State of each exec:");
for (auto const& exec : pending_execs)
XBT_INFO(" Exec on %s has state: %s", exec->get_host()->get_cname(), exec->get_state_str());
}
static void host_killer(sg4::Host* to_kill)
{
sg4::this_actor::sleep_for(10.0);
XBT_INFO("HostKiller turns off the host '%s'.", to_kill->get_cname());
to_kill->turn_off();
}
int main(int argc, char** argv)
{
sg4::Engine engine(&argc, argv);
auto* zone = sg4::create_full_zone("world");
std::vector<sg4::Host*> hosts;
for (const auto* name : {"Host1", "Host2", "Host3"}) {
auto* host = zone->create_host(name, "1f");
hosts.push_back(host);
}
/* Attaching a state profile (ie a list of events changing the on/off state of the resource) to host3.
* The syntax of the profile (second parameter) is a list of: "date state\n"
* The R"( )" thing is the C++ way of writing multiline strings, including literals \n.
* You'd have the same behavior by using "12 0\n20 1\n" instead.
* So here, the link is turned off at t=12 and back on at t=20.
* The last parameter is the period of that profile, meaning that it loops after 30 seconds.
*/
hosts[1]->set_state_profile(simgrid::kernel::profile::ProfileBuilder::from_string("profile name", R"(
12 0
20 1
)", 30));
zone->seal();
sg4::Actor::create("Dispatcher", hosts[2], dispatcher, hosts);
sg4::Actor::create("HostKiller", hosts[2], host_killer, hosts[0]);
engine.run();
return 0;
}
DVFS and pstates
This example shows how to define a set of pstates in the XML. The current pstate of a host can then be accessed and changed from the program.
See also simgrid::s4u::Host::get_pstate_speed()
and simgrid::s4u::Host::set_pstate()
.
View examples/cpp/exec-dvfs/s4u-exec-dvfs.cpp
/* Copyright (c) 2007-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. */
#include "simgrid/s4u.hpp"
XBT_LOG_NEW_DEFAULT_CATEGORY(test, "Pstate properties test");
namespace sg4 = simgrid::s4u;
static int dvfs()
{
double workload = 100E6;
sg4::Host* host = sg4::this_actor::get_host();
unsigned long nb = host->get_pstate_count();
XBT_INFO("Count of Processor states=%lu", nb);
XBT_INFO("Current power peak=%f", host->get_speed());
// Run a Computation
sg4::this_actor::execute(workload);
double exec_time = sg4::Engine::get_clock();
XBT_INFO("Computation1 duration: %.2f", exec_time);
// Change power peak
unsigned long new_pstate = 2;
XBT_INFO("Changing power peak value to %f (at index %lu)", host->get_pstate_speed(new_pstate), new_pstate);
host->set_pstate(new_pstate);
XBT_INFO("Current power peak=%f", host->get_speed());
// Run a second Computation
sg4::this_actor::execute(workload);
exec_time = sg4::Engine::get_clock() - exec_time;
XBT_INFO("Computation2 duration: %.2f", exec_time);
// Verify that the default pstate is set to 0
host = sg4::Host::by_name_or_null("MyHost2");
XBT_INFO("Count of Processor states=%lu", host->get_pstate_count());
XBT_INFO("Current power peak=%f", host->get_speed());
return 0;
}
int main(int argc, char* argv[])
{
sg4::Engine e(&argc, argv);
xbt_assert(argc ==<