Skip to content

Commit 35c3f0c

Browse files
committed
MPI_Waitsome performance improvement
by avoiding extra atomic exchanges. The fix is based on MPI spec: 12.4.2 Multiple threads completing the same request. A program in which two threads block, waiting on the same request, is erroneous. Similarly, the same request cannot appear in the array of requests of two concurrent MPI_{WAIT|TEST}{ANY|SOME|ALL} calls. In MPI, a request can only be completed once. Any combination of wait or test that violates this rule is erroneous." We add marked flag to the request structure. Only MPI_Waitsome thread will use/access it by any means. PML threads will not see/touch it. So given that any particular request can be used no more than in one MPI_Waitsome we are safe to do this change.
1 parent fb44c3b commit 35c3f0c

File tree

1 file changed

+19
-9
lines changed

1 file changed

+19
-9
lines changed

ompi/request/req_wait.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,8 @@ int ompi_request_default_wait_some(size_t count,
381381

382382
*outcount = 0;
383383

384+
memset(indices, 0, sizeof(indices[0]) * count);
385+
384386
rptr = requests;
385387
num_requests_null_inactive = 0;
386388
num_requests_done = 0;
@@ -399,6 +401,7 @@ int ompi_request_default_wait_some(size_t count,
399401
/* If the request is completed go ahead and mark it as such */
400402
assert( REQUEST_COMPLETE(request) );
401403
num_requests_done++;
404+
indices[i] = 1;
402405
} else {
403406
sync_sets++;
404407
}
@@ -427,17 +430,24 @@ int ompi_request_default_wait_some(size_t count,
427430
if( request->req_state == OMPI_REQUEST_INACTIVE ) {
428431
continue;
429432
}
430-
/* Atomically mark the request as pending. If this succeed
431-
* then the request was not completed, and it is now marked as
432-
* pending. Otherwise, the request is complete )either it was
433-
* before or it has been meanwhile). The major drawback here
434-
* is that we will do all the atomics operations in all cases.
433+
/* Here we have 3 possibilities:
434+
* a) request was found completed in the first loop
435+
* => ( indices[i] == 1 )
436+
* b) request was completed between first loop and this check
437+
* => ( indices[i] == 0 ) and we can NOT atomically mark the
438+
* request as pending.
439+
* c) request wasn't finished yet
440+
* => ( indices[i] == 0 ) and we CAN atomically mark the
441+
* request as pending.
442+
* NOTE that in any case (i >= num_requests_done) as latter grows
443+
* either slowly (in case of partial completion)
444+
* OR in parallel with `i` (in case of full set completion)
435445
*/
436-
if( !OPAL_ATOMIC_CMPSET_PTR(&request->req_complete, &sync, REQUEST_PENDING) ) {
437-
indices[num_requests_done] = i;
438-
num_requests_done++;
446+
if( indices[i] ){
447+
indices[num_requests_done++] = i;
448+
} else if( !OPAL_ATOMIC_CMPSET_PTR(&request->req_complete, &sync, REQUEST_PENDING) ) {
449+
indices[num_requests_done++] = i;
439450
} else {
440-
/* request wasn't finished during this call */
441451
sync_unsets++;
442452
}
443453
}

0 commit comments

Comments
 (0)