2012-06-18 18 views
6

Tôi đang làm việc với SSE nội tại lần đầu tiên và tôi gặp phải lỗi phân đoạn ngay cả sau khi đảm bảo liên kết bộ nhớ 16byte. Bài đăng này là một phần mở rộng cho câu hỏi trước đây của tôi:Lỗi phân đoạn khi làm việc với SSE nội tại do liên kết bộ nhớ không chính xác

How to allocate 16byte memory aligned data

Đây là cách tôi đã tuyên bố mảng của tôi:

float *V = (float*) memalign(16,dx*sizeof(float)); 

Khi tôi cố gắng để làm điều này:

__m128 v_i = _mm_load_ps(&V[i]); //It works 

Nhưng khi tôi làm điều này:

__m128 u1 = _mm_load_ps(&V[(i-1)]); //There is a segmentation fault 

Nhưng nếu tôi làm:

__m128 u1 = _mm_loadu_ps(&V[(i-1)]); //It works again 

Tuy nhiên tôi muốn loại bỏ sử dụng _mm_loadu_ps và muốn làm cho nó hoạt sử dụng _mm_load_ps chỉ.

Tôi đang làm việc với trình biên dịch icc của Intel.

Làm cách nào để giải quyết vấn đề này?

UPDATE:

sử dụng cả hai hoạt động trong đoạn mã sau:

void FDTD_base (float *V, float *U, int dx, float c0, float c1, float c2, float c3,  float c4) 
    { 
     int i, j, k; 
        for (i = 4; i < dx-4; i++) 
        { 

          U[i] = (c0 * (V[i]) //center 
            + c1 * (V[(i-1)] + V[(i+1)]) 
            + c2 * (V[(i-2)] + V[(i+2)]) 
            + c3 * (V[(i-3)] + V[(i+3)]) 
            + c4 * (V[(i-4)] + V[(i+4)])); 
        } 

     } 

SSE phiên bản:

  for (i=4; i < dx-4; i+=4) 
     { 
      v_i = _mm_load_ps(&V[i]); 
      __m128 center = _mm_mul_ps(v_i,c0_i); 

      __m128 u1 = _mm_loadu_ps(&V[(i-1)]); 
      u2 = _mm_loadu_ps(&V[(i+1)]); 

      u3 = _mm_loadu_ps(&V[(i-2)]); 
      u4 = _mm_loadu_ps(&V[(i+2)]); 

      u5 = _mm_loadu_ps(&V[(i-3)]); 
      u6 = _mm_loadu_ps(&V[(i+3)]); 

      u7 = _mm_load_ps(&V[(i-4)]); 
      u8 = _mm_load_ps(&V[(i+4)]); 

      __m128 tmp1 = _mm_add_ps(u1,u2); 
      __m128 tmp2 = _mm_add_ps(u3,u4); 
      __m128 tmp3 = _mm_add_ps(u5,u6); 
      __m128 tmp4 = _mm_add_ps(u7,u8); 

      __m128 tmp5 = _mm_mul_ps(tmp1,c1_i); 
      __m128 tmp6 = _mm_mul_ps(tmp2,c2_i); 
      __m128 tmp7 = _mm_mul_ps(tmp3,c3_i); 
      __m128 tmp8 = _mm_mul_ps(tmp4,c4_i); 

      __m128 tmp9 = _mm_add_ps(tmp5,tmp6); 
      __m128 tmp10 = _mm_add_ps(tmp7,tmp8); 

      __m128 tmp11 = _mm_add_ps(tmp9,tmp10); 
      __m128 tmp12 = _mm_add_ps(center,tmp11); 

      _mm_store_ps(&U[i], tmp12); 
    } 

Có cách nào hiệu quả hơn để làm điều này chỉ sử dụng _mm_load_ps()?

+0

'sizeof (float)' trên kiến ​​trúc của bạn là gì? – ecatmur

+0

@ecatmur: Tôi đang làm việc trên máy 64 bit. – PGOnTheGo

+0

không trả lời câu hỏi; có rất nhiều ABI 64 bit khác nhau. – ecatmur

Trả lời

11

