MPI defines the following basic data types, from which all other data types can be derived:
MPI_INT on IA32.
MPI\_UNSIGNED on IA32.
MPI_LONG_LONG_INT.
These basic types can then be used to construct new, more elaborate
data structures, by calling MPI type constructors. The type constructors
characterize all these new data structures simply in terms of
a type map, which is a list of pairs, each of which comprises
a type and a displacement:
This is a very low level characterization of the data structure and it is likely to lack portability between, e.g., 32-bit and 64-bit systems - due to, e.g., different meanings of ``long'' and ``long long'' on these systems.
The secret to writing portable programs is never
to assume any lengths and instead to call sizeof whenever
you need to use the lengths of various types in your code.
You can then help yourself by calling MPI address and extent functions
to check on the exact locations of various items in the structures.
The locations may not always be what you think, because in some cases
the data may have to be aligned at word or half-word boundaries,
in which case the compiler may pad the data, i.e., insert empty
space between, e.g., a character and the half-word boundary.
Following the last typed data item in the structure, located
at some displacement, we may still find some padding, if the
data structure has to be aligned with the word (half-word) boundary.
Consider the following example:
Let us call this object
MPI_Datatype new_typeThis new MPI type comprises five blocks of the following items.
MPI_LB and zero
length, and its displacement from the beginning of the structure
is zero bytes.
MPI_UB
and zero length, and its displacement from the beginning of the structure
is 20 bytes.
Now we convert this verbal description into the following call to function MPI_Type_create_struct as follows:
MPI_Type_create_struct(5, array_of_block_lengths, array_of_displacements,
array_of_types, &new_type);
wherearray_of_block_lengths = (1, 2, 2, 1, 1) array_of_displacements = (0, 4, 8, 16, 20) array_of_types = (MPI_LB, MPI_CHAR, MPI_FLOAT, MPI_SHORT, MPI_UB)
Observe that if this MPI structure corresponds to some C-language structure in your program, it is your responsibility, as the programmer, to ensure that the two are indeed the same.
MPI_Type_create_struct is an MPI-2 function.
This same function is called
MPI_Type_struct
in MPI-1.
In order to find out how a C-language structure is laid out in the memory
of your computer
you can use function
MPI_Get_address
in combination with sizeof.
Consider, for example, the following C-language (not an MPI) structure:
typedef struct {
char flavor;
char color;
int charge;
double mass;
double x, y, z;
double px, py, pz;
} Quark;
Quark tau;
To find how this structure should be described to MPI, you could do
something like:
int quark_address, flavor_address, color_address, charge_address, mass_address,
x_address, y_address, z_address, px_address, py_address, pz_address;
int flavor_offset, color_offset, charge_offset, mass_offset, ...
...
MPI_Get_address(&tau, &tau_address);
MPI_Get_address(&tau.flavor, &flavor_address);
MPI_Get_address(&tau.color, &color_address);
MPI_Get_address(&tau.charge, &charge_address);
MPI_Get_address(&tau.mass, &mass_address);
...
flavor_offset = flavor_address - tau_address;
color_offset = color_address - tau_address;
charge_offset = charge_address - tau_address;
mass_offset = mass_address - tau_address;
...
Then having these numbers in hand and using sizeof to get sizes
of char, double, etc., you would describe this structure
to MPI by calling MPI_Type_create_struct with appropriate parameters.
MPI_Get_address is an MPI-2 function.
There is an identical function in MPI-1, which is
called
MPI_Address.
MPI_Type_create_struct is one of the more general type constructors in
MPI. There are more specific constructors, of which we have already
encountered
MPI_Type_contiguous and
MPI_Type_vector .
A type constructor, which is somewhere in between
MPI_Type_create_struct and MPI_Type_vector
is
MPI_Type_indexed.
It is like MPI_Type_vector, meaning that it works with data
items of the same type, but as in MPI_Type_struct the data
can be placed at quite arbitrary locations in memory, not necessarily
with a regular stride and regular block length.