From cae4f3ce3a29af78349034eaa7206185fa66ebef Mon Sep 17 00:00:00 2001 From: =?utf8?q?Paul=20B=C3=A9daride?= Date: Wed, 23 Jan 2013 15:18:51 +0100 Subject: [PATCH 1/1] Add the msg tutorial of Arnauld Legrand to doxygen --- buildtools/Cmake/DefinePackages.cmake | 1 + buildtools/Cmake/GenerateDoc.cmake | 2 + doc/Doxyfile.in | 1 - doc/doxygen/introduction.doc | 492 +- doc/msg-tuto-src/deployment0.xml | 21 + doc/msg-tuto-src/deployment1.xml | 10 + doc/msg-tuto-src/deployment2.xml | 9 + doc/msg-tuto-src/deployment3.xml | 19 + doc/msg-tuto-src/deployment_general.xml | 9 + doc/msg-tuto-src/masterworker0.c | 157 + doc/msg-tuto-src/masterworker1.c | 179 + doc/msg-tuto-src/masterworker2.c | 176 + doc/msg-tuto-src/masterworker3.c | 179 + doc/msg-tuto-src/masterworker4.c | 209 + doc/msg-tuto-src/platforms/cloud.xml | 158 + doc/msg-tuto-src/platforms/g5k.xml | 565 ++ doc/msg-tuto-src/platforms/griffon.xml | 39 + doc/msg-tuto-src/platforms/peers.xml | 7510 +++++++++++++++++++++++ doc/msg-tuto-src/platforms/platform.xml | 51 + doc/sc3-description.png | Bin 0 -> 43409 bytes 20 files changed, 9778 insertions(+), 9 deletions(-) create mode 100644 doc/msg-tuto-src/deployment0.xml create mode 100644 doc/msg-tuto-src/deployment1.xml create mode 100644 doc/msg-tuto-src/deployment2.xml create mode 100644 doc/msg-tuto-src/deployment3.xml create mode 100644 doc/msg-tuto-src/deployment_general.xml create mode 100644 doc/msg-tuto-src/masterworker0.c create mode 100644 doc/msg-tuto-src/masterworker1.c create mode 100644 doc/msg-tuto-src/masterworker2.c create mode 100644 doc/msg-tuto-src/masterworker3.c create mode 100644 doc/msg-tuto-src/masterworker4.c create mode 100644 doc/msg-tuto-src/platforms/cloud.xml create mode 100644 doc/msg-tuto-src/platforms/g5k.xml create mode 100644 doc/msg-tuto-src/platforms/griffon.xml create mode 100644 doc/msg-tuto-src/platforms/peers.xml create mode 100644 doc/msg-tuto-src/platforms/platform.xml create mode 100644 doc/sc3-description.png diff --git a/buildtools/Cmake/DefinePackages.cmake b/buildtools/Cmake/DefinePackages.cmake index 56fd828081..9c58bb2f7a 100644 --- a/buildtools/Cmake/DefinePackages.cmake +++ b/buildtools/Cmake/DefinePackages.cmake @@ -588,6 +588,7 @@ set(DOC_TOOLS # these files get copied automatically to the html documentation set(DOC_IMG ${CMAKE_HOME_DIRECTORY}/doc/simgrid.css + ${CMAKE_HOME_DIRECTORY}/doc/sc3-description.png ${CMAKE_HOME_DIRECTORY}/doc/webcruft/Paje_MSG_screenshot.jpg ${CMAKE_HOME_DIRECTORY}/doc/webcruft/Paje_MSG_screenshot_thn.jpg ${CMAKE_HOME_DIRECTORY}/doc/webcruft/SGicon.gif diff --git a/buildtools/Cmake/GenerateDoc.cmake b/buildtools/Cmake/GenerateDoc.cmake index 72a2e456db..9b06ae06f2 100644 --- a/buildtools/Cmake/GenerateDoc.cmake +++ b/buildtools/Cmake/GenerateDoc.cmake @@ -49,6 +49,8 @@ if(DOXYGEN_PATH) ADD_CUSTOM_COMMAND(TARGET simgrid_documentation COMMAND ${FIG2DEV_PATH}/fig2dev -Lmap ${CMAKE_HOME_DIRECTORY}/doc/shared/fig/simgrid_modules.fig | perl -pe 's/imagemap/simgrid_modules/g'| perl -pe 's/ ${CMAKE_HOME_DIRECTORY}/doc/simgrid_modules.map + COMMAND pwd + COMMAND ${CMAKE_COMMAND} -E tar cvzf html/msg-tuto-src.tgz msg-tuto-src/ COMMAND ${CMAKE_COMMAND} -E echo "XX Run doxygen" COMMAND ${DOXYGEN_PATH}/doxygen Doxyfile COMMAND ${CMAKE_COMMAND} -E echo "XX Generate the index files" diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index f6d0b20457..7b4be67932 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -708,7 +708,6 @@ INPUT = doxygen/index.doc \ INPUT += @top_srcdir@/examples/msg/sendrecv/sendrecv.c \ @top_srcdir@/examples/msg/masterslave/masterslave_forwarder.c \ - @top_srcdir@/examples/msg/masterslave/masterslave_console.c \ @top_srcdir@/examples/msg/migration \ @top_srcdir@/examples/msg/suspend \ @top_srcdir@/examples/msg/properties \ diff --git a/doc/doxygen/introduction.doc b/doc/doxygen/introduction.doc index 62d52bdbae..6b2fa097a3 100644 --- a/doc/doxygen/introduction.doc +++ b/doc/doxygen/introduction.doc @@ -1,12 +1,6 @@ /*! @page introduction Introduction to SimGrid -This page does not really exist yet. In the meanwhile, please refer -to the tutorials -on the project web page, looking for the -SimGrid -101 tutorial. - -SimGrid is a toolkit +[SimGrid](http://simgrid.gforge.inria.fr/) is a toolkit that provides core functionalities for the simulation of distributed applications in heterogeneous distributed environments. @@ -15,4 +9,486 @@ distributed and parallel application scheduling on distributed computing platforms ranging from simple network of workstations to Computational Grids. -*/ \ No newline at end of file +# Scenario +The goal of this practical session is to illustrate various usage of +the MSG interface. To this end we will use the following simple setting: + +> Assume we have a (possibly large) bunch of (possibly large) data to +> process and which originally reside on a server (a.k.a. master). For +> sake of simplicity, we assume all input file require the same amount +> of computation. We assume the server can be helped by a (possibly +> large) set of worker machines. What is the best way to organize the +> computations ? + +Although this looks like a very simple setting it raises several +interesting questions: + +- Which algorithm should the master use to send workload? + + The most obvious algorithm would be to send tasks to workers in a + round-robin fashion. This is the initial code we provide you. + + A less obvious one but probably more efficient would be to set up + a request mechanism where client first ask for tasks, which allows + the server to decide which request to answer and possibly to send + the tasks to the fastest machines. Maybe you can think of a + smarter mechanism... + +- How much tasks should the client ask for? + + Indeed, if we set up a request mechanism and that workers only + send request whenever they have no more task to process, they are + likely to be poorly exploited since they will have to wait for the + master to consider their request and for the input data to be + transferred. A client should thus probably request a pool of tasks + but if it requests too much task, it is likely to lead to a poor + load-balancing... + +- How is the quality of such algorithm dependent on the platform + characteristics? on the task characteristics? + + Whenever the input communication time is very small compared to + processing time and workers are homogeneous, it is likely that the + round-robin algorithm performs very well. Would it still hold true + when transfer time is not negligible and the platform is, say, + a volunteer computing system ? + +- The network topology interconnecting the master and the workers + may be quite complicated. How does such topology impact the + previous result? + + When data transfers are the bottleneck, it is likely that a good + modeling of the platform becomes essential, in which case, you may + want to be able to account for complex platform topologies. + +- Do the algorithms depend on a perfect knowledge of this + topology? + + Should we still use a flat master worker deployment or should we + use a + +- How is such algorithm sensitive to external workload variation? + + What if bandwidth, latency and power can vary with no warning? + Shouldn't you study whether your algorithm is sensitive to such + load variations? + +- Although an algorithm may be more efficient than another, how + does it interfere with other applications? + + As you can see, this very simple setting may need to evolve way + beyond what you initially imagined. + +
Premature optimization is the root of all evil. -- D.E.Knuth
+ + Furthermore, writing your own simulator is much harder that what you + may imagine. This is why should rely on an established and flexible + one. + +The following figure is a screenshot of [triva][fn:1] visualizing a [SimGrid +simulation][fn:2] of two master worker applications (one in light gray and +the other in dark gray) running in concurrence and showing resource +usage over a long period of time. + +![Test](./sc3-description.png) + +# Prerequisites + +## Tutorials + +A lot of information on how to install and use Simgrid are +available on the [online documentation][fn:4] and in the tutorials: + +- http://simgrid.gforge.inria.fr/tutorials/simgrid-use-101.pdf +- http://simgrid.gforge.inria.fr/tutorials/simgrid-tracing-101.pdf +- http://simgrid.gforge.inria.fr/tutorials/simgrid-platf-101.pdf + +## Installing SimGrid + + sudo apt-get install simgrid + +This tutorial requires simgrid 3.8 at last so you may need to get +the [debian package](http://packages.debian.org/unstable/main/simgrid). Here is a shortcut: + +- AMD64: http://ftp.de.debian.org/debian/pool/main/s/simgrid/simgrid_3.8.1-2_amd64.deb +- i386: http://ftp.de.debian.org/debian/pool/main/s/simgrid/simgrid_3.8.1-2_i386.deb + +Then + +~~~~{.sh} +sudo dpkg -i simgrid_3.8*.deb +~~~~ + +# Recommended Steps + +## Installing Viva + +This [software][fn:1] will be useful to make fancy graph or treemap +visualizations and get a better understanding of simulations. You +will first need to install pajeng: + +~~~~{.sh} +sudo apt-get install git cmake build-essential libqt4-dev libboost-dev freeglut3-dev ; +git clone https://github.com/schnorr/pajeng.git +cd pajeng && mkdir -p build && cd build && cmake ../ -DCMAKE_INSTALL_PREFIX=$HOME && make -j install +cd ../../ +~~~~ + +Then you can install viva. + +~~~~{.sh} +sudo apt-get install libboost-dev libconfig++-dev libconfig8-dev libgtk2.0-dev freeglut3-dev +git clone https://github.com/schnorr/viva.git +cd viva && mkdir -p build_graph && cd build_graph && cmake ../ -DTUPI_LIBRARY=ON -DVIVA=ON -DCMAKE_INSTALL_PREFIX=$HOME && make -j install +cd ../../ +~~~~ + +## Installing Paje + +This [software][fn:5] provides a Gantt-chart visualization. + +~~~~{.sh} +sudo apt-get install paje.app +~~~~ + +## Installing Vite + +This software provides a [Gantt-chart visualization][fn:6]. + +~~~~{.sh} +sudo apt-get install vite +~~~~ + +# Let's get Started +## Setting up and Compiling. + +The corresponding archive with all source files and platform files +can be obtained [here](msg-tuto-src.tgz). + +~~~~{.sh} +tar zxf msg-tuto.tgz +cd msg-tuto/src +make +~~~~ + +As you can see, there is already a nice Makefile that compiles +everything for you. Now the tiny example has been compiled and it +can be easily run as follows: + +~~~~{.sh} +./masterworker0 platforms/platform.xml deployment0.xml 2>&1 +~~~~ + +If you create a single self-content C-file named foo.c, the +corresponding program will be simply compiled and linked with +SimGrid by typing: + +~~~~{.sh} +make foo +~~~~ + +For a more "fancy" output, you can try: + +~~~~{.sh} +./masterworker0 platforms/platform.xml deployment0.xml 2>&1 | simgrid-colorizer +~~~~ + +For a really fancy output, you should use [viva/triva][fn:1]: + +~~~~{.sh} +./masterworker0 platforms/platform.xml deployment0.xml --cfg=tracing:1\ + --cfg=tracing/uncategorized:1 --cfg=viva/uncategorized:uncat.plist +LANG=C ; viva simgrid.trace uncat.plist +~~~~ + +For a more classical Gantt-Chart visualization, you can produce a +[Paje][fn:5] trace: + +~~~~{.sh} +./masterworker0 platforms/platform.xml deployment0.xml --cfg=tracing:1 \ + --cfg=tracing/msg/process:1 +LANG=C ; Paje simgrid.trace +~~~~ + +Alternatively, you can use [vite][fn:6]. + +~~~~{.sh} +./masterworker0 platforms/platform.xml deployment0.xml --cfg=tracing:1\ + --cfg=tracing/msg/process:1 --cfg=tracing/basic:1 +vite simgrid.trace +~~~~ + +## Getting Rid of Workers in the Deployment File + +In the previous example, the deployment file `deployment0.xml` +is tightly connected to the platform file `platform.xml` and a +worker process is launched on each host: + +~~~~{.xml} + + + + + + + + + + + + + + + + + + + + + +~~~~ + +This is ok as the platform is rather small but will be painful when +using larger platforms. Instead, modify the simulator +`masterworker0.c` into `masterworker1.c` so that the master +launches a worker process on all the other machines at startup. The +new deployment file `deployment1.xml` should thus now simply be: + +~~~~{.xml} + + + + + + + + + + +~~~~ + +To this end you may need the following MSG functions, whose +behavior is described in the [online documentation](http://simgrid.gforge.inria.fr/simgrid/3.8.1/ref_guide/html/index.html) (hint: use the +search field to access directly the function you are looking for): + +~~~~{.c} +int MSG_get_host_number (void) +xbt_dynar_t MSG_hosts_as_dynar(void); +void * xbt_dynar_to_array (xbt_dynar_t dynar); +msg_process_t MSG_process_create(const char *name, xbt_main_func_t code, + void *data, msg_host_t host); +~~~~ + +Note that it may avoid bugs later to avoid launching a worker on +the master host so you probably want to remove it from the host +list. + +The `data` field of the `MSG_process_create` can be used to pass +a channel name that will be private between master +and workers (e.g., `master_name:worker_name`). Adding the +`master_name` in the channel name will allow to easily have several +masters and a worker per master on each machine. To this end, you +may need to use the following functions: + +~~~~{.c} +msg_host_t MSG_host_self(void); +const char * MSG_host_get_name(msg_host_t host); +msg_process_t MSG_process_self(void); +void * MSG_process_get_data(msg_process_t process); +~~~~ + +Again, you should check the [online documentation](http://simgrid.gforge.inria.fr/simgrid/3.8.1/ref_guide/html/index.html) +for more information. If you are not too much familiar with string +manipulation in C, you may want to use the following functions + +~~~~{.c} +char *strcpy(char *dest, const char *src); +char *strcat(char *dest, const char *src); +~~~~ + +## Setting up a Time Limit Mechanism + +In the current version, the number of tasks is defined in the +worker arguments. Hence, tasks are created at the very beginning of +the simulation. Instead, create tasks as needed and provide a time +limit indicating when it stops sending tasks. To this end, you will +obviously need to know what time it is[fn:7]: + +~~~~{.c} +double MSG_get_clock(void); +~~~~ + +Otherwise, a quite effective way of terminating the simulation +would be to use some of the following function[fn:7]: + +~~~~{.c} +void MSG_process_kill(msg_process_t process); +int MSG_process_killall(int reset_PIDs); +~~~~ + +Anyway, the new deployment `deployment2.xml` file should thus look +like this: + +~~~~{.xml} + + + + + + + + + +~~~~ + +It may also be a good idea to transform most of the `XBT_INFO` into +`XBT_DEBUG` (e.g., keep the information on the total number of +tasks processed). These debug messages can be activated as follows: + +~~~~{.sh} +./masterworker2 platforms/platform.xml deployment2.xml --log=msg_test.thres:debug +~~~~ + +## Using the Tracing Mechanism + +SimGrid can trace all resource consumption and the outcome can be +displayed with viva as illustrated [[*Setting%20up%20and%20Compiling.][here]]. However, when several +masters are deployed, it is hard to understand what happens. + +~~~~{.xml} + + + + + + + + + + + + + + + + + + + +~~~~ + +So let's use categories to track more precisely who does what and +when[fn:7]. + +~~~~{.c} +void TRACE_category(const char *category); +void MSG_task_set_category (msg_task_t task, const char *category); +~~~~ + +The outcome can then be visualized as follows: + +~~~~{.sh} +./masterworker3 platforms/platform.xml deployment3.xml --cfg=tracing:1\ + --cfg=tracing/categorized:1 --cfg=viva/categorized:viva_cat.plist +LANG=C; viva simgrid.trace viva_cat.plist +~~~~ + +Right now, you should realize that nothing is behaving like you +expect. Most workers are idle even though input data are ridiculous +and there are several masters deployed on the platform. Using a +Gantt-chart visualization may help: + +~~~~{.sh} +./masterworker3 platforms/platform.xml deployment3.xml --cfg=tracing:1 \ + --cfg=tracing/msg/process:1 +LANG=C; Paje simgrid.trace +~~~~ + +OK, so it should now be obvious that round robin is actually +very bad. + +## Improving the Scheduling + +Instead of a round-robin scheduling, let's implement a first-come +first-served mechanism. To this end, workers need to send a tiny +request first. A possible way to implement such a request with MSG +is to send on a specific channel (e.g., the name of the master +name) a task with payload 0 and whose attached data is the worker +name. This way, the master can keep track of which workers are idle +and willing to work. + +To know whether it has pending requests, the master can use the +following function[fn:7]: + +~~~~{.c} +int MSG_task_listen(const char *alias); +~~~~ + +If so, it should get the request and push the corresponding host +into a dynar so that they can later be retrieved when sending a +real task[fn:7]. + +~~~~{.c} +xbt_dynar_t xbt_dynar_new(const unsigned long elm_size, + void_f_pvoid_t const free_f); +void xbt_dynar_push(xbt_dynar_t const dynar, const void *src); +void xbt_dynar_shift(xbt_dynar_t const dynar, void *const dst); +unsigned long xbt_dynar_length(const xbt_dynar_t dynar); +~~~~ + +As you will soon realize, with such simple mechanisms, simple +deadlocks will soon appear. They can easily be removed with a +simple polling mechanism, hence the need for the following +function[fn:7]: + +~~~~{.c} +msg_error_t MSG_process_sleep(double nb_sec); +~~~~ + +As you should quickly realize, on the simple previous example, it +will double the throughput of the platform but will be quite +ineffective when input size of the tasks is not negligible anymore. + +From this, many things can easily be added. For example, you could: +- add a performance measurement mechanism; +- enable the master to make smart scheduling choices using + measurement information; +- allow workers to have several pending requests so as to overlap + communication and computations as much as possible; +- ... + +## Using More Elaborate Platforms + +SimGrid offers a rather powerful platform modeling mechanism. The +`src/platform/` repository comprises a variety of platform ranging +from simple ones to quite elaborated ones. Associated to a good +visualization tool to ensure your simulation is meaningful, they +can allow you to study to which extent your algorithm scales... + +What is the largest number of tasks requiring 50e6 flops and 1e5 +bytes that you manage to distribute and process in one hour on +`g5k.xml` (you should use `deployment_general.xml`)? + +# Points to improve for the next time + +- Propose equivalent exercises and skeleton in java. +- Propose a virtualbox image with everything (simgrid, paje, viva, + ...) already set up. +- Ease the installation on mac OS X (binary installer) and + windows. +- Explain that programming in C or java and having a working + development environment is a prerequisite. + +[fn:1]: http://triva.gforge.inria.fr/index.html +[fn:2]: http://hal.inria.fr/inria-00529569 +[fn:3]: http://hal.inria.fr/hal-00738321 +[fn:4]: http://simgrid.gforge.inria.fr/documentation.html +[fn:5]: http://paje.sourceforge.net/ +[fn:6]: http://vite.gforge.inria.fr/ +[fn:7]: http://simgrid.gforge.inria.fr/simgrid/3.8.1/ref_guide/html/index.html + + + + + +*/ diff --git a/doc/msg-tuto-src/deployment0.xml b/doc/msg-tuto-src/deployment0.xml new file mode 100644 index 0000000000..6d7bae7db8 --- /dev/null +++ b/doc/msg-tuto-src/deployment0.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/msg-tuto-src/deployment1.xml b/doc/msg-tuto-src/deployment1.xml new file mode 100644 index 0000000000..5d8fae4b67 --- /dev/null +++ b/doc/msg-tuto-src/deployment1.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/doc/msg-tuto-src/deployment2.xml b/doc/msg-tuto-src/deployment2.xml new file mode 100644 index 0000000000..fce6c1bc27 --- /dev/null +++ b/doc/msg-tuto-src/deployment2.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/doc/msg-tuto-src/deployment3.xml b/doc/msg-tuto-src/deployment3.xml new file mode 100644 index 0000000000..52ca7213d0 --- /dev/null +++ b/doc/msg-tuto-src/deployment3.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/doc/msg-tuto-src/deployment_general.xml b/doc/msg-tuto-src/deployment_general.xml new file mode 100644 index 0000000000..0f9c44b3a2 --- /dev/null +++ b/doc/msg-tuto-src/deployment_general.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/doc/msg-tuto-src/masterworker0.c b/doc/msg-tuto-src/masterworker0.c new file mode 100644 index 0000000000..519d031281 --- /dev/null +++ b/doc/msg-tuto-src/masterworker0.c @@ -0,0 +1,157 @@ +/* Copyright (c) 2007, 2008, 2009, 2010. 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 +#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" +XBT_LOG_NEW_DEFAULT_CATEGORY(msg_test, + "Messages specific for this msg example"); + +int master(int argc, char *argv[]); +int worker(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 */ + +/** Emitter function */ +int master(int argc, char *argv[]) +{ + int workers_count = 0; + msg_host_t *workers = 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); + } + } + + { /* Process organisation */ + workers_count = argc - 4; + workers = xbt_new0(msg_host_t, workers_count); + + for (i = 4; i < argc; i++) { + workers[i - 4] = MSG_get_host_by_name(argv[i]); + xbt_assert(workers[i - 4] != NULL, "Unknown host %s. Stopping Now! ", + argv[i]); + } + } + + XBT_INFO("Got %d workers and %d tasks to process", workers_count, + number_of_tasks); + + for (i = 0; i < number_of_tasks; i++) { + XBT_INFO("Sending \"%s\" to \"%s\"", + todo[i]->name, MSG_host_get_name(workers[i % workers_count])); + if (MSG_host_self() == workers[i % workers_count]) { + XBT_INFO("Hey ! It's me ! :)"); + } + + MSG_task_send(todo[i], MSG_host_get_name(workers[i % workers_count])); + XBT_INFO("Sent"); + } + + XBT_INFO + ("All tasks have been dispatched. Let's tell everybody the computation is over."); + for (i = 0; i < workers_count; i++) { + msg_task_t finalize = MSG_task_create("finalize", 0, 0, FINALIZE); + MSG_task_send(finalize, MSG_host_get_name(workers[i])); + } + + XBT_INFO("Goodbye now!"); + free(workers); + free(todo); + return 0; +} /* end_of_master */ + +/** Receiver function */ +int worker(int argc, char *argv[]) +{ + msg_task_t task = NULL; + _XBT_GNUC_UNUSED int res; + while (1) { + res = MSG_task_receive(&(task),MSG_host_get_name(MSG_host_self())); + xbt_assert(res == MSG_OK, "MSG_task_receive failed"); + + XBT_INFO("Received \"%s\"", MSG_task_get_name(task)); + if (!strcmp(MSG_task_get_name(task), "finalize")) { + MSG_task_destroy(task); + break; + } + + XBT_INFO("Processing \"%s\"", MSG_task_get_name(task)); + MSG_task_execute(task); + XBT_INFO("\"%s\" done", MSG_task_get_name(task)); + MSG_task_destroy(task); + task = NULL; + } + XBT_INFO("I'm done. See you!"); + return 0; +} /* end_of_worker */ + +/** Test function */ +msg_error_t test_all(const char *platform_file, + const char *application_file) +{ + msg_error_t res = MSG_OK; + + { /* Simulation setting */ + MSG_create_environment(platform_file); + } + { /* Application deployment */ + MSG_function_register("master", master); + MSG_function_register("worker", worker); + MSG_launch_application(application_file); + } + res = MSG_main(); + + XBT_INFO("Simulation time %g", MSG_get_clock()); + return res; +} /* end_of_test_all */ + + +/** Main function */ +int main(int argc, char *argv[]) +{ + msg_error_t res = MSG_OK; + + 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 */ diff --git a/doc/msg-tuto-src/masterworker1.c b/doc/msg-tuto-src/masterworker1.c new file mode 100644 index 0000000000..eb9123241a --- /dev/null +++ b/doc/msg-tuto-src/masterworker1.c @@ -0,0 +1,179 @@ +/* Copyright (c) 2007, 2008, 2009, 2010. 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 +#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" +XBT_LOG_NEW_DEFAULT_CATEGORY(msg_test, + "Messages specific for this msg example"); + +int master(int argc, char *argv[]); +int worker(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 */ + +static char * build_channel_name(char *buffer, const char *sender, const char* receiver) +{ + strcpy(buffer, sender); + strcat(buffer, ":"); + strcat(buffer, receiver); + return buffer; +} + +/** Emitter function */ +int master(int argc, char *argv[]) +{ + int workers_count = 0; + msg_host_t *workers = NULL; + msg_task_t *todo = NULL; + msg_host_t host_self = MSG_host_self(); + char *master_name = (char *) MSG_host_get_name(host_self); + int number_of_tasks = 0; + double task_comp_size = 0; + double task_comm_size = 0; + char channel[1024]; + + 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); + } + } + + { /* Process organisation */ + workers_count = MSG_get_host_number(); + workers = xbt_dynar_to_array(MSG_hosts_as_dynar()); + + for (i = 0; i < workers_count; i++) + if(host_self == workers[i]) { + workers[i] = workers[workers_count-1]; + workers_count--; + break; + } + + for (i = 0; i < workers_count; i++) + MSG_process_create("worker", worker, master_name, workers[i]); + } + + XBT_INFO("Got %d workers and %d tasks to process", workers_count, + number_of_tasks); + + for (i = 0; i < number_of_tasks; i++) { + build_channel_name(channel,master_name, + MSG_host_get_name(workers[i % workers_count])); + + XBT_INFO("Sending \"%s\" to channel \"%s\"", todo[i]->name, channel); + + MSG_task_send(todo[i], channel); + XBT_INFO("Sent"); + } + + XBT_INFO + ("All tasks have been dispatched. Let's tell everybody the computation is over."); + for (i = 0; i < workers_count; i++) { + msg_task_t finalize = MSG_task_create("finalize", 0, 0, FINALIZE); + MSG_task_send(finalize, build_channel_name(channel,master_name, + MSG_host_get_name(workers[i % workers_count]))); + } + + XBT_INFO("Goodbye now!"); + free(workers); + free(todo); + return 0; +} /* end_of_master */ + +/** Receiver function */ +int worker(int argc, char *argv[]) +{ + msg_task_t task = NULL; + _XBT_GNUC_UNUSED int res; + char channel[1024]; + + build_channel_name(channel,MSG_process_get_data(MSG_process_self()), + MSG_host_get_name(MSG_host_self())); + + XBT_INFO("Receiving on channel \"%s\"", channel); + + while (1) { + res = MSG_task_receive(&(task),channel); + xbt_assert(res == MSG_OK, "MSG_task_receive failed"); + + XBT_INFO("Received \"%s\"", MSG_task_get_name(task)); + if (!strcmp(MSG_task_get_name(task), "finalize")) { + MSG_task_destroy(task); + break; + } + + XBT_INFO("Processing \"%s\"", MSG_task_get_name(task)); + MSG_task_execute(task); + XBT_INFO("\"%s\" done", MSG_task_get_name(task)); + MSG_task_destroy(task); + task = NULL; + } + XBT_INFO("I'm done. See you!"); + return 0; +} /* end_of_worker */ + +/** Test function */ +msg_error_t test_all(const char *platform_file, + const char *application_file) +{ + msg_error_t res = MSG_OK; + + { /* Simulation setting */ + MSG_create_environment(platform_file); + } + { /* Application deployment */ + MSG_function_register("master", master); + MSG_function_register("worker", worker); + MSG_launch_application(application_file); + } + res = MSG_main(); + + XBT_INFO("Simulation time %g", MSG_get_clock()); + return res; +} /* end_of_test_all */ + + +/** Main function */ +int main(int argc, char *argv[]) +{ + msg_error_t res = MSG_OK; + + 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 */ diff --git a/doc/msg-tuto-src/masterworker2.c b/doc/msg-tuto-src/masterworker2.c new file mode 100644 index 0000000000..f86a47dcb9 --- /dev/null +++ b/doc/msg-tuto-src/masterworker2.c @@ -0,0 +1,176 @@ +/* Copyright (c) 2007, 2008, 2009, 2010. 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 +#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" +XBT_LOG_NEW_DEFAULT_CATEGORY(msg_test, + "Messages specific for this msg example"); + +int master(int argc, char *argv[]); +int worker(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 */ + +static char * build_channel_name(char *buffer, const char *sender, const char* receiver) +{ + strcpy(buffer, sender); + strcat(buffer, ":"); + strcat(buffer, receiver); + return buffer; +} + +/** Emitter function */ +int master(int argc, char *argv[]) +{ + int workers_count = 0; + msg_host_t *workers = NULL; + msg_task_t *todo = NULL; + msg_host_t host_self = MSG_host_self(); + char *master_name = (char *) MSG_host_get_name(host_self); + double task_comp_size = 0; + double task_comm_size = 0; + char channel[1024]; + double timeout = -1; + + int i; + + _XBT_GNUC_UNUSED int res = sscanf(argv[1], "%lg", &timeout); + 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]); + + { /* Process organisation */ + workers_count = MSG_get_host_number(); + workers = xbt_dynar_to_array(MSG_hosts_as_dynar()); + + for (i = 0; i < workers_count; i++) + if(host_self == workers[i]) { + workers[i] = workers[workers_count-1]; + workers_count--; + break; + } + + for (i = 0; i < workers_count; i++) + MSG_process_create("worker", worker, master_name, workers[i]); + } + + XBT_INFO("Got %d workers and will send tasks for %g seconds!", + workers_count, timeout); + + for (i = 0; 1; i++) { + char sprintf_buffer[64]; + msg_task_t task = NULL; + + if(MSG_get_clock()>timeout) break; + + sprintf(sprintf_buffer, "Task_%d", i); + task = MSG_task_create(sprintf_buffer, task_comp_size, task_comm_size, + NULL); + + build_channel_name(channel,master_name, + MSG_host_get_name(workers[i % workers_count])); + + XBT_DEBUG("Sending \"%s\" to channel \"%s\"", task->name, channel); + MSG_task_send(task, channel); + XBT_DEBUG("Sent"); + } + + int task_num = i; + + XBT_DEBUG + ("All tasks have been dispatched. Let's tell everybody the computation is over."); + for (i = 0; i < workers_count; i++) { + msg_task_t finalize = MSG_task_create("finalize", 0, 0, FINALIZE); + MSG_task_send(finalize, build_channel_name(channel,master_name, + MSG_host_get_name(workers[i % workers_count]))); + } + + XBT_INFO("Sent %d tasks in total!", task_num); + free(workers); + free(todo); + return 0; +} /* end_of_master */ + +/** Receiver function */ +int worker(int argc, char *argv[]) +{ + msg_task_t task = NULL; + _XBT_GNUC_UNUSED int res; + char channel[1024]; + + build_channel_name(channel,MSG_process_get_data(MSG_process_self()), + MSG_host_get_name(MSG_host_self())); + + XBT_DEBUG("Receiving on channel \"%s\"", channel); + + while (1) { + res = MSG_task_receive(&(task),channel); + xbt_assert(res == MSG_OK, "MSG_task_receive failed"); + + XBT_DEBUG("Received \"%s\"", MSG_task_get_name(task)); + if (!strcmp(MSG_task_get_name(task), "finalize")) { + MSG_task_destroy(task); + break; + } + + XBT_DEBUG("Processing \"%s\"", MSG_task_get_name(task)); + MSG_task_execute(task); + XBT_DEBUG("\"%s\" done", MSG_task_get_name(task)); + MSG_task_destroy(task); + task = NULL; + } + XBT_DEBUG("I'm done. See you!"); + return 0; +} /* end_of_worker */ + +/** Test function */ +msg_error_t test_all(const char *platform_file, + const char *application_file) +{ + msg_error_t res = MSG_OK; + + { /* Simulation setting */ + MSG_create_environment(platform_file); + } + { /* Application deployment */ + MSG_function_register("master", master); + MSG_function_register("worker", worker); + MSG_launch_application(application_file); + } + res = MSG_main(); + + XBT_INFO("Simulation time %g", MSG_get_clock()); + return res; +} /* end_of_test_all */ + + +/** Main function */ +int main(int argc, char *argv[]) +{ + msg_error_t res = MSG_OK; + + 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 */ diff --git a/doc/msg-tuto-src/masterworker3.c b/doc/msg-tuto-src/masterworker3.c new file mode 100644 index 0000000000..ca2bee393c --- /dev/null +++ b/doc/msg-tuto-src/masterworker3.c @@ -0,0 +1,179 @@ +/* Copyright (c) 2007, 2008, 2009, 2010. 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 +#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" +XBT_LOG_NEW_DEFAULT_CATEGORY(msg_test, + "Messages specific for this msg example"); + +int master(int argc, char *argv[]); +int worker(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 */ + +static char * build_channel_name(char *buffer, const char *sender, const char* receiver) +{ + strcpy(buffer, sender); + strcat(buffer, ":"); + strcat(buffer, receiver); + return buffer; +} + +/** Emitter function */ +int master(int argc, char *argv[]) +{ + int workers_count = 0; + msg_host_t *workers = NULL; + msg_task_t *todo = NULL; + msg_host_t host_self = MSG_host_self(); + char *master_name = (char *) MSG_host_get_name(host_self); + double task_comp_size = 0; + double task_comm_size = 0; + char channel[1024]; + double timeout = -1; + + int i; + + TRACE_category(master_name); + + _XBT_GNUC_UNUSED int res = sscanf(argv[1], "%lg", &timeout); + 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]); + + { /* Process organisation */ + workers_count = MSG_get_host_number(); + workers = xbt_dynar_to_array(MSG_hosts_as_dynar()); + + for (i = 0; i < workers_count; i++) + if(host_self == workers[i]) { + workers[i] = workers[workers_count-1]; + workers_count--; + break; + } + + for (i = 0; i < workers_count; i++) + MSG_process_create("worker", worker, master_name, workers[i]); + } + + XBT_INFO("Got %d workers and will send tasks for %g seconds!", + workers_count, timeout); + + for (i = 0; 1; i++) { + char sprintf_buffer[64]; + msg_task_t task = NULL; + + if(MSG_get_clock()>timeout) break; + + sprintf(sprintf_buffer, "Task_%d", i); + task = MSG_task_create(sprintf_buffer, task_comp_size, task_comm_size, + NULL); + MSG_task_set_category(task, master_name); + + build_channel_name(channel,master_name, + MSG_host_get_name(workers[i % workers_count])); + + XBT_DEBUG("Sending \"%s\" to channel \"%s\"", task->name, channel); + MSG_task_send(task, channel); + XBT_DEBUG("Sent"); + } + + int task_num = i; + + XBT_DEBUG + ("All tasks have been dispatched. Let's tell everybody the computation is over."); + for (i = 0; i < workers_count; i++) { + msg_task_t finalize = MSG_task_create("finalize", 0, 0, FINALIZE); + MSG_task_send(finalize, build_channel_name(channel,master_name, + MSG_host_get_name(workers[i % workers_count]))); + } + + XBT_INFO("Sent %d tasks in total!", task_num); + free(workers); + free(todo); + return 0; +} /* end_of_master */ + +/** Receiver function */ +int worker(int argc, char *argv[]) +{ + msg_task_t task = NULL; + _XBT_GNUC_UNUSED int res; + char channel[1024]; + + build_channel_name(channel,MSG_process_get_data(MSG_process_self()), + MSG_host_get_name(MSG_host_self())); + + XBT_DEBUG("Receiving on channel \"%s\"", channel); + + while (1) { + res = MSG_task_receive(&(task),channel); + xbt_assert(res == MSG_OK, "MSG_task_get failed"); + + XBT_DEBUG("Received \"%s\"", MSG_task_get_name(task)); + if (!strcmp(MSG_task_get_name(task), "finalize")) { + MSG_task_destroy(task); + break; + } + + XBT_DEBUG("Processing \"%s\"", MSG_task_get_name(task)); + MSG_task_execute(task); + XBT_DEBUG("\"%s\" done", MSG_task_get_name(task)); + MSG_task_destroy(task); + task = NULL; + } + XBT_DEBUG("I'm done. See you!"); + return 0; +} /* end_of_worker */ + +/** Test function */ +msg_error_t test_all(const char *platform_file, + const char *application_file) +{ + msg_error_t res = MSG_OK; + + { /* Simulation setting */ + MSG_create_environment(platform_file); + } + { /* Application deployment */ + MSG_function_register("master", master); + MSG_function_register("worker", worker); + MSG_launch_application(application_file); + } + res = MSG_main(); + + XBT_INFO("Simulation time %g", MSG_get_clock()); + return res; +} /* end_of_test_all */ + + +/** Main function */ +int main(int argc, char *argv[]) +{ + msg_error_t res = MSG_OK; + + 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 */ diff --git a/doc/msg-tuto-src/masterworker4.c b/doc/msg-tuto-src/masterworker4.c new file mode 100644 index 0000000000..24456d6258 --- /dev/null +++ b/doc/msg-tuto-src/masterworker4.c @@ -0,0 +1,209 @@ +/* Copyright (c) 2007, 2008, 2009, 2010. 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 +#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" +XBT_LOG_NEW_DEFAULT_CATEGORY(msg_test, + "Messages specific for this msg example"); + +int master(int argc, char *argv[]); +int worker(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 */ + +static char * build_channel_name(char *buffer, const char *sender, const char* receiver) +{ + strcpy(buffer, sender); + strcat(buffer, ":"); + strcat(buffer, receiver); + return buffer; +} + +/** Emitter function */ +int master(int argc, char *argv[]) +{ + int workers_count = 0; + msg_host_t *workers = NULL; + msg_task_t *todo = NULL; + msg_host_t host_self = MSG_host_self(); + char *master_name = (char *) MSG_host_get_name(host_self); + double task_comp_size = 0; + double task_comm_size = 0; + char channel[1024]; + double timeout = -1; + + int i; + + TRACE_category(master_name); + + _XBT_GNUC_UNUSED int res = sscanf(argv[1], "%lg", &timeout); + 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]); + + { /* Process organisation */ + workers_count = MSG_get_host_number(); + workers = xbt_dynar_to_array(MSG_hosts_as_dynar()); + + for (i = 0; i < workers_count; i++) + if(host_self == workers[i]) { + workers[i] = workers[workers_count-1]; + workers_count--; + break; + } + + for (i = 0; i < workers_count; i++) + MSG_process_create("worker", worker, master_name, workers[i]); + } + + XBT_INFO("Got %d workers and will send tasks for %g seconds!", + workers_count, timeout); + xbt_dynar_t idle_hosts = xbt_dynar_new(sizeof(msg_host_t), NULL); + msg_host_t request_host = NULL; + + for (i = 0; 1;) { + char sprintf_buffer[64]; + msg_task_t task = NULL; + + msg_task_t request = NULL; + while(MSG_task_listen(master_name)) { + res = MSG_task_receive(&(request),master_name); + xbt_assert(res == MSG_OK, "MSG_task_receive failed"); + request_host = MSG_task_get_data(request); + xbt_dynar_push(idle_hosts, &request_host); + MSG_task_destroy(request); + request = NULL; + } + + if(MSG_get_clock()>timeout) { + if(xbt_dynar_length(idle_hosts) == workers_count) break; + else { + MSG_process_sleep(.1); + continue; + } + } + + if(xbt_dynar_length(idle_hosts)<=0) { + /* No request. Let's wait... */ + MSG_process_sleep(.1); + continue; + } + + sprintf(sprintf_buffer, "Task_%d", i); + task = MSG_task_create(sprintf_buffer, task_comp_size, task_comm_size, + NULL); + MSG_task_set_category(task, master_name); + + xbt_dynar_shift(idle_hosts, &request_host); + + build_channel_name(channel,master_name, MSG_host_get_name(request_host)); + + XBT_DEBUG("Sending \"%s\" to channel \"%s\"", task->name, channel); + MSG_task_send(task, channel); + XBT_DEBUG("Sent"); + i++; + } + + int task_num = i; + + XBT_DEBUG + ("All tasks have been dispatched. Let's tell everybody the computation is over."); + for (i = 0; i < workers_count; i++) { + msg_task_t finalize = MSG_task_create("finalize", 0, 0, FINALIZE); + MSG_task_send(finalize, build_channel_name(channel,master_name, + MSG_host_get_name(workers[i % workers_count]))); + } + + XBT_INFO("Sent %d tasks in total!", task_num); + free(workers); + free(todo); + return 0; +} /* end_of_master */ + +/** Receiver function */ +int worker(int argc, char *argv[]) +{ + msg_task_t task = NULL; + _XBT_GNUC_UNUSED int res; + char channel[1024]; + + const char *my_master = MSG_process_get_data(MSG_process_self()); + build_channel_name(channel, my_master, MSG_host_get_name(MSG_host_self())); + + XBT_DEBUG("Receiving on channel \"%s\"", channel); + + while (1) { + /* Send a request */ + msg_task_t request = MSG_task_create("request", 0, 0, MSG_host_self()); + MSG_task_send(request, my_master); + + res = MSG_task_receive(&(task),channel); + xbt_assert(res == MSG_OK, "MSG_task_receive failed"); + + XBT_DEBUG("Received \"%s\"", MSG_task_get_name(task)); + if (!strcmp(MSG_task_get_name(task), "finalize")) { + MSG_task_destroy(task); + break; + } + + XBT_DEBUG("Processing \"%s\"", MSG_task_get_name(task)); + MSG_task_execute(task); + XBT_DEBUG("\"%s\" done", MSG_task_get_name(task)); + MSG_task_destroy(task); + task = NULL; + } + XBT_DEBUG("I'm done. See you!"); + return 0; +} /* end_of_worker */ + +/** Test function */ +msg_error_t test_all(const char *platform_file, + const char *application_file) +{ + msg_error_t res = MSG_OK; + + { /* Simulation setting */ + MSG_create_environment(platform_file); + } + { /* Application deployment */ + MSG_function_register("master", master); + MSG_function_register("worker", worker); + MSG_launch_application(application_file); + } + res = MSG_main(); + + XBT_INFO("Simulation time %g", MSG_get_clock()); + return res; +} /* end_of_test_all */ + + +/** Main function */ +int main(int argc, char *argv[]) +{ + msg_error_t res = MSG_OK; + + 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 */ diff --git a/doc/msg-tuto-src/platforms/cloud.xml b/doc/msg-tuto-src/platforms/cloud.xml new file mode 100644 index 0000000000..df5a88231c --- /dev/null +++ b/doc/msg-tuto-src/platforms/cloud.xml @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/msg-tuto-src/platforms/g5k.xml b/doc/msg-tuto-src/platforms/g5k.xml new file mode 100644 index 0000000000..9d20e6c973 --- /dev/null +++ b/doc/msg-tuto-src/platforms/g5k.xml @@ -0,0 +1,565 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/msg-tuto-src/platforms/griffon.xml b/doc/msg-tuto-src/platforms/griffon.xml new file mode 100644 index 0000000000..1ecc49831a --- /dev/null +++ b/doc/msg-tuto-src/platforms/griffon.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/msg-tuto-src/platforms/peers.xml b/doc/msg-tuto-src/platforms/peers.xml new file mode 100644 index 0000000000..5158ac2ba3 --- /dev/null +++ b/doc/msg-tuto-src/platforms/peers.xml @@ -0,0 +1,7510 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/msg-tuto-src/platforms/platform.xml b/doc/msg-tuto-src/platforms/platform.xml new file mode 100644 index 0000000000..81a1d91fa3 --- /dev/null +++ b/doc/msg-tuto-src/platforms/platform.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/sc3-description.png b/doc/sc3-description.png new file mode 100644 index 0000000000000000000000000000000000000000..0f6aed680bb230b72a225ae6bb6a9d3f10c49060 GIT binary patch literal 43409 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 literal 0 HcmV?d00001 -- 2.20.1