From: Hubert Ritzdorf Date: January 7, 2008 9:40:44 AM CST To: mpi-21@XXXXXXXXXXXXX Subject: Re: [mpi-21] Proposal EH2: add const keyword to the C bindings Reply-To: mpi-21@XXXXXXXXXXXXX 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*);