SimGrid  3.11
Versatile Simulation of Distributed Systems
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
Using SimGrid

This page is under work – sorry for the inconvinience (FIXME).

SimGrid comes with many examples provided in the examples/ directory. Those examples are described in section MSG examples . Those examples are commented and should be easy to understand. for a first step into SimGrid we also provide some more detailed examples in the sections below.

You should also check our online tutorial section that contains a generic tutorial about using SimGrid.

Using MSG

You should also check our online tutorial section that contains a dedicated tutorial.

Here are some examples on how to use MSG, the most used API.

tr MSG comes with an extensive set of examples. It is sometimes difficult to find the one you need. This list aims at helping you finding the example from which you can learn what you want to.

Basic examples and features

Asynchronous communications

Simulation of asynchronous communications between a sender and a receiver using a realistic platform and an external description of the deployment.


Code of the application

Preliminary declarations

#include <stdio.h>
#include "msg/msg.h" /* Yeah! If you want to use msg, you need to include msg/msg.h */
#include "xbt/sysdep.h" /* calloc, printf */
/* Create a log channel to have nice outputs. */
#include "xbt/log.h"
#include "xbt/asserts.h"
"Messages specific for this msg example");
int sender(int argc, char *argv[]);
int receiver(int argc, char *argv[]);
msg_error_t test_all(const char *platform_file,
const char *application_file);

Sender function

The sender send to a receiver an asynchronous message with the function "MSG_task_isend()". Cause this function is non-blocking we have to make "MSG_comm_test()" to know if the communication is finished for finally destroy it with function "MSG_comm_destroy()". It also available to "make MSG_comm_wait()" which make both of them.

C style arguments (argc/argv) are interpreted as:

  • the number of tasks to distribute
  • the computation size of each task
  • the size of the files associated to each task
  • a list of host that will accept those tasks.
  • the time to sleep at the beginning of the function
  • This time defined the process sleep time if time = 0 use of MSG_comm_wait() if time > 0 use of MSG_comm_test()

int sender(int argc, char *argv[])
{
long number_of_tasks = atol(argv[1]);
double task_comp_size = atof(argv[2]);
double task_comm_size = atof(argv[3]);
long receivers_count = atol(argv[4]);
double sleep_start_time = atof(argv[5]);
double sleep_test_time = atof(argv[6]);
XBT_INFO("sleep_start_time : %f , sleep_test_time : %f", sleep_start_time,
sleep_test_time);
msg_comm_t comm = NULL;
int i;
msg_task_t task = NULL;
MSG_process_sleep(sleep_start_time);
for (i = 0; i < number_of_tasks; i++) {
char mailbox[256];
char sprintf_buffer[256];
sprintf(mailbox, "receiver-%ld", i % receivers_count);
sprintf(sprintf_buffer, "Task_%d", i);
task =
MSG_task_create(sprintf_buffer, task_comp_size, task_comm_size,
NULL);
comm = MSG_task_isend(task, mailbox);
XBT_INFO("Send to receiver-%ld Task_%d", i % receivers_count, i);
if (sleep_test_time == 0) {
MSG_comm_wait(comm, -1);
} else {
while (MSG_comm_test(comm) == 0) {
MSG_process_sleep(sleep_test_time);
};
}
}
for (i = 0; i < receivers_count; i++) {
char mailbox[80];
sprintf(mailbox, "receiver-%ld", i % receivers_count);
task = MSG_task_create("finalize", 0, 0, 0);
comm = MSG_task_isend(task, mailbox);
XBT_INFO("Send to receiver-%ld finalize", i % receivers_count);
if (sleep_test_time == 0) {
MSG_comm_wait(comm, -1);
} else {
while (MSG_comm_test(comm) == 0) {
MSG_process_sleep(sleep_test_time);
};
}
}
XBT_INFO("Goodbye now!");
return 0;
} /* end_of_sender */

Receiver function

This function executes tasks when it receives them. As the receiving is asynchronous we have to test the communication to know if it is completed or not with "MSG_comm_test()" or wait for the completion "MSG_comm_wait()".

C style arguments (argc/argv) are interpreted as:

  • the id to use for received the communication.
  • the time to sleep at the beginning of the function
  • This time defined the process sleep time if time = 0 use of MSG_comm_wait() if time > 0 use of MSG_comm_test()

