6e0974bbc3
refs #92
137 lines
4.9 KiB
Plaintext
137 lines
4.9 KiB
Plaintext
[section:tutorial Tutorial]
|
|
|
|
A Boost.MPI program consists of many cooperating processes (possibly
|
|
running on different computers) that communicate among themselves by
|
|
passing messages. Boost.MPI is a library (as is the lower-level MPI),
|
|
not a language, so the first step in a Boost.MPI is to create an
|
|
[classref boost::mpi::environment mpi::environment] object
|
|
that initializes the MPI environment and enables communication among
|
|
the processes. The [classref boost::mpi::environment
|
|
mpi::environment] object is initialized with the program arguments
|
|
(which it may modify) in your main program. The creation of this
|
|
object initializes MPI, and its destruction will finalize MPI. In the
|
|
vast majority of Boost.MPI programs, an instance of [classref
|
|
boost::mpi::environment mpi::environment] will be declared
|
|
in `main` at the very beginning of the program.
|
|
[warning
|
|
Declaring an [classref boost::mpi::environment mpi::environment] at global scope is undefined behavior.
|
|
[footnote According to the MPI standard, initialization must take place at user's initiative after once the main function has been called.]
|
|
]
|
|
|
|
Communication with MPI always occurs over a *communicator*,
|
|
which can be created be simply default-constructing an object of type
|
|
[classref boost::mpi::communicator mpi::communicator]. This
|
|
communicator can then be queried to determine how many processes are
|
|
running (the "size" of the communicator) and to give a unique number
|
|
to each process, from zero to the size of the communicator (i.e., the
|
|
"rank" of the process):
|
|
|
|
#include <boost/mpi/environment.hpp>
|
|
#include <boost/mpi/communicator.hpp>
|
|
#include <iostream>
|
|
namespace mpi = boost::mpi;
|
|
|
|
int main()
|
|
{
|
|
mpi::environment env;
|
|
mpi::communicator world;
|
|
std::cout << "I am process " << world.rank() << " of " << world.size()
|
|
<< "." << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
If you run this program with 7 processes, for instance, you will
|
|
receive output such as:
|
|
|
|
[pre
|
|
I am process 5 of 7.
|
|
I am process 0 of 7.
|
|
I am process 1 of 7.
|
|
I am process 6 of 7.
|
|
I am process 2 of 7.
|
|
I am process 4 of 7.
|
|
I am process 3 of 7.
|
|
]
|
|
|
|
Of course, the processes can execute in a different order each time,
|
|
so the ranks might not be strictly increasing. More interestingly, the
|
|
text could come out completely garbled, because one process can start
|
|
writing "I am a process" before another process has finished writing
|
|
"of 7.".
|
|
|
|
If you should still have an MPI library supporting only MPI 1.1 you
|
|
will need to pass the command line arguments to the environment
|
|
constructor as shown in this example:
|
|
|
|
#include <boost/mpi/environment.hpp>
|
|
#include <boost/mpi/communicator.hpp>
|
|
#include <iostream>
|
|
namespace mpi = boost::mpi;
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
mpi::environment env(argc, argv);
|
|
mpi::communicator world;
|
|
std::cout << "I am process " << world.rank() << " of " << world.size()
|
|
<< "." << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
[include point_to_point.qbk]
|
|
[include collective.qbk]
|
|
[include user_data_types.qbk]
|
|
[include communicator.qbk]
|
|
[include threading.qbk]
|
|
[include skeleton_and_content.qbk]
|
|
|
|
[section:performance_optimizations Performance optimizations]
|
|
[section:serialization_optimizations Serialization optimizations]
|
|
|
|
To obtain optimal performance for small fixed-length data types not containing
|
|
any pointers it is very important to mark them using the type traits of
|
|
Boost.MPI and Boost.Serialization.
|
|
|
|
It was already discussed that fixed length types containing no pointers can be
|
|
using as [classref
|
|
boost::mpi::is_mpi_datatype `is_mpi_datatype`], e.g.:
|
|
|
|
namespace boost { namespace mpi {
|
|
template <>
|
|
struct is_mpi_datatype<gps_position> : mpl::true_ { };
|
|
} }
|
|
|
|
or the equivalent macro
|
|
|
|
BOOST_IS_MPI_DATATYPE(gps_position)
|
|
|
|
In addition it can give a substantial performance gain to turn off tracking
|
|
and versioning for these types, if no pointers to these types are used, by
|
|
using the traits classes or helper macros of Boost.Serialization:
|
|
|
|
BOOST_CLASS_TRACKING(gps_position,track_never)
|
|
BOOST_CLASS_IMPLEMENTATION(gps_position,object_serializable)
|
|
|
|
[endsect:serialization_optimizations]
|
|
|
|
[section:homogeneous_machines Homogeneous Machines]
|
|
|
|
More optimizations are possible on homogeneous machines, by avoiding
|
|
MPI_Pack/MPI_Unpack calls but using direct bitwise copy. This feature is
|
|
enabled by default by defining the macro [macroref BOOST_MPI_HOMOGENEOUS] in the include
|
|
file `boost/mpi/config.hpp`.
|
|
That definition must be consistent when building Boost.MPI and
|
|
when building the application.
|
|
|
|
In addition all classes need to be marked both as is_mpi_datatype and
|
|
as is_bitwise_serializable, by using the helper macro of Boost.Serialization:
|
|
|
|
BOOST_IS_BITWISE_SERIALIZABLE(gps_position)
|
|
|
|
Usually it is safe to serialize a class for which is_mpi_datatype is true
|
|
by using binary copy of the bits. The exception are classes for which
|
|
some members should be skipped for serialization.
|
|
|
|
[endsect:homogeneous_machines]
|
|
[endsect:performance_optimizations]
|
|
[endsect:tutorial]
|