【发布时间】:2011-07-13 20:40:13
【问题描述】:
我遇到了一个我不明白的性能问题。我正在处理的系统有两个线程,看起来像这样:
版本 A:
- 线程 1:数据处理 -> 数据选择 -> 数据格式化 -> FIFO
- 线程 2:FIFO -> 套接字
“选择”对数据进行精简,线程 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 块数据
- 两个版本都使用相同的 boost 库 (1.45)
- 两者具有相同的优化设置 (-O3)
- 两者都接收完全相同的数据,写出相同的数据,并以相同的速率写入。
- 两者都使用相同的阻塞写入调用。
- 我正在使用完全相同的设置 (Red Hat) 从同一个盒子进行测试
- 线程 2 的“格式化”部分不是问题(我将其删除并重现了问题)
- 网络上的小数据包不是问题(我使用的是 TCP_CORK,并且我已通过 wireshark 确认 TCP 段都是 ~16k)。
- 在套接字写入后立即休眠 1 毫秒会使套接字线程和 iperf(?!) 上的 CPU 使用率回到 0%。
- Poor man 的分析器显示很少(套接字线程几乎总是处于休眠状态)。
- Callgrind 显示的很少(套接字几乎不写寄存器)
- 为 netcat 切换 iperf(写入 /dev/null)不会改变任何东西(实际上 netcat 的 cpu 使用率约为 20%)。
我唯一能想到的是,我在套接字写入周围引入了一个更紧密的循环。但是,在 500 Mbps 时,我不希望我的进程 和 iperf 上的 cpu 使用率会增加?
我不知道为什么会发生这种情况。我和我的同事基本上没有想法。有什么想法或建议吗?在这一点上,我很乐意尝试任何事情。
【问题讨论】:
-
只是一个疯狂的猜测,但也许线程 2 的数据集不再适合 CPU 的缓存,而之前它可以?
-
听起来你需要像oprofile 这样的东西来分析。
标签: c++ multithreading performance sockets boost