int receiver(int argc, char *argv[])
{
msg_task_t task = NULL;
_XBT_GNUC_UNUSED msg_error_t res;
int id = -1;
char mailbox[80];
msg_comm_t res_irecv;
double sleep_start_time = atof(argv[2]);
double sleep_test_time = atof(argv[3]);
XBT_INFO("sleep_start_time : %f , sleep_test_time : %f", sleep_start_time,
sleep_test_time);
_XBT_GNUC_UNUSED int read;
read = sscanf(argv[1], "%d", &id);
xbt_assert(read,
"Invalid argument %s\n", argv[1]);
MSG_process_sleep(sleep_start_time);
sprintf(mailbox, "receiver-%d", id);
while (1) {
res_irecv = MSG_task_irecv(&(task), mailbox);
XBT_INFO("Wait to receive a task");
if (sleep_test_time == 0) {
res = MSG_comm_wait(res_irecv, -1);
xbt_assert(res == MSG_OK, "MSG_task_get failed");
} else {
while (MSG_comm_test(res_irecv) == 0) {
MSG_process_sleep(sleep_test_time);
};
}
MSG_comm_destroy(res_irecv);
XBT_INFO("Received \"%s\"", MSG_task_get_name(task));
if (!strcmp(MSG_task_get_name(task), "finalize")) {
break;
}
XBT_INFO("Processing \"%s\"", MSG_task_get_name(task));
XBT_INFO("\"%s\" done", MSG_task_get_name(task));
task = NULL;
}
XBT_INFO("I'm done. See you!");
return 0;
} /* end_of_receiver */

Simulation core

This function is the core of the simulation and is divided only into 3 parts thanks to MSG_create_environment() and MSG_launch_application().

  1. Simulation settings : MSG_create_environment() creates a realistic environment
  2. Application deployment : create the processes on the right locations with MSG_launch_application()
  3. The simulation is run with MSG_main()

Its arguments are:

  • platform_file: the name of a file containing an valid surfxml platform description.
  • application_file: the name of a file containing a valid surfxml application description

msg_error_t test_all(const char *platform_file,
const char *application_file)
{
/* MSG_config("workstation/model","KCCFLN05"); */
{ /* Simulation setting */
MSG_create_environment(platform_file);
}
{ /* Application deployment */
MSG_function_register("sender", sender);
MSG_function_register("receiver", receiver);
MSG_launch_application(application_file);
}
res = MSG_main();
XBT_INFO("Simulation time %g", MSG_get_clock());
return res;
} /* end_of_test_all */

Main function

This initializes MSG, runs a simulation, and free all data-structures created by MSG.

int main(int argc, char *argv[])
{
MSG_init(&argc, argv);
if (argc < 3) {
printf("Usage: %s platform_file deployment_file\n", argv[0]);
printf("example: %s msg_platform.xml msg_deployment.xml\n", argv[0]);
exit(1);
}
res = test_all(argv[1], argv[2]);
if (res == MSG_OK)
return 0;
else
return 1;
} /* end_of_main */

Waitall function for sender

The use of this function permit to send all messages and wait for the completion of all in one time.

int sender(int argc, char *argv[])
{
long number_of_tasks = atol(argv[1]);
double task_comp_size = atof(argv[2]);
double task_comm_size = atof(argv[3]);
long receivers_count = atol(argv[4]);
msg_comm_t *comm = xbt_new(msg_comm_t, number_of_tasks + receivers_count);
int i;
msg_task_t task = NULL;
for (i = 0; i < number_of_tasks; i++) {
char mailbox[256];
char sprintf_buffer[256];
sprintf(mailbox, "receiver-%ld", i % receivers_count);
sprintf(sprintf_buffer, "Task_%d", i);
task =
MSG_task_create(sprintf_buffer, task_comp_size, task_comm_size,
NULL);
comm[i] = MSG_task_isend(task, mailbox);
XBT_INFO("Send to receiver-%ld Task_%d", i % receivers_count, i);
}
for (i = 0; i < receivers_count; i++) {
char mailbox[80];
sprintf(mailbox, "receiver-%ld", i % receivers_count);
task = MSG_task_create("finalize", 0, 0, 0);
comm[i + number_of_tasks] = MSG_task_isend(task, mailbox);
XBT_INFO("Send to receiver-%ld finalize", i % receivers_count);
}
/* Here we are waiting for the completion of all communications */
MSG_comm_waitall(comm, (number_of_tasks + receivers_count), -1);
for (i = 0; i < number_of_tasks + receivers_count; i++)
MSG_comm_destroy(comm[i]);
XBT_INFO("Goodbye now!");
xbt_free(comm);
return 0;
} /* end_of_sender */

