【问题标题】:NASM ctypes SIMD - how to access 128-bit array returned to ctypes?NASM ctypes SIMD - 如何访问返回给 ctypes 的 128 位数组?
【发布时间】:2018-05-25 01:18:03
【问题描述】:

我有一个由 ctypes 调用的 NASM 64 dll。该程序将两个 64 位整数相乘并返回一个 128 位整数,因此我使用的是 xmm SIMD 指令。它循环 10,000 次并将其结果存储在 malloc 创建的内存缓冲区中。

这是执行 SIMD 计算的 NASM 代码部分:

cvtsi2sd xmm0,rax
mov rax,[pcalc_result_0]
cvtsi2sd xmm1,rax
PMULUDQ xmm0,xmm1

lea rdi,[rel s_ptr] ; Pointer
mov rbp,qword[rdi]
mov rcx,[s_ctr]
;movdqa [rbp + rcx],xmm0
movdqu [rbp + rcx],xmm0
add rcx,16

movdqa 指令不起作用(程序崩溃,即使它是使用 align=16 指令汇编的)。 movdqu 指令确实有效,但是当我将数组返回到 ctypes 时,我需要将返回指针转换为 128 位,但是没有 128 位 ctypes 数据类型。这是 ctypes 代码的相关部分:

CallName.argtypes = [ctypes.POINTER(ctypes.c_double)]
CallName.restype = ctypes.POINTER(ctypes.c_int64)

n0 = ctypes.cast(a[0],ctypes.POINTER(ctypes.c_int64))
n0_size = int(a[0+1] / 8)
x0 = n0[:n0_size]

其中 x0 是转换为可用形式的返回数组,但不是 128 位。

Handling 128-bit integers with ctypes 有一篇文章处理传入但不传出的 128 位数组。

我的问题是:

-- 我应该使用 movdqa 或 movdqu 以外的指令吗?在众多 SIMD 指令中,这些似乎是最合适的。

-- Python 可以处理任意大小的整数,但显然 ctypes 不能。当没有大于 64 位的 ctypes 大小时,有什么方法可以使用 ctypes 中的 128 位整数?

【问题讨论】:

    标签: pointers nasm ctypes


    【解决方案1】:

    您可以生成包含表示 128 位整数的 16 个字节的字节数组,并在字节格式之间进行转换。这可能没有对齐,因此您应该使用movdqu。我会使用输入/输出参数而不是返回值,这样 Python 就可以管理内存:

    >>> import ctypes
    >>> value = 0xaabbccddeeff
    >>> int128 = ctypes.create_string_buffer(value.to_bytes(16,'little',signed=True))
    >>> int128
    <ctypes.c_char_Array_17 object at 0x000001ECCB1D41C8>
    >>> int128.raw
    b'\xff\xee\xdd\xcc\xbb\xaa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
    

    (注意:缓冲区以空值结尾,这就是为什么它是 17 个字节)

    将此可写缓冲区传递给您的函数,该函数可以将结果写回同一个缓冲区。返回时使用以下内容转换回 Python 整数:

    >>> hex(int.from_bytes(int128.raw[:16],'little',signed=True))
    '0xaabbccddeeff'
    

    【讨论】:

    • 谢谢,马克。您的示例适用于单个 16 字节数字。我创建了一个 800K 字节的字符串缓冲区(用于 50,000 个 16 字节整数),但在返回时您的转换字符串仅返回一个整数,即使我增加了切片索引。例如: return_array = int.from_bytes(int128.raw[:160],'little',signed=True) 只返回一个整数,而不是 10 个整数。如何将返回的数组转换为 Python 整数数组,而不仅仅是第一个值?我对 .raw 做了进一步的研究,但它没有回答这个问题。
    • @RTC222 您必须一次遍历字符串 16 个字节来转换每个字节。例如.raw[0:16] 然后.raw[16:32] 等。单行:arr = [int.from_bytes(int128.raw[n:n+16],'little',signed=True) for n in range(0,len(int128.raw),16)]
    • 这行得通,但它会导致一个特定于 NASM 的问题。我在50,000个数据槽的每一个中任意插入了整数1983452,但是它返回了整数4701269677488209920。我认为这是因为64位数字是在偏移量零处插入的,但需要进行零扩展。因为它只填充 16 字节的低位四字。我想我需要一个 SIMD 指令,所以我现在要调查。非常感谢您的帮助。
    • 我的最后一条评论不是答案——一个 64 位的值在较低的四字中。我还在寻找答案。
    猜你喜欢
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多