From: Erez Haba Date: January 7, 2008 10:46:32 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 const keyword semantic as defined by C and C++ is still correct for the example you described below. 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@XXXXXXXXXXXXX On Behalf Of Hubert Ritzdorf Sent: Monday, January 07, 2008 7:41 AM To: mpi-21@XXXXXXXXXXXXX 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*);