Waitany function

The MSG_comm_waitany() function return the place of the first message send or receive from a xbt_dynar_t table.

From a sender

We can use this function to wait all sent messages.

int sender(int argc, char *argv[])
{
long number_of_tasks = atol(argv[1]);
double task_comp_size = atof(argv[2]);
double task_comm_size = atof(argv[3]);
long receivers_count = atol(argv[4]);
int diff_com = atol(argv[5]);
double coef = 0;
xbt_dynar_t d = xbt_dynar_new(sizeof(msg_comm_t), NULL);
int i;
msg_task_t task;
char mailbox[256];
char sprintf_buffer[256];
msg_comm_t comm;
for (i = 0; i < number_of_tasks; i++) {
if (diff_com == 0)
coef = 1;
else
coef = (i + 1);
sprintf(mailbox, "receiver-%ld", (i % receivers_count));
sprintf(sprintf_buffer, "Task_%d", i);
task =
MSG_task_create(sprintf_buffer, task_comp_size,
task_comm_size / coef, NULL);
comm = MSG_task_isend(task, mailbox);
XBT_INFO("Send to receiver-%ld %s comm_size %f", i % receivers_count,
sprintf_buffer, task_comm_size / coef);
}
/* Here we are waiting for the completion of all communications */
while (!xbt_dynar_is_empty(d)) {
}
/* Here we are waiting for the completion of all tasks */
sprintf(mailbox, "finalize");
msg_comm_t res_irecv;
_XBT_GNUC_UNUSED msg_error_t res_wait;
for (i = 0; i < receivers_count; i++) {
task = NULL;
res_irecv = MSG_task_irecv(&(task), mailbox);
res_wait = MSG_comm_wait(res_irecv, -1);
xbt_assert(res_wait == MSG_OK, "MSG_comm_wait failed");
MSG_comm_destroy(res_irecv);
}
XBT_INFO("Goodbye now!");
return 0;
} /* end_of_sender */

From a receiver

We can also wait for the arrival of all messages.

int receiver(int argc, char *argv[])
{
int id = -1;
int i;
char mailbox[80];
xbt_dynar_t comms = xbt_dynar_new(sizeof(msg_comm_t), NULL);
int tasks = atof(argv[2]);
msg_task_t *task = xbt_new(msg_task_t, tasks);
_XBT_GNUC_UNUSED int read;
read = sscanf(argv[1], "%d", &id);
xbt_assert(read, "Invalid argument %s\n", argv[1]);
sprintf(mailbox, "receiver-%d", id);
msg_comm_t res_irecv;
for (i = 0; i < tasks; i++) {
XBT_INFO("Wait to receive task %d", i);
task[i] = NULL;
res_irecv = MSG_task_irecv(&task[i], mailbox);
xbt_dynar_push_as(comms, msg_comm_t, res_irecv);
}
/* Here we are waiting for the receiving of all communications */
msg_task_t task_com;
while (!xbt_dynar_is_empty(comms)) {
_XBT_GNUC_UNUSED msg_error_t err;
xbt_dynar_remove_at(comms, MSG_comm_waitany(comms), &res_irecv);
task_com = MSG_comm_get_task(res_irecv);
MSG_comm_destroy(res_irecv);
XBT_INFO("Processing \"%s\"", MSG_task_get_name(task_com));
MSG_task_execute(task_com);
XBT_INFO("\"%s\" done", MSG_task_get_name(task_com));
err = MSG_task_destroy(task_com);
xbt_assert(err == MSG_OK, "MSG_task_destroy failed");
}
xbt_dynar_free(&comms);
xbt_free(task);
/* Here we tell to sender that all tasks are done */
sprintf(mailbox, "finalize");
res_irecv = MSG_task_isend(MSG_task_create(NULL, 0, 0, NULL), mailbox);
MSG_comm_wait(res_irecv, -1);
MSG_comm_destroy(res_irecv);
XBT_INFO("I'm done. See you!");
return 0;
} /* end_of_receiver */

Basic Master/Slaves

Simulation of a master-slave application using a realistic platform and an external description of the deployment.

Table of contents:


Preliminary declarations

