2012-06-18 39 views
11

Tôi đang cố gắng thực hiện vector hóa SSE trên một đoạn mã mà tôi cần mảng 1D của mình để được liên kết bộ nhớ 16 byte. Tuy nhiên, tôi đã thử một số cách để phân bổ 16byte bộ nhớ liên kết dữ liệu nhưng nó kết thúc lên được 4byte bộ nhớ liên kết.Cách phân bổ dữ liệu liên kết bộ nhớ 16byte

Tôi phải làm việc với trình biên dịch icc của Intel. Đây là một mẫu mã Tôi đang thử nghiệm với:

#include <stdio.h> 
    #include <stdlib.h> 

    void error(char *str) 
    { 
    printf("Error:%s\n",str); 
    exit(-1); 
    } 

    int main() 
    { 
    int i; 
    //float *A=NULL; 
    float *A = (float*) memalign(16,20*sizeof(float)); 

    //align 
    // if (posix_memalign((void **)&A, 16, 20*sizeof(void*)) != 0) 
    // error("Cannot align"); 

    for(i = 0; i < 20; i++) 
     printf("&A[%d] = %p\n",i,&A[i]); 

     free(A); 

     return 0; 
    } 

Đây là sản phẩm tôi nhận được:

&A[0] = 0x11fe010 
&A[1] = 0x11fe014 
&A[2] = 0x11fe018 
&A[3] = 0x11fe01c 
&A[4] = 0x11fe020 
&A[5] = 0x11fe024 
&A[6] = 0x11fe028 
&A[7] = 0x11fe02c 
&A[8] = 0x11fe030 
&A[9] = 0x11fe034 
&A[10] = 0x11fe038 
&A[11] = 0x11fe03c 
&A[12] = 0x11fe040 
&A[13] = 0x11fe044 
&A[14] = 0x11fe048 
&A[15] = 0x11fe04c 
&A[16] = 0x11fe050 
&A[17] = 0x11fe054 
&A[18] = 0x11fe058 
&A[19] = 0x11fe05c 

Nó được 4byte thẳng hàng mọi lúc, tôi đã sử dụng cả hai memalign, posix memalign. Vì tôi đang làm việc trên Linux, tôi không thể sử dụng _mm_malloc, tôi cũng không thể sử dụng _aligned_malloc. Tôi nhận được một lỗi tham nhũng bộ nhớ khi tôi cố gắng sử dụng _aligned_attribute (đó là thích hợp cho gcc một mình tôi nghĩ).

Bất kỳ ai cũng có thể giúp tôi tạo chính xác dữ liệu liên kết bộ nhớ 16byte cho icc trên nền tảng Linux.

+0

Làm thế nào để bạn biết nó là 4 byte phù hợp, đơn giản chỉ vì printf là chỉ outputting 4 byte tại một thời điểm? Chỉ vì bạn đang sử dụng thói quen memalign, bạn đang đặt nó vào một kiểu float. Khi bạn in bằng printf, nó biết cách xử lý thông qua kiểu nguyên thủy (float). – trumpetlicks

+1

Tại sao bạn không thể sử dụng "_mm_malloc" trên Linux? –

Trả lời

14

Bộ nhớ bạn cấp phát được căn chỉnh 16 byte. Xem:
&A[0] = 0x11fe010
Nhưng trong một mảng float, mỗi phần tử là 4 byte, do đó phần tử thứ hai là liên kết 4 byte.

Bạn có thể sử dụng một loạt các cấu trúc, mỗi dòng chứa một phao duy nhất, với aligned thuộc tính:

struct x { 
    float y; 
} __attribute__((aligned(16))); 
struct x *A = memalign(...); 
+0

Tôi nghĩ '__attribute__' là nội dung dựng sẵn của GCC, không có sẵn cho ICC. – Benoit

+0

@Benoit, GCC cụ thể thực sự, nhưng tôi nghĩ rằng ICC không hỗ trợ nó. [Xem tại đây] (http://software.intel.com/sites/products/collateral/hpc/compilers/intel_linux_compiler_compatibility_with_gnu_compilers.pdf) – ugoren

+0

@Benoit: Nếu bạn cần căn chỉnh cấu trúc trên 16, chỉ cần thêm 12 byte đệm tại kết thúc ... –

0

tôi tìm thấy mã này trên Wikipedia:

Example: get a 12bit aligned 4KBytes buffer with malloc() 

// unaligned pointer to large area 
void *up=malloc((1<<13)-1); 
// well aligned pointer to 4KBytes 
void *ap=aligntonext(up,12); 

where aligntonext() is meant as: 
move p to the right until next well aligned address if 
not correct already. A possible implementation is 

// PSEUDOCODE assumes uint32_t p,bits; for readability 
// --- not typesafe, not side-effect safe 
#define alignto(p,bits) (p>>bits<<bits) 
#define aligntonext(p,bits) alignto((p+(1<<bits)-1),bits) 
7

Địa chỉ trả về bởi memalign chức năng là 0x11fe010, là bội số của 0x10. Vì vậy, chức năng đang làm một điều đúng. Điều này cũng có nghĩa là mảng của bạn là được căn chỉnh chính xác trên ranh giới 16 byte. Những gì bạn đang làm sau này là in địa chỉ của mọi phần tử tiếp theo thuộc loại float trong mảng của bạn. Vì kích thước float chính xác là 4 byte trong trường hợp của bạn, mọi địa chỉ tiếp theo sẽ bằng với số trước đó là +4. Ví dụ: 0x11fe010 + 0x4 = 0x11FE014. Tất nhiên, địa chỉ 0x11FE014 không phải là bội số của 0x10. Nếu bạn sắp xếp tất cả các phao nổi trên ranh giới 16 byte, thì bạn sẽ phải lãng phí 16/4 - 1 byte cho mỗi phần tử. Kiểm tra kỹ các yêu cầu đối với nội tại mà bạn đang sử dụng.

1

AFAIK, cả hai memalignposix_memalign đang thực hiện công việc của mình.

&A[0] = 0x11fe010 

Điều này được căn chỉnh tới 16 byte.

&A[1] = 0x11fe014 

Khi bạn làm &A[1] bạn đang nói compiller thêm một vị trí để một con trỏ float. Nó sẽ không thể tránh khỏi dẫn đến:

&A[0] + sizeof(float) = 0x11fe010 + 4 = 0x11fe014 

Nếu bạn có ý định có mỗi yếu tố bên trong vector của bạn liên kết đến 16 byte, bạn nên xem xét khai báo một mảng của cấu trúc rộng 16 byte.

struct float_16byte 
{ 
    float data; 
    float padding[ 3 ]; 
} 
    A[ ELEMENT_COUNT ]; 

Sau đó, bạn phải phân bổ bộ nhớ cho ELEMENT_COUNT (20, trong ví dụ của bạn) biến:

struct float_16byte *A = (struct float_16byte *)memalign(16, ELEMENT_COUNT * sizeof(struct float_16byte)); 
0

Cá nhân tôi tin rằng mã của bạn là chính xác và phù hợp cho mã Intel SSE. Khi bạn tải dữ liệu vào sổ đăng ký XMM, tôi tin rằng bộ xử lý chỉ có thể tải 4 dữ liệu phao liền kề từ bộ nhớ chính với bộ nhớ đầu tiên được căn chỉnh 16 byte.

Tóm lại, tôi tin rằng những gì bạn đã làm là chính xác những gì bạn muốn.

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