sizeof(float) là 4, chỉ mỗi mục nhập thứ tư trong V sẽ được căn chỉnh chính xác. Hãy nhớ rằng _mm_load_ps tải bốn phao cùng một lúc. Đối số, tức là con trỏ đến float đầu tiên, cần được căn chỉnh với 16 byte.

Tôi giả định rằng trong ví dụ của bạn i là bội số của bốn, nếu không _mm_load_ps(&V[i]) sẽ không thành công.

Cập nhật

Đây là cách tôi sẽ đề nghị thực hiện trượt trên ví dụ cửa sổ bằng tải thẳng hàng và shuffle:

__m128 v_im1; 
__m128 v_i = _mm_load_ps(&V[0]); 
__m128 v_ip1 = _mm_load_ps(&V[4]); 

for (i = 4 ; i < dx ; i += 4) { 

    /* Get the three vectors in this 'frame'. */ 
    v_im1 = v_i; v_i = v_ip1; v_ip1 = _mm_load_ps(&V[i+4]); 

    /* Get the u1..u8 from the example code. */ 
    __m128 u3 = _mm_shuffle_ps(v_im1 , v_i , 3 + (4<<2) + (0<<4) + (1<<6)); 
    __m128 u4 = _mm_shuffle_ps(v_i , v_ip1 , 3 + (4<<2) + (0<<4) + (1<<6)); 

    __m128 u1 = _mm_shuffle_ps(u3 , v_i , 1 + (2<<2) + (1<<4) + (2<<6)); 
    __m128 u2 = _mm_shuffle_ps(v_i , u4 , 1 + (2<<2) + (1<<4) + (2<<6)); 

    __m128 u5 = _mm_shuffle_ps(v_im1 , u3 , 1 + (2<<2) + (1<<4) + (2<<6)); 
    __m128 u6 = _mm_shuffle_ps(u4 , v_ip1 , 1 + (2<<2) + (1<<4) + (2<<6)); 

    __m128 u7 = v_im1; 
    __m128 u8 = v_ip1; 

    /* Do your computation and store. */ 
    ... 

    } 

Lưu ý rằng đây là một chút khó khăn kể từ khi _mm_shuffle_ps chỉ có thể đưa hai giá trị từ mỗi đối số, đó là lý do tại sao trước tiên chúng tôi cần phải thực hiện u3u4 để sử dụng lại chúng cho các giá trị khác với các chồng chéo khác nhau.

Cũng lưu ý rằng các giá trị u1, u3, và u5 cũng có thể được phục hồi từ u2, u4u6 trong phiên trước đó.

Lưu ý, cuối cùng, tôi có chưa xác minh mã ở trên! Đọc tài liệu cho _mm_shuffle_ps và kiểm tra xem đối số thứ ba, công cụ chọn có đúng cho từng trường hợp không.

+0

Pedro: bạn nói đúng. tôi là bội số của 4 trong ví dụ của tôi. Nhưng làm cách nào để khắc phục lỗi phân đoạn? – PGOnTheGo

+0

@ Hello_PG: Điều đó tùy thuộc vào những gì bạn muốn làm. Bạn có phải thực hiện thao tác SIMD trên tất cả các phần tử của 'V' theo nhóm bốn, ví dụ: 'V [0..3]', 'V [4..7]', 'V [8..11]'? Hay bạn có một cửa sổ trượt có chiều dài bốn, ví dụ: 'v [0..3]', 'V [1..4]', 'V [2..5]'? Trong trường hợp trước, bạn chỉ có thể sử dụng vòng lặp 'for' trên' i', tăng 'i' bằng' 4' trong mỗi lần lặp. Trong trường hợp sau, bạn bị kẹt với '_mm_loadu_ps' không hiệu quả kém hơn. – Pedro

+0

Mã của tôi liên quan đến khái niệm cửa sổ trượt. Về cơ bản nó là một stencil 1D, đòi hỏi tôi phải theo dõi 4 yếu tố lân cận. Tôi đã cập nhật mã bằng cả _mm_load_ps và _mm_loadu_ps..Xin vui lòng tìm mã trong bài đăng được cập nhật của tôi. Đây có phải là cách tốt nhất để giải quyết nó? – PGOnTheGo

Các vấn đề liên quan