【问题标题】:Performance of LLVM-Compiler on native C code vs Python+NumbaLLVM 编译器在原生 C 代码与 Python+Numba 上的性能
【发布时间】:2021-02-16 08:31:07
【问题描述】:

我最近做了一些关于 Python 性能优化的测试。一部分是使用 SWIG 对 Monte-Carlo Pi 计算进行基准测试,并编译一个库以在 Python 中导入。另一种解决方案是使用 Numba。现在我完全想知道为什么本地 C 解决方案比 Numba 更差,即使 LLVM 编译器用于两者。所以我想知道我是否做错了什么。

笔记本电脑上的运行时

native C module: 7.09 s
Python+Numba:    2.75 s

原生 C 代码

#include "swigtest.h"
#include <time.h>
#include <stdlib.h>
#include <stdio.h>

float monte_carlo_pi(long nsamples)
{
    int accGlob=0;
    int accLoc=0;
    int i,ns;
    float x,y;
    float res;
    float iRMX=1.0/(float) RAND_MAX;
    
    srand(time(NULL));
    
    for(i=0;i<nsamples;i++)
    {
      x = (float)rand()*iRMX;
      y = (float)rand()*iRMX;

      if((x*x + y*y) < 1.0) { acc += 1;}      
    }    
      
    res = 4.0 * (float) acc / (float) nsamples;
      
    printf("cres = %.5f\n",res);
    
    return res;
}

swigtest.i

%module swigtest

%{
#define SWIG_FILE_WITH_INIT
#include "swigtest.h"
%}

float monte_carlo_pi(long nsamples);

编译器调用

clang.exe swigtest.c swigtest_wrap.c -Ofast -o _swigtest.pyd -I C:\python37\include -shared -L c:\python37\libs -g0 -mtune=intel -msse4.2 -mmmx

testswig.py

from swigtest import monte_carlo_pi
import time
import os

start = time.time()
   
pi = monte_carlo_pi(250000000)

print("pi: %.5f" % pi)
print("tm:",time.time()-start)

带有 Numba 的 Python 版本

from numba import jit
import random
import time

start = time.time()

@jit(nopython=True,cache=True,fastmath=True)
def monte_carlo_pi(nsamples: int)-> float:
    acc:int = 0
    for i in range(nsamples):
        x:float = random.random()
        y:float = random.random()
        if (x * x + y * y) < 1.0: acc += 1
        
    return 4.0 * acc / nsamples
    
pi = monte_carlo_pi(250000000)

print("pi:",pi)
print("tm:",time.time()-start)

【问题讨论】:

  • 问题是,时间都花在了哪里。我不会感到惊讶,这发生在随机数生成中。使用不同的随机数生成器会导致不同的时序
  • 我也认为 rand 可能是问题所在。另一方面,它是一个可用数十年的功能,因此应尽可能优化。
  • 您是否运行了分析器? rand 是否针对速度或“随机性”进行了优化?
  • 没有。我会检查一下,但是可以预期 rand 会消耗时间。 Numba 是否与另一个随机生成器一起工作?因为其他 C 代码显然或多或少是最优的......
  • 除了随机数生成器之外,与相同的编译器设置(march=native、O3、Ofast)和使用相同的数据类型(double 和 int64)进行比较也是有意义的。看看monte_carlo_pi.inspect_types(),你可以看到 Numba 实现中使用了哪些数据类型。

标签: python performance clang llvm numba


【解决方案1】:

到目前为止的总结:

rand() 函数似乎消耗了大部分时间。使用这样的确定性方法

...
ns     = (long) sqrt((double)nsamples)+1;
dx     = 1./sqrt((double)nsamples);
dy     = dx;
...
for(i=0;i<ns;i++)
          for(k=0;k<ns;k++)
          {
            x = i*dx;
            y = k*dy;

            if((x*x + y*y) < 1.0) { accLoc += 1;}      
          }  
...

而不是 rand() 导致执行时间只有 0.04 s!显然 Numba 使用了另一个更有效的随机函数。

【讨论】:

猜你喜欢
  • 2015-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-19
  • 2013-04-28
相关资源
最近更新 更多