From treumann@XXXXXXXXXX Tue Jan 8 14:41:22 2008 Delivered-To: mpifrm-mpi-21-outgoing@XXXXXXXXXXXXXXXXXXXXXXX X-Original-To: mpifrm-mpi-21@XXXXXXXXXXXXXXXXXXXXXXX Delivered-To: mpifrm-mpi-21@XXXXXXXXXXXXXXXXXXXXXXX In-Reply-To: <6B68D01C00C9994A8E150183E62A119E6F9B5DF269@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX> Subject: RE: [mpi-21] Proposal EH2: add const keyword to the C bindings To: mpi-21@XXXXXXXXXXXXX X-Mailer: Lotus Notes Release 7.0 HF277 June 21, 2006 From: Richard Treumann Date: Tue, 8 Jan 2008 15:40:20 -0500 X-MIMETrack: Serialize by Router on D01ML064/01/M/IBM(Release 7.0.2FP2 IGS702FP2HF5|November 8, 2007) at 01/08/2008 15:40:24 MIME-Version: 1.0 Content-type: multipart/alternative; Boundary="0__=0ABBF959DFFECF818f9e8a93df938690918c0ABBF959DFFECF81" Content-Disposition: inline X-Virus-Scanned: by amavisd-new-20030616-p10 (Debian) at mailbouncer.mcs.anl.gov Sender: owner-mpi-21@XXXXXXXXXXXXX Precedence: bulk Reply-To: mpi-21@XXXXXXXXXXXXX X-Virus-Scanned: by amavisd-new-20030616-p10 (Debian) at mailbouncer.mcs.anl.gov X-Spam-Status: No, hits=-0.4 tagged_above=-1.0 required=5.3 tests=AWL, BAYES_00, HTML_10_20, HTML_MESSAGE X-Spam-Level: --0__=0ABBF959DFFECF818f9e8a93df938690918c0ABBF959DFFECF81 Content-type: text/plain; charset=US-ASCII Content-transfer-encoding: quoted-printable This whole discussion will quickly get convoluted. When a block of code that has a function call (MPI_Isend) is compiled a= nd some data structure (buf[]) that is used in that block of code is passe= d by reference to the function (without const), the compiler must make the pessimistic assumption that any part of that data structure could be changed by the time the call returns. If there is a subexpression tha= t involves data from buf[] that was evaluated before the call to MPI_Send= , it must be evaluated again after the return. If MPI_Send promises buf[] i= s const then the compiler can skip the re-evaluation. With const, the compiler may act on the expectation buf[] does not chan= ge. The earlier MPI_Irecv call in the example passed buf[1] and that means buf[1] can change any time between the entry to MPI_Irecv and the retur= n from MPI_Wait. You cannot even assume it will not change in the MPI_Ire= cv call. For this reason, the MPI rules forbid reading buf[1] between the MPI_Irecv and the MPI_Wait. If the block of code that contains the MPI_= Send call is making any use of buf[1] at the time of the call then it is in violation of MPI rules anyway. It will lead to trouble on some MPI implementation whether buf[] is labeled const or not on the MPI_Send. T= he value of buf[1] can change asynchronously any time between MPI_Irecv an= d MPI_Wait without any need for a function call. The MPI rules presumably would allow the block of code to access buf[0]= and buf[2] before and after the call to MPI_Send and the MPI_Send will not change buf[0] or buf[2]. The practical effect of labeling buf[] const = will be correct as long as the MPI rules are followed and there is no code i= n the vicinity that references buf[1]. The Forum will need to decide if it is worth debating the precise meani= ng of const or whether there is an actual situation where the const labe= l is dangerous as long as MPI rules are followed. It seem to me labeling buf= [] const can do no harm as long as the application follows the rules with respect to the outstanding MPI_Irecv. Dick Dick Treumann - MPI Team/TCEM IBM Systems & Technology Group Dept 0lva / MS P963 -- 2455 South Road -- Poughkeepsie, NY 12601 Tele (845) 433-7846 Fax (845) 433-8363 owner-mpi-21@mpi-forum.org wrote on 01/08/2008 11:54:46 AM: > The MPI_Send function is not modifying the buf[] using the send > buffer pointer *passed in* to the MPI_Send function, but rather > buf[]is modified as a side effect of some other function call. > > This is perfectly alright and inline with the *const* keyword > definition. The *const* keyword does not guarantees that the object > will not be modified; it guarantees that it will not be modified > using the passed in pointer (directly or indirectly). > > Thanks, > .Erez > > -----Original Message----- > From: owner-mpi-21@mpi-forum.org [mailto:owner-mpi-21@mpi-forum.org] > On Behalf Of Hubert Ritzdorf > Sent: Tuesday, January 08, 2008 7:45 AM > To: mpi-21@mpi-forum.org > Subject: Re: [mpi-21] Proposal EH2: add const keyword to the C bindin= gs > > > > Erez Haba wrote: > > The const keyword semantic as defined by C and C++ is still > correct for the example you described below. > > > The ISO C standard (ISO/IEC 9899:1999) says in section 6.7.3 Semantic= s 5: > > If an attempt is made to modify an object defined with a const-qualif= ied > type through use > of an lvalue with non-const-qualified type, the behavior is undefined= . > > The C object is "buf[]" (including all elements) and if MPI_Send() wo= uld > change > this const-qualified object, the behavior should be undefined and not= > portable > (Annex J "Portability issues"). > > Hubert > > The "const" keyword is a contract saying that the object with the > memory layout as defined by the interface (MPI_Send) is guaranteed > no to be changed by the function. Although most uses of the "const" > keyword is for contiguous memory, it is perfectly okay to use if for > non contig. > > Still, even if this was an ill example where it would receive into > buf[2], it would be correct; as the MPI_Send function is not using > the buf pointer to receive directly into it, but rather get it from > another source. > > > > Thanks, > > .Erez > > > > -----Original Message----- > > From: owner-mpi-21@mpi-forum.org [mailto:owner-mpi-21@mpi-forum. > org] On Behalf Of Hubert Ritzdorf > > Sent: Monday, January 07, 2008 7:41 AM > > To: mpi-21@mpi-forum.org > > Subject: Re: [mpi-21] Proposal EH2: add const keyword to the C bind= ings > > > > Hi, > > > > is the proposed const keyword for buffers really correct > > for the following example: > > > > { > > int buf[3]; > > MPI_Datatype type_0_2; > > MPI_Request req; > > > > /* Create derived datatype "type_0_2" for buf [0] and buf[2] */ > > > > MPI_Type_vector (2, 1, 2, MPI_INT, &type_0_2); > > MPI_Type_commit (&type_0_2); > > > > /* Post receive of buf[1] > > Now it is assumed, that buf is not received in MPI_Irecv() */ > > MPI_Irecv (buf+1, 1, MPI_INT, ..., &req) > > > > /* Note: MPI_Send may receive buf[1] in order to ensure progress ! = */ > > MPI_Send (buf, 1, type_0_2, ...) > > > > /* Does the compiler assume that buf[1] is not changed in MPI_Send = () > > since buf is declared as const void * in the proposed MPI_Send () > > definition ? > > Would a good debug tool abort since buf[1] has changed > > during MPI_Send () ? */ > > ... > > > > MPI_Wait (&req) > > } > > > > > > I think that the const key word is not correct since the contents o= f the > > object > > "buf" is/may be changed in the MPI send call. This proposal would w= ork only > > for always contiguous buffers. > > > > Since every MPI function call is allowed to receive/get data of non-blocking > > receive/get requests (in order to ensure/optimize progress) and > > the non-blocking receive/get may be issued with a non-contiguous datatype, > > I assume that most of the proposed changes are not correct. The con= st > > keyword in > > the C++ bindings has to be removed correspondingly (might be a > > correction in > > MPI 2.1). > > > > > > Hubert Ritzdorf > > NEC Europe > > > > > > > > Erez Haba wrote: > > > >> This is the proposal to add the _/const/_ keyword to the MPI C > >> bindings where appropriate. I think that this change is appropriat= e > >> for the MPI 2.2 revision. > >> Thanks, > >> .Erez > >> *Background:* > >> The const keyword in C defines a contract between the library > >> implementer and the library user. Using the const keyword the libr= ary > >> contracts that it will not change its input object. This contract > >> enables some compile-time optimization, but more important it prov= ides > >> clearer and const-correct interface to the library user. (more on > >> _http://en.wikipedia.org/wiki/Const_correctness_) > >> The MPI C bindings as defined by the MPI 1.1 & 2.0 standards are > >> missing the _const_ keyword for many of the input only parameters.= > >> *Proposal:* > >> Add the const keyword to the API's listed below. > >> *Rational:* > >> The missing const keyword means that the contract between the user= and > >> the MPI library is weaker than it should be. Users need to cast aw= ay > >> const-ness before calling MPI and compilers cannot optimize the ca= ller > >> or the library code taking into account the const-ness of the parameter. > >> The C++ binding has already implemented a const correct interface.= > >> This change catches up with the C++ interface. (I notice that C++ > >> interface implementations cast away the const-ness when calling th= eir > >> C binding). > >> *Backward **C**ompatibility:* > >> There should not be any backward compatibility issue: already comp= iled > >> programs should run without a problem with a new dynamically loade= d > >> library as there is no change to the size of the parameters. The C= > >> linkers do not check for const correctness, thus no error here. > >> Recompiled programs should see no new compilation errors or warnin= g > >> since the const keyword guarantees a stronger contract; any non co= nst > >> pointer is automatically promoted to be const. > >> *Cons:* > >> Compilers that still do not support the const keyword. > >> MPI library implementations need to change their C header files. > >> Source level backward compatibility issue, in-case I am wrong. > >> /Note: a//dding the const keyword to the point-to-point and > >> collectives API//'//s send buffer //depends on the //"//Proposal E= H1: > >> Send buffer access//"//./ > >> *Adding the const keyword:* > >> I have compiled the list of API's that are missing the const keywo= rds. > >> I've grouped these API's by functionality and the parameter where = the > >> const keyword is applied. The last section lists 4 API's where I > >> suggest not adding the const keyword as it would break source leve= l > >> backward compatibility. > >> */* Point-to-point send buffer** *****/* > >> int MPI_Bsend(_const_ void*, int, MPI_Datatype, int, int, MPI_Comm= ); > >> int MPI_Bsend_init(_const_ void*, int, MPI_Datatype, int,int, > >> MPI_Comm, MPI_Request*); > >> int MPI_Ibsend(_const_ void*, int, MPI_Datatype, int, int, MPI_Com= m, > >> MPI_Request*); > >> int MPI_Irsend(_const_ void*, int, MPI_Datatype, int, int, MPI_Com= m, > >> MPI_Request*); > >> int MPI_Isend(_const_ void*, int, MPI_Datatype, int, int, MPI_Comm= , > >> MPI_Request*); > >> int MPI_Issend(_const_ void*, int, MPI_Datatype, int, int, MPI_Com= m, > >> MPI_Request*); > >> int MPI_Rsend(_const_ void*, int, MPI_Datatype, int, int, MPI_Comm= ); > >> int MPI_Rsend_init(_const_ void*, int, MPI_Datatype, int,int, > >> MPI_Comm, MPI_Request*); > >> int MPI_Send(_const_ void*, int, MPI_Datatype, int, int, MPI_Comm)= ; > >> int MPI_Send_init(_const_ void*, int, MPI_Datatype, int, int, > >> MPI_Comm, MPI_Request*); > >> int MPI_Sendrecv(_const_ void*, int, MPI_Datatype,int, int, void*,= > >> int, MPI_Datatype, int, int, MPI_Comm, MPI_Status*); > >> int MPI_Sendrecv_replace(void*, int, MPI_Datatype, int, int, int, = int, > >> MPI_Comm, MPI_Status*); > >> int MPI_Ssend(_const_ void*, int, MPI_Datatype, int, int, MPI_Comm= ); > >> int MPI_Ssend_init(_const_ void*, int, MPI_Datatype, int,int, > >> MPI_Comm, MPI_Request*); > >> */* Collectives send buffer** *****/* > >> int MPI_Accumulate(_const_ void*, int, MPI_Datatype, int, MPI_Aint= , > >> int, MPI_Datatype, MPI_Op, MPI_Win); > >> int MPI_Allgather(_const_ void* , int, MPI_Datatype, void*, int, > >> MPI_Datatype, MPI_Comm); > >> int MPI_Allgatherv(_const_ void* , int, MPI_Datatype, void*, _cons= t_ > >> int*, _const_ int*, MPI_Datatype, MPI_Comm); > >> int MPI_Allreduce(_const_ void* , void*, int, MPI_Datatype, MPI_Op= , > >> MPI_Comm); > >> int MPI_Alltoall(_const_ void* , int, MPI_Datatype, void*, int, > >> MPI_Datatype, MPI_Comm); > >> int MPI_Alltoallv(_const_ void* , _const_ int*, _const_ int*, > >> MPI_Datatype, void*, _const_ int*, _const_ int*, MPI_Datatype, MPI_Comm); > >> int MPI_Alltoallw(_const_ void*, _const_ int [], _const_ int [], > >> MPI_Datatype [], void*, _const_ int [], _const_ int [], MPI_Dataty= pe > >> [], MPI_Comm); > >> int MPI_Exscan(_const_ void*, void*, int, MPI_Datatype, MPI_Op, > >> MPI_Comm) ; > >> int MPI_Gather(_const_ void* , int, MPI_Datatype, void*, int, > >> MPI_Datatype, int, MPI_Comm); > >> int MPI_Gatherv(_const_ void* , int, MPI_Datatype, void*, _const_ > >> int*, _const_ int*, MPI_Datatype, int, MPI_Comm); > >> int MPI_Reduce(_const_ void* , void*, int, MPI_Datatype, MPI_Op, i= nt, > >> MPI_Comm); > >> int MPI_Reduce_scatter(_const_ void* , void*, _const_ int*, > >> MPI_Datatype, MPI_Op, MPI_Comm); > >> int MPI_Scan(_const_ void* , void*, int, MPI_Datatype, MPI_Op, MPI_Comm ); > >> int MPI_Scatter(_const_ void* , int, MPI_Datatype, void*, int, > >> MPI_Datatype, int, MPI_Comm); > >> int MPI_Scatterv(_const_ void* , _const_ int*, _const_ int*, > >> MPI_Datatype, void*, int, MPI_Datatype, int, MPI_Comm); > >> */* RMA put buffer** *****/* > >> int MPI_Put(_const_ void*, int, MPI_Datatype, int, MPI_Aint, int, > >> MPI_Datatype, MPI_Win); > >> */* File IO write buffer** *****/* > >> int MPI_File_iwrite(MPI_File, _const_ void*, int, MPI_Datatype, > >> MPIO_Request*); > >> int MPI_File_iwrite_at(MPI_File, MPI_Offset, _const_ void*, int, > >> MPI_Datatype, MPIO_Request*); > >> int MPI_File_iwrite_shared(MPI_File, _const_ void*, int, MPI_Datat= ype, > >> MPIO_Request*); > >> int MPI_File_write(MPI_File, _const_ void*, int, MPI_Datatype, > >> MPI_Status*); > >> int MPI_File_write_all(MPI_File, _const_ void*, int, MPI_Datatype,= > >> MPI_Status*); > >> int MPI_File_write_all_begin(MPI_File, _const_ void*, int, MPI_Datatype); > >> int MPI_File_write_all_end(MPI_File, _const_ void*, MPI_Status*); > >> int MPI_File_write_at(MPI_File, MPI_Offset, _const_ void*, int, > >> MPI_Datatype, MPI_Status*); > >> int MPI_File_write_at_all(MPI_File, MPI_Offset, _const_ void*, int= , > >> MPI_Datatype, MPI_Status*); > >> int MPI_File_write_at_all_begin(MPI_File, MPI_Offset, _const_ void= *, > >> int, MPI_Datatype); > >> int MPI_File_write_at_all_end(MPI_File, _const_ void*, MPI_Status*= ); > >> int MPI_File_write_ordered(MPI_File, _const_ void*, int, MPI_Datat= ype, > >> MPI_Status*); > >> int MPI_File_write_ordered_begin(MPI_File, _const_ void*, int, > >> MPI_Datatype); > >> int MPI_File_write_ordered_end(MPI_File, _const_ void*, MPI_Status= *); > >> int MPI_File_write_shared(MPI_File, _const_ void*, int, MPI_Dataty= pe, > >> MPI_Status*); > >> */* Input string** *****/* > >> int MPI_Add_error_string(int, _const_ char*); > >> int MPI_Close_port(_const_ char*); > >> int MPI_Comm_accept(_const_ char*, MPI_Info, int, MPI_Comm, MPI_Comm*); > >> int MPI_Comm_connect(_const_ char*, MPI_Info, int, MPI_Comm, MPI_Comm*); > >> int MPI_Comm_set_name(MPI_Comm, _const_ char*); > >> int MPI_Comm_spawn(_const_ char*, char*[], int, MPI_Info, int, > >> MPI_Comm, MPI_Comm*, int []); > >> int MPI_File_delete(_const_ char*, MPI_Info); > >> int MPI_File_open(MPI_Comm, _const_ char*, int, MPI_Info, MPI_File= *); > >> int MPI_File_set_view(MPI_File, MPI_Offset, MPI_Datatype, > >> MPI_Datatype, _const_ char*, MPI_Info); > >> int MPI_Info_delete(MPI_Info, _const_ char*); > >> int MPI_Info_get(MPI_Info, _const_ char*, int, char*, int*); > >> int MPI_Info_get_valuelen(MPI_Info, _const_ char*, int*, int*); > >> int MPI_Info_set(MPI_Info, _const_ char*, _const_ char*); > >> int MPI_Lookup_name(_const_ char*, MPI_Info, char*); > >> int MPI_Publish_name(_const_ char*, MPI_Info, _const_ char*); > >> int MPI_Type_set_name(MPI_Datatype, _const_ char*); > >> int MPI_Unpublish_name(_const_ char*, MPI_Info, _const_ char*); > >> int MPI_Win_set_name(MPI_Win, _const_ char*); > >> */* Index/Count arrays** *****/* > >> int MPI_Cart_create(MPI_Comm, int, _const_ int*, _const_ int*, int= , > >> MPI_Comm*); > >> int MPI_Cart_map(MPI_Comm, int, _const_ int*, _const_ int*, _const= _ int*); > >> int MPI_Cart_rank(MPI_Comm, _const_ int*, int*); > >> int MPI_Cart_sub(MPI_Comm, _const_ int*, MPI_Comm*); > >> int MPI_Graph_create(MPI_Comm, int, _const_ int*, _const_ int*, in= t, > >> MPI_Comm*); > >> int MPI_Graph_map(MPI_Comm, int, _const_ int*, _const_ int*, int*)= ; > >> int MPI_Group_excl(MPI_Group, int, _const_ int*, MPI_Group*); > >> int MPI_Group_incl(MPI_Group, int, _const_ int*, MPI_Group*); > >> int MPI_Group_translate_ranks(MPI_Group, int, _const_ int*, MPI_Gr= oup, > >> int*); > >> int MPI_Type_create_darray(int, int, int, _const_ int [], _const_ = int > >> [], _const_ int [], _const_ int [], int, MPI_Datatype, MPI_Datatyp= e*); > >> int MPI_Type_create_hindexed(int, _const_ int [], _const_ MPI_Aint= [], > >> MPI_Datatype, MPI_Datatype*); > >> int MPI_Type_create_indexed_block(int, int, _const_ int [], > >> MPI_Datatype, MPI_Datatype*); > >> int MPI_Type_create_struct(int, _const_ int [], _const_ MPI_Aint [= ], > >> _const_ MPI_Datatype [], MPI_Datatype*); > >> int MPI_Type_create_subarray(int, _const_ int [], _const_ int [], > >> _const_ int [], int, MPI_Datatype, MPI_Datatype*); > >> int MPI_Type_hindexed(int, _const_ int*, _const_ MPI_Aint*, > >> MPI_Datatype, MPI_Datatype*); > >> int MPI_Type_indexed(int, _const_ int*, _const_ int*, MPI_Datatype= , > >> MPI_Datatype*); > >> int MPI_Type_struct(int, _const_ int*, _const_ MPI_Aint*, > >> MPI_Datatype*, MPI_Datatype*); > >> */* Pack/Unpack datarep string and input buffer** *****/* > >> int MPI_Pack(_const_ void*, int, MPI_Datatype, void*, int, int*, > >> MPI_Comm); > >> int MPI_Pack_external(_const_ char*, _const_ void*, int, MPI_Datat= ype, > >> void*, MPI_Aint, MPI_Aint*); > >> int MPI_Pack_external_size(_const_ char*, int, MPI_Datatype, MPI_Aint*); > >> int MPI_Unpack(_const_ void*, int, _const_ int*, void*, int, > >> MPI_Datatype, MPI_Comm); > >> int MPI_Unpack_external(_const_ char*, _const_ void*, MPI_Aint, > >> MPI_Aint*, void*, int, MPI_Datatype); > >> */* Miscellany** *****/* > >> int MPI_Address(_const_ void*, MPI_Aint*); > >> int MPI_Get_address(_const_ void*, MPI_Aint*); > >> int MPI_Status_c2f(_const_ MPI_Status*, MPI_Fint*); > >> int MPI_Status_f2c(_const_ MPI_Fint*, MPI_Status*); > >> int MPI_Test_cancelled(_const_ MPI_Status*, int*); > >> */* N**OT CHANGING **the following API's to keep backward > >> compatibility and ease of use** *****/* > >> int MPI_Comm_spawn(_const_ char*, /*const*/char*[], int, MPI_Info,= > >> int, MPI_Comm, MPI_Comm*, int []); > >> int MPI_Comm_spawn_multiple(int, /*const*/char*[], /*const*/char**= [], > >> /*const*/int [],/*const*/MPI_Info [], int, MPI_Comm, MPI_Comm*, in= t []); > >> int MPI_Group_range_excl(MPI_Group, int, /*const*/int [][3], MPI_Group*); > >> int MPI_Group_range_incl(MPI_Group, int, /*const*/int [][3], MPI_Group*); > >> > > > > > > >= --0__=0ABBF959DFFECF818f9e8a93df938690918c0ABBF959DFFECF81 Content-type: text/html; charset=US-ASCII Content-Disposition: inline Content-transfer-encoding: quoted-printable

This whole discussion will quickly get convoluted.

When a block of code that has a function call (MPI_Isend) is compiled a= nd some data structure (buf[]) that is used in that block of code is pa= ssed by reference to the function (without const), the compiler must ma= ke the pessimistic assumption that any part of that data structure coul= d be changed by the time the call returns. If there is a subexpressio= n that involves data from buf[] that was evaluated before the call to M= PI_Send, it must be evaluated again after the return. If MPI_Send prom= ises buf[] is const then the compiler can skip the re-evaluation.

With const, the compiler may act on the expectation buf[] does not chan= ge.

The earlier MPI_Irecv call in the example passed buf[1] and that means = buf[1] can change any time between the entry to MPI_Irecv and the retur= n from MPI_Wait. You cannot even assume it will not change in the MPI_I= recv call. For this reason, the MPI rules forbid reading buf[1] between= the MPI_Irecv and the MPI_Wait. If the block of code that contains the= MPI_Send call is making any use of buf[1] at the time of the call then= it is in violation of MPI rules anyway. It will lead to trouble on som= e MPI implementation whether buf[] is labeled const or not on the MPI_S= end. The value of buf[1] can change asynchronously any time between MPI= _Irecv and MPI_Wait without any need for a function call.

The MPI rules presumably would allow the block of code to access buf[0]= and buf[2] before and after the call to MPI_Send and the MPI_Send will= not change buf[0] or buf[2]. The practical effect of labeling buf[] c= onst will be correct as long as the MPI rules are followed and there is= no code in the vicinity that references buf[1].

The Forum will need to decide if it is worth debating the precise meani= ng of const or whether there is an actual situation where the const l= abel is dangerous as long as MPI rules are followed. It seem to me labe= ling buf[] const can do no harm as long as the application follows the = rules with respect to the outstanding MPI_Irecv.

Dick


Dick Treumann - MPI Team/TCEM
IBM Systems & Technology Group
Dept 0lva / MS P963 -- 2455 South Road -- Poughkeepsie, NY 12601
Tele (845) 433-7846 Fax (845) 433-8363


owner-mpi-21@mpi-forum.org wrote on 01/08/2008 11:54:46 AM:

> The MPI_Send function is not modifying the buf[] using the send > buffer pointer *passed in* to the MPI_Send function, but rather > buf[]is modified as a side effect of some other function call.
= >
> This is perfectly alright and inline with the *const* keyword
= > definition. The *const* keyword does not guarantees that the objec= t
> will not be modified; it guarantees that it will not be modified <= br> > using the passed in pointer (directly or indirectly).
>
> Thanks,
> .Erez
>
> -----Original Message-----
> From: owner-mpi-21@mpi-forum.org [mailto:owner-mpi-21@mpi-forum.org]
> On Behalf Of Hubert Ritzdorf
> Sent: Tuesday, January 08, 2008 7:45 AM
> To: mpi-21@mpi-forum.org
> Subject: Re: [mpi-21] Proposal EH2: add const keyword to the C bin= dings
>
>
>
> Erez Haba wrote:
> > The const keyword semantic as defined by C and C++ is still <= br> > correct for the example you described below.
> >
> The ISO C standard (ISO/IEC 9899:1999) says in section 6.7.3 Seman= tics 5:
>
> If an attempt is made to modify an object defined with a const-qua= lified
> type through use
> of an lvalue with non-const-qualified type, the behavior is undefi= ned.
>
> The C object is "buf[]" (including all elements) and if = MPI_Send() would
> change
> this const-qualified object, the behavior should be undefined and = not
> portable
> (Annex J "Portability issues").
>
> Hubert
> > The "const" keyword is a contract saying that the o= bject with the
> memory layout as defined by the interface (MPI_Send) is guaranteed=
> no to be changed by the function. Although most uses of the "= const"
> keyword is for contiguous memory, it is perfectly okay to use if f= or
> non contig.
> > Still, even if this was an ill example where it would receive= into
> buf[2], it would be correct; as the MPI_Send function is not using=
> the buf pointer to receive directly into it, but rather get it fro= m
> another source.
> >
> > Thanks,
> > .Erez
> >
> > -----Original Message-----
> > From: owner-mpi-21@mpi-forum.org [mailto:owner-mpi-21@mpi-forum.
> org] On Behalf Of Hubert Ritzdorf
> > Sent: Monday, January 07, 2008 7:41 AM
> > To: mpi-21@mpi-forum.org
> > Subject: Re: [mpi-21] Proposal EH2: add const keyword to the = C bindings
> >
> > Hi,
> >
> > is the proposed const keyword for buffers really correct
> > for the following example:
> >
> > {
> > int buf[3];
> > MPI_Datatype type_0_2;
> > MPI_Request req;
> >
> > /* Create derived datatype "type_0_2" for buf [0] a= nd buf[2] */
> >
> > MPI_Type_vector (2, 1, 2, MPI_INT, &type_0_2);
> > MPI_Type_commit (&type_0_2);
> >
> > /* Post receive of buf[1]
> > Now it is assumed, that buf is not received in MPI_Irecv() */=
> > MPI_Irecv (buf+1, 1, MPI_INT, ..., &req)
> >
> > /* Note: MPI_Send may receive buf[1] in order to ensure progr= ess ! */
> > MPI_Send (buf, 1, type_0_2, ...)
> >
> > /* Does the compiler assume that buf[1] is not changed in MPI= _Send ()
> > since buf is declared as const void * in the proposed MPI_Sen= d ()
> > definition ?
> > Would a good debug tool abort since buf[1] has changed
> > during MPI_Send () ? */
> > ...
> >
> > MPI_Wait (&req)
> > }
> >
> >
> > I think that the const key word is not correct since the cont= ents of the
> > object
> > "buf" is/may be changed in the MPI send call. This = proposal would work only
> > for always contiguous buffers.
> >
> > Since every MPI function call is allowed to receive/get data = of non-blocking
> > receive/get requests (in order to ensure/optimize progress) a= nd
> > the non-blocking receive/get may be issued with a non-contigu= ous datatype,
> > I assume that most of the proposed changes are not correct. T= he const
> > keyword in
> > the C++ bindings has to be removed correspondingly (might be = a
> > correction in
> > MPI 2.1).
> >
> >
> > Hubert Ritzdorf
> > NEC Europe
> >
> >
> >
> > Erez Haba wrote:
> >
> >> This is the proposal to add the _/const/_ keyword to the = MPI C
> >> bindings where appropriate. I think that this change is a= ppropriate
> >> for the MPI 2.2 revision.
> >> Thanks,
> >> .Erez
> >> *Background:*
> >> The const keyword in C defines a contract between the lib= rary
> >> implementer and the library user. Using the const keyword= the library
> >> contracts that it will not change its input object. This = contract
> >> enables some compile-time optimization, but more importan= t it provides
> >> clearer and const-correct interface to the library user. = (more on
> >> _http://en.wikipedia.org/wiki/Const_correctness_)
> >> The MPI C bindings as defined by the MPI 1.1 & 2.0 st= andards are
> >> missing the _const_ keyword for many of the input only pa= rameters.
> >> *Proposal:*
> >> Add the const keyword to the API's listed below.
> >> *Rational:*
> >> The missing const keyword means that the contract between= the user and
> >> the MPI library is weaker than it should be. Users need t= o cast away
> >> const-ness before calling MPI and compilers cannot optimi= ze the caller
> >> or the library code taking into account the const-ness of= the parameter.
> >> The C++ binding has already implemented a const correct i= nterface.
> >> This change catches up with the C++ interface. (I notice = that C++
> >> interface implementations cast away the const-ness when c= alling their
> >> C binding).
> >> *Backward **C**ompatibility:*
> >> There should not be any backward compatibility issue: alr= eady compiled
> >> programs should run without a problem with a new dynamica= lly loaded
> >> library as there is no change to the size of the paramete= rs. The C
> >> linkers do not check for const correctness, thus no error= here.
> >> Recompiled programs should see no new compilation errors = or warning
> >> since the const keyword guarantees a stronger contract; a= ny non const
> >> pointer is automatically promoted to be const.
> >> *Cons:*
> >> Compilers that still do not support the const keyword. > >> MPI library implementations need to change their C header= files.
> >> Source level backward compatibility issue, in-case I am w= rong.
> >> /Note: a//dding the const keyword to the point-to-point a= nd
> >> collectives API//'//s send buffer //depends on the //&quo= t;//Proposal EH1:
> >> Send buffer access//"//./
> >> *Adding the const keyword:*
> >> I have compiled the list of API's that are missing the co= nst keywords.
> >> I've grouped these API's by functionality and the paramet= er where the
> >> const keyword is applied. The last section lists 4 API's = where I
> >> suggest not adding the const keyword as it would break so= urce level
> >> backward compatibility.
> >> */* Point-to-point send buffer** *****/*
> >> int MPI_Bsend(_const_ void*, int, MPI_Datatype, int, int,= MPI_Comm);
> >> int MPI_Bsend_init(_const_ void*, int, MPI_Datatype, int,= int,
> >> MPI_Comm, MPI_Request*);
> >> int MPI_Ibsend(_const_ void*, int, MPI_Datatype, int, int= , MPI_Comm,
> >> MPI_Request*);
> >> int MPI_Irsend(_const_ void*, int, MPI_Datatype, int, int= , MPI_Comm,
> >> MPI_Request*);
> >> int MPI_Isend(_const_ void*, int, MPI_Datatype, int, int,= MPI_Comm,
> >> MPI_Request*);
> >> int MPI_Issend(_const_ void*, int, MPI_Datatype, int, int= , MPI_Comm,
> >> MPI_Request*);
> >> int MPI_Rsend(_const_ void*, int, MPI_Datatype, int, int,= MPI_Comm);
> >> int MPI_Rsend_init(_const_ void*, int, MPI_Datatype, int,= int,
> >> MPI_Comm, MPI_Request*);
> >> int MPI_Send(_const_ void*, int, MPI_Datatype, int, int, = MPI_Comm);
> >> int MPI_Send_init(_const_ void*, int, MPI_Datatype, int, = int,
> >> MPI_Comm, MPI_Request*);
> >> int MPI_Sendrecv(_const_ void*, int, MPI_Datatype,int, in= t, void*,
> >> int, MPI_Datatype, int, int, MPI_Comm, MPI_Status*);
> >> int MPI_Sendrecv_replace(void*, int, MPI_Datatype, int, i= nt, int, int,
> >> MPI_Comm, MPI_Status*);
> >> int MPI_Ssend(_const_ void*, int, MPI_Datatype, int, int,= MPI_Comm);
> >> int MPI_Ssend_init(_const_ void*, int, MPI_Datatype, int,= int,
> >> MPI_Comm, MPI_Request*);
> >> */* Collectives send buffer** *****/*
> >> int MPI_Accumulate(_const_ void*, int, MPI_Datatype, int,= MPI_Aint,
> >> int, MPI_Datatype, MPI_Op, MPI_Win);
> >> int MPI_Allgather(_const_ void* , int, MPI_Datatype, void= *, int,
> >> MPI_Datatype, MPI_Comm);
> >> int MPI_Allgatherv(_const_ void* , int, MPI_Datatype, voi= d*, _const_
> >> int*, _const_ int*, MPI_Datatype, MPI_Comm);
> >> int MPI_Allreduce(_const_ void* , void*, int, MPI_Datatyp= e, MPI_Op,
> >> MPI_Comm);
> >> int MPI_Alltoall(_const_ void* , int, MPI_Datatype, void*= , int,
> >> MPI_Datatype, MPI_Comm);
> >> int MPI_Alltoallv(_const_ void* , _const_ int*, _const_ i= nt*,
> >> MPI_Datatype, void*, _const_ int*, _const_ int*, MPI_Data= type, MPI_Comm);
> >> int MPI_Alltoallw(_const_ void*, _const_ int [], _const_ = int [],
> >> MPI_Datatype [], void*, _const_ int [], _const_ int [], M= PI_Datatype
> >> [], MPI_Comm);
> >> int MPI_Exscan(_const_ void*, void*, int, MPI_Datatype, M= PI_Op,
> >> MPI_Comm) ;
> >> int MPI_Gather(_const_ void* , int, MPI_Datatype, void*, = int,
> >> MPI_Datatype, int, MPI_Comm);
> >> int MPI_Gatherv(_const_ void* , int, MPI_Datatype, void*,= _const_
> >> int*, _const_ int*, MPI_Datatype, int, MPI_Comm);
> >> int MPI_Reduce(_const_ void* , void*, int, MPI_Datatype, = MPI_Op, int,
> >> MPI_Comm);
> >> int MPI_Reduce_scatter(_const_ void* , void*, _const_ int= *,
> >> MPI_Datatype, MPI_Op, MPI_Comm);
> >> int MPI_Scan(_const_ void* , void*, int, MPI_Datatype, MP= I_Op, MPI_Comm );
> >> int MPI_Scatter(_const_ void* , int, MPI_Datatype, void*,= int,
> >> MPI_Datatype, int, MPI_Comm);
> >> int MPI_Scatterv(_const_ void* , _const_ int*, _const_ in= t*,
> >> MPI_Datatype, void*, int, MPI_Datatype, int, MPI_Comm); > >> */* RMA put buffer** *****/*
> >> int MPI_Put(_const_ void*, int, MPI_Datatype, int, MPI_Ai= nt, int,
> >> MPI_Datatype, MPI_Win);
> >> */* File IO write buffer** *****/*
> >> int MPI_File_iwrite(MPI_File, _const_ void*, int, MPI_Dat= atype,
> >> MPIO_Request*);
> >> int MPI_File_iwrite_at(MPI_File, MPI_Offset, _const_ void= *, int,
> >> MPI_Datatype, MPIO_Request*);
> >> int MPI_File_iwrite_shared(MPI_File, _const_ void*, int, = MPI_Datatype,
> >> MPIO_Request*);
> >> int MPI_File_write(MPI_File, _const_ void*, int, MPI_Data= type,
> >> MPI_Status*);
> >> int MPI_File_write_all(MPI_File, _const_ void*, int, MPI_= Datatype,
> >> MPI_Status*);
> >> int MPI_File_write_all_begin(MPI_File, _const_ void*, int= , MPI_Datatype);
> >> int MPI_File_write_all_end(MPI_File, _const_ void*, MPI_S= tatus*);
> >> int MPI_File_write_at(MPI_File, MPI_Offset, _const_ void*= , int,
> >> MPI_Datatype, MPI_Status*);
> >> int MPI_File_write_at_all(MPI_File, MPI_Offset, _const_ v= oid*, int,
> >> MPI_Datatype, MPI_Status*);
> >> int MPI_File_write_at_all_begin(MPI_File, MPI_Offset, _co= nst_ void*,
> >> int, MPI_Datatype);
> >> int MPI_File_write_at_all_end(MPI_File, _const_ void*, MP= I_Status*);
> >> int MPI_File_write_ordered(MPI_File, _const_ void*, int, = MPI_Datatype,
> >> MPI_Status*);
> >> int MPI_File_write_ordered_begin(MPI_File, _const_ void*,= int,
> >> MPI_Datatype);
> >> int MPI_File_write_ordered_end(MPI_File, _const_ void*, M= PI_Status*);
> >> int MPI_File_write_shared(MPI_File, _const_ void*, int, M= PI_Datatype,
> >> MPI_Status*);
> >> */* Input string** *****/*
> >> int MPI_Add_error_string(int, _const_ char*);
> >> int MPI_Close_port(_const_ char*);
> >> int MPI_Comm_accept(_const_ char*, MPI_Info, int, MPI_Com= m, MPI_Comm*);
> >> int MPI_Comm_connect(_const_ char*, MPI_Info, int, MPI_Co= mm, MPI_Comm*);
> >> int MPI_Comm_set_name(MPI_Comm, _const_ char*);
> >> int MPI_Comm_spawn(_const_ char*, char*[], int, MPI_Info,= int,
> >> MPI_Comm, MPI_Comm*, int []);
> >> int MPI_File_delete(_const_ char*, MPI_Info);
> >> int MPI_File_open(MPI_Comm, _const_ char*, int, MPI_Info,= MPI_File*);
> >> int MPI_File_set_view(MPI_File, MPI_Offset, MPI_Datatype,=
> >> MPI_Datatype, _const_ char*, MPI_Info);
> >> int MPI_Info_delete(MPI_Info, _const_ char*);
> >> int MPI_Info_get(MPI_Info, _const_ char*, int, char*, int= *);
> >> int MPI_Info_get_valuelen(MPI_Info, _const_ char*, int*, = int*);
> >> int MPI_Info_set(MPI_Info, _const_ char*, _const_ char*);=
> >> int MPI_Lookup_name(_const_ char*, MPI_Info, char*);
> >> int MPI_Publish_name(_const_ char*, MPI_Info, _const_ cha= r*);
> >> int MPI_Type_set_name(MPI_Datatype, _const_ char*);
> >> int MPI_Unpublish_name(_const_ char*, MPI_Info, _const_ c= har*);
> >> int MPI_Win_set_name(MPI_Win, _const_ char*);
> >> */* Index/Count arrays** *****/*
> >> int MPI_Cart_create(MPI_Comm, int, _const_ int*, _const_ = int*, int,
> >> MPI_Comm*);
> >> int MPI_Cart_map(MPI_Comm, int, _const_ int*, _const_ int= *, _const_ int*);
> >> int MPI_Cart_rank(MPI_Comm, _const_ int*, int*);
> >> int MPI_Cart_sub(MPI_Comm, _const_ int*, MPI_Comm*);
> >> int MPI_Graph_create(MPI_Comm, int, _const_ int*, _const_= int*, int,
> >> MPI_Comm*);
> >> int MPI_Graph_map(MPI_Comm, int, _const_ int*, _const_ in= t*, int*);
> >> int MPI_Group_excl(MPI_Group, int, _const_ int*, MPI_Grou= p*);
> >> int MPI_Group_incl(MPI_Group, int, _const_ int*, MPI_Grou= p*);
> >> int MPI_Group_translate_ranks(MPI_Group, int, _const_ int= *, MPI_Group,
> >> int*);
> >> int MPI_Type_create_darray(int, int, int, _const_ int [],= _const_ int
> >> [], _const_ int [], _const_ int [], int, MPI_Datatype, MP= I_Datatype*);
> >> int MPI_Type_create_hindexed(int, _const_ int [], _const_= MPI_Aint [],
> >> MPI_Datatype, MPI_Datatype*);
> >> int MPI_Type_create_indexed_block(int, int, _const_ int [= ],
> >> MPI_Datatype, MPI_Datatype*);
> >> int MPI_Type_create_struct(int, _const_ int [], _const_ M= PI_Aint [],
> >> _const_ MPI_Datatype [], MPI_Datatype*);
> >> int MPI_Type_create_subarray(int, _const_ int [], _const_= int [],
> >> _const_ int [], int, MPI_Datatype, MPI_Datatype*);
> >> int MPI_Type_hindexed(int, _const_ int*, _const_ MPI_Aint= *,
> >> MPI_Datatype, MPI_Datatype*);
> >> int MPI_Type_indexed(int, _const_ int*, _const_ int*, MPI= _Datatype,
> >> MPI_Datatype*);
> >> int MPI_Type_struct(int, _const_ int*, _const_ MPI_Aint*,=
> >> MPI_Datatype*, MPI_Datatype*);
> >> */* Pack/Unpack datarep string and input buffer** *****/*=
> >> int MPI_Pack(_const_ void*, int, MPI_Datatype, void*, int= , int*,
> >> MPI_Comm);
> >> int MPI_Pack_external(_const_ char*, _const_ void*, int, = MPI_Datatype,
> >> void*, MPI_Aint, MPI_Aint*);
> >> int MPI_Pack_external_size(_const_ char*, int, MPI_Dataty= pe, MPI_Aint*);
> >> int MPI_Unpack(_const_ void*, int, _const_ int*, void*, i= nt,
> >> MPI_Datatype, MPI_Comm);
> >> int MPI_Unpack_external(_const_ char*, _const_ void*, MPI= _Aint,
> >> MPI_Aint*, void*, int, MPI_Datatype);
> >> */* Miscellany** *****/*
> >> int MPI_Address(_const_ void*, MPI_Aint*);
> >> int MPI_Get_address(_const_ void*, MPI_Aint*);
> >> int MPI_Status_c2f(_const_ MPI_Status*, MPI_Fint*);
> >> int MPI_Status_f2c(_const_ MPI_Fint*, MPI_Status*);
> >> int MPI_Test_cancelled(_const_ MPI_Status*, int*);
> >> */* N**OT CHANGING **the following API's to keep backward=
> >> compatibility and ease of use** *****/*
> >> int MPI_Comm_spawn(_const_ char*, /*const*/char*[], int, = MPI_Info,
> >> int, MPI_Comm, MPI_Comm*, int []);
> >> int MPI_Comm_spawn_multiple(int, /*const*/char*[], /*cons= t*/char**[],
> >> /*const*/int [],/*const*/MPI_Info [], int, MPI_Comm, MPI_= Comm*, int []);
> >> int MPI_Group_range_excl(MPI_Group, int, /*const*/int [][= 3], MPI_Group*);
> >> int MPI_Group_range_incl(MPI_Group, int, /*const*/int [][= 3], MPI_Group*);
> >>
> >
> >
> >
>
= --0__=0ABBF959DFFECF818f9e8a93df938690918c0ABBF959DFFECF81--