意外的套接字CPU利用率

时间:2011-03-11 23:20:13

标签: c++ multithreading performance sockets boost

我遇到了一个我不理解的性能问题。我正在研究的系统有两个看起来像这样的线程:

版本A:

  • 线程1:数据处理 - >数据选择 - >数据格式 - > FIFO
  • 线程2:FIFO - >插座

其中'Selection'使数据变细,而线程1末尾的FIFO是线程2开头的FIFO(FIFO实际上是TBB并发队列)。出于性能原因,我将线程更改为如下所示:

版本B:

  • 线程1:数据处理 - >数据选择 - > FIFO
  • 线程2:FIFO - >数据格式 - >插座

最初,这种优化证明是成功的。线程1能够实现更高的吞吐量。我对Thread 2的性能看起来并不太认真,因为我预计CPU使用率会更高,并且(由于数据变薄)这不是主要问题。但是,我的一位同事要求对版本A和版本B进行性能比较。为了测试设置我有线程2的套接字(一个boost asio tcp套接字)写入同一个框(127.0.0.1)上的iperf实例显示最大吞吐量的目标。

为了比较这两个设置我首先尝试强制系统以500 Mbps的速率从套接字写出数据。作为性能测试的一部分,我监控了顶部。我看到的让我感到惊讶。版本A没有出现在'top -H'上,也没有出现在iperf上(这实际上是被怀疑的)。然而,版本B(我的'增强版')出现在'top -H'上,cpu利用率约为10%,而且(奇怪的是)iperf出现了8%。

显然,这对我来说意味着我做错了什么。我似乎无法证明我的确如此!我已经确认的事情:

  • 这两个版本都为套接字提供了32k的数据块
  • 两个版本都使用相同的升级库(1.45)
  • 两者都具有相同的优化设置(-O3)
  • 两者都接收完全相同的数据,写出相同的数据,并以相同的速率写入。
  • 两者都使用相同的阻塞写入调用。
  • 我正在使用完全相同的设置(Red Hat)从同一个盒子进行测试
  • 线程2的“格式化”部分问题(我删除了它并重现了问题)
  • 网络上的小数据包问题(我正在使用TCP_CORK,我已经通过wireshark确认TCP分段都是~16k)。
  • 在套接字写入后立即进行1 ms的睡眠会使套接字线程和iperf(?!)上的CPU使用率回到0%。
  • 穷人的探查器显示很少(套接字线程几乎总是在睡觉)。
  • Callgrind显示很少(套接字写甚至几乎没有寄存器)
  • 为netcat切换iperf(写入/ dev / null)不会改变任何东西(实际上netcat的cpu使用率是~20%)。

我唯一能想到的是我在套接字写入中引入了一个更紧密的循环。但是,在500 Mbps时,我不希望我的进程 iperf上的cpu使用量会增加吗?

我不知道为什么会这样。我的同事和我基本上没有想法。有什么想法或建议吗?我很乐意在这一点上尝试任何事情。

3 个答案:

答案 0 :(得分:0)

如果没有代码片段或实际数据量,这将很难分析。

有一件事是我想到的:如果预格式化的数据流明显大于后格式化,那么您可能会花费更多的带宽/周期来通过FIFO(套接字)边界复制更多数据。

尝试估算或测量每个阶段的数据速率。如果“选择”输出的数据速率较高,请考虑将格式移动到边界另一侧的效果。配置A中的select->格式转换是否可能不需要复制,配置B是否需要大量复制?

......只是在没有更深入了解系统的猜测中。

答案 1 :(得分:0)

如果FIFO是版本A中的瓶颈怎么办。那么两个线程都会在大多数时间内等待FIFO。在版本B中,您将更快地将数据移交给iperf

答案 2 :(得分:0)

您在FIFO队列中存储的确切内容是什么?你存储数据包,即缓冲区吗?

在版本A中,您将格式化数据(可能是字节)写入队列。因此,在套接字上发送它只需写出一个固定大小的缓冲区。

但是在版本B中,您将高级数据存储在队列中。格式化它现在创建更大的缓冲区大小,直接写入套接字。这导致TCp / ip堆栈在分段和处理中花费CPU周期。开销...

这是我的理论基于你到目前为止所说的内容。