Logo AND Algorithmique Numérique Distribuée

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