上一章中,我们对不同线程的状态进行分片,避免了线程之间的同步,将传输速度提升到了 1522.738 Gbps,可惜依然只达到了总带宽 3200 Gbps 的 47.6%。显然 CPU 仍然是瓶颈,我们需要进一步优化。

我们在 ContinuePostWrite() 函数中提交新的 WRITE 操作时,每次只会提交一个操作。随后 CPU 的控制流就会离开这个函数,进入到其他的函数中。这样 CPU 的控制流就会频繁地在不同的函数之间切换,导致 CPU 的缓存失效率增加。我们可以尝试将多个操作一起提交,减少 CPU 的控制流切换。我们把本章的程序命名为 14_batch.cpp

批量提交操作

本章的修改非常简单。只需要在 ContinuePostWrite() 函数中增加一个循环,每次提交16个操作。

struct RandomFillRequestState {
  // ...

  void ContinuePostWrite(size_t gpu_idx) {
    constexpr int kBatchSize = 16;
    auto &s = write_states[gpu_idx];
    if (s.i_repeat == total_repeat)
      return;
    auto page_size = request_msg->page_size;
    auto num_pages = request_msg->num_pages;
    auto &group = (*net_groups)[gpu_idx];
    for (int i = 0; i < kBatchSize; ++i) {
      auto net_idx = group.GetNext();
      group.nets[net_idx]->PostWrite(...);
      ++posted_write_ops[gpu_idx];

      if (++s.i_page == num_pages) {
        s.i_page = 0;
        if (++s.i_buf == buf_per_gpu) {
          s.i_buf = 0;
          if (++s.i_repeat == total_repeat)
            return;
        }
      }
    }
  }
};

运行效果

从上面的视频中可以看到,我们在 ContinuePostWrite() 一次性提交16个操作之后,传输速度达到了 2589.488 Gbps,达到了总带宽 3200 Gbps 的 80.9%,相比起之前的 1522.567 Gbps 几乎翻倍。现在我们已经离满速 3200 Gbps 不远了,下一章我们将进一步榨干性能。

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