Commit 72320371 authored by James Dinan's avatar James Dinan
Browse files

[svn-r10213] Implementation of MPI-3 RMA Fetch_and_op

Adds implementation of atomic fetch-and-op operation and several test cases.

Reviewer: buntinas
parent 75742e03
......@@ -1787,6 +1787,10 @@ int MPIDI_CH3_PktHandler_CAS( MPIDI_VC_t *, MPIDI_CH3_Pkt_t *,
MPIDI_msg_sz_t *, MPID_Request ** );
int MPIDI_CH3_PktHandler_CASResp( MPIDI_VC_t *, MPIDI_CH3_Pkt_t *,
MPIDI_msg_sz_t *, MPID_Request ** );
int MPIDI_CH3_PktHandler_FOP( MPIDI_VC_t *, MPIDI_CH3_Pkt_t *,
MPIDI_msg_sz_t *, MPID_Request ** );
int MPIDI_CH3_PktHandler_FOPResp( MPIDI_VC_t *, MPIDI_CH3_Pkt_t *,
MPIDI_msg_sz_t *, MPID_Request ** );
int MPIDI_CH3_PktHandler_Get( MPIDI_VC_t *, MPIDI_CH3_Pkt_t *,
MPIDI_msg_sz_t *, MPID_Request ** );
int MPIDI_CH3_PktHandler_GetResp( MPIDI_VC_t *, MPIDI_CH3_Pkt_t *,
......
......@@ -79,6 +79,116 @@ typedef union {
#endif
} MPIDI_CH3_CAS_Immed_u;
/* Union over all types that are allowed in a Fetch-and-op operation. This
is used to allocate enough space in the packet header for immediate
data. */
typedef union {
char fop_char;
short fop_short;
int fop_int;
long fop_long;
MPI_Aint fop_aint;
MPI_Offset fop_offset;
#if defined(HAVE_INT8_T)
int8_t fop_int8_t;
#endif
#if defined(HAVE_INT16_T)
int16_t fop_int16_t;
#endif
#if defined(HAVE_INT32_T)
int32_t fop_int32_t;
#endif
#if defined(HAVE_INT64_T)
int64_t fop_int64_t;
#endif
#if defined(HAVE_UINT8_T)
uint8_t fop_uint8_t;
#endif
#if defined(HAVE_UINT16_T)
uint16_t fop_uint16_t;
#endif
#if defined(HAVE_UINT32_T)
uint32_t fop_uint32_t;
#endif
#if defined(HAVE_UINT64_T)
uint64_t fop_uint64_t;
#endif
#if defined(HAVE_LONG_LONG_INT)
long long fop_long_long;
#endif
#if defined(HAVE_FORTRAN_BINDING)
MPI_Fint fop_fint;
#endif
#if defined(HAVE__BOOL)
_Bool fop__bool;
#endif
#if defined(HAVE_CXX_BINDING)
MPIR_CXX_BOOL_CTYPE fop_cxx_bool;
#endif
#if defined(MPIR_INTEGER1_CTYPE)
MPIR_INTEGER1_CTYPE fop_integer1;
#endif
#if defined(MPIR_INTEGER2_CTYPE)
MPIR_INTEGER2_CTYPE fop_integer2;
#endif
#if defined(MPIR_INTEGER4_CTYPE)
MPIR_INTEGER4_CTYPE fop_integer4;
#endif
#if defined(MPIR_INTEGER8_CTYPE)
MPIR_INTEGER8_CTYPE fop_integer8;
#endif
#if defined(MPIR_INTEGER16_CTYPE)
MPIR_INTEGER16_CTYPE fop_integer16;
#endif
float fop_float;
double fop_double;
#if defined(HAVE_LONG_DOUBLE)
long double fop_long_double;
#endif
#if defined(MPIR_REAL4_CTYPE)
MPIR_REAL4_CTYPE fop_mpir_real4_ctype;
#endif
#if defined(MPIR_REAL8_CTYPE)
MPIR_REAL8_CTYPE fop_mpir_real8_ctype;
#endif
#if defined(MPIR_REAL16_CTYPE)
MPIR_REAL16_CTYPE fop_mpir_real16_ctype;
#endif
struct {
double re;
double im;
} fop_d_complex;
#if defined(HAVE_LONG_DOUBLE)
struct {
long double re;
long double im;
} fop_ld_complex;
#endif
struct {
float re;
float im;
} fop_s_complex;
#if defined(HAVE_FORTRAN_BINDING)
struct {
MPIR_FC_REAL_CTYPE re;
MPIR_FC_REAL_CTYPE im;
} fop_s_fc_complex;
struct {
MPIR_FC_DOUBLE_CTYPE re;
MPIR_FC_DOUBLE_CTYPE im;
} fop_d_fc_complex;
#endif
} MPIDI_CH3_FOP_Immed_u;
/*
* MPIDI_CH3_Pkt_type_t
*
......@@ -116,6 +226,9 @@ typedef enum MPIDI_CH3_Pkt_type
MPIDI_CH3_PKT_CAS,
MPIDI_CH3_PKT_CAS_UNLOCK,
MPIDI_CH3_PKT_CAS_RESP,
MPIDI_CH3_PKT_FOP,
MPIDI_CH3_PKT_FOP_UNLOCK,
MPIDI_CH3_PKT_FOP_RESP,
MPIDI_CH3_PKT_FLOW_CNTL_UPDATE, /* FIXME: Unused */
MPIDI_CH3_PKT_CLOSE,
MPIDI_CH3_PKT_END_CH3
......@@ -312,6 +425,33 @@ typedef struct MPIDI_CH3_Pkt_cas_resp
}
MPIDI_CH3_Pkt_cas_resp_t;
typedef struct MPIDI_CH3_Pkt_fop
{
MPIDI_CH3_Pkt_type_t type;
MPI_Datatype datatype;
void *addr;
MPI_Op op;
MPI_Request request_handle;
MPI_Win target_win_handle; /* Used in the last RMA operation in each
* epoch for decrementing rma op counter in
* active target rma and for unlocking window
* in passive target rma. Otherwise set to NULL*/
/* source_win_handle is omitted here to reduce
* the packet size. If this is the last FETCH_OP
* packet, the type will be set to FETCH_OP_UNLOCK */
MPIDI_CH3_FOP_Immed_u origin_data;
}
MPIDI_CH3_Pkt_fop_t;
typedef struct MPIDI_CH3_Pkt_fop_resp
{
MPIDI_CH3_Pkt_type_t type;
MPI_Request request_handle;
MPIDI_CH3_FOP_Immed_u data;
}
MPIDI_CH3_Pkt_fop_resp_t;
typedef struct MPIDI_CH3_Pkt_lock
{
MPIDI_CH3_Pkt_type_t type;
......@@ -405,6 +545,8 @@ typedef union MPIDI_CH3_Pkt
MPIDI_CH3_Pkt_close_t close;
MPIDI_CH3_Pkt_cas_t cas;
MPIDI_CH3_Pkt_cas_resp_t cas_resp;
MPIDI_CH3_Pkt_fop_t fop;
MPIDI_CH3_Pkt_fop_resp_t fop_resp;
# if defined(MPIDI_CH3_PKT_DECL)
MPIDI_CH3_PKT_DECL
# endif
......
......@@ -13,7 +13,8 @@ typedef enum MPIDI_RMA_Op_type_e {
MPIDI_RMA_LOCK = 26,
MPIDI_RMA_ACC_CONTIG = 27,
MPIDI_RMA_GET_ACCUMULATE = 28,
MPIDI_RMA_COMPARE_AND_SWAP = 29
MPIDI_RMA_COMPARE_AND_SWAP = 29,
MPIDI_RMA_FETCH_AND_OP = 30
} MPIDI_RMA_Op_type_t;
/* Special case RMA operations */
......
......@@ -594,6 +594,12 @@ int MPIDI_CH3_PktHandler_Init( MPIDI_CH3_PktHandler_Fcn *pktArray[],
MPIDI_CH3_PktHandler_CAS;
pktArray[MPIDI_CH3_PKT_CAS_RESP] =
MPIDI_CH3_PktHandler_CASResp;
pktArray[MPIDI_CH3_PKT_FOP] =
MPIDI_CH3_PktHandler_FOP;
pktArray[MPIDI_CH3_PKT_FOP_UNLOCK] =
MPIDI_CH3_PktHandler_FOP;
pktArray[MPIDI_CH3_PKT_FOP_RESP] =
MPIDI_CH3_PktHandler_FOPResp;
/* End of default RMA operations */
fn_fail:
......
......@@ -251,3 +251,83 @@ fn_fail:
}
#undef FUNCNAME
#define FUNCNAME MPIDI_Fetch_and_op
#undef FCNAME
#define FCNAME MPIDI_QUOTE(FUNCNAME)
int MPIDI_Fetch_and_op(const void *origin_addr, void *result_addr,
MPI_Datatype datatype, int target_rank,
MPI_Aint target_disp, MPI_Op op, MPID_Win *win_ptr)
{
int mpi_errno = MPI_SUCCESS;
int rank;
MPIDI_RMA_ops *new_ptr;
MPIU_CHKPMEM_DECL(1);
MPIDI_STATE_DECL(MPID_STATE_MPIDI_COMPARE_AND_SWAP);
MPIDI_RMA_FUNC_ENTER(MPID_STATE_MPIDI_COMPARE_AND_SWAP);
if (target_rank == MPI_PROC_NULL) {
goto fn_exit;
}
rank = win_ptr->myrank;
/* The datatype and op must be predefined. This is checked above the ADI,
* so there's no need to check it again here. */
if (target_rank == rank) {
void *dest_addr = (char *) win_ptr->base + win_ptr->disp_unit * target_disp;
int len, one;
MPI_User_function *uop;
MPID_Datatype_get_size_macro(datatype, len);
MPIU_Memcpy(result_addr, dest_addr, len);
uop = MPIR_OP_HDL_TO_FN(op);
one = 1;
(*uop)((void *) origin_addr, dest_addr, &one, &datatype);
goto fn_exit;
}
else {
/* Append this operation to the RMA ops queue */
MPIU_INSTR_DURATION_START(rmaqueue_alloc);
MPIU_CHKPMEM_MALLOC(new_ptr, MPIDI_RMA_ops *, sizeof(MPIDI_RMA_ops),
mpi_errno, "RMA operation entry");
MPIU_INSTR_DURATION_END(rmaqueue_alloc);
if (win_ptr->rma_ops_list_tail)
win_ptr->rma_ops_list_tail->next = new_ptr;
else
win_ptr->rma_ops_list_head = new_ptr;
win_ptr->rma_ops_list_tail = new_ptr;
MPIU_INSTR_DURATION_START(rmaqueue_set);
new_ptr->next = NULL;
new_ptr->type = MPIDI_RMA_FETCH_AND_OP;
new_ptr->origin_addr = (void *) origin_addr;
new_ptr->origin_count = 1;
new_ptr->origin_datatype = datatype;
new_ptr->target_rank = target_rank;
new_ptr->target_disp = target_disp;
new_ptr->target_count = 1;
new_ptr->target_datatype = datatype;
new_ptr->result_addr = result_addr;
new_ptr->result_count = 1;
new_ptr->result_datatype = datatype;
new_ptr->op = op;
MPIU_INSTR_DURATION_END(rmaqueue_set);
}
fn_exit:
MPIU_CHKPMEM_COMMIT();
MPIDI_RMA_FUNC_EXIT(MPID_STATE_MPIDI_COMPARE_AND_SWAP);
return mpi_errno;
/* --BEGIN ERROR HANDLING-- */
fn_fail:
MPIU_CHKPMEM_REAP();
goto fn_exit;
/* --END ERROR HANDLING-- */
}
......@@ -28,18 +28,6 @@
/* --END ERROR HANDLING-- */
#undef FUNCNAME
#define FUNCNAME MPIDI_Fetch_and_op
#undef FCNAME
#define FCNAME MPIDI_QUOTE(FUNCNAME)
int MPIDI_Fetch_and_op(const void *origin_addr, void *result_addr,
MPI_Datatype datatype, int target_rank, MPI_Aint target_disp,
MPI_Op op, MPID_Win *win)
{
MPIDI_FUNC_NOTIMPL(FETCH_AND_OP)
}
#undef FUNCNAME
#define FUNCNAME MPIDI_Rput
#undef FCNAME
......
......@@ -36,6 +36,7 @@ MPIU_INSTR_DURATION_DECL(rmapkt_acc_predef);
MPIU_INSTR_DURATION_DECL(rmapkt_acc_immed);
MPIU_INSTR_DURATION_DECL(rmapkt_acc_immed_op);
MPIU_INSTR_DURATION_DECL(rmapkt_cas);
MPIU_INSTR_DURATION_DECL(rmapkt_fop);
MPIU_INSTR_DURATION_EXTERN_DECL(rmaqueue_alloc);
MPIU_INSTR_DURATION_EXTERN_DECL(rmaqueue_set);
void MPIDI_CH3_RMA_InitInstr(void);
......@@ -70,6 +71,7 @@ void MPIDI_CH3_RMA_InitInstr(void)
MPIU_INSTR_DURATION_INIT(rmapkt_acc_immed,0,"RMA:PKTHANDLER for Accum immed");
MPIU_INSTR_DURATION_INIT(rmapkt_acc_immed_op,0,"RMA:PKTHANDLER for Accum immed operation");
MPIU_INSTR_DURATION_INIT(rmapkt_cas,0,"RMA:PKTHANDLER for Compare-and-swap");
MPIU_INSTR_DURATION_INIT(rmapkt_fop,0,"RMA:PKTHANDLER for Fetch-and-op");
}
/* These are used to use a common routine to complete lists of RMA
......@@ -290,6 +292,7 @@ int MPIDI_Win_fence(int assert, MPID_Win *win_ptr)
if (mpi_errno) { MPIU_ERR_POP(mpi_errno); }
break;
case (MPIDI_RMA_COMPARE_AND_SWAP):
case (MPIDI_RMA_FETCH_AND_OP):
mpi_errno = MPIDI_CH3I_Send_immed_rmw_msg(curr_ptr, win_ptr,
source_win_handle, target_win_handle,
&curr_ptr->request );
......@@ -895,7 +898,35 @@ static int MPIDI_CH3I_Send_immed_rmw_msg(MPIDI_RMA_ops *rma_op,
MPIU_ERR_CHKANDJUMP(mpi_errno, mpi_errno, MPI_ERR_OTHER, "**ch3|rmamsg");
}
/* TODO: Fetch-and-op implementation will go here */
else if (rma_op->type == MPIDI_RMA_FETCH_AND_OP) {
MPIDI_CH3_Pkt_t upkt;
MPIDI_CH3_Pkt_fop_t *fop_pkt = &upkt.fop;
MPIU_Assert(len <= sizeof(MPIDI_CH3_FOP_Immed_u));
/* If this is the last operation, it also unlocks the window
at the target. */
if (source_win_handle != MPI_WIN_NULL) {
MPIDI_Pkt_init(fop_pkt, MPIDI_CH3_PKT_FOP_UNLOCK);
} else {
MPIDI_Pkt_init(fop_pkt, MPIDI_CH3_PKT_FOP);
}
fop_pkt->addr = (char *) win_ptr->base_addrs[rma_op->target_rank] + win_ptr->disp_units[rma_op->target_rank] * rma_op->target_disp;
fop_pkt->datatype = rma_op->target_datatype;
fop_pkt->target_win_handle = target_win_handle;
fop_pkt->request_handle = resp_req->handle;
fop_pkt->op = rma_op->op;
MPIU_Memcpy( (void *) &fop_pkt->origin_data, rma_op->origin_addr, len );
comm_ptr = win_ptr->comm_ptr;
MPIDI_Comm_get_vc_set_active(comm_ptr, rma_op->target_rank, &vc);
MPIU_THREAD_CS_ENTER(CH3COMM,vc);
mpi_errno = MPIDI_CH3_iStartMsg(vc, fop_pkt, sizeof(*fop_pkt), &req);
MPIU_THREAD_CS_EXIT(CH3COMM,vc);
MPIU_ERR_CHKANDJUMP(mpi_errno, mpi_errno, MPI_ERR_OTHER, "**ch3|rmamsg");
}
else {
MPIU_ERR_SETANDJUMP(mpi_errno, MPI_ERR_OTHER, "**ch3|rmamsg");
......@@ -1437,6 +1468,7 @@ int MPIDI_Win_complete(MPID_Win *win_ptr)
if (mpi_errno) { MPIU_ERR_POP(mpi_errno); }
break;
case (MPIDI_RMA_COMPARE_AND_SWAP):
case (MPIDI_RMA_FETCH_AND_OP):
mpi_errno = MPIDI_CH3I_Send_immed_rmw_msg(curr_ptr, win_ptr,
source_win_handle, target_win_handle,
&curr_ptr->request );
......@@ -1777,7 +1809,9 @@ int MPIDI_Win_unlock(int dest, MPID_Win *win_ptr)
MPIDI_Comm_get_vc_set_active(comm_ptr, dest, &vc);
/* TODO: MPI-3: Add lock->cas->unlock optimization */
if (rma_op->next->next == NULL && rma_op->next->type != MPIDI_RMA_COMPARE_AND_SWAP) {
if ( rma_op->next->next == NULL &&
rma_op->next->type != MPIDI_RMA_COMPARE_AND_SWAP &&
rma_op->next->type != MPIDI_RMA_FETCH_AND_OP ) {
/* Single put, get, or accumulate between the lock and unlock. If it
* is of small size and predefined datatype at the target, we
* do an optimization where the lock and the RMA operation are
......@@ -2021,7 +2055,8 @@ static int MPIDI_CH3I_Do_passive_target_rma(MPID_Win *win_ptr,
pkt is not needed. If there is no get, rma done pkt is needed */
if (win_ptr->rma_ops_list_tail->type == MPIDI_RMA_GET ||
win_ptr->rma_ops_list_tail->type == MPIDI_RMA_COMPARE_AND_SWAP) {
win_ptr->rma_ops_list_tail->type == MPIDI_RMA_COMPARE_AND_SWAP ||
win_ptr->rma_ops_list_tail->type == MPIDI_RMA_FETCH_AND_OP) {
/* last operation sends a response message. no need to wait
for an additional rma done pkt */
*wait_for_rma_done_pkt = 0;
......@@ -2120,6 +2155,7 @@ static int MPIDI_CH3I_Do_passive_target_rma(MPID_Win *win_ptr,
if (mpi_errno) { MPIU_ERR_POP(mpi_errno); }
break;
case (MPIDI_RMA_COMPARE_AND_SWAP):
case (MPIDI_RMA_FETCH_AND_OP):
win_ptr->pt_rma_puts_accs[curr_ptr->target_rank]++;
mpi_errno = MPIDI_CH3I_Send_immed_rmw_msg(curr_ptr, win_ptr,
source_win_handle, target_win_handle,
......@@ -3242,6 +3278,135 @@ int MPIDI_CH3_PktHandler_CASResp( MPIDI_VC_t *vc ATTRIBUTE((unused)),
}
#undef FUNCNAME
#define FUNCNAME MPIDI_CH3_PktHandler_FOP
#undef FCNAME
#define FCNAME MPIDI_QUOTE(FUNCNAME)
int MPIDI_CH3_PktHandler_FOP( MPIDI_VC_t *vc, MPIDI_CH3_Pkt_t *pkt,
MPIDI_msg_sz_t *buflen, MPID_Request **rreqp )
{
int mpi_errno = MPI_SUCCESS;
MPIDI_CH3_Pkt_t upkt;
MPIDI_CH3_Pkt_fop_resp_t *fop_resp_pkt = &upkt.fop_resp;
MPIDI_CH3_Pkt_fop_t *fop_pkt = &pkt->fop;
MPID_Win *win_ptr;
MPID_Request *req;
MPI_User_function *uop;
int len, one;
MPIDI_STATE_DECL(MPID_STATE_MPIDI_CH3_PKTHANDLER_FOP);
MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_CH3_PKTHANDLER_FOP);
MPIU_DBG_MSG(CH3_OTHER,VERBOSE,"received FOP pkt");
MPIU_INSTR_DURATION_START(rmapkt_fop);
/* return the number of bytes processed in this function */
/* data_len == 0 (all within packet) */
*buflen = sizeof(MPIDI_CH3_Pkt_t);
*rreqp = NULL;
MPIDI_Pkt_init(fop_resp_pkt, MPIDI_CH3_PKT_FOP_RESP);
fop_resp_pkt->request_handle = fop_pkt->request_handle;
/* Copy old value into the response packet */
MPID_Datatype_get_size_macro(fop_pkt->datatype, len);
MPIU_Assert(len <= sizeof(MPIDI_CH3_FOP_Immed_u));
MPIU_Memcpy( (void *)&fop_resp_pkt->data, fop_pkt->addr, len );
/* Send the response packet */
MPIU_THREAD_CS_ENTER(CH3COMM,vc);
mpi_errno = MPIDI_CH3_iStartMsg(vc, fop_resp_pkt, sizeof(*fop_resp_pkt), &req);
MPIU_THREAD_CS_EXIT(CH3COMM,vc);
MPIU_ERR_CHKANDJUMP(mpi_errno != MPI_SUCCESS, mpi_errno, MPI_ERR_OTHER, "**ch3|rmamsg");
if (req != NULL) {
MPID_Request_release(req);
}
/* Apply the op */
uop = MPIR_OP_HDL_TO_FN(fop_pkt->op);
one = 1;
(*uop)((void *) &fop_pkt->origin_data, fop_pkt->addr, &one, &fop_pkt->datatype);
/* There are additional steps to take if this is a passive
target RMA or the last operation from the source */
MPID_Win_get_ptr(fop_pkt->target_win_handle, win_ptr);
/* if passive target RMA, increment counter */
if (win_ptr->current_lock_type != MPID_LOCK_NONE)
win_ptr->my_pt_rma_puts_accs++;
if (fop_pkt->type == MPIDI_CH3_PKT_FOP_UNLOCK) {
/* Last RMA operation from source. If active
target RMA, decrement window counter. If
passive target RMA, release lock on window and
grant next lock in the lock queue if there is
any. If it's a shared lock or a lock-put-unlock
type of optimization, we also need to send an
ack to the source. */
if (win_ptr->current_lock_type == MPID_LOCK_NONE) {
/* FIXME: MT: this has to be done atomically */
win_ptr->my_counter -= 1;
MPIDI_CH3_Progress_signal_completion();
}
else {
mpi_errno = MPIDI_CH3I_Release_lock(win_ptr);
/* Without the following signal_completion call, we
sometimes hang */
MPIDI_CH3_Progress_signal_completion();
}
}
fn_exit:
MPIU_INSTR_DURATION_END(rmapkt_fop);
MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_CH3_PKTHANDLER_FOP);
return mpi_errno;
fn_fail:
goto fn_exit;
}
#undef FUNCNAME
#define FUNCNAME MPIDI_CH3_PktHandler_FOPResp
#undef FCNAME
#define FCNAME MPIDI_QUOTE(FUNCNAME)
int MPIDI_CH3_PktHandler_FOPResp( MPIDI_VC_t *vc ATTRIBUTE((unused)),
MPIDI_CH3_Pkt_t *pkt,
MPIDI_msg_sz_t *buflen, MPID_Request **rreqp )
{
int mpi_errno = MPI_SUCCESS;
MPIDI_CH3_Pkt_fop_resp_t *fop_resp_pkt = &pkt->fop_resp;
MPID_Request *req;
int len;
MPIDI_STATE_DECL(MPID_STATE_MPIDI_CH3_PKTHANDLER_FOPRESP);
MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_CH3_PKTHANDLER_FOPRESP);
MPIU_DBG_MSG(CH3_OTHER,VERBOSE,"received FOP response pkt");
MPID_Request_get_ptr(fop_resp_pkt->request_handle, req);
MPID_Datatype_get_size_macro(req->dev.datatype, len);
MPIU_Memcpy( req->dev.user_buf, (void *)&fop_resp_pkt->data, len );
MPIDI_CH3U_Request_complete( req );
*buflen = sizeof(MPIDI_CH3_Pkt_t);
*rreqp = NULL;
fn_exit:
MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_CH3_PKTHANDLER_FOPRESP);
return mpi_errno;
fn_fail:
goto fn_exit;
}
#undef FUNCNAME
#define FUNCNAME MPIDI_CH3_PktHandler_Lock
#undef FCNAME
......
......@@ -82,7 +82,8 @@ noinst_PROGRAMS = \
win_dynamic_acc \
get_acc_local \
compare_and_swap \
linked_list
linked_list \
fetch_and_op
strided_acc_indexed_LDADD = $(LDADD) -lm
strided_acc_onelock_LDADD = $(LDADD) -lm
......
/* -*- Mode: C; c-basic-offset:4 ; -*- */
/*
*
* (C) 2012 by Argonne National Laboratory.
* See COPYRIGHT in top-level directory.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <mpi.h>
#include "mpitest.h"
/* MPI-3 is not yet standardized -- allow MPI-3 routines to be switched off.
*/
#if !defined(USE_STRICT_MPI) && defined(MPICH2)
# define TEST_MPI3_ROUTINES 1
#endif
static const int SQ_LIMIT = 10;
static int SQ_COUNT = 0;
#define SQUELCH(X) \
do { \
if (SQ_COUNT < SQ_LIMIT) { \
SQ_COUNT++; \
X \
} \
} while (0)
#define ITER 100
const int verbose = 0;
int main(int argc, char **argv) {
int i, j, rank, nproc;
int errors = 0, all_errors = 0;
int *val_ptr, *res_ptr;
MPI_Win win;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
val_ptr = malloc(sizeof(int)*nproc);
res_ptr = malloc(sizeof(int)*nproc);
val_ptr[0] = 0;
MPI_Win_create(val_ptr, sizeof(int)*nproc, sizeof(int), MPI_INFO_NULL, MPI_COMM_WORLD, &win);
#ifdef TEST_MPI3_ROUTINES
/* Test self communication */
for (i = 0; i < ITER; i++) {
int one = 1, result;
MPI_Win_lock(MPI_LOCK_EXCLUSIVE, rank, 0, win);
MPIX_Fetch_and_op(&one, &result, MPI_INT, rank, 0, MPI_SUM, win);
MPI_Win_unlock(rank, win);
}
MPI_Win_lock(MPI_LOCK_EXCLUSIVE, rank, 0, win);
if (val_ptr[0] != ITER) {
SQUELCH( printf("%d->%d -- SELF: expected %d, got %d\n", rank, rank, ITER, val_ptr[0]); );