10

簡単に言えば、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 から test を呼び出すと、期待どおりに動作します。

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 日、18:45:15) [GCC 4.4.1]
  • でこぼこ: 1.4.0

y が整列され、x の整列は問題にならないという規定 (python コードを参照) を取りました (ただし、x を明示的に整列しても問題は解決しません)。

また、b と f をロードするときに _mm_load_pd の代わりに _mm_loadu_pd を使用することにも注意してください。C のみのバージョンでは、_mm_load_pd が機能します (予想どおり)。ただし、_mm_load_pd を使用して ctypes を介して関数を呼び出すと、(最適化とは関係なく) 常にセグメンテーション違反が発生します。

この問題を解決するために数日間試みましたが、成功しませんでした...そして、モニターを打ち負かして死ぬ寸前です。任意の入力を歓迎します。ダニエル

4

3 に答える 3

2

Python からいくつかの SSE コードを呼び出そうとして、これに噛まれました。問題は、GCC がスタックが 16 バイト境界 (アーキテクチャ上の最大のネイティブ型、つまり SSE 型)、その仮定ですべてのオフセットを計算します。その仮定が偽の場合、SSE 命令はトラップします。

答えはコンパイルすることのようです

gcc -mstackrealign
これにより、関数プロローグが常にスタックを 16 バイトに揃えるように変更されます。

于 2011-06-20T22:19:04.463 に答える
1

numpy ビルド システムを使用して拡張機能をビルドして、潜在的な cflags/ldflags の違いを軽減してみてください: http://projects.scipy.org/numpy/wiki/NumpySconsExtExamples

于 2010-08-28T20:32:44.050 に答える
-1

Numpy 1.5.0b2 にアップグレードしてみましたか。以下を実行するだけです(ただし、他のものを壊す可能性があることに注意してください(すべてのpyrexを再コンパイルする必要があります):

sudo easy_install -U numpy

H5PY を使用しようとしたときに ctypes で同様の問題が発生し (最新バージョンの numpy を取得するには .deb を再コンパイルする必要がありました)、最新のアップグレードで修正された weave に関する大きな問題もありました。

于 2010-08-28T03:22:01.670 に答える