[mpi-21] C++ predefined MPI handles, const, IN/INOUT/OUT, etc.

Jeff Squyres jsquyres at [hidden]
Wed Jan 23 07:04:35 CST 2008



On Jan 23, 2008, at 4:33 AM, Rolf Rabenseifner wrote:

> you are referencing to MPI-1.1, Sect. 2.2.
> The full Chapter 2 of MPI-1.1 is deprecated and substituted by
> the full Chapter 2 of MPI-2.0.
> In the substituting MPI-2.0 Sect. 2.3, there exist the
> following new paragraph:
>  "MPI’s use of IN, OUT and INOUT is intended to indicate to the user
>   how an argument is to be used, but does not provide a rigorous
>   classification that can be translated directly into all language
>   bindings (e.g., INTENT in Fortran 90 bindings or const in C  
> bindings).
>   For instance, the “constant” MPI BOTTOM can usually be passed to OUT
>   buffer arguments. Similarly, MPI STATUS IGNORE can be passed as the
>   OUT status argument."

Ok; I missed that text -- thanks.

So replace every instance of "MPI-1:2.2" in my original text with  
"MPI-2:2.3", where exactly the same special case definition exists.

> My comments and alternative-proposal from Tue, 22 Jan 2008 17:29:51
> was about this paragraph (updated text to reflect also the "IN" of  
> "INOUT"):
>
>> An alternative-proposal would be to add a clarifying sentence in
>> Terms and Conventions, MPI-2.0 Sect. 2.5.1, page 9, line 7:
>> Handle arguments can be marked at INOUT to indicate that the handle
>> itself may be changed by the routine (e.g., in MPI_TYPE_COMMIT),
>> or to indicate that the object referenced by the handle
>   already exists and
>> may be changed but the handle itself is kept unchanged
>> (e.g., MPI_TYPE_SET_NAME).

Per the text in my summary mail (below), I think that that would be  
exactly the wrong thing to say (and it would be redundant with  
MPI-2:2.3).  My point is that this special case definition for [IN]OUT  
should go away if no one can specify the reason why it's there.

Indeed, the text that Rolf cites in MPI-2:2.3 both strengthens and  
weakens my arguments:

  - STRENGTHEN: "MPI's use of IN, OUT and INOUT is intended to  
indicate to the user how an argument is to be used..."
  - WEAKEN: "...but does not provide a rigorous classification that  
can be translated directly into all language bindings (e.g., INTENT in  
Fortran 90 bindings or const in C++ bindings)."

However, the latter part of the sentence can be ignored because it  
says that IN/OUT/INOUT do not *have* to be used as a rigorous  
classification.

This clears the way for the 3 proposals that I sent the other day:

1. Make all the SET_NAME and SET_ERRHANDLER functions have IN MPI  
handle arguments (vs. INOUT) -- by the new sentence in MPI-2:2.3, the  
value of the argument is not being changed by the function call (per  
the already-existing C bindings).  So these are now clearly IN  
arguments.  Also, make the C++ bindings for these functions be const.

2. Restore the "const" to the C++ MPI predefined handles that were  
removed in ballot 2.

3. Make MPI::COMM_WORLD and MPI::COMM_SELF be const.

Additionally, I would like to request/motion/whatever that the "remove  
const from more C++ constants" item be withdrawn from what was  
supposed to be on ballot 3 but got moved to ballot 4.

*** The end goal is to make all the MPI C++ constants be  
"const" (except MPI::BOTTOM, as we discussed in Chicago) and have all  
the SET_NAME and SET_ERRHANDLER methods be const.

Thanks.

- Jeff

