[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [mpi-21] Proposal EH2: add const keyword to the C bindings



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 [mailto: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@xxxxxxxxxxxxx [mailto: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*);
>>
>
>
>