#include <errno.h>
#include "simix/smx_private.h"
#include "surf/surf.h"
+#include "simgrid/sg_config.h"
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_base, smpi, "Logging specific to SMPI (base)");
if(ref->src == MPI_ANY_SOURCE)ref->real_src = req->src;
if(ref->tag == MPI_ANY_TAG)ref->real_tag = req->tag;
if(ref->real_size < req->real_size) ref->truncated = 1;
- else ref->truncated = 0;
+ if(req->detached==1){
+ ref->detached_sender=req; //tie the sender to the receiver, as it is detached and has to be freed in the receiver
+ }
return 1;
}else return 0;
}
if(req->src == MPI_ANY_SOURCE)req->real_src = ref->src;
if(req->tag == MPI_ANY_TAG)req->real_tag = ref->tag;
if(req->real_size < ref->real_size) req->truncated = 1;
- else ref->truncated = 0;
+ if(ref->detached==1){
+ req->detached_sender=ref; //tie the sender to the receiver, as it is detached and has to be freed in the receiver
+ }
+
return 1;
} else return 0;
}
+
+typedef struct s_smpi_factor *smpi_factor_t;
+typedef struct s_smpi_factor {
+ long factor;
+ int nb_values;
+ double values[4];//arbitrary set to 4
+} s_smpi_factor_t;
+xbt_dynar_t smpi_os_values = NULL;
+xbt_dynar_t smpi_or_values = NULL;
+
+
+// Methods used to parse and store the values for timing injections in smpi
+// These are taken from surf/network.c and generalized to have more factors
+// These methods should be merged with those in surf/network.c (moved somewhere in xbt ?)
+
+static int factor_cmp(const void *pa, const void *pb)
+{
+ return (((s_smpi_factor_t*)pa)->factor > ((s_smpi_factor_t*)pb)->factor);
+}
+
+
+static xbt_dynar_t parse_factor(const char *smpi_coef_string)
+{
+ char *value = NULL;
+ unsigned int iter = 0;
+ s_smpi_factor_t fact;
+ int i=0;
+ xbt_dynar_t smpi_factor, radical_elements, radical_elements2 = NULL;
+
+ smpi_factor = xbt_dynar_new(sizeof(s_smpi_factor_t), NULL);
+ radical_elements = xbt_str_split(smpi_coef_string, ";");
+ xbt_dynar_foreach(radical_elements, iter, value) {
+ fact.nb_values=0;
+ radical_elements2 = xbt_str_split(value, ":");
+ if (xbt_dynar_length(radical_elements2) <2 || xbt_dynar_length(radical_elements2) > 5)
+ xbt_die("Malformed radical for smpi factor!");
+ for(i =0; i<xbt_dynar_length(radical_elements2);i++ ){
+ if (i==0){
+ fact.factor = atol(xbt_dynar_get_as(radical_elements2, i, char *));
+ }else{
+ fact.values[fact.nb_values] = atof(xbt_dynar_get_as(radical_elements2, i, char *));
+ fact.nb_values++;
+ }
+ }
+
+ xbt_dynar_push_as(smpi_factor, s_smpi_factor_t, fact);
+ XBT_DEBUG("smpi_factor:\t%ld : %d values, first: %f", fact.factor, fact.nb_values ,fact.values[0]);
+ xbt_dynar_free(&radical_elements2);
+ }
+ xbt_dynar_free(&radical_elements);
+ iter=0;
+ xbt_dynar_sort(smpi_factor, &factor_cmp);
+ xbt_dynar_foreach(smpi_factor, iter, fact) {
+ XBT_DEBUG("smpi_factor:\t%ld : %d values, first: %f", fact.factor, fact.nb_values ,fact.values[0]);
+ }
+ return smpi_factor;
+}
+
+static double smpi_os(double size)
+{
+ if (!smpi_os_values)
+ smpi_os_values =
+ parse_factor(sg_cfg_get_string("smpi/os"));
+
+ unsigned int iter = 0;
+ s_smpi_factor_t fact;
+ double current=0.0;
+ xbt_dynar_foreach(smpi_os_values, iter, fact) {
+ if (size <= fact.factor) {
+ XBT_DEBUG("os : %lf <= %ld return %f", size, fact.factor, current);
+ return current;
+ }else{
+ current=fact.values[0]+fact.values[1]*size;
+ }
+ }
+ XBT_DEBUG("os : %lf > %ld return %f", size, fact.factor, current);
+
+ return current;
+}
+
+static double smpi_or(double size)
+{
+ if (!smpi_or_values)
+ smpi_or_values =
+ parse_factor(sg_cfg_get_string("smpi/or"));
+
+ unsigned int iter = 0;
+ s_smpi_factor_t fact;
+ double current=0.0;
+ xbt_dynar_foreach(smpi_or_values, iter, fact) {
+ if (size <= fact.factor) {
+ XBT_DEBUG("or : %lf <= %ld return %f", size, fact.factor, current);
+ return current;
+ }else
+ current=fact.values[0]+fact.values[1]*size;
+ }
+ XBT_DEBUG("or : %lf > %ld return %f", size, fact.factor, current);
+
+ return current;
+}
+
static MPI_Request build_request(void *buf, int count,
MPI_Datatype datatype, int src, int dst,
int tag, MPI_Comm comm, unsigned flags)
if(datatype->has_subtype == 1){
// This part handles the problem of non-contiguous memory
old_buf = buf;
- buf = malloc(count*smpi_datatype_size(datatype));
+ buf = xbt_malloc(count*smpi_datatype_size(datatype));
if (flags & SEND) {
subtype->serialize(old_buf, buf, count, datatype->substruct);
}
request->action = NULL;
request->flags = flags;
request->detached = 0;
+ request->detached_sender = NULL;
+
+ request->truncated = 0;
+ request->real_size = 0;
+ request->real_tag = 0;
+
+ request->refcount=1;
#ifdef HAVE_TRACING
request->send = 0;
request->recv = 0;
#endif
+ if (flags & SEND) smpi_datatype_unuse(datatype);
+
return request;
}
MPI_Request request =
build_request(buf, count, datatype, smpi_comm_rank(comm), dst, tag,
comm, PERSISTENT | SEND);
-
+ request->refcount++;
return request;
}
MPI_Request request =
build_request(buf, count, datatype, src, smpi_comm_rank(comm), tag,
comm, PERSISTENT | RECV);
-
+ request->refcount++;
return request;
}
"Cannot (re)start a non-finished communication");
if(request->flags & RECV) {
print_request("New recv", request);
- if (request->size < surf_cfg_get_int("smpi/async_small_thres"))
+ if (request->size < sg_cfg_get_int("smpi/async_small_thres"))
mailbox = smpi_process_mailbox_small();
else
mailbox = smpi_process_mailbox();
// we make a copy here, as the size is modified by simix, and we may reuse the request in another receive later
request->real_size=request->size;
+ smpi_datatype_use(request->old_type);
request->action = simcall_comm_irecv(mailbox, request->buf, &request->real_size, &match_recv, request);
- if (request->action)request->action->comm.refcount++;
+
+ double sleeptime = smpi_or(request->size);
+ if(sleeptime!=0.0){
+ simcall_process_sleep(sleeptime);
+ XBT_DEBUG("receiving size of %zu : sleep %lf ", request->size, smpi_or(request->size));
+ }
+
} else {
int receiver = smpi_group_index(smpi_comm_group(request->comm), request->dst);
/* return;*/
/* }*/
print_request("New send", request);
- if (request->size < surf_cfg_get_int("smpi/async_small_thres")) { // eager mode
+ if (request->size < sg_cfg_get_int("smpi/async_small_thres")) { // eager mode
mailbox = smpi_process_remote_mailbox_small(receiver);
}else{
XBT_DEBUG("Send request %p is not in the permanent receive mailbox (buf: %p)",request,request->buf);
}
if (request->size < 64*1024 ) { //(FIXME: this limit should be configurable)
void *oldbuf = NULL;
+ request->detached = 1;
+ request->refcount++;
if(request->old_type->has_subtype == 0){
oldbuf = request->buf;
- request->detached = 1;
if (oldbuf){
- request->buf = malloc(request->size);
+ request->buf = xbt_malloc(request->size);
memcpy(request->buf,oldbuf,request->size);
}
}
}
// we make a copy here, as the size is modified by simix, and we may reuse the request in another receive later
request->real_size=request->size;
-
+ smpi_datatype_use(request->old_type);
+ double sleeptime = smpi_os(request->size);
+ if(sleeptime!=0.0){
+ simcall_process_sleep(sleeptime);
+ XBT_DEBUG("sending size of %zu : sleep %lf ", request->size, smpi_os(request->size));
+ }
request->action =
simcall_comm_isend(mailbox, request->size, -1.0,
request->buf, request->real_size,
request,
// detach if msg size < eager/rdv switch limit
request->detached);
- if (request->action)request->action->comm.refcount++;
#ifdef HAVE_TRACING
/* FIXME: detached sends are not traceable (request->action == NULL) */
void smpi_mpi_request_free(MPI_Request * request)
{
- xbt_free(*request);
- *request = MPI_REQUEST_NULL;
+
+ if((*request) != MPI_REQUEST_NULL){
+ (*request)->refcount--;
+ if((*request)->refcount<0) xbt_die("wrong refcount");
+
+ if((*request)->refcount==0){
+ xbt_free(*request);
+ *request = MPI_REQUEST_NULL;
+ }
+ }else{
+ xbt_die("freeing an already free request");
+ }
}
MPI_Request smpi_isend_init(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);
+ build_request(buf, count, datatype, smpi_comm_rank(comm), dst, tag,
+ comm, NON_PERSISTENT | SEND);
smpi_mpi_start(request);
return request;
int src, int tag, MPI_Comm comm)
{
MPI_Request request =
- smpi_irecv_init(buf, count, datatype, src, tag, comm);
+ build_request(buf, count, datatype, src, smpi_comm_rank(comm), tag,
+ comm, NON_PERSISTENT | RECV);
smpi_mpi_start(request);
return request;
void smpi_mpi_send(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 | RECV_DELETE);
-
- smpi_mpi_start(request);
+ MPI_Request request;
+ request = smpi_mpi_isend(buf, count, datatype, dst, tag, comm);
smpi_mpi_wait(&request, MPI_STATUS_IGNORE);
}
static void finish_wait(MPI_Request * request, MPI_Status * status)
{
MPI_Request req = *request;
-
- if(status != MPI_STATUS_IGNORE) {
- status->MPI_SOURCE = req->src == MPI_ANY_SOURCE ? req->real_src : req->src;
- status->MPI_TAG = req->tag == MPI_ANY_TAG ? req->real_tag : req->tag;
- if(req->truncated)
- status->MPI_ERROR = MPI_ERR_TRUNCATE;
- else status->MPI_ERROR = MPI_SUCCESS ;
- // this handles the case were size in receive differs from size in send
- // FIXME: really this should just contain the count of receive-type blocks,
- // right?
- status->count = req->real_size;
- }
- req = *request;
-
- print_request("Finishing", req);
- MPI_Datatype datatype = req->old_type;
-
- if(datatype->has_subtype == 1){
- // This part handles the problem of non-contignous memory
- // the unserialization at the reception
- s_smpi_subtype_t *subtype = datatype->substruct;
- if(req->flags & RECV) {
- subtype->unserialize(req->buf, req->old_buf, req->real_size/smpi_datatype_size(datatype) , datatype->substruct);
- }
- if(req->detached == 0) free(req->buf);
- }
-
-
-
- if(req->flags & NON_PERSISTENT) {
- if(req->flags & RECV &&
- req->action &&
- (req->action->state == SIMIX_DONE))
- {
- MPI_Request sender_request = (MPI_Request)SIMIX_comm_get_src_data(req->action);
- if((sender_request!=MPI_REQUEST_NULL) &&
- ( sender_request->detached ) &&
- ( sender_request->flags & RECV_DELETE))
- {
- //we are in a receiver's wait from a detached send
- //we have to clean the sender's side request here.... but only if done by a send, not an isend
- //the request lives senderside for an isend. As detached is currently for send + isend, we use RECV_DELETE to separate them
- //FIXME : see if just removing detached status for isend is also good
- smpi_mpi_request_free(&sender_request);
- }
+ if(!(req->detached && req->flags & SEND)){
+ if(status != MPI_STATUS_IGNORE) {
+ status->MPI_SOURCE = req->src == MPI_ANY_SOURCE ? req->real_src : req->src;
+ status->MPI_TAG = req->tag == MPI_ANY_TAG ? req->real_tag : req->tag;
+ if(req->truncated)
+ status->MPI_ERROR = MPI_ERR_TRUNCATE;
+ else status->MPI_ERROR = MPI_SUCCESS ;
+ // this handles the case were size in receive differs from size in send
+ // FIXME: really this should just contain the count of receive-type blocks,
+ // right?
+ status->count = req->real_size;
}
+ print_request("Finishing", req);
+ MPI_Datatype datatype = req->old_type;
- if(req->action){
- //if we want to free our request, we have to invalidate it at the other end of the comm
- if(req->flags & SEND){
- req->action->comm.src_data=MPI_REQUEST_NULL;
- }else{
- req->action->comm.dst_data=MPI_REQUEST_NULL;
+ if(datatype->has_subtype == 1){
+ // This part handles the problem of non-contignous memory
+ // the unserialization at the reception
+ s_smpi_subtype_t *subtype = datatype->substruct;
+ if(req->flags & RECV) {
+ subtype->unserialize(req->buf, req->old_buf, req->real_size/smpi_datatype_size(datatype) , datatype->substruct);
}
-
- smx_action_t temp=req->action;
- if(req->action->comm.refcount == 1)req->action = NULL;
- SIMIX_comm_destroy(temp);
+ if(req->detached == 0) free(req->buf);
}
+ smpi_datatype_unuse(datatype);
+ }
+ if(req->detached_sender!=NULL){
+ smpi_mpi_request_free(&(req->detached_sender));
+ }
-
+ if(req->flags & NON_PERSISTENT) {
smpi_mpi_request_free(request);
-
-
} else {
- if(req->action)SIMIX_comm_destroy(req->action);
req->action = NULL;
}
}
else
flag = simcall_comm_test((*request)->action);
if(flag) {
+ (*request)->refcount++;
finish_wait(request, status);
}else{
smpi_empty_status(status);
print_request("New iprobe", request);
// We have to test both mailboxes as we don't know if we will receive one one or another
- if (surf_cfg_get_int("smpi/async_small_thres")>0){
+ if (sg_cfg_get_int("smpi/async_small_thres")>0){
mailbox = smpi_process_mailbox_small();
XBT_DEBUG("trying to probe the perm recv mailbox");
request->action = simcall_comm_iprobe(mailbox, request->src, request->tag, &match_recv, (void*)request);
print_request("Waiting", *request);
if ((*request)->action != NULL) { // this is not a detached send
simcall_comm_wait((*request)->action, -1.0);
- finish_wait(request, status);
}
+ finish_wait(request, status);
+
// FIXME for a detached send, finish_wait is not called:
}
comms = xbt_dynar_new(sizeof(smx_action_t), NULL);
map = xbt_new(int, count);
size = 0;
- XBT_DEBUG("Wait for one of");
+ XBT_DEBUG("Wait for one of %d", count);
for(i = 0; i < count; i++) {
- if((requests[i] != MPI_REQUEST_NULL) && (requests[i]->action != NULL)) {
- print_request("Waiting any ", requests[i]);
- xbt_dynar_push(comms, &requests[i]->action);
- map[size] = i;
- size++;
+ if(requests[i] != MPI_REQUEST_NULL) {
+ if (requests[i]->action != NULL) {
+ XBT_DEBUG("Waiting any %p ", requests[i]);
+ xbt_dynar_push(comms, &requests[i]->action);
+ map[size] = i;
+ size++;
+ }else{
+ //This is a finished detached request, let's return this one
+ size=0;//so we free the dynar but don't do the waitany call
+ index=i;
+ finish_wait(&requests[i], status);//cleanup if refcount = 0
+ requests[i]=MPI_REQUEST_NULL;//set to null
+ break;
+ }
}
}
if(size > 0) {
}
}
}
-
for(c = 0; c < count; c++) {
if(MC_is_active()) {
smpi_mpi_wait(&requests[c], pstat);
}
}
}
+
return retvalue;
}