2015-02-23 13 views
5

Câu hỏi của tôi là về vấn đề của cụm từ sau đây từ cuốn sách:mảng của cấu trúc (AoS) vs Cơ cấu Mảng (SOA) trên ngẫu nhiên đọc cho vector hóa

Thật không may, hình thức SoA không phải là lý tưởng trong tất cả hoàn cảnh. Đối với trường hợp ngẫu nhiên hoặc không mạch lạc, tập hợp được sử dụng để truy cập dữ liệu và biểu mẫu SoA có thể dẫn đến dữ liệu không cần thiết được đọc vào bộ nhớ cache, do đó giảm hiệu suất. Trong trường hợp này, việc sử dụng biểu mẫu AoS thay vào đó sẽ dẫn đến một bộ làm việc nhỏ hơn và cải thiện hiệu suất . Nói chung, mặc dù, nếu tính toán là được vector hóa, biểu mẫu SoA được ưu tiên.

My đoán về việc tại sao AoS có thể dẫn đến hiệu suất tốt hơn là khi khác nhau, hoặc tốt hơn hết, lĩnh vực trong cơ cấu tương tự đang tham gia trong thời gian vector hóa đơn.

Ví dụ (chỉ là một khái niệm, không có bê tông, hoặc mã làm việc tại tất cả):

/*Note that the types of data I maintain the same intentionally, 
    to simplify discussion*/ 
struct Data { 
    float mean; 
    float distribution[10] 
} 

và xác định mảng của những có ngẫu nhiên từ một số nguồn dữ liệu

Data aos[5];

nay , nếu trong vòng lặp vectơ tôi làm điều gì đó như:

float* dataPtr = &(aos[0].mean); 

#pragma simd 
for(int i=0; i< 60; i++) 
{ 
    const float mean = (*dataPtr); 
    /*do something with mean */ 

    dataPtr++; 

    /*do something with distribution */ 
} 

điều này sẽ dẫn đến hiệu suất tốt hơn, gây ra trong trường hợp của SoA, tôi sẽ đẩy thêm dòng bộ nhớ cache thông tin mà tôi thực sự có thể yêu cầu trong quá trình tính toán này. Một số CPU trước khi bộ nhớ đệm? Điều đó trong trường hợp AoS dẫn đến hiệu suất tốt hơn thay thế.

Giả sử của tôi có chính xác không, hoặc có điều gì khác không?

+3

Từ viết tắt có ba chữ cái: SoA = Cấu trúc mảng, AoS = Mảng cấu trúc. –

+0

@ HansPassant: đó là cách họ gọi, và viết tên đầy đủ xuống làm cho tiêu đề quá dài và không kém xấu xí. – Tigran

+3

@Tigran: Xác định các điều khoản một lần, vì lợi ích của những người không biết thuật ngữ của cuốn sách của bạn, không mất nhiều thời gian. –

Trả lời

8

Bạn có thể song song chương trình của mình theo hai cách: theo chiều ngang và chiều dọc. Tôi nghĩ bạn đang trộn lẫn hai cách tiếp cận này.

Song song ngang xử lý từng làn trong đơn vị SIMD của bạn dưới dạng một "chuỗi" riêng biệt hoạt động trên một dữ liệu khác. Sự song song theo chiều dọc làm cho toàn bộ đơn vị SIMD hoạt động trên cùng một đối tượng dữ liệu, cố gắng hưởng lợi từ tính đa chiều bên trong của nó.

Để đưa ra ví dụ cụ thể: hãy xem xét bạn có 2 mảng XY vectơ 3D mà bạn muốn thêm.

  • cách tiếp cận theo chiều ngang: mỗi làn đường của đơn vị SIMD sẽ làm gì:

    for(idx = 0; idx<size; idx+=SIMD_size) { 
        ... = X[idx+laneid].x + Y[idx+laneid].x; 
        ... = X[idx+laneid].y + Y[idx+laneid].y; 
        ... = X[idx+laneid].z + Y[idx+laneid].z; 
    } 
    
  • cách tiếp cận theo chiều dọc: mỗi làn đường của đơn vị SIMD có một thành phần khác nhau của vector cùng:

    for(idx = 0; idx<size; idx+=1) { 
        ... = X[idx].coord(laneid) + Y[idx].coord(laneid); 
    } 
    