#include <stdio.h>
#include "msg/msg.h" /* Yeah! If you want to use msg, you need to include msg/msg.h */
#include "xbt/sysdep.h" /* calloc, printf */
/* Create a log channel to have nice outputs. */
#include "xbt/log.h"
#include "xbt/asserts.h"
"Messages specific for this msg example");
int master(int argc, char *argv[]);
int slave(int argc, char *argv[]);
int forwarder(int argc, char *argv[]);
msg_error_t test_all(const char *platform_file,
const char *application_file);
#define FINALIZE ((void*)221297) /* a magic number to tell people to stop working */
int master(int argc, char *argv[])
{
int slaves_count = 0;
msg_host_t *slaves = NULL;
msg_task_t *todo = NULL;
int number_of_tasks = 0;
double task_comp_size = 0;
double task_comm_size = 0;
int i;
_XBT_GNUC_UNUSED int res = sscanf(argv[1], "%d", &number_of_tasks);
xbt_assert(res,"Invalid argument %s\n", argv[1]);
res = sscanf(argv[2], "%lg", &task_comp_size);
xbt_assert(res, "Invalid argument %s\n", argv[2]);
res = sscanf(argv[3], "%lg", &task_comm_size);
xbt_assert(res, "Invalid argument %s\n", argv[3]);
{ /* Task creation */
char sprintf_buffer[64];
todo = xbt_new0(msg_task_t, number_of_tasks);
for (i = 0; i < number_of_tasks; i++) {
sprintf(sprintf_buffer, "Task_%d", i);
todo[i] =
MSG_task_create(sprintf_buffer, task_comp_size, task_comm_size,
NULL);
}

Master code

This function has to be assigned to a msg_process_t that will behave as the master. It should not be called directly but either given as a parameter to MSG_process_create() or registered as a public function through MSG_function_register() and then automatically assigned to a process through MSG_launch_application().

C style arguments (argc/argv) are interpreted as:

  • the number of tasks to distribute
  • the computation size of each task
  • the size of the files associated to each task
  • a list of host that will accept those tasks.

Tasks are dumbly sent in a round-robin style.

}
{ /* Process organisation */
slaves_count = argc - 4;
slaves = xbt_new0(msg_host_t, slaves_count);
for (i = 4; i < argc; i++) {
slaves[i - 4] = MSG_get_host_by_name(argv[i]);
xbt_assert(slaves[i - 4] != NULL, "Unknown host %s. Stopping Now! ",
argv[i]);
}
}
XBT_INFO("Got %d slaves and %d tasks to process", slaves_count,
number_of_tasks);
for (i = 0; i < slaves_count; i++)
XBT_DEBUG("%s", MSG_host_get_name(slaves[i]));
for (i = 0; i < number_of_tasks; i++) {
XBT_INFO("Sending \"%s\" to \"%s\"",
todo[i]->name, MSG_host_get_name(slaves[i % slaves_count]));
if (MSG_host_self() == slaves[i % slaves_count]) {
XBT_INFO("Hey ! It's me ! :)");
}
MSG_task_send(todo[i], MSG_host_get_name(slaves[i % slaves_count]));
XBT_INFO("Sent");
}
("All tasks have been dispatched. Let's tell everybody the computation is over.");
for (i = 0; i < slaves_count; i++) {
msg_task_t finalize = MSG_task_create("finalize", 0, 0, FINALIZE);
MSG_task_send(finalize, MSG_host_get_name(slaves[i]));
}
XBT_INFO("Goodbye now!");
free(slaves);
free(todo);
return 0;
} /* end_of_master */

Slave code

This function has to be assigned to a msg_process_t that has to behave as a slave. Just like the master fuction (described in Master code), it should not be called directly.

This function keeps waiting for tasks and executes them as it receives them.

int slave(int argc, char *argv[])
{
msg_task_t task = NULL;
_XBT_GNUC_UNUSED int res;
while (1) {
xbt_assert(res == MSG_OK, "MSG_task_get failed");
XBT_INFO("Received \"%s\"", MSG_task_get_name(task));
if (!strcmp(MSG_task_get_name(task), "finalize")) {
break;
}
XBT_INFO("Processing \"%s\"", MSG_task_get_name(task));
XBT_INFO("\"%s\" done", MSG_task_get_name(task));
task = NULL;
}
XBT_INFO("I'm done. See you!");
return 0;
} /* end_of_slave */

Forwarder code

This function has to be assigned to a msg_process_t that has to behave as a forwarder. Just like the master function (described in Master code), it should not be called directly.

