上一章中,批量提交新的 WRITE 操作,使得传输速度达到了 2589.488 Gbps,达到了总带宽 3200 Gbps 的 80.9%。现在满速 3200 Gbps 已经近在咫尺了。

注意到我们每次提交 WRITE 操作的时候,PostWrite() 函数都会调用 ProgressPendingOps()。可以想象的是,如果在同一批次的操作中,如果第一次的 ProgressPendingOps() 无法进步,那么后续的操作必然也无法进步。然而每一次的 ProgressPendingOps() 都会将操作从队头取出,调用 fi_writemsg(),再放回队头。这样的操作是非常低效的。我们可以尝试让 PostWrite() 懒一点,不要每次都调用 ProgressPendingOps()。我们把本章的程序命名为 15_lazy.cpp

惰性提交操作

为了体现操作的惰性,我们把函数名从 PostWrite() 改为 LazyPostWrite(),并且去掉了 ProgressPendingOps() 的调用。

void Network::LazyPostWrite(
    RdmaWriteOp &&write, std::function<void(Network &, RdmaOp &)> &&callback) {
  auto *op = new RdmaOp{
      .type = RdmaOpType::kWrite,
      .write = std::move(write),
      .callback = std::move(callback),
  };
  pending_ops.push_back(op);
  // Caller needs to poll completion to progress pending ops
}

在后续的主循环中,我们会通过 PollCompletion() 调用 ProgressPendingOps(),因此我们无需做更多的修改。

运行效果

从上面的视频中可以看到,我们达到了 3108.283 Gbps,即总带宽 3200 Gbps 的 97.1%。对比第七章中单网卡的 97.433 Gbps (97.4%),以及第三章libfabric 自带的 fi_rma_bw 测试工具达到的 94.751 Gbps (94.8%),我们的程序已经非常接近满速了。

至此,我们已经榨干了 AWS p5 集群的 3200 Gbps 带宽。在这个系列文章中,我们从零开始,认识了 RDMA、EFA、libfabric,感悟了高性能网络系统设计哲学,然后编写代码,一步步地实现了 RECVSEND、GPUDirect RDMA WRITE、操作队列,接着扩展到多网卡,再进行了一系列的优化,最终达到了 3108.283 Gbps (97.1%) 的传输速度。希望这个系列文章对大家有所帮助。

本章代码:https://github.com/abcdabcd987/libfabric-efa-demo/blob/master/src/15_lazy.cpp