使用单核与2+核时的页面错误数是后者的10倍

2024-06-26 13:47:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我在Linux下用python3.6/Numpy开发的并行代码中观察到一个奇怪的行为:在两个内核上运行它比在单个内核上运行快大约3倍。我不确定我是否了解确切的问题,但我设法找到了一些线索:

  1. 使用perf,我发现一个内核比两个内核出现更多的页面错误(部分运行是因为它们是长时间运行的作业):

1芯

   57414.449252      task-clock:u (msec)       #    1.000 CPUs utilized          
              0      context-switches:u        #    0.000 K/sec                  
              0      cpu-migrations:u          #    0.000 K/sec                  
     22,583,368      page-faults:u             #    0.393 M/sec                  
115,569,738,160      cycles:u                  #    2.013 GHz                    
 22,655,695,268      stalled-cycles-frontend:u #   19.60% frontend cycles idle   
 32,251,136,400      stalled-cycles-backend:u  #   27.91% backend cycles idle    
189,041,318,733      instructions:u            #    1.64  insn per cycle         
                                               #    0.17  stalled cycles per insn
 38,298,469,811      branches:u                #  667.053 M/sec                  
    654,389,291      branch-misses:u           #    1.71% of all branches        
 83,343,166,583      L1-dcache-loads:u         # 1451.606 M/sec                  
    318,284,548      L1-dcache-load-misses:u   #    0.38% of all L1-dcache hits  
 25,589,478,853      L1-icache-loads:u         #  445.698 M/sec                  
  2,560,674,130      L1-icache-load-misses:u   #   10.01% of all L1-icache hits  
 83,377,552,384      dTLB-loads:u              # 1452.205 M/sec                  
    216,145,062      dTLB-load-misses:u        #    0.26% of all dTLB cache hits 
 25,626,979,550      iTLB-loads:u              #  446.351 M/sec                  
     55,847,490      iTLB-load-misses:u        #    0.22% of all iTLB cache hits 
        222,176      L1-dcache-prefetches:u    #    0.004 M/sec                  
        220,870      L1-dcache-prefetch-misses:u #    0.004 M/sec                

2芯

  111569.269846      task-clock:u (msec)       #    1.837 CPUs utilized         
              0      context-switches:u        #    0.000 K/sec                 
              0      cpu-migrations:u          #    0.000 K/sec                 
      4,415,116      page-faults:u             #    0.040 M/sec                 
330,750,606,867      cycles:u                  #    2.965 GHz                   
 69,517,418,862      stalled-cycles-frontend:u #   21.02% frontend cycles idle  
104,365,888,484      stalled-cycles-backend:u  #   31.55% backend cycles idle   
609,338,385,634      instructions:u            #    1.84  insn per cycle        
                                               #    0.17  stalled cycles per ins
125,341,622,204      branches:u                # 1123.442 M/sec                 
  1,860,702,685      branch-misses:u           #    1.48% of all branches       
261,941,396,767      L1-dcache-loads:u         # 2347.792 M/sec                 
    935,372,306      L1-dcache-load-misses:u   #    0.36% of all L1-dcache hits 
 79,306,212,694      L1-icache-loads:u         #  710.825 M/sec                 
  7,337,551,130      L1-icache-load-misses:u   #    9.25% of all L1-icache hits 
261,578,594,355      dTLB-loads:u              # 2344.540 M/sec                 
    425,510,820      dTLB-load-misses:u        #    0.16% of all dTLB cache hits
 79,008,997,415      iTLB-loads:u              #  708.161 M/sec                 
    102,332,385      iTLB-load-misses:u        #    0.13% of all iTLB cache hits
        944,223      L1-dcache-prefetches:u    #    0.008 M/sec                 
        945,497      L1-dcache-prefetch-misses:u #    0.008 M/sec               
  1. 运行perf top表示大约35%的时间花在内核中,这些函数是最主要的贡献者:

    ^{pr3}$。你知道吗
  2. 我觉得至少有一部分问题是在复制大约15×3500个浮点数的Numpy数组时产生的,但不是每次都是。该代码基本上是在物理参数的笛卡尔网格上计算模型,并对包含几个Numpy数组的对象进行频繁复制。现在,对于该对象的某些副本(但不是所有副本),我假设由于页面错误,这个~15×3500 Numpy数组的副本需要花费~15倍的时间。代码经常创建/删除这些对象,但是与每个进程相关联的总体内存变化缓慢(结果被写入一个共享的RawArray),因此我认为通常应该重新分配内存(在销毁前一个对象之后不久创建一个新对象)。这只发生在使用单个内核时,而不是在使用更多内核时。

  3. 我试着在同一时间用一个内核启动两个独立的运行,它们都有大量的页面错误。因此,它似乎与同时运行多个进程无关。

  4. 在单核上运行时,我尝试了使用多处理(spawn和fork)和不使用多处理(spawn和fork)两种方法,结果是相同的,页面错误的数量很高。所以这似乎没有关系

  5. 这在Archlinux python包和Anaconda包中都会发生。

  6. 这发生在AMD EPYC 7351(512 GB或RAM)和Intel Core i7 6700K(64 GB RAM)(均运行Linux)上。该代码使用~10gb的RAM,主要以rawrarray的形式存储结果。每个对象中使用的RAM应该是~500kb,并且在任何给定时刻RAM中不应该有超过7-8个。

我有点搞不懂为什么在单核上运行时会出现如此多的页面错误,而在2+核上运行时却没有。你知道会发生什么吗?有什么办法可以解决吗?我试图衡量代码如何随着内核数量的增加而扩展,因此我希望在单个内核上运行时有一个可靠的数据点。同样,使用2个内核比在单个内核上运行快3倍。你知道吗


Tags: ofl1loadsecall内核hitsdcache