【问题标题】:Performance cost of threading constructs: missed optimisations and memory allocation线程构造的性能成本:错过的优化和内存分配
【发布时间】:2015-09-21 15:46:57
【问题描述】:

我们遇到了一个奇怪的现象,其中包含头文件会导致某些内存分配密集型工作负载的性能下降 5-10%。

此头文件将线程池声明为全局变量。此线程池从未在应用程序中以任何容量(尚未)使用。也就是说,除了在程序启动时创建这个静态线程池之外,应用程序完全是单线程的。删除标头后,性能损失就消失了。

通过一些研究,由于某些编译器优化不再可能,多线程应用程序似乎会导致一些性能损失。每当以任何形式或容量实例化与线程相关的构造时,是否有可能关闭此类优化?

或者,由于在执行大量内存分配时性能损失似乎最为明显,在编译/链接阶段编译器是否可能意识到线程构造已被实例化,因此它切换到线程安全的内存分配器?

这发生在带有 GCC 和 clang 的 Linux 64 位工作站上。正在使用来自 C++11 的标准线程原语。

编辑我还应该提到,根据我们的测试,当使用 tcmalloc 分配器而不是默认分配器时,性能差异似乎消失了。

【问题讨论】:

  • 这真的很吸引人。您是否可以发布一个最小的可编译示例来演示该现象?
  • 除了添加的变量之外,目标文件是否发生了变化?
  • 这种“在程序启动时创建静态线程池”是否涉及主线程和/或工作线程中的任何内存分配?
  • 您在不支持的情况下做了一些假设。然而,在 Linux 上,有一个工具可以测量性能并找到争用点。它是perf (perf.wiki.kernel.org/index.php/Main_Page)。您需要使用它并准确找出问题的根源(而不是猜测)。 brendangregg.com/linuxperf.html 是一个关于性能调优的知名博客。作为提示:perf record - 使用 CPU 周期记录应用程序性能(对于 CPU 密集型应用程序),perf record -F 99 记录应用程序性能以找到争用点。
  • 如果优化被关闭,那么你应该能够在区分objdump -d 的输出时看到这一点。否则……那些线程“活着”吗?那么原因可能是操作系统给了他们时间片,尽管这表明线程设施的实现很不幸。

标签: c++ multithreading c++11


【解决方案1】:

多线程 malloc 和其他一些检查函数会产生锁定成本,这与您所看到的一致。我希望 malloc 实现通过线程头文件中的某些指令更改为线程(和锁定)版本。

这是一个合理的成本,并导致程序的输出更易于理解,但代价是单线程示例的奇怪性能变化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-24
    • 2014-04-30
    • 2011-08-03
    • 1970-01-01
    • 2018-08-22
    • 2016-04-21
    • 1970-01-01
    • 2018-09-14
    相关资源
    最近更新 更多