简而言之,我试图从python调用一个共享库,更具体地说,从numpy调用。共享库使用sse2指令在C中实现。启用优化,即使用-O2或-O1构建库时,我在通过ctypes调用共享库时遇到奇怪的段错误。禁用优化(-O0),一切都按预期进行,就像直接将库链接到c程序(优化与否)一样。附上你发现一个剪辑,显示我的系统上描绘的行为。启用优化后,gdb将在emmintrin.h:113中的__builtin_ia32_loadupd(__P)中报告段错误。 __P的值报告为已优化。
test.c的:
#include <emmintrin.h>
#include <complex.h>
void test(const int m, const double* x, double complex* y) {
int i;
__m128d _f, _x, _b;
double complex f __attribute__( (aligned(16)) );
double complex b __attribute__( (aligned(16)) );
__m128d* _p;
b = 1;
_b = _mm_loadu_pd( (double *) &b );
_p = (__m128d*) y;
for(i=0; i<m; ++i) {
f = cexp(-I*x[i]);
_f = _mm_loadu_pd( (double *) &f );
_x = _mm_loadu_pd( (double *) &x[i] );
_f = _mm_shuffle_pd(_f, _f, 1);
*_p = _mm_add_pd(*_p, _f);
*_p = _mm_add_pd(*_p, _x);
*_p = _mm_mul_pd(*_p,_b);
_p++;
}
return;
}
编译器标志: gcc -o libtest.so -shared -std = c99 -msse2 -fPIC -O2 -g -lm test.c
test.py:
import numpy as np
import os
def zerovec_aligned(nr, dtype=np.float64, boundary=16):
'''Create an aligned array of zeros.
'''
size = nr * np.dtype(dtype).itemsize
tmp = np.zeros(size + boundary, dtype=np.uint8)
address = tmp.__array_interface__['data'][0]
offset = boundary - address % boundary
return tmp[offset:offset + size].view(dtype=dtype)
lib = np.ctypeslib.load_library('libtest', '.' )
lib.test.restype = None
lib.test.argtypes = [np.ctypeslib.ctypes.c_int,
np.ctypeslib.ndpointer(np.float64, flags=('C', 'A') ),
np.ctypeslib.ndpointer(np.complex128, flags=('C', 'A', 'W') )]
n = 13
y = zerovec_aligned(n, dtype=np.complex128)
x = np.ones(n, dtype=np.float64)
# x = zerovec_aligned(n, dtype=np.float64)
# x[:] = 1.
lib.test(n,x,y)
从C调用测试按预期工作:
call_from_c.c:
#include <stdio.h>
#include <complex.h>
#include <stdlib.h>
#include <emmintrin.h>
void test(const int m, const double* x, double complex* y);
int main() {
int i;
const int n = 11;
double complex *y = (double complex*) _mm_malloc(n*sizeof(double complex), 16);
double *x = (double *) malloc(n*sizeof(double));
for(i=0; i<n; ++i) {
x[i] = 1;
y[i] = 0;
}
test(n, x, y);
for(i=0; i<n; ++i)
printf("[%f %f]\n", creal(y[i]), cimag(y[i]));
return 1;
}
编译并致电:
gcc -std = c99 -otestc -msse2 -L。 -ltest call_from_c.c
export LD_LIBRARY_PATH = $ {LD_LIBRARY_PATH}:。
./testc
......有效。
我的系统:
我已采取规定(参见Python代码)使y对准和x的取向并不重要(我想;明确地对准X不虽然解决问题)。
另请注意,在加载b和f时,我使用_mm_loadu_pd而不是_mm_load_pd。对于仅C版本_mm_load_pd工作(如预期的那样)。但是,通过ctypes调用函数时使用 _mm_load_pd始终是segfaults(独立于优化)。
我已经尝试了好几天来解决这个问题而没有成功......我正在濒临监视器死亡。欢迎任何投入。 丹尼尔
答案 0 :(得分:2)
我只是因为尝试从python调用一些SSE代码而感到困惑,问题似乎是GCC想要假设堆栈在16字节边界上对齐(架构上最大的本机类型,即SSE类型),并用该假设计算所有偏移量。当该假设为假时,SSE指令将陷阱。
答案似乎是用
gcc -mstackrealign编译,它改变了函数序言,以便始终将堆栈对齐到16个字节。
答案 1 :(得分:1)
尝试使用numpy构建系统构建扩展,以打折潜在的cflags / ldflags差异: http://projects.scipy.org/numpy/wiki/NumpySconsExtExamples
答案 2 :(得分:-1)
您是否尝试升级到Numpy 1.5.0b2。只需运行以下命令(但要小心它可能会破坏其他东西(你必须重新编译所有pyrex):
sudo easy_install -U numpy
当我尝试使用H5PY时,我遇到了与ctypes类似的问题(我不得不重新编译.deb以获得最新版本的numpy)以及编织的主要问题是最新的升级已经修复。