> Best regards
> Rolf
>
>
> On Tue, 22 Jan 2008 20:07:05 -0500
> Jeff Squyres <jsquyres_at_[hidden]> wrote:
>> The 3 proposals that I sent about C++ issues are both intertwined and
>> represent a very complex set of issues.
>>
>> Shorter version
>> ===============
>>
>> Does anyone know/remember why the "special case" for the definition  
>> of
>> OUT parameters exists in MPI-1:2.2?
>>
>> I ask because the C++ bindings were modeled off the IN/OUT/INOUT
>> designations of the language neutral bindings.  MPI_COMM_SET_NAME  
>> (and
>> others) use the "special case" definition of the [IN]OUT designation
>> for the MPI communicator handle parameter.  Two facts indicate that  
>> we
>> should either override this INOUT designation for the C++ binding  
>> (and
>> therefore make the method const) and/or revisit the "special case"
>> language in MPI-1:2.2:
>>
>> 1. The C binding does not allow the implementation to change the
>> handle value
>> 2. The following is a valid MPI code:
>>
>>    MPI::Intracomm cxx_comm = MPI::COMM_WORLD;
>>    cxx_comm.Set_name("foo");
>>    MPI::COMM_WORLD.Get_name(name, len);
>>    cout << name << endl;
>>
>>   The output will be "foo" even though we set the name on cxx_comm
>> and retrieved it from MPI::COMM_WORLD ***because the state changed on
>> the underlying MPI object, not the upper-level handles*** (the same  
>> is
>> true for error handlers).
>>
>> Hence, the Set_name() method should be const because the MPI handle
>> will not (and cannot) change.  Similar arguments apply to keeping the
>> MPI predefined C++ handles as "const" (MPI::INT, etc.) -- their  
>> values
>> must never change during execution.  It then follows that unless  
>> there
>> is a good reason for the "special case" language in MPI-1:2.2, it
>> should be removed.
>>
>> Longer version / more details
>> =============================
>>
>> At the heart of the issue seems to be text from MPI-1:2.2 about the
>> definition of IN, OUT, and INOUT parameters to MPI functions.  This
>> text was used to guide many of the decisions about the C++ bindings,
>> such as the const-ness (or not) of C++ methods and MPI predefined C++
>> handles.  The text states:
>>
>> -----
>> * the call uses but does not update an argument marked IN
>> * the call may update an argument marked OUT
>> * the call both uses and updates an argument marked INOUT
>>
>> There is one special case -- if an argument is a handle to an opaque
>> object (these terms are defined in Section 2.4.1) and the object is
>> updated by the procedure call, then the argument is marked OUT.  It  
>> is
>> marked this way even though the handle itself is not modified -- we
>> use the OUT attribute to denote that what the handle _references_ is
>> updated.
>> -----
>>
>> The special case for the OUT definition is important because the C++
>> bindings were created to mimic the IN, OUT, and INOUT behavior in a
>> language that is stricter than C and Fortran: C++ will fail to  
>> compile
>> if an application violates the defined semantics (which is a good
>> thing).
>>
>> *** The big question: does anyone know/remember why this special case
>> *** for the "OUT" definition exists?
>>
>> The special case seems to imply that *explicit* changes to MPI  
>> objects
>> should be marked as an [IN]OUT parameter (e.g., SET_NAME and
>> SET_ERRHANDLER).  Apparently, *implicit* changes to the underlying  
>> MPI
>> object (such as MPI_ISEND) do not count / should be IN (i.e., many  
>> MPI
>> implementation *do* change the state either on the communicator or
>> something related to the communicator when a send or receive is
>> initiated, even though the communicator is an IN argument).
>>
>> But remember that MPI clearly states that the handle is separate from
>> the underlying MPI object.  So why does the binding care if the back-
>> end object is updated?  (regardless of whether the change to the
>> object is explicit or implicit)
>>
>> For example, the language-neutral binding for MPI_COMM_SET_NAME has
>> the communicator as an INOUT argument.  This clearly falls within the
>> "special case" definition because the function semantics explicitly
>> change state on the underlying MPI object.
>>
>> But note that the C binding is "int MPI_Comm_set_name(MPI_Comm
>> comm, ...)". Notice that the comm is passed by value, not by
>> reference.  So even though the language neutral binding called that
>> parameter INOUT, it's not possible for the MPI implementation to
>> change the value of the handle.
>>
>> My claim is that if we want to ensure that the C++ bindings match the
>> C bindings (i.e., that the implementation cannot change the value of
>> the MPI handle), then the method should be const (i.e.,
>> cxx_comm.Set_name(...)) *because the handle value will not, and
>> ***cannot***, change*.
>>
>> Simply put: regardless of language or implementation, MPI handles  
>> must
>> have true handle semantics.  For example:
>>
>>    MPI::Intracomm cxx_comm = MPI::COMM_WORLD;
>>    cxx_comm.Set_name("C++ r00l3z!");
>>
>>    MPI::COMM_WORLD.Get_name(name, len);
>>    cout << name << endl;
>>
>> The above will output "C++ r00l3z!" because cxx_comm and
>> MPI::COMM_WORLD are handles referring to the same underlying
>> communicator.  Hence, the only state that the handles have is  
>> whatever
>> refers to their back-end MPI object.   Having Set_name() be const
>> keeps the *handle* const, not the underlying MPI object.
>>
>> Tying this all together:
>>
>> 1. cxx_comm.Set_name() *cannot* change state on the cxx_comm handle
>> because cxx_comm.Get_name() and MPI::COMM_WORLD.Get_name() must  
>> return
>> the same results (the same is true for error handlers).  Hence,
>> regardless of the implementation of the C++ bindings, the handle  
>> value
>> cannot change.  Therefore, this method (and all the others like it)
>> should be const.
>>
>> 2. As a related issue, if no one can remember why the "special case"
>> exists for OUT, then I think we should remove this text and then
>> change all those INOUT parameters for the functions I cited in my
>> earlier proposal to IN.  This would make the C++ bindings consistent
>> with the IN/OUT/INOUT specifications of the language-neutral  
>> bindings.
>>
>> 3. All the MPI C++ predefined handles should be const for many of the
>> same reasons.  Regardless of what happens to the underlying MPI
>> object, the value of the handle cannot ever change.  This is
>> guaranteed by MPI-2:2.5.4 pages 10 lines 38-41:
>>
>> "All named constants, with the exceptions noted below for Fortran,  
>> can
>> be used in initialization expressions or assignments.  These  
>> constants
>> do not change values during execution.  Opaque objects accessed by
>> constant handles are defined and do not change value between MPI
>> initialization MPI_INIT and MPI completion MPI_FINALIZE."
>>
>> Hence, they should all be "const".
>>
>> -----
>>
>> In short: C++ gives us stronger protections to ensure that
>> applications don't shoot themselves in the foot.  If the MPI
>> predefined handles are const, then statements like "MPI::INT =
>> my_dtype;" will fail to compile.  This is a Good Thing.
>>
>> The original C++ bindings tried to take advantage of const, but  
>> missed
>> a few points.  Ballot two and one of the items in ballot 3  
>> incorrectly
>> tried to fix these points by removing const in several places.  That
>> "fixes" the problem, but removes many of the good qualities that we
>> can get in C++ with "const".  So let's fix the real problem and leave
>> "const" in the C++ bindings.
>>
>> Are you confused yet?  :-)
>>
>> -- 
>> Jeff Squyres
>> Cisco Systems
>>
>> _______________________________________________
>> mpi-21 mailing list
>> mpi-21_at_[hidden]
>> http://lists.cs.uiuc.edu/mailman/listinfo/mpi-21
>
>
>
> Dr. Rolf Rabenseifner . . . . . . . . . .. email rabenseifner_at_[hidden]
> High Performance Computing Center (HLRS) . phone ++49(0)711/685-65530
> University of Stuttgart . . . . . . . . .. fax ++49(0)711 / 685-65832
> Head of Dpmt Parallel Computing . . . www.hlrs.de/people/rabenseifner
> Nobelstr. 19, D-70550 Stuttgart, Germany . (Office: Allmandring 30)
>


-- 
Jeff Squyres
Cisco Systems




More information about the Mpi-21 mailing list