Phương pháp tiếp cận theo chiều dọc dễ triển khai hơn. Trong thực tế, trình biên dịch đang cố gắng tự động vector hóa đã. Vấn đề là khi chiều rộng của đơn vị SIMD đang tăng lên, việc thực hiện không thể hưởng lợi từ nó. Nếu bạn chuyển từ SIMD từ 4 sang 16 rộng, bạn vẫn chỉ thêm 3 số song song với vectơ 3D của mình.

Phương pháp tiếp cận ngang khó hơn. Bạn thường phải xử lý các nhánh phân tách, các cuộc gọi hàm, v.v ... và - bạn muốn tổ chức lại dữ liệu của mình thành Cấu trúc-Mảng - để các trường tương ứng của đối tượng dữ liệu khác nhau nằm cạnh nhau trong bộ nhớ.


Bây giờ, trở lại câu hỏi của bạn: SoA làm cho tinh thần chỉ nếu bạn làm song song ngang. Khi mỗi làn đường truy cập vào cùng một trường của đối tượng khác nhau, SoA cho phép thay thế một lệnh thu thập tốn kém với việc tìm nạp bộ nhớ đơn được căn chỉnh tốt hơn. Nếu bạn cố gắng làm theo chiều dọc, như trong ví dụ của bạn trong câu hỏi - không ai thậm chí xem xét thực hiện SoA ngay từ đầu - việc truy cập vào nhiều trường của cùng một đối tượng sẽ khiến "thu thập".

Tuy nhiên, với quyền truy cập ngẫu nhiên, SoA có thể không phải là tùy chọn tốt nhất ngay cả khi bạn thực hiện song song theo chiều ngang. Đầu tiên, bạn sẽ không có lợi khi có SoA bởi vì bạn vẫn cần phải tập hợp đắt tiền. Tuy nhiên, khi các trường của cùng một đối tượng được trải đều trên bộ nhớ, mỗi lần tải sẽ đạt đến một làn đường bộ nhớ cache khác. Không chỉ nó làm tăng việc sử dụng băng thông bộ nhớ, nó cũng có thể gây ra bộ đệm cache. Đây là lý do tại sao SoA không hiệu quả với quyền truy cập ngẫu nhiên.

Một giải pháp tốt hơn là có cách tiếp cận lai: Bạn đóng gói dữ liệu của mình trong một mảng-của-cấu trúc-của-mảng-của-SIMD-với-kích thước. Nhưng đó là một câu chuyện khác ...

+1

Có thể muốn đề cập đến trường hợp bệnh lý với SoA - nơi hai thành phần của cùng một cấu trúc lôgic có tranh cãi dòng bộ nhớ cache (đọc từ một nguyên nhân khác để dỡ bỏ) – Yakk

1

Có, bạn có vẻ hiểu tình hình.

Nếu bạn đọc nhiều giá trị từ cùng một cấu trúc, thì CPU sẽ chỉ cần tìm nạp nhiều dòng bộ nhớ cache vì nó cần cho những cấu trúc đó - có lẽ chỉ một, nếu cấu trúc được sắp xếp tốt. Vì vậy, bộ nhớ cache có thể trông như thế này (nơi v là những giá trị mà bạn muốn, và khe cắm trống là những giá trị khác)

line 1: | v | | v | v | | | v | | 

Nếu những giá trị từng phải được đọc từ một mảng riêng biệt, sau đó nó sẽ phải lấy một toàn bộ dòng bộ nhớ cache cho mỗi giá trị. Vì vậy, bộ nhớ cache có thể trông giống như

line 1: | | | v | | | | | | 
line 2: | | | | | v | | | | 
line 3: | | v | | | | | | | 
line 4: | | | v | | | | | | 

Nếu bạn đang làm việc qua mảng theo thứ tự thì tốt - bạn sẽ sớm cần thêm các giá trị được tìm nạp.

Tuy nhiên, nếu bạn không làm việc theo thứ tự (trong sách, bạn đang ở trong "tình huống ngẫu nhiên hoặc không mạch lạc"), sau đó tìm nạp nhiều hơn bạn cần mỗi lần sẽ lãng phí dung lượng trong bộ nhớ cache và bạn ' sẽ kết thúc bằng cách sử dụng băng thông bộ nhớ nhiều hơn nếu các giá trị cần thiết được với nhau trong một cấu trúc.

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