|
14 | 14 | #include <sched.h> |
15 | 15 | #include <stdlib.h> |
16 | 16 | #include <string.h> |
| 17 | +#include <time.h> |
17 | 18 | #include <unistd.h> |
18 | 19 |
|
19 | 20 | #ifndef FLAGCX_RMA_QUEUE_SIZE |
@@ -51,17 +52,29 @@ struct flagcxRmaDoneWaitCtx { |
51 | 52 | volatile uint64_t *doneSeqsCpu; // pointer to proxy's doneSeqsCpu[peer] |
52 | 53 | uint64_t opSeq; // sequence to wait for |
53 | 54 | volatile int *rmaError; // proxy error flag |
| 55 | + pthread_mutex_t *doneMutex; // proxy done condvar mutex |
| 56 | + pthread_cond_t *doneCond; // proxy done condvar |
54 | 57 | }; |
55 | 58 |
|
56 | 59 | // Host-func callback: blocks stream until proxy signals completion. |
| 60 | +// Uses condvar to sleep instead of spinning — zero CPU while waiting. |
57 | 61 | static void flagcxRmaDoneWaitHostFunc(void *arg) { |
58 | 62 | struct flagcxRmaDoneWaitCtx *ctx = (struct flagcxRmaDoneWaitCtx *)arg; |
| 63 | + pthread_mutex_lock(ctx->doneMutex); |
59 | 64 | while (__atomic_load_n(ctx->doneSeqsCpu, __ATOMIC_ACQUIRE) < ctx->opSeq) { |
60 | 65 | if (__atomic_load_n(ctx->rmaError, __ATOMIC_ACQUIRE)) { |
61 | 66 | break; |
62 | 67 | } |
63 | | - sched_yield(); |
| 68 | + struct timespec ts; |
| 69 | + clock_gettime(CLOCK_REALTIME, &ts); |
| 70 | + ts.tv_nsec += 1000000; // 1ms timeout as safety net |
| 71 | + if (ts.tv_nsec >= 1000000000) { |
| 72 | + ts.tv_sec++; |
| 73 | + ts.tv_nsec -= 1000000000; |
| 74 | + } |
| 75 | + pthread_cond_timedwait(ctx->doneCond, ctx->doneMutex, &ts); |
64 | 76 | } |
| 77 | + pthread_mutex_unlock(ctx->doneMutex); |
65 | 78 | free(ctx); |
66 | 79 | } |
67 | 80 |
|
@@ -96,14 +109,16 @@ static flagcxResult_t flagcxRmaWaitDone(struct flagcxRmaProxyState *proxy, |
96 | 109 | return deviceAdaptor->streamWaitValue64(stream, &proxy->doneSeqsDev[peer], |
97 | 110 | opSeq, 0); |
98 | 111 | } else { |
99 | | - // HOST_FUNC: launch callback that polls doneSeqsCpu until done |
| 112 | + // HOST_FUNC: launch callback that waits on doneCond until done |
100 | 113 | struct flagcxRmaDoneWaitCtx *ctx = |
101 | 114 | (struct flagcxRmaDoneWaitCtx *)malloc(sizeof(*ctx)); |
102 | 115 | if (ctx == NULL) |
103 | 116 | return flagcxSystemError; |
104 | 117 | ctx->doneSeqsCpu = &proxy->doneSeqsCpu[peer]; |
105 | 118 | ctx->opSeq = opSeq; |
106 | 119 | ctx->rmaError = &proxy->rmaError; |
| 120 | + ctx->doneMutex = &proxy->doneMutex; |
| 121 | + ctx->doneCond = &proxy->doneCond; |
107 | 122 | return deviceAdaptor->launchHostFunc(stream, flagcxRmaDoneWaitHostFunc, |
108 | 123 | ctx); |
109 | 124 | } |
@@ -313,6 +328,12 @@ flagcxRmaProxyPollNonPersistCompletion(struct flagcxRmaProxyState *proxy, |
313 | 328 | __atomic_store_n(&proxy->doneSeqsCpu[peer], desc->opSeq, |
314 | 329 | __ATOMIC_RELEASE); |
315 | 330 | __atomic_fetch_add(&proxy->completionCount, 1ULL, __ATOMIC_RELEASE); |
| 331 | + // Wake HOST_FUNC waiters sleeping on doneCond |
| 332 | + if (!proxy->useStreamOps) { |
| 333 | + pthread_mutex_lock(&proxy->doneMutex); |
| 334 | + pthread_cond_broadcast(&proxy->doneCond); |
| 335 | + pthread_mutex_unlock(&proxy->doneMutex); |
| 336 | + } |
316 | 337 | } |
317 | 338 | free(desc); |
318 | 339 | did = true; |
@@ -570,6 +591,9 @@ flagcxResult_t flagcxHeteroRmaProxyStart(flagcxHeteroComm_t comm) { |
570 | 591 | flagcxIntruQueueConstruct(&proxy->inProgressQueues[p]); |
571 | 592 | } |
572 | 593 |
|
| 594 | + pthread_mutex_init(&proxy->doneMutex, NULL); |
| 595 | + pthread_cond_init(&proxy->doneCond, NULL); |
| 596 | + |
573 | 597 | // Allocate device memory for stream-based synchronization. |
574 | 598 | proxy->doneSeqsDev = NULL; |
575 | 599 | proxy->doneSeqsCpu = NULL; |
@@ -659,6 +683,8 @@ flagcxResult_t flagcxHeteroRmaProxyStart(flagcxHeteroComm_t comm) { |
659 | 683 | deviceAdaptor->gdrMemFree(proxy->readySeqsDev, NULL); |
660 | 684 | for (int p = 0; p < nRanks; p++) |
661 | 685 | pthread_mutex_destroy(&proxy->peerProducerMutexes[p]); |
| 686 | + pthread_cond_destroy(&proxy->doneCond); |
| 687 | + pthread_mutex_destroy(&proxy->doneMutex); |
662 | 688 | free(proxy->circularBuffers); |
663 | 689 | free((void *)proxy->pis); |
664 | 690 | free((void *)proxy->cis); |
@@ -691,6 +717,9 @@ flagcxResult_t flagcxHeteroRmaProxyStop(flagcxHeteroComm_t comm) { |
691 | 717 | for (int p = 0; p < proxy->nRanks; p++) |
692 | 718 | pthread_mutex_destroy(&proxy->peerProducerMutexes[p]); |
693 | 719 |
|
| 720 | + pthread_cond_destroy(&proxy->doneCond); |
| 721 | + pthread_mutex_destroy(&proxy->doneMutex); |
| 722 | + |
694 | 723 | // Free CPU mappings / host memory |
695 | 724 | if (proxy->useStreamOps && deviceAdaptor->gdrPtrMunmap != NULL) { |
696 | 725 | if (proxy->doneSeqsCpu != NULL) |
|
0 commit comments