Cython 和 SIMD 内在函数:防止 SIMD 内在函数的参数转换为 python 对象

Posted

技术标签:

【中文标题】Cython 和 SIMD 内在函数:防止 SIMD 内在函数的参数转换为 python 对象【英文标题】:Cython and SIMD intrinsic: preventing conversion to python object for SIMD intrinsic function's argument 【发布时间】:2020-04-06 16:43:56 【问题描述】:

我在通过 cython 尝试 SIMD 内在函数方面取得了一些成功。现在我正在努力让 AVX 中的比较函数工作,因为比较函数需要一个不应转换为 python 对象的参数。

cdef extern from "immintrin.h" nogil:  # in this example, we use SSE2
    ctypedef float  __m256
    const int _CMP_GT_OS

    __m256 _mm256_loadu_ps  (float *__P) nogil  
    void   _mm256_storeu_ps (float *__P, __m256 __A) nogil
    __m256 _mm256_set1_ps   (__m256 __A) nogil
    __m256 _mm256_cmp_ps    (__m256 __A, __m256 __B, _CMP_GT_OS) nogil


@cython.boundscheck(False)      # turn off bounds-checking for entire function
@cython.wraparound (False)      # turn off negative index wrapping for entire function
@cython.cdivision  (True )        
cdef void Example_v4 (float *A, float *B, float delx) :
    ### this example for A & B having exactly 8 elements

    cdef:
        __m256 mA, mB, mdelx, mOut
        float *out = <float*> malloc( 8 * sizeof(float)) 
        int i

    with nogil:
        mdelx = _mm256_set1_ps( delx )
        mA    = _mm256_loadu_ps( &A[0] )
        mB    = _mm256_loadu_ps( &B[0] )        

        mOut = _mm256_cmp_ps  ( mA, mB, _CMP_GT_OS )        
        _mm256_storeu_ps( &out[0], mOut )

    print ( " i     out  " )
    for i in range(8):
        print ( i, out[i] )
    return

问题是当我编译 cython 代码时,我将此部分突出显示为问题。

        mOut = _mm256_cmp_ps  ( mA, mB, _CMP_GT_OS ) 

with  ^ symbol pointing at _CMP_GT_OS

和消息

Converting to Python object not allowed without gil

我认为问题不在于 gil,内部函数在英特尔官方文档中定义为

__m256 _mm256_cmp_ps (__m256 __A, __m256 __B, const int imm8)

imm8 可以是多种操作类型,_CMP_GT_OS 就是其中之一。 我不知道如何处理第三个参数并阻止它转换为 python,因为内在函数只识别 C/C++ const int。知道如何解决这个问题吗?

【问题讨论】:

mOut的cdef类型是什么?我认为这就是为什么它抱怨转换为 python 对象的原因。也许你的意思是mOut1 这可能是错字:应该是 mOut1 而不是 mOut(或其他方式) 是的,一个错字。对不起,我编辑了一些东西来简化这个问题,忘了改变它。我会编辑它。但问题仍然如我所描述。 不确定这是否是您的问题,但 __m256 _mm256_cmp_ps (__m256 __A, __m256 __B, _CMP_GT_OS) nogil 中的 _CMP_GT_OS 看起来很奇怪。不应该是const int吗? 包装 cmp_ps 时忘记输入第三个参数,cython 假定它是对象 【参考方案1】:

我做了两个改变: 在 cdef extern 部分,我为其添加了一个值。我仍然不能 100% 确定如何使用此功能。所以这都是反复试验,但至少这样做,我可以继续检查并做更多的反复试验。

cdef extern from "immintrin.h" nogil:  # in this example, we use SSE2
    ctypedef float  __m256
    const int _CMP_GT_OS = 14

    ## other definition like in the question
    __m256 _mm256_cmp_ps    (__m256 __A, __m256 __B, const int _CMP_GT_OS) nogil

仅更改 _mm256_cmp_ps 部分中的声明不起作用。我必须先给它赋值。

现在可以正常编译,可以在python端调用使用。至于结果,还是很奇怪,不知道这样对不对。当我了解更多时,我会报告。在此期间,请随时加入。谢谢。

【讨论】:

如果您不能使用 C 编译器的符号常量,请查看 asm 手册,其中有一个名称谓词编号表:felixcloutier.com/x86/cmpps。 (cmppd 按字母顺序排列,因此在英特尔的原始手册中更早,并且有一个更好的表格:felixcloutier.com/x86/cmppd)。但我不认为那是你的问题,对不起 nvm。 @PeterCordes 感谢您的帮助。我将 NaN 放在 True 的位置。感觉不对,我认为基于 SSE 案例,true 应该是 -1.0。需要了解更多信息。 大声笑,不是-1.0f,您将所有位设置为1,因此您可以将其与_mm256_and_ps 或其他任何东西一起使用,以清零或保留另一个向量的某些元素。作为float 位模式的全1 代表-QNaN @PeterCordes ,谢谢彼得,接受您的建议,现在一切正常。现在这足以完全重写昂贵的计算部分来使用它。希望我能看到至少 2 倍的加速。有点遗憾的是,曾经容易阅读的短代码现在看起来很陌生而且更长。

以上是关于Cython 和 SIMD 内在函数:防止 SIMD 内在函数的参数转换为 python 对象的主要内容,如果未能解决你的问题,请参考以下文章

带有 AVX SIMD 的 Cython:代码运行一次正确,但如果需要再次运行则挂起

与 SIMD 内在函数进行比较和交换

如何在有或没有 SIMD 内在函数的情况下从 Zig 构建和链接到 CGLM

我可以将 SIMD 内在函数用于在云上运行的软件吗?

我可以将SIMD内在函数用于在云上运行的软件吗?

英特尔 SIMD 内在函数:_mm256_i64scatter_pd