C style arguments (argc/argv) are interpreted as a list of host that will accept those tasks.

This function keeps waiting for tasks and dispathes them to its slaves.

int forwarder(int argc, char *argv[])
{
int i;
int slaves_count;
msg_host_t *slaves;
{ /* Process organisation */
slaves_count = argc - 1;
slaves = xbt_new0(msg_host_t, slaves_count);
for (i = 1; i < argc; i++) {
slaves[i - 1] = MSG_get_host_by_name(argv[i]);
if (slaves[i - 1] == NULL) {
XBT_INFO("Unknown host %s. Stopping Now! ", argv[i]);
abort();
}
}
}
i = 0;
while (1) {
msg_task_t task = NULL;
int a;
if (a == MSG_OK) {
XBT_INFO("Received \"%s\"", MSG_task_get_name(task));
if (MSG_task_get_data(task) == FINALIZE) {
("All tasks have been dispatched. Let's tell everybody the computation is over.");
for (i = 0; i < slaves_count; i++)
MSG_task_send(MSG_task_create("finalize", 0, 0, FINALIZE),
MSG_host_get_name(slaves[i]));
break;
}
XBT_INFO("Sending \"%s\" to \"%s\"",
MSG_task_get_name(task), MSG_host_get_name(slaves[i % slaves_count]));
MSG_task_send(task, MSG_host_get_name(slaves[i % slaves_count]));
i++;
} else {
XBT_INFO("Hey ?! What's up ? ");
xbt_die("Unexpected behavior");
}
}
xbt_free(slaves);
XBT_INFO("I'm done. See you!");
return 0;
} /* end_of_forwarder */

Simulation core

This function is the core of the simulation and is divided only into 3 parts thanks to MSG_create_environment() and MSG_launch_application().

  1. Simulation settings : MSG_create_environment() creates a realistic environment
  2. Application deployment : create the processes on the right locations with MSG_launch_application()
  3. The simulation is run with MSG_main()

Its arguments are:

  • platform_file: the name of a file containing an valid surfxml platform description.
  • application_file: the name of a file containing a valid surfxml application description

msg_error_t test_all(const char *platform_file,
const char *application_file)
{
/* MSG_config("workstation/model","KCCFLN05"); */
{ /* Simulation setting */
MSG_create_environment(platform_file);
}
{ /* Application deployment */
MSG_function_register("master", master);
MSG_function_register("slave", slave);
MSG_function_register("forwarder", forwarder);
MSG_launch_application(application_file);
}
res = MSG_main();
XBT_INFO("Simulation time %g", MSG_get_clock());
return res;
} /* end_of_test_all */

Main() function

This initializes MSG, runs a simulation, and free all data-structures created by MSG.

int main(int argc, char *argv[])
{
MSG_init(&argc, argv);
if (argc < 3) {
printf("Usage: %s platform_file deployment_file\n", argv[0]);
printf("example: %s msg_platform.xml msg_deployment.xml\n", argv[0]);
exit(1);
}
res = test_all(argv[1], argv[2]);
if (res == MSG_OK)
return 0;
else
return 1;
} /* end_of_main */

Helping files

Example of application file

<?xml version='1.0'?>
<!DOCTYPE platform SYSTEM "http://simgrid.gforge.inria.fr/simgrid.dtd">
<platform version="3">
<!-- The master process (with some arguments) -->
<process host="Tremblay" function="master">
<argument value="20"/> <!-- Number of tasks -->
<argument value="50000000"/> <!-- Computation size of tasks -->
<argument value="1000000"/> <!-- Communication size of tasks -->
<argument value="Jupiter"/> <!-- First slave -->
<argument value="Fafard"/> <!-- Second slave -->
<argument value="Ginette"/> <!-- Third slave -->
<argument value="Bourassa"/> <!-- Last slave -->
<argument value="Tremblay"/> <!-- Me! I can work too! -->
</process>
<!-- The slave process (with no argument) -->
<process host="Tremblay" function="slave" on_failure="RESTART"/>
<process host="Jupiter" function="slave" on_failure="RESTART"/>
<process host="Fafard" function="slave" on_failure="RESTART"/>
<process host="Ginette" function="slave" on_failure="RESTART"/>
<process host="Bourassa" function="slave" on_failure="RESTART"/>
</platform>

Example of platform file

