不同机器之间std clock的显着性能差异

Significant performance difference of std clock between different machines

测试其他东西时我偶然发现了一些我还没有弄明白的东西。

让我们看看这个片段:

#include <iostream>
#include <chrono>

int main () {
  int i = 0;
  using namespace std::chrono_literals;

  auto const end = std::chrono::system_clock::now() + 5s;
  while (std::chrono::system_clock::now() < end) {
    ++i;
  }
  std::cout << i;
}

我注意到计数在很大程度上取决于我执行它的机器。
我用 gcc 7.3、8.2 和 clang 6.0 编译过 std=c++17 -O3.

在 i7-4790(4.17.14-arch1-1-ARCH 内核)上:~3e8
但在 Xeon E5-2630 v4 (3.10.0-514.el7.x86_64) 上:~8e6

现在这是我想了解的差异,所以我已经检查过 perf stat -d

在 i7 上:

       4999.419546      task-clock:u (msec)       #    0.999 CPUs utilized          
                 0      context-switches:u        #    0.000 K/sec                  
                 0      cpu-migrations:u          #    0.000 K/sec                  
               120      page-faults:u             #    0.024 K/sec                  
    19,605,598,394      cycles:u                  #    3.922 GHz                      (49.94%)
    33,601,884,120      instructions:u            #    1.71  insn per cycle           (62.48%)
     7,397,994,820      branches:u                # 1479.771 M/sec                    (62.53%)
            34,788      branch-misses:u           #    0.00% of all branches          (62.58%)
    10,809,601,166      L1-dcache-loads:u         # 2162.171 M/sec                    (62.41%)
            13,632      L1-dcache-load-misses:u   #    0.00% of all L1-dcache hits    (24.95%)
             3,944      LLC-loads:u               #    0.789 K/sec                    (24.95%)
             1,034      LLC-load-misses:u         #   26.22% of all LL-cache hits     (37.42%)

       5.003180401 seconds time elapsed

       4.969048000 seconds user
       0.016557000 seconds sys

至强:

       5001.000000      task-clock (msec)         #    0.999 CPUs utilized          
                42      context-switches          #    0.008 K/sec                  
                 2      cpu-migrations            #    0.000 K/sec                  
               412      page-faults               #    0.082 K/sec                  
    15,100,238,798      cycles                    #    3.019 GHz                      (50.01%)
       794,184,899      instructions              #    0.05  insn per cycle           (62.51%)
       188,083,219      branches                  #   37.609 M/sec                    (62.49%)
            85,924      branch-misses             #    0.05% of all branches          (62.51%)
       269,848,346      L1-dcache-loads           #   53.959 M/sec                    (62.49%)
           246,532      L1-dcache-load-misses     #    0.09% of all L1-dcache hits    (62.51%)
            13,327      LLC-loads                 #    0.003 M/sec                    (49.99%)
             7,417      LLC-load-misses           #   55.65% of all LL-cache hits     (50.02%)

       5.006139971 seconds time elapsed

突然出现的是 Xeon 上每个周期的少量指令以及我不理解的非零上下文切换。但是,我无法使用这些诊断来得出解释。

为了让问题更加古怪,在尝试调试时,我还在一台机器上静态编译并在另一台机器上执行。

在 Xeon 上,静态编译的可执行文件的输出降低了约 10%,在 xeon 或 i7 上编译没有区别。
在 i7 上做同样的事情,计数器实际上从 3e8 下降到 ~2e7

最后我还有两个问题:

编辑: 在将 centos 7 机器上的内核更新到 4.18 之后,我们实际上看到了从 ~ 8e65e6 的额外下降。

perf 有趣地显示了不同的数字:

   5002.000000      task-clock:u (msec)       #    0.999 CPUs utilized          
             0      context-switches:u        #    0.000 K/sec                  
             0      cpu-migrations:u          #    0.000 K/sec                  
           119      page-faults:u             #    0.024 K/sec                  
   409,723,790      cycles:u                  #    0.082 GHz                      (50.00%)
   392,228,592      instructions:u            #    0.96  insn per cycle           (62.51%)
   115,475,503      branches:u                #   23.086 M/sec                    (62.51%)
        26,355      branch-misses:u           #    0.02% of all branches          (62.53%)
   115,799,571      L1-dcache-loads:u         #   23.151 M/sec                    (62.51%)
        42,327      L1-dcache-load-misses:u   #    0.04% of all L1-dcache hits    (62.50%)
            88      LLC-loads:u               #    0.018 K/sec                    (49.96%)
             2      LLC-load-misses:u         #    2.27% of all LL-cache hits     (49.98%)

   5.005940327 seconds time elapsed

   0.533000000 seconds user
   4.469000000 seconds sys

有趣的是,不再有上下文切换,每个周期的指令显着增加,但周期和 colck 非常低!

感谢 @Imran 上面的评论,我已经能够在两台机器上重现各自的测量结果。 (发布此答案以结束问题,如果 Imran 应该 post 我很乐意接受他的答案)

确实与可用时钟源有关。不幸的是,XEON 在其内核参数中有 notsc 标志,这就是 tsc 时钟源不可用和未被选中的原因。

因此对于 运行 遇到此问题的任何人:
1. 检查 /sys/devices/system/clocksource/clocksource0/current_clocksource
中的时钟源 2. 检查 /sys/devices/system/clocksource/clocksource0/available_clocksource
中可用的时钟源 3. 如果找不到 tsc,请检查 dmesg | grep tsc 以检查 notsc

的内核参数