From: Erez Haba Date: January 8, 2008 10:54:46 AM CST To: "mpi-21@mpi-forum.org" Subject: RE: [mpi-21] Proposal EH2: add const keyword to the C bindings Reply-To: mpi-21@XXXXXXXXXXXXX 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@XXXXXXXXXXXXX On Behalf Of Hubert Ritzdorf Sent: Tuesday, January 08, 2008 7:45 AM To: mpi-21@XXXXXXXXXXXXX Subject: Re: [mpi-21] Proposal EH2: add const keyword to the C bindings 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 Semantics 5: If an attempt is made to modify an object defined with a const-qualified 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() 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 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 > 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] 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 > 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) 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 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 appropriate >> 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 library >> contracts that it will not change its input object. This contract >> enables some compile-time optimization, but more important 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 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 away >> const-ness before calling MPI and compilers cannot optimize the >> caller >> 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 their >> C binding). >> *Backward **C**ompatibility:* >> There should not be any backward compatibility issue: already >> compiled >> programs should run without a problem with a new dynamically loaded >> 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 warning >> since the const keyword guarantees a stronger contract; any 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 wrong. >> /Note: a//dding the const keyword to the point-to-point and >> collectives API//'//s send buffer //depends on the //"//Proposal EH1: >> Send buffer access//"//./ >> *Adding the const keyword:* >> I have compiled the list of API's that are missing the const >> keywords. >> 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 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, 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*, _const_ >> 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_Datatype >> [], 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, 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, 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_Datatype, >> 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_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*, MPI_Status*); >> int MPI_File_write_shared(MPI_File, _const_ void*, int, MPI_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_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*, int, >> 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_Group, >> int*); >> int MPI_Type_create_darray(int, int, int, _const_ int [], _const_ int >> [], _const_ int [], _const_ int [], int, MPI_Datatype, >> MPI_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_ 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_Datatype, >> 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*, >> 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*); >> > > >