<?xml version='1.0'?>
<!DOCTYPE platform SYSTEM "http://simgrid.gforge.inria.fr/simgrid.dtd">
<platform version="3">
<AS id="AS0" routing="Full">
<!-- ljlkj -->
<host id="Tremblay" power="98.095Mf"/>
<host id="Jupiter" power="76.296Mf"/>
<host id="Fafard" power="76.296Mf"/>
<host id="Ginette" power="48.492Mf"/>
<host id="Bourassa" power="48.492Mf"/>
<link id="6" bandwidth="41.279125MBps" latency="59.904us"/>
<link id="11" bandwidth="252.75kBps" latency="5.70455ms"/>
<link id="3" bandwidth="34.285625MBps" latency="514.433us"/>
<link id="7" bandwidth="11.618875MBps" latency="189.98us"/>
<link id="9" bandwidth="7.20975MBps" latency="1.461517ms"/>
<link id="12" bandwidth="1.792625MBps" latency="7.877863ms"/>
<link id="2" bandwidth="118.6825MBps" latency="136.931us"/>
<link id="8" bandwidth="8.158MBps" latency="270.544us"/>
<link id="1" bandwidth="34.285625MBps" latency="514.433us"/>
<link id="4" bandwidth="10.099625MBps" latency="479.78us"/>
<link id="0" bandwidth="41.279125MBps" latency="59.904us"/>
<link id="10" bandwidth="4.67975MBps" latency="848.712us"/>
<link id="5" bandwidth="27.94625MBps" latency="278.066us"/>
<link id="loopback" bandwidth="498MBps" latency="15us" sharing_policy="FATPIPE"/>
<route src="Tremblay" dst="Tremblay"><link_ctn id="loopback"/></route>
<route src="Jupiter" dst="Jupiter"><link_ctn id="loopback"/></route>
<route src="Fafard" dst="Fafard"><link_ctn id="loopback"/></route>
<route src="Ginette" dst="Ginette"><link_ctn id="loopback"/></route>
<route src="Bourassa" dst="Bourassa"><link_ctn id="loopback"/></route>
<route src="Tremblay" dst="Jupiter">
<link_ctn id="9"/>
</route>
<route src="Tremblay" dst="Fafard">
<link_ctn id="4"/><link_ctn id="3"/><link_ctn id="2"/><link_ctn id="0"/><link_ctn id="1"/><link_ctn id="8"/>
</route>
<route src="Tremblay" dst="Ginette">
<link_ctn id="4"/><link_ctn id="3"/><link_ctn id="5"/>
</route>
<route src="Tremblay" dst="Bourassa">
<link_ctn id="4"/><link_ctn id="3"/><link_ctn id="2"/><link_ctn id="0"/><link_ctn id="1"/><link_ctn id="6"/><link_ctn id="7"/>
</route>
<route src="Jupiter" dst="Fafard">
<link_ctn id="9"/><link_ctn id="4"/><link_ctn id="3"/><link_ctn id="2"/><link_ctn id="0"/><link_ctn id="1"/><link_ctn id="8"/>
</route>
<route src="Jupiter" dst="Ginette">
<link_ctn id="9"/><link_ctn id="4"/><link_ctn id="3"/><link_ctn id="5"/>
</route>
<route src="Jupiter" dst="Bourassa">
<link_ctn id="9"/><link_ctn id="4"/><link_ctn id="3"/><link_ctn id="2"/><link_ctn id="0"/><link_ctn id="1"/><link_ctn id="6"/><link_ctn id="7"/>
</route>
<route src="Fafard" dst="Ginette">
<link_ctn id="8"/><link_ctn id="1"/><link_ctn id="0"/><link_ctn id="2"/><link_ctn id="5"/>
</route>
<route src="Fafard" dst="Bourassa">
<link_ctn id="8"/><link_ctn id="6"/><link_ctn id="7"/>
</route>
<route src="Ginette" dst="Bourassa">
<link_ctn id="5"/><link_ctn id="2"/><link_ctn id="0"/><link_ctn id="1"/><link_ctn id="6"/><link_ctn id="7"/>
</route>
</AS>
</platform>

Using SMPI

You should check our online tutorial section that contains a dedicated tutorial.

Using Model Checking

You should check our online tutorial section that contains a dedicated tutorial.

Using Trace

Check out the Tracing Simulations section.

You should check our online tutorial section that contains a dedicated tutorial.

Using SimDag

You should check our online tutorial section that contains a dedicated tutorial.

Using SIMIX

You should check our online tutorial section that contains a dedicated tutorial.