【问题标题】:what can cause huge variation in runtime of a multithreaded code什么会导致多线程代码运行时的巨大变化
【发布时间】:2016-04-05 15:38:01
【问题描述】:

我不确定 stackoverflow 是否是最好的论坛,但它就在这里......

我们正在对我们的软件进行基准测试。突然间,我们看到了巨大的性能下降。为了测试发生了什么,我们多次在相同的输入上运行该软件。结果令人吃惊(巨大的性能变化):

Solution time = 9.69 sec.
Solution time = 7.55 sec.
Solution time = 4.78 sec.
Solution time = 5.12 sec.
Solution time = 6.94 sec.
Solution time = 2.15 sec.
Solution time = 5.48 sec.

我们的软件是多线程的,在 12 核机器的每个核心(禁用超线程)上只启动一个线程。机器上没有其他东西在运行。在周末之前,我们从未有过这样的运行时间变化。

一时兴起,我们在启用 cpu 绑定的情况下重复了测试(即将 12 个线程中的每一个固定到不同的核心):

Solution time = 0.95 sec.
Solution time = 0.95 sec.
Solution time = 0.95 sec.
Solution time = 0.95 sec.
Solution time = 0.94 sec.
Solution time = 0.95 sec.
Solution time = 0.95 sec.

目前我不知道是什么原因造成的。据我们所知,机器的配置没有任何变化(RHEL 6.6)。如有任何建议,我将不胜感激...

谢谢, --拉齐

编辑

再次强调一下:在过去,非绑定代码确实表现出变化,但最多在 10-15% 左右,平均而言,它非常接近于 cpu 绑定代码(在1-2%)。只是从上周末开始,我们才开始看到这种变化,据我们所知,环境没有任何变化。但是(显然)一定发生了一些变化,我想知道它可能是什么。

EDIT2

我通过 perf 运行代码(重复 10 次),这就是我得到的。

使用 cpu 绑定:

   15713.138442  task-clock-msecs         #      9.341 CPUs    ( +-   0.037% )
           6958  context-switches         #      0.000 M/sec   ( +-   0.357% )
             11  CPU-migrations           #      0.000 M/sec   ( +-   1.786% )
          49147  page-faults              #      0.003 M/sec   ( +-   0.514% )
    45890046261  cycles                   #   2920.489 M/sec   ( +-   0.030% )
    51929307378  instructions             #      1.132 IPC     ( +-   0.021% )
    11050565282  branches                 #    703.269 M/sec   ( +-   0.032% )
      446256370  branch-misses            #      4.038 %       ( +-   0.003% )
      421789915  cache-references         #     26.843 M/sec   ( +-   0.048% )
       18989944  cache-misses             #      1.209 M/sec   ( +-   0.305% )

    1.682190890  seconds time elapsed   ( +-   0.131% )

没有 cpu 绑定:

   36219.945761  task-clock-msecs         #      5.677 CPUs    ( +-   3.978% )
           8742  context-switches         #      0.000 M/sec   ( +-   1.677% )
             34  CPU-migrations           #      0.000 M/sec   ( +-   5.243% )
          48799  page-faults              #      0.001 M/sec   ( +-   0.839% )
   106384797638  cycles                   #   2937.188 M/sec   ( +-   3.989% )
    93465235493  instructions             #      0.879 IPC     ( +-   3.085% )
    23685574664  branches                 #    653.937 M/sec   ( +-   3.672% )
      477076300  branch-misses            #      2.014 %       ( +-   0.563% )
      414008416  cache-references         #     11.430 M/sec   ( +-   0.189% )
       17910783  cache-misses             #      0.495 M/sec   ( +-   1.468% )

    6.380128466  seconds time elapsed   ( +-   5.171% )

请注意,代码是确定性的,即它始终采用相同的执行路径。但是有可能一个线程正忙于等待轮到它与全局确定性状态同步。但是为什么会在周期/指令/等方面造成如此巨大的差异......

还请注意,我已尝试将线程以随机顺序固定到内核,以检验按照创建顺序将线程固定到内核会产生影响的假设。但这并没有什么区别,它仍然很快。

【问题讨论】:

  • 虽然时间差异很大,但我怀疑数据局部性至关重要,而跨内核的线程迁移是造成这种情况的原因。我不禁想知道您的算法是否最大限度地利用了 CPU 中的 L1 和 L2 缓存。您能否就该算法的作用提供一些见解?
  • 另外,你确定你的代码是可重入的吗?任何互斥体,任何需要更新的共享结构?
  • 它是一个混合整数规划求解器。是的,缓存位置确实很重要(不幸的是,我们只得到了大约 90% 的缓存命中率,而且看起来不可能改进)。直到上周末,非绑定代码和 CPU 绑定代码之间的差异为 1-2%,而我们在非绑定代码中观察到的最大变化约为 10-15%。毕竟机器没有加载,内核没有理由频繁迁移线程。是的,代码是可重入的,而且就 helgrind 来说它是正确的。
  • 您可能需要分析您的算法。它会与外界互动吗?任何文件或套接字 i/o?
  • 编辑了帖子,因为很难在评论中添加表格...

标签: linux multithreading performance binding cpu


【解决方案1】:

问题已解决。按照 ekarak 的建议,我深入研究了分析,发现当我们的线程交互并相互等待时,时间被浪费了。凭直觉我重新启动了机器,然后一切恢复正常。

现在,我们在一个集群中有 40 台机器,并且都表现出这种行为。这意味着要么存在外部影响,要么机器的正常运行时间发挥了作用。我用谷歌搜索了“linux uptime 209”,结果发现在这些机器运行的内核中,sched_clock() 中存在一个溢出错误,该错误在 208.5 天后触发。

所以...我们遇到了与机器上的线程交互相关的问题,这些问题已经运行了 209 天,并且 sched_clock() 中存在一个在 208.5 天后出现的错误。这对我来说太巧合了,所以我断定这是我们的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-06
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多