Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add new entry in Release_Notes.
[simgrid.git] / docs / source / app_smpi.rst
1 .. _SMPI_doc:
2
3 ===============================
4 SMPI: Simulate MPI Applications
5 ===============================
6
7 .. raw:: html
8
9    <object id="TOC" data="graphical-toc.svg" type="image/svg+xml"></object>
10    <script>
11    window.onload=function() { // Wait for the SVG to be loaded before changing it
12      var elem=document.querySelector("#TOC").contentDocument.getElementById("SMPIBox")
13      elem.style="opacity:0.93999999;fill:#ff0000;fill-opacity:0.1";
14      elem.style="opacity:0.93999999;fill:#ff0000;fill-opacity:0.1;stroke:#000000;stroke-width:0.35277778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1";
15    }
16    </script>
17    <br/>
18    <br/>
19
20 SMPI enables the study of MPI application by emulating them on top of
21 the SimGrid simulator. This is particularly interesting to study
22 existing MPI applications within the comfort of the simulator.
23
24 To get started with SMPI, you should head to :ref:`the SMPI tutorial
25 <usecase_smpi>`. You may also want to read the `SMPI reference
26 article <https://hal.inria.fr/hal-01415484>`_ or these `introductory
27 slides <http://simgrid.org/tutorials/simgrid-smpi-101.pdf>`_.  If you
28 are new to MPI, you should first take our online `SMPI CourseWare
29 <https://simgrid.github.io/SMPI_CourseWare/>`_. It consists in several
30 projects that progressively introduce the MPI concepts. It proposes to
31 use SimGrid and SMPI to run the experiments, but the learning
32 objectives are centered on MPI itself.
33
34 Our goal is to enable the study of **unmodified MPI applications**.
35 Some constructs and features are still missing, but we can probably
36 add them on demand.  If you already used MPI before, SMPI should sound
37 very familiar to you: Use smpicc instead of mpicc, and smpirun instead
38 of mpirun. The main difference is that smpirun takes a :ref:`simulated
39 platform <platform>` as an extra parameter.
40
41 For **further scalability**, you may modify your code to speed up your
42 studies or save memory space.  Maximal **simulation accuracy**
43 requires some specific care from you.
44
45 -------------------------
46 What can run within SMPI?
47 -------------------------
48
49 You can run unmodified MPI applications (both C/C++ and Fortran) within
50 SMPI, provided that you only use MPI calls that we implemented. Global
51 variables should be handled correctly on Linux systems.
52
53 ....................
54 MPI coverage of SMPI
55 ....................
56
57 SMPI support a large faction of the MPI interface: we pass many of the MPICH coverage tests, and many of the existing
58 :ref:`proxy apps <SMPI_proxy_apps>` run almost unmodified on top of SMPI. But our support is still incomplete, with I/O
59 primitives the being one of the major missing feature.
60
61 The full list of functions that remain to be implemented is documented in the file `include/smpi/smpi.h
62 <https://framagit.org/simgrid/simgrid/tree/master/include/smpi/smpi.h>`_ in your version of SimGrid, between two lines
63 containing the ``FIXME`` marker. If you miss a feature, please get in touch with us: we can guide you through the SimGrid
64 code to help you implementing it, and we'd be glad to integrate your contribution to the main project.
65
66 .. _SMPI_what_globals:
67
68 .................................
69 Privatization of global variables
70 .................................
71
72 Concerning the globals, the problem comes from the fact that usually,
73 MPI processes run as real UNIX processes while they are all folded
74 into threads of a unique system process in SMPI. Global variables are
75 usually private to each MPI process while they become shared between
76 the processes in SMPI.  The problem and some potential solutions are
77 discussed in this article: `Automatic Handling of Global Variables for
78 Multi-threaded MPI Programs
79 <http://charm.cs.illinois.edu/newPapers/11-23/paper.pdf>` (note that
80 this article does not deal with SMPI but with a competing solution
81 called AMPI that suffers of the same issue).  This point used to be
82 problematic in SimGrid, but the problem should now be handled
83 automatically on Linux.
84
85 Older versions of SimGrid came with a script that automatically
86 privatized the globals through static analysis of the source code. But
87 our implementation was not robust enough to be used in production, so
88 it was removed at some point. Currently, SMPI comes with two
89 privatization mechanisms that you can :ref:`select at runtime
90 <cfg=smpi/privatization>`.  The dlopen approach is used by
91 default as it is much faster and still very robust.  The mmap approach
92 is an older approach that proves to be slower.
93
94 With the **mmap approach**, SMPI duplicates and dynamically switch the
95 ``.data`` and ``.bss`` segments of the ELF process when switching the
96 MPI ranks. This allows each ranks to have its own copy of the global
97 variables.  No copy actually occurs as this mechanism uses ``mmap()``
98 for efficiency. This mechanism is considered to be very robust on all
99 systems supporting ``mmap()`` (Linux and most BSDs). Its performance
100 is questionable since each context switch between MPI ranks induces
101 several syscalls to change the ``mmap`` that redirects the ``.data``
102 and ``.bss`` segments to the copies of the new rank. The code will
103 also be copied several times in memory, inducing a slight increase of
104 memory occupation.
105
106 Another limitation is that SMPI only accounts for global variables
107 defined in the executable. If the processes use external global
108 variables from dynamic libraries, they won't be switched
109 correctly. The easiest way to solve this is to statically link against
110 the library with these globals. This way, each MPI rank will get its
111 own copy of these libraries. Of course you should never statically
112 link against the SimGrid library itself.
113
114 With the **dlopen approach**, SMPI loads several copies of the same
115 executable in memory as if it were a library, so that the global
116 variables get naturally duplicated. It first requires the executable
117 to be compiled as a relocatable binary, which is less common for
118 programs than for libraries. But most distributions are now compiled
119 this way for security reason as it allows one to randomize the address
120 space layout. It should thus be safe to compile most (any?) program
121 this way.  The second trick is that the dynamic linker refuses to link
122 the exact same file several times, be it a library or a relocatable
123 executable. It makes perfectly sense in the general case, but we need
124 to circumvent this rule of thumb in our case. To that extend, the
125 binary is copied in a temporary file before being re-linked against.
126 ``dlmopen()`` cannot be used as it only allows 256 contexts, and as it
127 would also duplicate SimGrid itself.
128
129 This approach greatly speeds up the context switching, down to about
130 40 CPU cycles with our raw contexts, instead of requesting several
131 syscalls with the ``mmap()`` approach. Another advantage is that it
132 permits one to run the SMPI contexts in parallel, which is obviously not
133 possible with the ``mmap()`` approach. It was tricky to implement, but
134 we are not aware of any flaws, so smpirun activates it by default.
135
136 In the future, it may be possible to further reduce the memory and
137 disk consumption. It seems that we could `punch holes
138 <https://lwn.net/Articles/415889/>`_ in the files before dl-loading
139 them to remove the code and constants, and mmap these area onto a
140 unique copy. If done correctly, this would reduce the disk- and
141 memory- usage to the bare minimum, and would also reduce the pressure
142 on the CPU instruction cache. See the `relevant bug
143 <https://github.com/simgrid/simgrid/issues/137>`_ on github for
144 implementation leads.\n
145
146 Also, currently, only the binary is copied and dlopen-ed for each MPI
147 rank. We could probably extend this to external dependencies, but for
148 now, any external dependencies must be statically linked into your
149 application. As usual, SimGrid itself shall never be statically linked
150 in your app. You don't want to give a copy of SimGrid to each MPI rank:
151 that's ways too much for them to deal with.
152
153 .. todo: speak of smpi/privatize-libs here
154
155 .. _SMPI_online:
156
157 ---------------------------
158 Online SMPI: live execution
159 ---------------------------
160
161 In this mode, your application is actually executed. Every computation
162 occurs for real while every communication is simulated. In addition,
163 the executions are automatically benchmarked so that their timings can
164 be applied within the simulator.
165
166 SMPI can also go offline by replaying a trace. :ref:`Trace replay
167 <SMPI_offline>` is usually ways faster than online simulation (because
168 the computation are skipped), but it can only applied to applications
169 with constant execution and communication patterns (for the exact same
170 reason).
171
172 ...................
173 Compiling your Code
174 ...................
175
176 If your application is in C, then simply use ``smpicc`` as a
177 compiler just like you use mpicc with other MPI implementations. This
178 script still calls your default compiler (gcc, clang, ...) and adds
179 the right compilation flags along the way. If your application is in
180 C++, Fortran 77 or Fortran 90, use respectively ``smpicxx``,
181 ``smpiff`` or ``smpif90``.
182
183 If you use cmake, set the variables ``MPI_C_COMPILER``, ``MPI_CXX_COMPILER`` and
184 ``MPI_Fortran_COMPILER`` to the full path of smpicc, smpicxx and smpiff (or
185 smpif90), respectively. Example:
186
187 .. code-block:: console
188
189    $ cmake -DMPI_C_COMPILER=/opt/simgrid/bin/smpicc -DMPI_CXX_COMPILER=/opt/simgrid/bin/smpicxx -DMPI_Fortran_COMPILER=/opt/simgrid/bin/smpiff .
190
191 ....................
192 Simulating your Code
193 ....................
194
195 Use the ``smpirun`` script as follows:
196
197 .. code-block:: console
198
199    $ smpirun -hostfile my_hostfile.txt -platform my_platform.xml ./program -blah
200
201 - ``my_hostfile.txt`` is a classical MPI hostfile (that is, this file
202   lists the machines on which the processes must be dispatched, one
203   per line). Using the ``hostname:num_procs`` syntax will deploy num_procs
204   MPI processes on the host, sharing available cores (equivalent to listing
205   the same host num_procs times on different lines).
206 - ``my_platform.xml`` is a classical SimGrid platform file. Of course,
207   the hosts of the hostfile must exist in the provided platform.
208 - ``./program`` is the MPI program to simulate, that you compiled with ``smpicc``
209 - ``-blah`` is a command-line parameter passed to this program.
210
211 ``smpirun`` accepts other parameters, such as ``-np`` if you don't
212 want to use all the hosts defined in the hostfile, ``-map`` to display
213 on which host each rank gets mapped of ``-trace`` to activate the
214 tracing during the simulation. You can get the full list by running
215 ``smpirun -help``
216
217 Finally, you can pass :ref:`any valid SimGrid parameter <options>` to your
218 program. In particular, you can pass ``--cfg=network/model:ns-3`` to
219 switch to use :ref:`models_ns3`. These parameters should be placed after
220 the name of your binary on the command line.
221
222 ...............................
223 Debugging your Code within SMPI
224 ...............................
225
226 If you want to explore the automatic platform and deployment files
227 that are generated by ``smpirun``, add ``-keep-temps`` to the command
228 line.
229
230 You can also run your simulation within valgrind or gdb using the
231 following commands. Once in GDB, each MPI ranks will be represented as
232 a regular thread, and you can explore the state of each of them as
233 usual.
234
235 .. code-block:: console
236
237    $ smpirun -wrapper valgrind ...other args...
238    $ smpirun -wrapper "gdb --args" --cfg=contexts/factory:thread ...other args...
239
240 Some shortcuts are available:
241
242 - ``-gdb`` is equivalent to ``-wrapper "gdb --args" -keep-temps``, to run within gdb debugger
243 - ``-lldb`` is equivalent to ``-wrapper "lldb --" -keep-temps``, to run within lldb debugger
244 - ``-vgdb`` is equivalent to ``-wrapper "valgrind --vgdb=yes --vgdb-error=0" -keep-temps``,
245   to run within valgrind and allow to attach a debugger
246
247 To help locate bottlenecks and largest allocations in the simulated application,
248 the -analyze flag can be passed to smpirun. It will activate
249 :ref:`smpi/display-timing<cfg=smpi/display-timing>` and
250 :ref:`smpi/display-allocs<cfg=smpi/display-allocs>` options and provide hints
251 at the end of execution.
252
253 SMPI will also report MPI handle (Comm, Request, Op, Datatype...) leaks
254 at the end of execution. This can help identify memory leaks that can trigger
255 crashes and slowdowns.
256 By default it only displays the number of leaked items detected.
257 Option :ref:`smpi/list-leaks:n<cfg=smpi/list-leaks>` can be used to display the
258 n first leaks encountered and their type. To get more information, running smpirun
259 with ``-wrapper "valgrind --leak-check=full --track-origins=yes"`` should show
260 the exact origin of leaked handles.
261 Known issue : MPI_Cancel may trigger internal leaks within SMPI.
262
263
264 .. _SMPI_use_colls:
265
266 ................................
267 Simulating Collective Operations
268 ................................
269
270 MPI collective operations are crucial to the performance of MPI
271 applications and must be carefully optimized according to many
272 parameters. Every existing implementation provides several algorithms
273 for each collective operation, and selects by default the best suited
274 one, depending on the sizes sent, the number of nodes, the
275 communicator, or the communication library being used.  These
276 decisions are based on empirical results and theoretical complexity
277 estimation, and are very different between MPI implementations. In
278 most cases, the users can also manually tune the algorithm used for
279 each collective operation.
280
281 SMPI can simulate the behavior of several MPI implementations:
282 OpenMPI, MPICH, `STAR-MPI <http://star-mpi.sourceforge.net/>`_, and
283 MVAPICH2. For that, it provides 115 collective algorithms and several
284 selector algorithms, that were collected directly in the source code
285 of the targeted MPI implementations.
286
287 You can switch the automatic selector through the
288 ``smpi/coll-selector`` configuration item. Possible values:
289
290  - **ompi:** default selection logic of OpenMPI (version 4.1.2)
291  - **mpich**: default selection logic of MPICH (version 3.3b)
292  - **mvapich2**: selection logic of MVAPICH2 (version 1.9) tuned
293    on the Stampede cluster
294  - **impi**: preliminary version of an Intel MPI selector (version
295    4.1.3, also tuned for the Stampede cluster). Due the closed source
296    nature of Intel MPI, some of the algorithms described in the
297    documentation are not available, and are replaced by mvapich ones.
298  - **default**: legacy algorithms used in the earlier days of
299    SimGrid. Do not use for serious perform performance studies.
300
301 .. todo:: default should not even exist.
302
303 ....................
304 Available Algorithms
305 ....................
306
307 You can also pick the algorithm used for each collective with the
308 corresponding configuration item. For example, to use the pairwise
309 alltoall algorithm, one should add ``--cfg=smpi/alltoall:pair`` to the
310 line. This will override the selector (if any) for this algorithm.  It
311 means that the selected algorithm will be used
312
313 .. Warning:: Some collective may require specific conditions to be
314    executed correctly (for instance having a communicator with a power
315    of two number of nodes only), which are currently not enforced by
316    SimGrid. Some crashes can be expected while trying these algorithms
317    with unusual sizes/parameters
318
319 To retrieve the full list of implemented algorithms in your version of SimGrid, simply use ``smpirun --help-coll``.
320
321 MPI_Alltoall
322 ^^^^^^^^^^^^
323
324 Most of these are best described in `STAR-MPI's white paper <https://doi.org/10.1145/1183401.1183431>`_.
325
326 ``default``: naive one, by default. |br|
327 ``ompi``: use openmpi selector for the alltoall operations. |br|
328 ``mpich``: use mpich selector for the alltoall operations. |br|
329 ``mvapich2``: use mvapich2 selector for the alltoall operations. |br|
330 ``impi``: use intel mpi selector for the alltoall operations. |br|
331 ``automatic (experimental)``: use an automatic self-benchmarking algorithm. |br|
332 ``bruck``: Described by Bruck et. al. in `this paper <http://ieeexplore.ieee.org/xpl/articleDetails.jsp?arnumber=642949>`_. |br|
333 ``2dmesh``: organizes the nodes as a two dimensional mesh, and perform allgather along the dimensions. |br|
334 ``3dmesh``: adds a third dimension to the previous algorithm. |br|
335 ``rdb``: recursive doubling``: extends the mesh to a nth dimension, each one containing two nodes. |br|
336 ``pair``: pairwise exchange, only works for power of 2 procs, size-1 steps, each process sends and receives from the same process at each step. |br|
337 ``pair_light_barrier``: same, with small barriers between steps to avoid contention. |br|
338 ``pair_mpi_barrier``: same, with MPI_Barrier used. |br|
339 ``pair_one_barrier``: only one barrier at the beginning. |br|
340 ``ring``: size-1 steps, at each step a process send to process (n+i)%size, and receives from (n-i)%size. |br|
341 ``ring_light_barrier``: same, with small barriers between some phases to avoid contention. |br|
342 ``ring_mpi_barrier``: same, with MPI_Barrier used. |br|
343 ``ring_one_barrier``: only one barrier at the beginning. |br|
344 ``basic_linear``: posts all receives and all sends, starts the communications, and waits for all communication to finish. |br|
345 ``mvapich2_scatter_dest``: isend/irecv with scattered destinations, posting only a few messages at the same time. |br|
346
347 MPI_Alltoallv
348 ^^^^^^^^^^^^^
349
350 ``default``: naive one, by default. |br|
351 ``ompi``: use openmpi selector for the alltoallv operations. |br|
352 ``mpich``: use mpich selector for the alltoallv operations. |br|
353 ``mvapich2``: use mvapich2 selector for the alltoallv operations. |br|
354 ``impi``: use intel mpi selector for the alltoallv operations. |br|
355 ``automatic (experimental)``: use an automatic self-benchmarking algorithm. |br|
356 ``bruck``: same as alltoall. |br|
357 ``pair``: same as alltoall. |br|
358 ``pair_light_barrier``: same as alltoall. |br|
359 ``pair_mpi_barrier``: same as alltoall. |br|
360 ``pair_one_barrier``: same as alltoall. |br|
361 ``ring``: same as alltoall. |br|
362 ``ring_light_barrier``: same as alltoall. |br|
363 ``ring_mpi_barrier``: same as alltoall. |br|
364 ``ring_one_barrier``: same as alltoall. |br|
365 ``ompi_basic_linear``: same as alltoall. |br|
366
367 MPI_Gather
368 ^^^^^^^^^^
369
370 ``default``: naive one, by default. |br|
371 ``ompi``: use openmpi selector for the gather operations. |br|
372 ``mpich``: use mpich selector for the gather operations. |br|
373 ``mvapich2``: use mvapich2 selector for the gather operations. |br|
374 ``impi``: use intel mpi selector for the gather operations. |br|
375 ``automatic (experimental)``: use an automatic self-benchmarking algorithm which will iterate over all implemented versions and output the best. |br|
376 ``ompi_basic_linear``: basic linear algorithm from openmpi, each process sends to the root. |br|
377 ``ompi_binomial``: binomial tree algorithm. |br|
378 ``ompi_linear_sync``: same as basic linear, but with a synchronization at the beginning and message cut into two segments. |br|
379 ``mvapich2_two_level``: SMP-aware version from MVAPICH. Gather first intra-node (defaults to mpich's gather), and then exchange with only one process/node. Use mvapich2 selector to change these to tuned algorithms for Stampede cluster. |br|
380
381 MPI_Barrier
382 ^^^^^^^^^^^
383
384 ``default``: naive one, by default. |br|
385 ``ompi``: use openmpi selector for the barrier operations. |br|
386 ``mpich``: use mpich selector for the barrier operations. |br|
387 ``mvapich2``: use mvapich2 selector for the barrier operations. |br|
388 ``impi``: use intel mpi selector for the barrier operations. |br|
389 ``automatic (experimental)``: use an automatic self-benchmarking algorithm. |br|
390 ``ompi_basic_linear``: all processes send to root. |br|
391 ``ompi_two_procs``: special case for two processes. |br|
392 ``ompi_bruck``: nsteps = sqrt(size), at each step, exchange data with rank-2^k and rank+2^k. |br|
393 ``ompi_recursivedoubling``: recursive doubling algorithm. |br|
394 ``ompi_tree``: recursive doubling type algorithm, with tree structure. |br|
395 ``ompi_doublering``: double ring algorithm. |br|
396 ``mvapich2_pair``: pairwise algorithm. |br|
397 ``mpich_smp``: barrier intra-node, then inter-node. |br|
398
399 MPI_Scatter
400 ^^^^^^^^^^^
401
402 ``default``: naive one, by default. |br|
403 ``ompi``: use openmpi selector for the scatter operations. |br|
404 ``mpich``: use mpich selector for the scatter operations. |br|
405 ``mvapich2``: use mvapich2 selector for the scatter operations. |br|
406 ``impi``: use intel mpi selector for the scatter operations. |br|
407 ``automatic (experimental)``: use an automatic self-benchmarking algorithm. |br|
408 ``ompi_basic_linear``: basic linear scatter. |br|
409 ``ompi_linear_nb``: linear scatter, non blocking sends. |br|
410 ``ompi_binomial``: binomial tree scatter. |br|
411 ``mvapich2_two_level_direct``: SMP aware algorithm, with an intra-node stage (default set to mpich selector), and then a basic linear inter node stage. Use mvapich2 selector to change these to tuned algorithms for Stampede cluster. |br|
412 ``mvapich2_two_level_binomial``: SMP aware algorithm, with an intra-node stage (default set to mpich selector), and then a binomial phase. Use mvapich2 selector to change these to tuned algorithms for Stampede cluster. |br|
413
414 MPI_Reduce
415 ^^^^^^^^^^
416
417 ``default``: naive one, by default. |br|
418 ``ompi``: use openmpi selector for the reduce operations. |br|
419 ``mpich``: use mpich selector for the reduce operations. |br|
420 ``mvapich2``: use mvapich2 selector for the reduce operations. |br|
421 ``impi``: use intel mpi selector for the reduce operations. |br|
422 ``automatic (experimental)``: use an automatic self-benchmarking algorithm. |br|
423 ``arrival_pattern_aware``: root exchanges with the first process to arrive. |br|
424 ``binomial``: uses a binomial tree. |br|
425 ``flat_tree``: uses a flat tree. |br|
426 ``NTSL``: Non-topology-specific pipelined linear-bcast function. |br| 0->1, 1->2 ,2->3, ....., ->last node: in a pipeline fashion, with segments of 8192 bytes. |br|
427 ``scatter_gather``: scatter then gather. |br|
428 ``ompi_chain``: openmpi reduce algorithms are built on the same basis, but the topology is generated differently for each flavor. chain = chain with spacing of size/2, and segment size of 64KB. |br|
429 ``ompi_pipeline``: same with pipeline (chain with spacing of 1), segment size depends on the communicator size and the message size. |br|
430 ``ompi_binary``: same with binary tree, segment size of 32KB. |br|
431 ``ompi_in_order_binary``: same with binary tree, enforcing order on the operations. |br|
432 ``ompi_binomial``: same with binomial algo (redundant with default binomial one in most cases). |br|
433 ``ompi_basic_linear``: basic algorithm, each process sends to root. |br|
434 ``mvapich2_knomial``: k-nomial algorithm. Default factor is 4 (mvapich2 selector adapts it through tuning). |br|
435 ``mvapich2_two_level``: SMP-aware reduce, with default set to mpich both for intra and inter communicators. Use mvapich2 selector to change these to tuned algorithms for Stampede cluster. |br|
436 ``rab``: `Rabenseifner <https://fs.hlrs.de/projects/par/mpi//myreduce.html>`_'s reduce algorithm. |br|
437
438 MPI_Allreduce
439 ^^^^^^^^^^^^^
440
441 ``default``: naive one, by defautl. |br|
442 ``ompi``: use openmpi selector for the allreduce operations. |br|
443 ``mpich``: use mpich selector for the allreduce operations. |br|
444 ``mvapich2``: use mvapich2 selector for the allreduce operations. |br|
445 ``impi``: use intel mpi selector for the allreduce operations. |br|
446 ``automatic (experimental)``: use an automatic self-benchmarking algorithm. |br|
447 ``lr``: logical ring reduce-scatter then logical ring allgather. |br|
448 ``rab1``: variations of the  `Rabenseifner <https://fs.hlrs.de/projects/par/mpi//myreduce.html>`_ algorithm: reduce_scatter then allgather. |br|
449 ``rab2``: variations of the  `Rabenseifner <https://fs.hlrs.de/projects/par/mpi//myreduce.html>`_ algorithm: alltoall then allgather. |br|
450 ``rab_rsag``: variation of the  `Rabenseifner <https://fs.hlrs.de/projects/par/mpi//myreduce.html>`_ algorithm: recursive doubling reduce_scatter then recursive doubling allgather. |br|
451 ``rdb``: recursive doubling. |br|
452 ``smp_binomial``: binomial tree with smp: binomial intra. |br| SMP reduce, inter reduce, inter broadcast then intra broadcast. |br|
453 ``smp_binomial_pipeline``: same with segment size = 4096 bytes. |br|
454 ``smp_rdb``: intra``: binomial allreduce, inter: Recursive doubling allreduce, intra``: binomial broadcast. |br|
455 ``smp_rsag``: intra: binomial allreduce, inter: reduce-scatter, inter:allgather, intra: binomial broadcast. |br|
456 ``smp_rsag_lr``: intra: binomial allreduce, inter: logical ring reduce-scatter, logical ring inter:allgather, intra: binomial broadcast. |br|
457 ``smp_rsag_rab``: intra: binomial allreduce, inter: rab reduce-scatter, rab inter:allgather, intra: binomial broadcast. |br|
458 ``redbcast``: reduce then broadcast, using default or tuned algorithms if specified. |br|
459 ``ompi_ring_segmented``: ring algorithm used by OpenMPI. |br|
460 ``mvapich2_rs``: rdb for small messages, reduce-scatter then allgather else. |br|
461 ``mvapich2_two_level``: SMP-aware algorithm, with mpich as intra algorithm, and rdb as inter (Change this behavior by using mvapich2 selector to use tuned values). |br|
462 ``rab``: default `Rabenseifner <https://fs.hlrs.de/projects/par/mpi//myreduce.html>`_ implementation. |br|
463
464 MPI_Reduce_scatter
465 ^^^^^^^^^^^^^^^^^^
466
467 ``default``: naive one, by default. |br|
468 ``ompi``: use openmpi selector for the reduce_scatter operations. |br|
469 ``mpich``: use mpich selector for the reduce_scatter operations. |br|
470 ``mvapich2``: use mvapich2 selector for the reduce_scatter operations. |br|
471 ``impi``: use intel mpi selector for the reduce_scatter operations. |br|
472 ``automatic (experimental)``: use an automatic self-benchmarking algorithm. |br|
473 ``ompi_basic_recursivehalving``: recursive halving version from OpenMPI. |br|
474 ``ompi_ring``: ring version from OpenMPI. |br|
475 ``ompi_butterfly``: butterfly version from OpenMPI. |br|
476 ``mpich_pair``: pairwise exchange version from MPICH. |br|
477 ``mpich_rdb``: recursive doubling version from MPICH. |br|
478 ``mpich_noncomm``: only works for power of 2 procs, recursive doubling for noncommutative ops. |br|
479
480
481 MPI_Allgather
482 ^^^^^^^^^^^^^
483
484 ``default``: naive one, by default. |br|
485 ``ompi``: use openmpi selector for the allgather operations. |br|
486 ``mpich``: use mpich selector for the allgather operations. |br|
487 ``mvapich2``: use mvapich2 selector for the allgather operations. |br|
488 ``impi``: use intel mpi selector for the allgather operations. |br|
489 ``automatic (experimental)``: use an automatic self-benchmarking algorithm. |br|
490 ``2dmesh``: see alltoall. |br|
491 ``3dmesh``: see alltoall. |br|
492 ``bruck``: Described by Bruck et.al. in <a href="http://ieeexplore.ieee.org/xpl/articleDetails.jsp?arnumber=642949"> Efficient algorithms for all-to-all communications in multiport message-passing systems</a>. |br|
493 ``GB``: Gather - Broadcast (uses tuned version if specified). |br|
494 ``loosely_lr``: Logical Ring with grouping by core (hardcoded, default processes/node: 4). |br|
495 ``NTSLR``: Non Topology Specific Logical Ring. |br|
496 ``NTSLR_NB``: Non Topology Specific Logical Ring, Non Blocking operations. |br|
497 ``pair``: see alltoall. |br|
498 ``rdb``: see alltoall. |br|
499 ``rhv``: only power of 2 number of processes. |br|
500 ``ring``: see alltoall. |br|
501 ``SMP_NTS``: gather to root of each SMP, then every root of each SMP node. post INTER-SMP Sendrecv, then do INTRA-SMP Bcast for each receiving message, using logical ring algorithm (hardcoded, default processes/SMP: 8). |br|
502 ``smp_simple``: gather to root of each SMP, then every root of each SMP node post INTER-SMP Sendrecv, then do INTRA-SMP Bcast for each receiving message, using simple algorithm (hardcoded, default processes/SMP: 8). |br|
503 ``spreading_simple``: from node i, order of communications is i -> i + 1, i -> i + 2, ..., i -> (i + p -1) % P. |br|
504 ``ompi_neighborexchange``: Neighbor Exchange algorithm for allgather. Described by Chen et.al. in  `Performance Evaluation of Allgather Algorithms on Terascale Linux Cluster with Fast Ethernet <http://ieeexplore.ieee.org/xpl/articleDetails.jsp?tp=&arnumber=1592302>`_. |br|
505 ``mvapich2_smp``: SMP aware algorithm, performing intra-node gather, inter-node allgather with one process/node, and bcast intra-node
506
507 MPI_Allgatherv
508 ^^^^^^^^^^^^^^
509
510 ``default``: naive one, by default. |br|
511 ``ompi``: use openmpi selector for the allgatherv operations. |br|
512 ``mpich``: use mpich selector for the allgatherv operations. |br|
513 ``mvapich2``: use mvapich2 selector for the allgatherv operations. |br|
514 ``impi``: use intel mpi selector for the allgatherv operations. |br|
515 ``automatic (experimental)``: use an automatic self-benchmarking algorithm. |br|
516 ``GB``: Gatherv - Broadcast (uses tuned version if specified, but only for Bcast, gatherv is not tuned). |br|
517 ``pair``: see alltoall. |br|
518 ``ring``: see alltoall. |br|
519 ``ompi_neighborexchange``: see allgather. |br|
520 ``ompi_bruck``: see allgather. |br|
521 ``mpich_rdb``: recursive doubling algorithm from MPICH. |br|
522 ``mpich_ring``: ring algorithm from MPICh - performs differently from the  one from STAR-MPI.
523
524 MPI_Bcast
525 ^^^^^^^^^
526
527 ``default``: naive one, by default. |br|
528 ``ompi``: use openmpi selector for the bcast operations. |br|
529 ``mpich``: use mpich selector for the bcast operations. |br|
530 ``mvapich2``: use mvapich2 selector for the bcast operations. |br|
531 ``impi``: use intel mpi selector for the bcast operations. |br|
532 ``automatic (experimental)``: use an automatic self-benchmarking algorithm. |br|
533 ``arrival_pattern_aware``: root exchanges with the first process to arrive. |br|
534 ``arrival_pattern_aware_wait``: same with slight variation. |br|
535 ``binomial_tree``: binomial tree exchange. |br|
536 ``flattree``: flat tree exchange. |br|
537 ``flattree_pipeline``: flat tree exchange, message split into 8192 bytes pieces. |br|
538 ``NTSB``: Non-topology-specific pipelined binary tree with 8192 bytes pieces. |br|
539 ``NTSL``: Non-topology-specific pipelined linear with 8192 bytes pieces. |br|
540 ``NTSL_Isend``: Non-topology-specific pipelined linear with 8192 bytes pieces, asynchronous communications. |br|
541 ``scatter_LR_allgather``: scatter followed by logical ring allgather. |br|
542 ``scatter_rdb_allgather``: scatter followed by recursive doubling allgather. |br|
543 ``arrival_scatter``: arrival pattern aware scatter-allgather. |br|
544 ``SMP_binary``: binary tree algorithm with 8 cores/SMP. |br|
545 ``SMP_binomial``: binomial tree algorithm with 8 cores/SMP. |br|
546 ``SMP_linear``: linear algorithm with 8 cores/SMP. |br|
547 ``ompi_split_bintree``: binary tree algorithm from OpenMPI, with message split in 8192 bytes pieces. |br|
548 ``ompi_pipeline``: pipeline algorithm from OpenMPI, with message split in 128KB pieces. |br|
549 ``mvapich2_inter_node``: Inter node default mvapich worker. |br|
550 ``mvapich2_intra_node``: Intra node default mvapich worker. |br|
551 ``mvapich2_knomial_intra_node``:  k-nomial intra node default mvapich worker. default factor is 4.
552
553 Automatic Evaluation
554 ^^^^^^^^^^^^^^^^^^^^
555
556 .. warning:: This is still very experimental.
557
558 An automatic version is available for each collective (or even as a selector). This specific
559 version will loop over all other implemented algorithm for this particular collective, and apply
560 them while benchmarking the time taken for each process. It will then output the quickest for
561 each process, and the global quickest. This is still unstable, and a few algorithms which need
562 specific number of nodes may crash.
563
564 Adding an algorithm
565 ^^^^^^^^^^^^^^^^^^^
566
567 To add a new algorithm, one should check in the src/smpi/colls folder
568 how other algorithms are coded. Using plain MPI code inside SimGrid
569 can't be done, so algorithms have to be changed to use smpi version of
570 the calls instead (MPI_Send will become smpi_mpi_send). Some functions
571 may have different signatures than their MPI counterpart, please check
572 the other algorithms or contact us using the `>SimGrid
573 user mailing list <https://sympa.inria.fr/sympa/info/simgrid-community>`_,
574 or on `>Mattermost <https://framateam.org/simgrid/channels/town-square>`_.
575
576 Example: adding a "pair" version of the Alltoall collective.
577
578  - Implement it in a file called alltoall-pair.c in the src/smpi/colls folder. This file should include colls_private.hpp.
579
580  - The name of the new algorithm function should be smpi_coll_tuned_alltoall_pair, with the same signature as MPI_Alltoall.
581
582  - Once the adaptation to SMPI code is done, add a reference to the file ("src/smpi/colls/alltoall-pair.c") in the SMPI_SRC part of the DefinePackages.cmake file inside buildtools/cmake, to allow the file to be built and distributed.
583
584  - To register the new version of the algorithm, simply add a line to the corresponding macro in src/smpi/colls/cools.h ( add a "COLL_APPLY(action, COLL_ALLTOALL_SIG, pair)" to the COLL_ALLTOALLS macro ). The algorithm should now be compiled and be selected when using --cfg=smpi/alltoall:pair at runtime.
585
586  - To add a test for the algorithm inside SimGrid's test suite, juste add the new algorithm name in the ALLTOALL_COLL list found inside teshsuite/smpi/CMakeLists.txt . When running ctest, a test for the new algorithm should be generated and executed. If it does not pass, please check your code or contact us.
587
588  - Please submit your patch for inclusion in SMPI, for example through a pull request on GitHub or directly per email.
589
590
591 Tracing of Internal Communications
592 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
593
594 By default, the collective operations are traced as a unique operation
595 because tracing all point-to-point communications composing them could
596 result in overloaded, hard to interpret traces. If you want to debug
597 and compare collective algorithms, you should set the
598 ``tracing/smpi/internals`` configuration item to 1 instead of 0.
599
600 Here are examples of two alltoall collective algorithms runs on 16 nodes,
601 the first one with a ring algorithm, the second with a pairwise one.
602
603 .. image:: /img/smpi_simgrid_alltoall_ring_16.png
604    :align: center
605
606 Alltoall on 16 Nodes with the Ring Algorithm.
607
608 .. image:: /img/smpi_simgrid_alltoall_pair_16.png
609    :align: center
610
611 Alltoall on 16 Nodes with the Pairwise Algorithm.
612
613 .. _SMPI_mix_s4u:
614
615 .............................
616 Mixing S4U and MPI simulation
617 .............................
618
619 Mixing both interfaces is very easy. This can be useful to easily implement a service in S4U that is provided by your
620 infrastructure in some way, and test how your MPI application interacts with this service. Or you can use it to start more than
621 one MPI application in your simulation, and study their interactions. For that, you just need to use
622 :cpp:ref:`SMPI_app_instance_register` in a regular S4U program, as shown in the example below. Compile it as usual (with gcc or
623 g++, **not** smpicc) and execute it directly (**not** with smpirun).
624
625 .. doxygenfunction:: SMPI_app_instance_start
626
627 .. tabs::
628
629    .. group-tab:: Example
630
631       Here is a simple example of use, which starts the function ``alltoall_mpi`` as a MPI instance on 4 hosts, along several
632       S4U actors doing a master/workers.
633
634       .. showfile:: examples/smpi/smpi_s4u_masterworker/masterworker_mailbox_smpi.cpp
635          :language: cpp
636
637    .. group-tab:: Deployment file
638
639       .. showfile:: examples/smpi/smpi_s4u_masterworker/deployment_masterworker_mailbox_smpi.xml
640          :language: xml
641
642 ..............................................
643 Adapting your MPI code for further scalability
644 ..............................................
645
646 As detailed in the `reference article
647 <http://hal.inria.fr/hal-01415484>`_, you may want to adapt your code
648 to improve the simulation performance. But these tricks may seriously
649 hinder the result quality (or even prevent the app to run) if used
650 wrongly. We assume that if you want to simulate an HPC application,
651 you know what you are doing. Don't prove us wrong!
652
653 Reducing your memory footprint
654 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
655
656 If you get short on memory (the whole app is executed on a single node when
657 simulated), you should have a look at the SMPI_SHARED_MALLOC and
658 SMPI_SHARED_FREE macros. It allows one to share memory areas between processes: The
659 purpose of these macro is that the same line malloc on each process will point
660 to the exact same memory area. So if you have a malloc of 2M and you have 16
661 processes, this macro will change your memory consumption from 2M*16 to 2M
662 only. Only one block for all processes.
663
664 If your program is ok with a block containing garbage value because all
665 processes write and read to the same place without any kind of coordination,
666 then this macro can dramatically shrink your memory consumption. For example,
667 that will be very beneficial to a matrix multiplication code, as all blocks will
668 be stored on the same area. Of course, the resulting computations will useless,
669 but you can still study the application behavior this way.
670
671 Naturally, this won't work if your code is data-dependent. For example, a Jacobi
672 iterative computation depends on the result computed by the code to detect
673 convergence conditions, so turning them into garbage by sharing the same memory
674 area between processes does not seem very wise. You cannot use the
675 SMPI_SHARED_MALLOC macro in this case, sorry.
676
677 This feature is demoed by the example file
678 `examples/smpi/NAS/dt.c <https://framagit.org/simgrid/simgrid/tree/master/examples/smpi/NAS/dt.c>`_
679
680 .. _SMPI_use_faster:
681
682 Toward Faster Simulations
683 ^^^^^^^^^^^^^^^^^^^^^^^^^
684
685 If your application is too slow, try using SMPI_SAMPLE_LOCAL,
686 SMPI_SAMPLE_GLOBAL and friends to indicate which computation loops can
687 be sampled. Some of the loop iterations will be executed to measure
688 their duration, and this duration will be used for the subsequent
689 iterations. These samples are done per processor with
690 SMPI_SAMPLE_LOCAL, and shared between all processors with
691 SMPI_SAMPLE_GLOBAL. Of course, none of this will work if the execution
692 time of your loop iteration are not stable. If some parameters have an
693 incidence on the timing of a kernel, and if they are reused often
694 (same kernel launched with a few different sizes during the run, for example),
695 SMPI_SAMPLE_LOCAL_TAG and SMPI_SAMPLE_GLOBAL_TAG can be used, with a tag
696 as last parameter, to differentiate between calls. The tag is a character
697 chain crafted by the user, with a maximum size of 128, and should include
698 what is necessary to group calls of a given size together.
699
700 This feature is demoed by the example file
701 `examples/smpi/NAS/ep.c <https://framagit.org/simgrid/simgrid/tree/master/examples/smpi/NAS/ep.c>`_
702
703 Ensuring Accurate Simulations
704 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
705
706 Out of the box, SimGrid may give you fairly accurate results, but
707 there is a plenty of factors that could go wrong and make your results
708 inaccurate or even plainly wrong. Actually, you can only get accurate
709 results of a nicely built model, including both the system hardware
710 and your application. Such models are hard to pass over and reuse in
711 other settings, because elements that are not relevant to an
712 application (say, the latency of point-to-point communications,
713 collective operation implementation details or CPU-network
714 interaction) may be irrelevant to another application. The dream of
715 the perfect model, encompassing every aspects is only a chimera, as
716 the only perfect model of the reality is the reality. If you go for
717 simulation, then you have to ignore some irrelevant aspects of the
718 reality, but which aspects are irrelevant is actually
719 application-dependent...
720
721 The only way to assess whether your settings provide accurate results
722 is to double-check these results. If possible, you should first run
723 the same experiment in simulation and in real life, gathering as much
724 information as you can. Try to understand the discrepancies in the
725 results that you observe between both settings (visualization can be
726 precious for that). Then, try to modify your model (of the platform,
727 of the collective operations) to reduce the most preeminent differences.
728
729 If the discrepancies come from the computing time, try adapting the
730 ``smpi/host-speed``: reduce it if your simulation runs faster than in
731 reality. If the error come from the communication, then you need to
732 fiddle with your platform file.
733
734 Be inventive in your modeling. Don't be afraid if the names given by
735 SimGrid does not match the real names: we got very good results by
736 modeling multicore/GPU machines with a set of separate hosts
737 interconnected with very fast networks (but don't trust your model
738 because it has the right names in the right place either).
739
740 Finally, you may want to check `this article
741 <https://hal.inria.fr/hal-00907887>`_ on the classical pitfalls in
742 modeling distributed systems.
743
744 .. _SMPI_proxy_apps:
745
746 ......................
747 Examples of SMPI Usage
748 ......................
749
750 A small amount of examples can be found directly in the SimGrid
751 archive, under `examples/smpi <https://framagit.org/simgrid/simgrid/-/tree/master/examples/smpi>`_.
752 Some show how to simply run MPI code in SimGrid, how to use the
753 tracing/replay mechanism or how to use plugins written in S4U to
754 extend the simulator abilities.
755
756 Another source of examples lay in the SimGrid archive, under
757 `teshsuite/smpi <https://framagit.org/simgrid/simgrid/-/tree/master/examples/smpi>`_.
758 They are not in the ``examples`` directory because they probably don't
759 constitute pedagogical examples. Instead, they are intended to stress
760 our implementation during the tests. Some of you may be interested
761 anyway.
762
763 But the best source of SMPI examples is certainly the `proxy app
764 <https://framagit.org/simgrid/SMPI-proxy-apps>`_ external project.
765 Proxy apps are scale models of real, massive HPC applications: each of
766 them exhibits the same communication and computation patterns than the
767 massive application that it stands for. But they last only a few
768 thousands lines instead of some millions of lines. These proxy apps
769 are usually provided for educational purpose, and also to ensure that
770 the represented large HPC applications will correctly work with the
771 next generation of runtimes and hardware. `This project
772 <https://framagit.org/simgrid/SMPI-proxy-apps>`_ gathers proxy apps
773 from different sources, along with the patches needed (if any) to run
774 them on top of SMPI.
775
776 .. _SMPI_offline:
777
778 --------------------------
779 Offline SMPI: Trace Replay
780 --------------------------
781
782 Although SMPI is often used for :ref:`online simulation
783 <SMPI_online>`, where the application is executed for real, you can
784 also go for offline simulation through trace replay.
785
786 SimGrid uses time-independent traces, in which each actor is given a
787 script of the actions to do sequentially. These trace files can
788 actually be captured with the online version of SMPI, as follows:
789
790 .. code-block:: console
791
792    $ smpirun -trace-ti --cfg=tracing/filename:LU.A.32 -np 32 -platform ../cluster_backbone.xml bin/lu.A.32
793
794 The produced trace is composed of a file ``LU.A.32`` and a folder
795 ``LU.A.32_files``. The file names don't match with the MPI ranks, but
796 that's expected.
797
798 To replay this with SMPI, you need to first compile the provided
799 ``smpi_replay.cpp`` file, that comes from
800 `simgrid/examples/smpi/replay
801 <https://framagit.org/simgrid/simgrid/tree/master/examples/smpi/replay>`_.
802
803 .. code-block:: console
804
805    $ smpicxx ../replay.cpp -O3 -o ../smpi_replay
806
807 Afterward, you can replay your trace in SMPI as follows:
808
809 .. code-block:: console
810
811    $ smpirun -np 32 -platform ../cluster_torus.xml -ext smpi_replay ../smpi_replay LU.A.32
812
813 All the outputs are gone, as the application is not really simulated
814 here. Its trace is simply replayed. But if you visualize the live
815 simulation and the replay, you will see that the behavior is
816 unchanged. The simulation does not run much faster on this very
817 example, but this becomes very interesting when your application
818 is computationally hungry.
819
820 -------------------------
821 Troubleshooting with SMPI
822 -------------------------
823
824 .........................................
825 ./configure or cmake refuse to use smpicc
826 .........................................
827
828 If your configuration script (such as ``./configure`` or ``cmake``) reports that the compiler is not
829 functional or that you are cross-compiling, try to define the
830 ``SMPI_PRETEND_CC`` environment variable before running the
831 configuration.
832
833 .. code-block:: console
834
835    $ SMPI_PRETEND_CC=1 ./configure # here come the configure parameters
836    $ make
837
838 Indeed, the programs compiled with ``smpicc`` cannot be executed
839 without ``smpirun`` (they are shared libraries and do weird things on
840 startup), while configure wants to test them directly.  With
841 ``SMPI_PRETEND_CC`` smpicc does not compile as shared, and the SMPI
842 initialization stops and returns 0 before doing anything that would
843 fail without ``smpirun``.
844
845 .. warning::
846
847   Make sure that SMPI_PRETEND_CC is only set when calling the configuration script but
848   not during the actual execution, or any program compiled with smpicc
849   will stop before starting.
850
851 .....................................................
852 ./configure or cmake do not pick smpicc as a compiler
853 .....................................................
854
855 In addition to the previous answers, some projects also need to be
856 explicitly told what compiler to use, as follows:
857
858 .. code-block:: console
859
860    $ SMPI_PRETEND_CC=1 cmake CC=smpicc # here come the other configure parameters
861    $ make
862
863 Maybe your configure is using another variable, such as ``cc`` (in
864 lower case) or similar. Just check the logs.
865
866 .....................................
867 error: unknown type name 'useconds_t'
868 .....................................
869
870 Try to add ``-D_GNU_SOURCE`` to your compilation line to get rid
871 of that error.
872
873 The reason is that SMPI provides its own version of ``usleep(3)``
874 to override it and to block in the simulation world, not in the real
875 one. It needs the ``useconds_t`` type for that, which is declared
876 only if you declare ``_GNU_SOURCE`` before including
877 ``unistd.h``. If your project includes that header file before
878 SMPI, then you need to ensure that you pass the right configuration
879 defines as advised above.
880
881 .. |br| raw:: html
882
883    <br />