Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

datatype: map builtin MPI datatypes to internal types #7264

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

hzhou
Copy link
Contributor

@hzhou hzhou commented Jan 15, 2025

Pull Request Description

Many of the MPI Datatypes are redundant, for example, MPI_INT, MPI_INT32_t, MPI_INTEGER. The new ABI proposal requires setting some of these types at runtime, for example, MPI_Abi_set_fortran_info. In this PR, we create a set of fixed-size internal datatypes and then map all external builtin types to internal ones. This allows runtime setting and resetting any builtin types. And internally, we only need to support a fixed set.

/* Internal supported types
 * The handle bit pattern follows the convention of builtin types, except
 * the last two bytes are type categories rather than indexes.
 *
 * Internally we support FIXED, SIGNED, UNSIGNED, FLOAT, and COMPLEX.
 * Other types can be added when supported, e.g. bfloat16 or logicals that
 * doesn't follow the C convention of zero/nonzero.
 */
#define MPIR_TYPE_FIXED         0x80    /* communication-only, op not supported */
#define MPIR_TYPE_SIGNED        0x81    /* including C boolean */
#define MPIR_TYPE_UNSIGNED      0x82
#define MPIR_TYPE_FLOAT         0x83    /* C native floating point */
#define MPIR_TYPE_COMPLEX       0x84    /* 2 C native floating point */
/* Pair types support communication and MPI_MINLOC and MPI_MAXLOC ops. The 1st value type
 * is SIGNED, UNSIGNED, FLOAT, COMPLEX as defined above. We add a mask for pair types.
 * E.g. MPI_FLOATINT become MPIR_TYPE_FLOAT | MPIR_TYPE_PAIR_MASK */
#define MPIR_TYPE_PAIR_MASK      0x10   /* the 2nd type is C int */
#define MPIR_TYPE_PAIR2_MASK     0x20   /* the 2nd type is the same as 1st type, e.g. MPI_2REAL */


#define MPIR_FIXED0            ((MPI_Datatype)0x4c000080)       /* 0-size, internally equivallent to MPI_DATATYPE_NULL */
#define MPIR_FIXED1            ((MPI_Datatype)0x4c000180)
#define MPIR_FIXED2            ((MPI_Datatype)0x4c000280)
#define MPIR_FIXED4            ((MPI_Datatype)0x4c000480)
#define MPIR_FIXED8            ((MPI_Datatype)0x4c000880)
#define MPIR_FIXED16           ((MPI_Datatype)0x4c001080)
#define MPIR_SIGNED_INT1       ((MPI_Datatype)0x4c000181)
#define MPIR_SIGNED_INT2       ((MPI_Datatype)0x4c000281)
#define MPIR_SIGNED_INT4       ((MPI_Datatype)0x4c000481)
#define MPIR_SIGNED_INT8       ((MPI_Datatype)0x4c000881)
#define MPIR_SIGNED_INT16      ((MPI_Datatype)0x4c001081)
#define MPIR_UNSIGNED_INT1     ((MPI_Datatype)0x4c000182)
#define MPIR_UNSIGNED_INT2     ((MPI_Datatype)0x4c000282)
#define MPIR_UNSIGNED_INT4     ((MPI_Datatype)0x4c000482)
#define MPIR_UNSIGNED_INT8     ((MPI_Datatype)0x4c000882)
#define MPIR_UNSIGNED_INT16    ((MPI_Datatype)0x4c001082)
#define MPIR_FLOAT1            ((MPI_Datatype)0x4c000183)
#define MPIR_FLOAT2            ((MPI_Datatype)0x4c000283)
#define MPIR_FLOAT4            ((MPI_Datatype)0x4c000483)
#define MPIR_FLOAT8            ((MPI_Datatype)0x4c000883)
#define MPIR_FLOAT16           ((MPI_Datatype)0x4c001083)
#define MPIR_COMPLEX2          ((MPI_Datatype)0x4c000284)
#define MPIR_COMPLEX4          ((MPI_Datatype)0x4c000484)
#define MPIR_COMPLEX8          ((MPI_Datatype)0x4c000884)
#define MPIR_COMPLEX16         ((MPI_Datatype)0x4c001084)
#define MPIR_COMPLEX32         ((MPI_Datatype)0x4c002084)


extern MPI_Datatype MPIR_Internal_types[];
#define MPIR_DATATYPE_REPLACE_BUILTIN(type) \
    do { \
        if (HANDLE_IS_BUILTIN(type)) { \
            (type) = MPIR_Internal_types[(type) & 0xff]; \
        } \
    } while (0)

Discussion

  • For communication routines, such as MPI_Send, MPI_Bcast, we can replace builtin datatypes with MPIR_FIXED#, since all we care is the data size.
  • For reduction routines, such as MPI_Reduce, MPI_Accumulate, we can replace builtin datatypes with internal types (but not MPIR_FIXED#)
  • For datatype creation routines, I think we can replace all builtin "oldtype" with MPIR_FIXED#. We don't need worry about reduction op because we'll always rely on user op for them.
  • NOTE: once we convert to internal types, we'll not be able to perform strict type matching validation, such as matching MPI_INT to MPI_FLOAT. But we don't perform such validation today anyway. It is an extra overhead that we can't afford. In principle, we could perform strict type matching under e.g. --enable-error-checking=2

[skip warnings]

Author Checklist

  • Provide Description
    Particularly focus on why, not what. Reference background, issues, test failures, xfail entries, etc.
  • Commits Follow Good Practice
    Commits are self-contained and do not do two things at once.
    Commit message is of the form: module: short description
    Commit message explains what's in the commit.
  • Passes All Tests
    Whitespace checker. Warnings test. Additional tests via comments.
  • Contribution Agreement
    For non-Argonne authors, check contribution agreement.
    If necessary, request an explicit comment from your companies PR approval manager.

configure.ac Outdated Show resolved Hide resolved
configure.ac Outdated Show resolved Hide resolved
hzhou added 6 commits January 16, 2025 17:50
Many builtin or predefined datatypes are equivalent. Define a list of
supported internal types and map predefined datatypes to internal
datatypes. This way, internally we only need support a fixed list of
datatypes.
Add op support for internal types such as MPIR_SIGNED_INT8 etc.
So that internally we only deal with fixed types.

FIXME: type creation routines should swap types at a later stage so the
get_content still work correctly.
For v/w collectives with array inputs, we need array dimensions for
parameter validation and potential large count swap. Get the dimension
at the front of the function to avoid duplicating code.

Note: we need this dimension for swapping input datatype with internal
datatype.
We need allocate local arrays for swapping large count array inputs. Use
MPIR_CHLMEM_MALLOC simplifies the checking of MPL_free.
Swap builtin datatyps with internal builtins upon user input, so that
internally we deal with a fixed set of builtin datatypes.

TODO: handle the swap for datatype creation routines inside the impl
functions. This is because we need report the original input datatypes
in MPI_Type_get_contents.
hzhou added 4 commits January 16, 2025 22:08
For example, map MPI_INT to MPIR_SIGNED_INT4 at configure and init time,
and internally only deal with MPIR_SIGNED_INT4.
It is unnecessary. And internal types don't have corresponding
datatype structures.
The external builtin datatypes, e.g. MPI_INT, may be reconfigured at
runtime. This won't be the case practically, but it is possibility by
design, so that all MPI builtin datatypes, MPI_INT or MPI_INTEGER, are
treated the same.
Reorder the MPI datatype definitions according to their builtin index.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants