+#include "xbt/time.h"
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_base, smpi,
+ "Logging specific to SMPI (base)");
+XBT_LOG_EXTERNAL_CATEGORY(smpi_base);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_bench);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_kernel);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_mpi);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_mpi_dt);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_coll);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_receiver);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_sender);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_util);
+
+void smpi_process_init(int* argc, char*** argv) {
+ int index;
+ smpi_process_data_t data;
+ smx_process_t proc;
+
+ proc = SIMIX_process_self();
+ index = atoi((*argv)[1]);
+ data = smpi_process_remote_data(index);
+ SIMIX_process_set_data(proc, data);
+ if (*argc > 2) {
+ free((*argv)[1]);
+ memmove(&(*argv)[1], &(*argv)[2], sizeof(char *) * (*argc - 2));
+ (*argv)[(*argc) - 1] = NULL;
+ }
+ (*argc)--;
+ DEBUG2("<%d> New process in the game: %p", index, proc);
+}
+
+void smpi_process_destroy(void) {
+ int index = smpi_process_index();
+
+ DEBUG1("<%d> Process left the game", index);
+}
+
+static MPI_Request build_request(void* buf, int count, MPI_Datatype datatype, int src, int dst, int tag, MPI_Comm comm, unsigned flags) {
+ MPI_Request request;
+
+ request = xbt_new(s_smpi_mpi_request_t, 1);
+ request->buf = buf;
+ request->size = smpi_datatype_size(datatype) * count;
+ request->src = src;
+ request->dst = dst;
+ request->tag = tag;
+ request->comm = comm;
+ request->rdv = NULL;
+ request->pair = NULL;
+ request->complete = 0;
+ request->match = MPI_REQUEST_NULL;
+ request->flags = flags;
+#ifdef HAVE_TRACING
+ request->send = 0;
+ request->recv = 0;
+#endif
+ return request;
+}
+
+/* MPI Low level calls */
+MPI_Request smpi_mpi_send_init(void* buf, int count, MPI_Datatype datatype, int dst, int tag, MPI_Comm comm) {
+ MPI_Request request = build_request(buf, count, datatype, smpi_comm_rank(comm), dst, tag, comm, PERSISTENT | SEND);
+
+ return request;
+}
+
+MPI_Request smpi_mpi_recv_init(void* buf, int count, MPI_Datatype datatype, int src, int tag, MPI_Comm comm) {
+ MPI_Request request = build_request(buf, count, datatype, src, smpi_comm_rank(comm), tag, comm, PERSISTENT | RECV);
+
+ return request;
+}
+
+void smpi_mpi_start(MPI_Request request) {
+ xbt_assert0(request->complete == 0, "Cannot start a non-finished communication");
+ if((request->flags & RECV) == RECV) {
+ smpi_process_post_recv(request);
+ print_request("New recv", request);
+ request->pair = SIMIX_network_irecv(request->rdv, request->buf, &request->size);
+ } else {
+ smpi_process_post_send(request->comm, request); // FIXME
+ print_request("New send", request);
+ request->pair = SIMIX_network_isend(request->rdv, request->size, -1.0, request->buf, request->size, NULL);
+ }
+}
+
+void smpi_mpi_startall(int count, MPI_Request* requests) {
+ int i;
+
+ for(i = 0; i < count; i++) {
+ smpi_mpi_start(requests[i]);
+ }
+}
+
+void smpi_mpi_request_free(MPI_Request* request) {
+ xbt_free(*request);
+ *request = MPI_REQUEST_NULL;
+}
+
+MPI_Request smpi_isend_init(void* buf, int count, MPI_Datatype datatype, int dst, int tag, MPI_Comm comm) {
+ MPI_Request request = build_request(buf, count, datatype, smpi_comm_rank(comm), dst, tag, comm, NON_PERSISTENT | SEND);
+
+ return request;
+}
+
+MPI_Request smpi_mpi_isend(void* buf, int count, MPI_Datatype datatype, int dst, int tag, MPI_Comm comm) {
+ MPI_Request request = smpi_isend_init(buf, count, datatype, dst, tag, comm);
+
+ smpi_mpi_start(request);
+ return request;
+}
+
+MPI_Request smpi_irecv_init(void* buf, int count, MPI_Datatype datatype, int src, int tag, MPI_Comm comm) {
+ MPI_Request request = build_request(buf, count, datatype, src, smpi_comm_rank(comm), tag, comm, NON_PERSISTENT | RECV);
+
+ return request;
+}
+
+MPI_Request smpi_mpi_irecv(void* buf, int count, MPI_Datatype datatype, int src, int tag, MPI_Comm comm) {
+ MPI_Request request = smpi_irecv_init(buf, count, datatype, src, tag, comm);
+
+ smpi_mpi_start(request);
+ return request;
+}
+
+void smpi_mpi_recv(void* buf, int count, MPI_Datatype datatype, int src, int tag, MPI_Comm comm, MPI_Status* status) {
+ MPI_Request request;
+
+ request = smpi_mpi_irecv(buf, count, datatype, src, tag, comm);
+ smpi_mpi_wait(&request, status);
+}
+
+void smpi_mpi_send(void* buf, int count, MPI_Datatype datatype, int dst, int tag, MPI_Comm comm) {
+ MPI_Request request;
+
+ request = smpi_mpi_isend(buf, count, datatype, dst, tag, comm);
+ smpi_mpi_wait(&request, MPI_STATUS_IGNORE);
+}
+
+void smpi_mpi_sendrecv(void* sendbuf, int sendcount, MPI_Datatype sendtype, int dst, int sendtag, void* recvbuf, int recvcount, MPI_Datatype recvtype, int src, int recvtag, MPI_Comm comm, MPI_Status* status) {
+ MPI_Request requests[2];
+ MPI_Status stats[2];
+
+ requests[0] = smpi_isend_init(sendbuf, sendcount, sendtype, dst, sendtag, comm);
+ requests[1] = smpi_irecv_init(recvbuf, recvcount, recvtype, src, recvtag, comm);
+ smpi_mpi_startall(2, requests);
+ smpi_mpi_waitall(2, requests, stats);
+ if(status != MPI_STATUS_IGNORE) {
+ // Copy receive status
+ memcpy(status, &stats[1], sizeof(MPI_Status));
+ }
+}
+
+int smpi_mpi_get_count(MPI_Status* status, MPI_Datatype datatype) {
+ return status->count / smpi_datatype_size(datatype);
+}
+
+static void finish_wait(MPI_Request* request, MPI_Status* status) {
+ if(status != MPI_STATUS_IGNORE) {
+ status->MPI_SOURCE = (*request)->src;
+ status->MPI_TAG = (*request)->tag;
+ status->MPI_ERROR = MPI_SUCCESS;
+ status->count = SIMIX_communication_get_dst_buf_size((*request)->pair);
+ }
+ print_request("finishing wait", *request);
+ if((*request)->complete == 1) {
+ SIMIX_rdv_destroy((*request)->rdv);
+ } else {
+ (*request)->match->complete = 1;
+ (*request)->match->match = MPI_REQUEST_NULL;
+ }
+ if(((*request)->flags & NON_PERSISTENT) == NON_PERSISTENT) {
+ smpi_mpi_request_free(request);
+ } else {
+ (*request)->rdv = NULL;
+ (*request)->pair = NULL;
+ }
+}
+
+int smpi_mpi_test(MPI_Request* request, MPI_Status* status) {
+ int flag = (*request)->complete;
+
+ if(flag) {
+ smpi_mpi_wait(request, status);
+ }
+ return flag;
+}
+
+int smpi_mpi_testany(int count, MPI_Request requests[], int* index, MPI_Status* status) {
+ int i, flag;
+
+ *index = MPI_UNDEFINED;
+ flag = 0;
+ for(i = 0; i < count; i++) {
+ if(requests[i] != MPI_REQUEST_NULL && requests[i]->complete) {
+ smpi_mpi_wait(&requests[i], status);
+ *index = i;
+ flag = 1;
+ break;
+ }
+ }
+ return flag;
+}
+
+void smpi_mpi_wait(MPI_Request* request, MPI_Status* status) {
+ print_request("wait", *request);
+ SIMIX_network_wait((*request)->pair, -1.0);
+ finish_wait(request, status);
+}
+
+int smpi_mpi_waitany(int count, MPI_Request requests[], MPI_Status* status) {
+ xbt_dynar_t comms;
+ int i, size, index;
+ int* map;
+
+ index = MPI_UNDEFINED;
+ if(count > 0) {
+ // First check for already completed requests
+ for(i = 0; i < count; i++) {
+ if(requests[i] != MPI_REQUEST_NULL && requests[i]->complete) {
+ index = i;
+ smpi_mpi_wait(&requests[index], status);
+ break;
+ }
+ }
+ if(index == MPI_UNDEFINED) {
+ // Otherwise, wait for a request to complete
+ comms = xbt_dynar_new(sizeof(smx_comm_t), NULL);
+ map = xbt_new(int, count);
+ size = 0;
+ DEBUG0("Wait for one of");
+ for(i = 0; i < count; i++) {
+ if(requests[i] != MPI_REQUEST_NULL && requests[i]->complete == 0) {
+ print_request(" ", requests[i]);
+ xbt_dynar_push(comms, &requests[i]->pair);
+ map[size] = i;
+ size++;
+ }
+ }
+ if(size > 0) {
+ index = SIMIX_network_waitany(comms);
+ index = map[index];
+ finish_wait(&requests[index], status);
+ }
+ xbt_free(map);
+ xbt_dynar_free(&comms);
+ }
+ }
+ return index;
+}
+
+void smpi_mpi_waitall(int count, MPI_Request requests[], MPI_Status status[]) {
+ int index;
+ MPI_Status stat;
+
+ while(count > 0) {
+ index = smpi_mpi_waitany(count, requests, &stat);
+ if(index == MPI_UNDEFINED) {
+ break;
+ }
+ if(status != MPI_STATUS_IGNORE) {
+ memcpy(&status[index], &stat, sizeof(stat));
+ }
+ // FIXME: check this -v
+ // Move the last request to the found position
+ requests[index] = requests[count - 1];
+ requests[count - 1] = MPI_REQUEST_NULL;
+ count--;
+ }
+}
+
+int smpi_mpi_waitsome(int incount, MPI_Request requests[], int* indices, MPI_Status status[]) {
+ int i, count;
+
+ count = 0;
+ for(i = 0; i < incount; i++) {
+ if(requests[i] != MPI_REQUEST_NULL && requests[i]->complete) {
+ smpi_mpi_wait(&requests[i], status != MPI_STATUS_IGNORE ? &status[i] : MPI_STATUS_IGNORE);
+ indices[count] = i;
+ count++;
+ }
+ }
+ return count;
+}
+
+void smpi_mpi_bcast(void* buf, int count, MPI_Datatype datatype, int root, MPI_Comm comm) {
+ // arity=2: a binary tree, arity=4 seem to be a good setting (see P2P-MPI))
+ nary_tree_bcast(buf, count, datatype, root, comm, 4);
+}
+
+void smpi_mpi_barrier(MPI_Comm comm) {
+ // arity=2: a binary tree, arity=4 seem to be a good setting (see P2P-MPI))
+ nary_tree_barrier(comm, 4);
+}