-
Notifications
You must be signed in to change notification settings - Fork 7
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
Improve ABI for identifying an MPI implementation #159
Comments
Greetings Simon; thanks for the suggestion. I wonder if you can clarify something for me, because I'm not entirely sure I understand the problem you're trying to solve. You want to fix the length of the string that is returned by Specifically: I'm trying to understand why it would be necessary to have this as a fixed length. Are you trying to ship a binary with a fixed-length buffer for calling |
@jsquyres They want to get away from requiring a C compiler...
|
To clarify: I don't want to fix the length, I just want to specify an upperbound, so that allocating a buffer of that length would be sufficient and guaranteed not to cause a buffer overflow. Since the C version of
The constant Unfortunately in the case of MPI this is complicated by the lack of a standard ABI (e.g. the size and alignment of types like Now that most MPI installations are ABI compatible with one of MPICH, OpenMPI or Microsoft MPI, if we can identify the implementation without needing to invoke a C compiler, then we can provide pre-generated files specifying the necessary types and constants, and fallback to our current code generation machinery only in the cases where it does not conform to one of those. |
An alternative could be a query function int MPI_Get_max_library_version_string(int *length) MPI_Get_max_library_version_string(length, ierror)
INTEGER, INTENT(OUT) :: length
INTEGER, OPTIONAL, INTENT(OUT) :: ierror MPI_GET_MAX_LIBRARY_VERSION_STRING(LENGTH, IERROR)
INTEGER LENGTH, IERROR |
I think if larger changes are under consideration, I would prefer something that could address point 2 as well: one example would be making the version string available via an |
Ok, that's a fair point: you want to be able to have some information that is available to C and Fortran at compile time, but is not necessarily available at run time (e.g., in Open MPI's case, To be more multi-language friendly, I'd actually take @omor1's proposal and raise you: have a symbol that can be used to find all such compile-time values (not just
struct MPI_Constants_t {
MAX_LIBRARY_VERSION_STRING,
// ...others
} MPI_Constants = {
.MAX_LIBRARY_VERSION_STRING = implementation_specific_value,
// ...others
}
I hear you on this one: the situation just plain sucks. There's unfortunately too much historical baggage here -- MPI was not designed with an ABI in the beginning; it's hard to reverse-graft an ABI on to 25+ years of software and design. MPI v4.0 is all but in the bag, and ABI didn't make the cut. I think the next best hope is MPI-5.0, and the potential for more-than-C-and-Fortran native bindings. |
Thanks @jsquyres, that would work for the constants C |
I don't quite understand, probably because I don't know enough about how other languages (e.g., Julia) work. The MPI handles (e.g., MPI_COMM_WORLD) are defined to be run-time values. Open MPI's handles are pointers to static objects, and are therefore effectively only retrievable at run-time. MPICH's handles just happen to be integers. Regardless, this scheme was not designed such that applications should know or care what the value of these handles are. My assumption is that you are looking for a way to get the values of these handles into Julia -- correct? If so, is there an interact-with-C mechanism in Julia such that you can effectively either bind a Julia value to a C value (like Fortran), or at least load a Julia value from a C value? |
We have figured out a reasonably robust way of getting the values of the handles: we determine the Fortran constants (which are C integers), then at |
There was a discussion previous in #137 regarding whether C MPI programs that do not include the |
I think that the Forum is amenable to keeping the door open to other languages. Indeed, there's groups working on opening the door wider in future revisions of the MPI spec. So let's keep having the conversation here... 😄 In Julia, is there no way to get the size of a C type? (again, forgive my ignorance here) What do you need the alignment for? Julia shouldn't be creating new MPI handles -- you should always be getting them from C, right? |
Julia knows the sizes of the builtin C types, and you can construct Julia types which match arbitrary C types in size and alignment, but there is no way to figure out how a C type is defined without parsing the header (which requires a C compiler).
Alignment is dependent on how the handle type is defined (e.g. a struct containing two 32-bit integers has different alignment than a 64-bit pointer). My point was that if you want to make the ABI queryable, you would need to know both size and alignment of the various handles. You could expose these via the proposed That said, I think a more robust solution would be to define a mechanism by which implementations could identify their ABI, and then leave it up to them to specify it how they wish. |
On a related note: another recent pain point we were experiencing is that there does not appear to be a consistent mechanism for determining whether an MPI implementation supports the CUDA-aware interface (OpenMPI provides |
Agreed that this is an important conversation—just pointing out that the current standard makes that somewhat difficult. I know that when I was working on a binding for Apple's Swift language around three years ago I basically resorted to wrapping around all the functions and constants with inline functions so as to force a common ABI (the Swift–C interface had issues with function-like macros in Open MPI and imported enums as the Swift type I don't know if a similar technique works for Julia, since it seems that its C integration uses a different mechanism than Swift.
Any GPU interoperability is incredibly implementation-specific and not specified by the standard. The are currently no proposals to add such support to the standard as far as I know. Querying for extensions might be a useful addition actually, but that should definitely be discussed in a different issue. A workaround might be to use |
Regarding C MPI handles—the standard actually restricts how they can be implemented. On page 13 (MPI-3.1 §2.5.1) the following is stated:
The only types in C that supports these are pointers and arithmetic types. Now I suppose an implementation could technically use |
I think that this is boiling down to two important questions:
I think that @dalcinl is also interested in such things. |
@jsquyres A maximum level of ABI exposure should allow a third party library to access ALL of MPI by just doing
I don't think this is really too much work for implementors. And as I said, I have a pure Python-based reimplementation of mpi4py that can be used to test ABI features (and run all of mpi4py's testsuite, which, as you may remember, is quite picky and tests for almost all of the MPI API). Anything missing in my list above would be relatively easy to catch using my Python stuff. Right now, my alternative mpi4py implementation (not public yet) is not functional in ABI mode, simply because there is no MPI exposing a full ABI interface. I'm using Python's Just my two cents... |
Thanks for the details.
By "dylib entry point", do you mean "something you can find via a specific Also, in your comments, are you referring to "ABI" as "the guaranteed-to-be-the-same parts of an MPI implementation that can be used to discover what you need to know about the not-guaranteed-to-be-the-same parts of an MPI implementation"? If so, I like that idea quite a lot. 😄
Let me ask a larger question: given that we're talking about breaking the 1:1 correspondence between C and <...any other language binding...>, is it necessary for the C usage of
Can you clarify: are you looking for a golden "empty" (in the MPI sense of the word) MPI_Status that you can use to compare to other statuses to see if they, too, are empty?
Sessions is coming. 😄 MPI-4 isn't going to contain everything that was envisioned for Sessions, but work will proceed for Sessions beyond MPI-4. |
Note that the integer constants can be also be implemented as macros (or enums). I think that technically most or all MPI implementations actually violate the standard on this point (or at least my interpretation of it), as they implement the various handle constants via macros as well. i.e. most (or all?) implementations don't actually have a symbol named e.g. I'm referring to MPI-3.1 §A.1.1 pp. 669:
I agree with this; using |
Yes.
ABI-friendly functions maybe would be enough. But is it worth the complication? Why don't you just export symbols? Also, this way, there is little room for MPI implementors to screw things 😆. Note that Note that my proposal is not really an ABI proposal. A real ABI proposal would involve making all implementations agree on the values of these constants. Good look with that! And even then, the implementation of builtin handles as constants may be tricky for Open MPI.
I'm not sure I understood your question. My proposal is an ABI interface for
Maybe not deprecate, but discourage its use in new code such that profiling libraries may benefit from the intercepting these calls.
If C had "constructors" in the C++ sense, how would you code the default constructor for In [1]: from mpi4py import MPI
In [2]: s = MPI.Status()
In [3]: assert s.Get_source() == MPI.ANY_SOURCE
In [4]: assert s.Get_tag() == MPI.ANY_TAG
In [5]: assert s.Get_error() == MPI.SUCCESS
In [6]: assert s.Is_cancelled() == False
In [7]: assert s.Get_count(MPI.BYTE) == False |
I have to agree with the idea of having MPI_Status setters/getters for each of the predefined fields {MPI_SOURCE, MPI_TAG, and MPI_ERROR}. Note that while the MPI spec defines these fields, it does NOT specify an order in which these appear in the structure. Nor does it specify any additional information such as structure size. One might assume that the structure size for example, might be fairly standard but you'd be wrong. HPMPI is/was 32 bytes, MPICH1.2 was 16 bytes, MPICH3.0 is 20 bytes as is OpenMPI, and SGI is 24 bytes. For purely interpreted wrappers that don't include "mpi.h" to understand the actual MPI structure layouts, having setter/getter functions to these "opaque" objects would actually go a long way in enabling progress on MPI ABI development (in my opinion). |
Thanks, Jeff.
I think this is an interesting direction, and I’m encouraged by the flexibility in the solution. It would be great to continue to discuss the needs as well.
One of the many constituencies for MPI are users that need low latency for communications. MPI (the standard) is designed to permit low-overhead implementations. It isn’t perfect at this, but has been good enough for many users and applications. This is something to remember while looking on API changes to support different forms of ABI.
Bill
William Gropp
Director and Chief Scientist, NCSA
Thomas M. Siebel Chair in Computer Science
University of Illinois Urbana-Champaign
… On Feb 4, 2020, at 9:17 AM, Jeff Squyres ***@***.***> wrote:
I think that this is boiling down to two important questions:
In the current generation of MPI implementations, what is needed to allow third-party bindings packages discover what they need to know about the back-end C implementation?
Handles and constants are one set of things. Are there more?
We might want to have a separate discussion about this somewhere (another GitHub issue? a Webex? ...?), since it's not really a Forum-level issue.
In the next generation standard (and by consequence, MPI implementations), what is needed to allow "pluggable" bindings packages to integrate with MPI implementations?
E.g., what standardized hooks are necessary to allow a third-party bindings package for language XYZ to integrate with a given MPI implementation?
The question may ultimately be relevant to things other than third-party bindings packages, but bindings packages seem like a good place to start.
I think that @dalcinl <https://github.com/dalcinl> is also interested in such things.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub <#159?email_source=notifications&email_token=ADJFGZRMZUATGA23EYE2VR3RBGBHVA5CNFSM4KLU7HG2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEKX7UYA#issuecomment-581958240>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/ADJFGZQQF3WHIGK67J2JMTDRBGBHVANCNFSM4KLU7HGQ>.
|
I appreciate that there is a lot more that could be done, but given the large amount of effort required I would again request that my original proposal of specifying a maximum length be considered. We currently use this assumption in our codebase: |
Standardizing https://github.com/jeffhammond/blog/blob/main/MPI_Needs_ABI_Part_2.md#the-mpi_status-object Forcing users to user new APIs to query a struct is absurd. We've defined the public fields for decades. Yeah, it sucks that implementers will have to do some hard work here, but users outnumber implementers by orders-of-magnitude, and there is no excuse to keep pushing all the pain of not having an ABI onto thousands of users to placate 10 MPI maintainers. |
Flawless... I agree with every bit. |
Problem
I realise the specification of an MPI ABI is a very complicated endeavour, but as a very small step in this direction, I would like to propose that there be an ABI for identifying a particular MPI implementation.
This is important when using MPI with other languages: I am one of the maintainers of the Julia language MPI bindings, and one of the biggest difficulties is identifying which implementation of MPI is being used. At the moment, we compile a small C program to identify the MPI implementation and the necessary constants, but this has many drawbacks in terms of usability (namely that it requires a C compiler, and makes it difficult to switch between versions).
MPI_Get_library_version
can currently be used to identify an implementation, but it is not well specified as a C ABI as it is not possible to determine the following without parsing a header file:MPI_MAX_LIBRARY_VERSION_STRING
from the header file)stdcall
)Proposal
Point 1 could easily be addressed by adding in the specification the maximum value of
MPI_MAX_LIBRARY_VERSION_STRING
: the largest value I have seen is 8192 used by mpich.Point 2 is more difficult to standardize, since it is much more platform specific. However it only affects one implementation on one platform, and on that platform it appears to be the dominant implementation, so this is less of an issue. If anyone does have a suggestion for solving this, I would be grateful.
Changes to the Text
Impact on Implementation
As far as I know, this should not affect any implementations. If it does, the value can be chosen to be larger.
Impact on Users
This will make it easier to develop MPI bindings in languages other than C or Fortran, which in turn should improve user experience.
References
There is some discussion of this problem in JuliaParallel/MPI.jl#169.
The text was updated successfully, but these errors were encountered: