2010-06-15 27 views
10

簡而言之,我試圖從Python,更具體地說,從numpy調用共享庫。共享庫使用sse2指令在C中實現。啓用優化,即使用-O2或-O1構建庫,當通過ctypes調用共享庫時,我正面臨奇怪的段錯誤。禁用優化(-O0),一切都按預期運行,就像將庫直接鏈接到c程序時一樣(優化與否)。附上你發現一個剪輯,展現了我的系統上劃定的行爲。啓用優化後,gdb會在emmintrin.h:113的__builtin_ia32_loadupd(__P)中報告段錯誤。 __P的值被報告爲已優化。numpy通過ctypes調用sse2

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的

測試。潘岳:

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
...作品。

我的系統:

  • Ubuntu Linux操作系統的i686 2.6.31-22-通用
  • 編譯器:GCC(Ubuntu的4.4.1-4ubuntu9)
  • 的Python:Python的2.6.4(r264:75706 ,2009年12月7日,十八點45分15秒)[GCC 4.4.1]
  • numpy的:1.4.0

我已採取規定(參見Python代碼)使y對準和x的對準不應該磨砂r(我認爲;明確地對齊x並不能解決問題)。

請注意,在加載b和f時,我使用_mm_loadu_pd而不是_mm_load_pd。對於僅限C的版本,_mm_load_pd可以正常工作(如預期的那樣)。但是,當通過ctypes使用 _mm_load_pd調用函數時總是出現segfaults(與優化無關)。

我已經嘗試了幾天來解決這個問題沒有成功......而我正在瀕死我的顯示器死亡。任何輸入歡迎。 丹尼爾

+0

如果您從C調用「測試」函數,是否會得到相同的錯誤? – Tarantula 2010-06-15 23:01:09

+0

編號從C調用測試運行平穩...我已經更新了原來的職位,並從C的示例調用。 – Daniel 2010-06-16 11:03:40

+0

如何從等式中刪除numpy並直接使用ctypes? – tonfa 2010-08-22 14:45:41

回答

-1

你有沒有嘗試升級到Numpy 1.5.0b2。只要運行以下(但要注意,可能會破壞其他的東西(你將不得不重新編譯所有耐熱玻璃):

sudo easy_install -U numpy 

我是有當我試圖用H5PY ctypes的類似問題(我不得不重新編譯.deb以獲得最新版本的numpy),並且還有編織的最新升級固定的主要問題。

2

我剛剛通過這個嘗試調用從蟒蛇一些SSE碼咬傷,這個問題似乎是,GCC希望假設堆棧在16字節邊界(體系結構上最大的本機類型,即SSE類型)上對齊,並計算所有帶該假設的偏移量。當這個假設是錯誤的時候,SSE指令就會陷入困境。

答案似乎是用

gcc -mstackrealign
編譯,它將函數序言改爲始終將堆棧對齊到16個字節。