15

到目前为止,我在http://julialang.org/上看到的 Julia 性能基准测试,将 Julia 与纯 Python 或 Python+NumPy 进行了比较。与 NumPy 不同,SciPy 使用 BLAS 和 LAPACK 库,我们可以在其中获得最佳的多线程 SIMD 实现。如果我们假设 Julia 和 Python 在调用 BLAS 和 LAPACK 函数时(在底层)的性能是相同的,那么当使用 Numba 或 NumbaPro 处理不调用 BLAS 或 LAPACK 函数的代码时,Julia 的性能与 CPython 相比如何?

我注意到的一件事是 Julia 使用的是 LLVM v3.3,而 Numba 使用的是基于 LLVM v3.5 构建的 llvmlite。Julia 的旧 LLVM 是否会阻止在 Intel Haswell(AVX2 指令)等较新架构上实现最佳 SIMD?

我对处理非常大的向量的意大利面条代码和小型 DSP 循环的性能比较感兴趣。由于将数据移入和移出 GPU 设备内存的开销,对我而言,后者由 CPU 比 GPU 更有效地处理。我只对单个 Intel Core-i7 CPU 的性能感兴趣,因此集群性能对我来说并不重要。我特别感兴趣的是创建 DSP 功能的并行实现的简单性和成功性。

这个问题的第二部分是 Numba 与 NumbaPro 的比较(忽略 MKL BLAS)。考虑到Numba中装饰器target="parallel"的新nogil论点,真的需要@jitNumbaPro 吗?

4

3 回答 3

9

这是一个非常广泛的问题。关于基准测试请求,您最好自己运行一些符合您自己需求的小型基准测试。要回答其中一个问题:

我注意到的一件事是 Julia 使用的是 LLVM v3.3,而 Numba 使用的是基于 LLVM v3.5 构建的 llvmlite。Julia 的旧 LLVM 是否会阻止在 Intel Haswell(AVX2 指令)等较新架构上实现最佳 SIMD?

[2017/01+:以下信息不再适用于当前的 Julia 版本]

Julia 确实在 LLVM 3.3 中关闭了 avx2,因为 Haswell 上有一些严重的错误。

Julia 使用 LLVM 3.3 构建当前版本和 nightlies,但您可以使用 3.5、3.6 和通常的 svn trunk 构建(如果我们尚未针对特定日期的某些 API 更改进行更新,请提交问题)。为此,请设置LLVM_VER=svn(例如)Make.user,然后继续按照构建说明进行操作。

于 2015-04-09T21:57:42.477 回答
5

请参阅此处(第 4 节),了解我个人从事的一些同行评审基准。比较是在 Julia 和 PyPy 之间进行的。

于 2015-04-10T00:02:49.573 回答
-2

(比较无与伦比永远是一把双刃剑。

下面的内容是出于公平的信念,应该将 LLVM / JIT 驱动的代码基准与其他一些 LLVM / JIT 驱动的替代方案进行比较,任何派生的结论都应作为合理支持的决策的基础。)


简介:(东西numba和[我们]的结果在页面下方有点低)

恕我直言,官方网站提供了一组性能测试列表,其中陈述了两类事实。第一个与性能测试的执行方式有关(julia,使用 LLVM 编译的代码执行 v/s python,仍然是 GIL 步进的解释代码执行)。二、其他语言完成同一个“benchmark-task”需要多长时间,以C编译代码执行为相对时间单位=1.0

带有结果的表格上方的章节标题 (cit.:)

高性能 JIT 编译器
Julia 基于 LLVM 的即时 (JIT) 编译器与该语言的设计相结合,使其能够接近并经常匹配 C 的性能。 我认为比较苹果和苹果要更严格一些,只用了一个的“基准任务”-s,称为.

在此处输入图像描述
pi-sum

这是解释型 python 的第二个最差时间,它的运行速度比 LLVM/JIT 编译的 julia-code 或 C 编译的替代方案慢 21.99 倍。

于是小实验故事开始了。

@numba.jit( JulSUM, nogil = True )

让我们开始比较苹果和苹果。如果据报道 Julia 代码的运行速度提高了 22 倍,那么我们首先测量一个普通解释的 Python 代码运行。

>>> def JulSUM():
...     sum = 0.
...     j   = 0
...     while j < 500:
...           j   += 1
...           sum  = 0.
...           k    = 0
...           while k < 10000:
...                 k   += 1
...                 sum += 1. / ( k * k )
...     return sum
...
>>> from zmq import Stopwatch
>>> aClk = Stopwatch()
>>> aClk.start();_=JulSUM();aClk.stop()
1271963L
1270088L
1279277L
1277371L
1279390L
1274231L

所以,核心pi-sum运行大约 1.27x.xxx [us] ~ 大约 1.27~1.28 [s]

鉴于语言演示表格行pi-sum,LLVM/JIT 驱动的 julia 代码执行速度应该快 22 倍,即低于~ 57.92 [ms]

>>> 1274231 / 22
57919

因此,让我们使用numba.jit(v24.0)将橙子转换为苹果

>>> import numba
>>> JIT_JulSUM = numba.jit( JulSUM )
>>> aClk.start();_=JIT_JulSUM();aClk.stop()
1175206L
>>> aClk.start();_=JIT_JulSUM();aClk.stop()
35512L
37193L
37312L
35756L
34710L

因此,在 JIT 编译器完成工作后,numba-LLVM'ed python 的基准测试时间约为 34.7 ~ 37.3 [ms]

我们能走得更远吗?

哦,当然,我们还没有做太多的numba调整,虽然代码示例是如此微不足道,但预计不会有太多令人惊讶的进步。

首先,让我们删除这里不必要的 GIL 步进:

>>> JIT_NOGIL_JulSUM = numba.jit( JulSUM, nogil = True )
>>> aClk.start();_=JIT_NOGIL_JulSUM();aClk.stop()
85795L
>>> aClk.start();_=JIT_NOGIL_JulSUM();aClk.stop()
35526L
35509L
34720L
35906L
35506L

nogil=True
不会使执行更远,
但仍会减少一些 [ms],将所有结果驱动到 ~ 35.9 [ms]

>>> JIT_NOGIL_NOPYTHON_JulSUM = numba.jit( JulSUM, nogil = True, nopython = True )
>>> aClk.start();_=JIT_NOGIL_NOPYTHON_JulSUM();aClk.stop()
84429L
>>> aClk.start();_=JIT_NOGIL_NOPYTHON_JulSUM();aClk.stop()
35779L
35753L
35515L
35758L
35585L
35859L

nopython=True
只做最后的润色
,以使所有结果始终保持在 ~ 35.86 [ms](相对于 LLVM/JIT-julia 的 ~57.92 [ms] )


DSP处理的结语:

对于关于加速 DSP 处理的额外好处的 OP 问题,
可以尝试测试numba+英特尔 Python(通过 Anaconda),英特尔在二进制文件中开辟了新视野,针对 IA64 处理器内部性进行了优化,因此代码-基于英特尔对 ILP4 的了解、向量化和分支预测详细信息,他们自己的 CPU 在运行时展示的执行可能会享受额外的 CPU 绑定技巧。值得一试来比较这一点(另外一个人可能会喜欢他们集成到 VisualStudio 中的非破坏性代码分析工具,其中可以实时分析体外代码执行热点——这是 DSP 工程师会喜欢的东西,他/她不会吗?

于 2017-01-01T20:14:23.707 回答