错误处理和通信器中止
所有 MCCL 调用返回一个 MCCL 错误代码,如下表所总结。如果 MCCL 调用返回的错误代码与 mcclSuccess 和 mcclInternalError 不同,并且如果 MCCL_DEBUG 设置为 WARN,MCCL 将打印一个人类可读的消息来解释发生了什么。如果 MCCL_DEBUG 设置为 INFO,MCCL 还将打印导致错误的调用堆栈。此消息旨在帮助用户解决问题。
下表总结了如何理解和处理不同的错误。每个案例在以下部分中都有详细说明。
| 错误 | 描述 | 解决方案 | 错误处理 | 组行为 |
|---|---|---|---|---|
mcclSuccess | 无错误 | 无 | 无 | 无 |
mcclUnhandledMusaError | MUSA 调用期间出错(1) | MUSA 配置/使用(1) | 通信器中止(5) | 全局(6) |
mcclSystemError | 系统调用期间出错(1) | 系统配置/使用(1) | 通信器中止(5) | 全局(6) |
mcclInternalError | MCCL 内部出错(2) | 在 MCCL 中修复(2) | 通信器中止(5) | 全局(6) |
mcclInvalidArgument | MCCL 调用的一个参数无效(3) | 在应用程序中修复(3) | 无(3) | 单独(3) |
mcclInvalidUsage | MCCL 调用的使用无效(4) | 在应用程序中修复(4) | 通信器中止(5) | 全局(6) |
mcclInProgress | MCCL 调用仍在进行中 | 使用 mcclCommGetAsyncError 轮询完成 | 无 | 无 |
(1) mcclUnhandledMusaError 和 mcclSystemError 表明 MCCL 对外部组件的调用失败,导致 MCCL 操作失败。错误消息应该解释用户应该查看哪个组件并尝试修复,可能需要系统管理员的帮助。
(2) mcclInternalError 表示 MCCL 错误。它可能不会在 MCCL_DEBUG=WARN 时报告消息,因为它需要在 MCCL 源代码中修复。MCCL_DEBUG=INFO 将打印导致错误的回溯。
(3) mcclInvalidArgument 表示参数值不正确,如空指针或越界值。当返回此错误时,MCCL 调用没有效果。组状态保持不变,通信器仍然正常工作。应用程序可以调用 mcclCommAbort 或继续好像调用没有发生。此错误将立即返回对于组内发生的调用,并适用于该特定的 MCCL 调用。它不会被 mcclGroupEnd 返回,因为 mcclGroupEnd 不接受任何参数。
(4) mcclInvalidUsage 在动态条件导致失败时返回,表示 MCCL API 的使用不正确。
(5) 这些错误对通信器是致命的。为了恢复,应用程序需要在通信器上调用 mcclCommAbort 并重新创建它。
(6) 组内操作的动态错误总是由 mcclGroupEnd 报告,并适用于组内的所有操作,这些操作可能已完成或未完成。应用程序必须在组内的所有通信器上调用 mcclCommAbort。
异步错误和错误处理
一些通信错误,特别是网络错误,通过 mcclCommGetAsyncError 函数报告。经历异步错误的操作通常不会进展,也不会完成。当发生异步错误时,应该中止操作并使用 mcclCommAbort 销毁通信器。当等待 MCCL 操作完成时,应用程序应该调用 mcclCommGetAsyncError 并在发生错误时销毁通信器。
为了安全地中止 MCCL 通信器,MCCL 要求应用程序将通信器设置为非阻塞模式,并确保在调用 mcclCommAbort 时,没有任何线程正在调用任何 MCCL 操作。设置为非阻塞模式后,所有 MCCL 调用,除了 mcclCommDestroy 和 mcclCommAbort,都会变为非阻塞调用。因此,mcclCommAbort 可以在任何阶段调用,包括通信器初始化期间、通信过程中,或通信器最终释放阶段。如果 MCCL 通信器被设置为阻塞模式,那么当发生网络错误时,线程可能会卡在 MCCL 调用内部。
以下代码显示了如何等待 MCCL 操作并轮询异步错误,而不是使用 musaStreamSynchronize。
int mcclStreamSynchronize(musaStream_t stream, mcclComm_t comm) {
musaError_t musaErr;
mcclResult_t mcclErr, mcclAsyncErr;
while (1) {
musaErr = musaStreamQuery(stream);
if (musaErr == musaSuccess)
return 0;
if (musaErr != musaErrorNotReady) {
printf("MUSA Error : musaStreamQuery returned %d\n", musaErr);
return 1;
}
mcclErr = mcclCommGetAsyncError(comm, &mcclAsyncErr);
if (mcclErr != mcclSuccess) {
printf("MCCL Error : mcclCommGetAsyncError returned %d\n", mcclErr);
return 1;
}
if (mcclAsyncErr != mcclSuccess) {
// 发生了异步错误。停止操作并销毁通信器
mcclErr = mcclCommAbort(comm);
if (mcclErr != mcclSuccess)
printf("MCCL Error : mcclCommDestroy returned %d\n", mcclErr);
// 调用者可以中止或尝试创建新的通信器。
return 2;
}
// 我们可能希望让其他线程(包括 MCCL 线程)使用 CPU。
sched_yield();
}
}
相关链接:

