2013-08-23 41 views
10

Nhiệm vụ rất đơn giản, writting một seqence của biến số nguyên để nhớ:Cách nhanh chóng (est) để viết một seqence của số nguyên để bộ nhớ toàn cầu?

đang Original:

for (size_t i=0; i<1000*1000*1000; ++i) 
{ 
    data[i]=i; 
}; 

đang song song:

size_t stepsize=len/N; 

#pragma omp parallel num_threads(N) 
    { 
     int threadIdx=omp_get_thread_num(); 

     size_t istart=stepsize*threadIdx; 
     size_t iend=threadIdx==N-1?len:istart+stepsize; 
#pragma simd 
     for (size_t i=istart; i<iend; ++i) 
      x[i]=i; 
    }; 

Việc thực hiện sucks, phải mất 1,6 giây để viết 1G uint64 biến (bằng 5 GB mỗi giây), bằng cách song song đơn giản (open mp parallel) của mã trên, tốc độ tăng chút, nhưng hiệu suất vẫn sucks, mất 1,4 giây với 4 chủ đề và 1,35 với 6 chủ đề trên i7 3970.

Các theortical băng thông bộ nhớ của giàn khoan của tôi (i7 3970/64g DDR3-1600) là 51,2 GB/sec, đối với ví dụ trên, băng thông bộ nhớ đạt được chỉ bằng khoảng 1/10 của băng thông lý thuyết, thậm chí thông qua ứng dụng là khá nhiều băng thông bộ nhớ bị giới hạn.

Bất kỳ ai biết cách cải thiện mã?

Tôi đã viết rất nhiều mã bộ nhớ bị ràng buộc trên GPU, khá dễ dàng để GPU tận dụng tối đa băng thông bộ nhớ của thiết bị GPU (ví dụ: 85% + băng thông lý thuyết).

EDIT:

Mã này được biên soạn bởi Intel ICC 13.1, đến 64bit nhị phân, và với Optimzation tối đa (O3) và đường dẫn mã AVX trên, cũng như tự động vectorization.

UPDATE:

Tôi đã thử tất cả các mã dưới đây (nhờ Paul R), không có gì đặc biệt xảy ra, tôi tin rằng trình biên dịch là hoàn toàn có khả năng làm các loại tối ưu hóa SIMD/vector hóa.

Đối với lý do tại sao tôi muốn lấp đầy những con số đó, tốt, câu chuyện dài ngắn:

phần của nó một hiệu suất cao máy tính không đồng nhất algorthim, ở phía bên thiết bị, algorthim rất hiệu quả đến mức độ mà bộ đa GPU quá nhanh đến mức tôi thấy sự tắc nghẽn hiệu suất xảy ra khi CPU cố gắng viết một vài số lượng seqence của các số vào bộ nhớ.

Trong số nguyên nhân, biết CPU mà hút tại điền số (ngược lại, GPU có thể điền seqence số với tốc độ rất gần (238GB/sec ra khỏi 288GB/sec trên GK110 vs một 5GB thảm hại/sec trong số 51.2GB/sec trên CPU) với băng thông lý thuyết của bộ nhớ toàn cầu của GPU), tôi có thể thay đổi algorthim của mình một chút, nhưng điều khiến tôi tự hỏi là tại sao CPU lại quá tệ khi lấp đầy số lượng ở đây.

Đối với băng thông bộ nhớ của giàn khoan của tôi, tôi tin rằng băng thông (51.2GB) là về đúng, dựa trên thử nghiệm memcpy() tôi, băng thông đạt khoảng 80% + của băng thông theoritical (> 40GB/giây).

+4

Bạn đã thử tối ưu hóa mã chưa? Ví dụ. sử dụng -O3 nếu bạn đang sử dụng 'gcc'? –

+1

Tối thiểu, bạn nên thử mở nó ra. * Tối ưu hóa ghế bành *. – unwind

+0

Thử thực hiện 2 lần viết mỗi lần lặp. Có lẽ 4, 8, 16. –

Trả lời

10

Giả sử đây là x86, và rằng bạn chưa bão hòa băng thông DRAM có sẵn, bạn có thể thử sử dụng SSE2 hoặc AVX2 viết 2 hoặc 4 nguyên tố tại một thời điểm:

SSE2:

#include "emmintrin.h" 

const __m128i v2 = _mm_set1_epi64x(2); 
__m128i v = _mm_set_epi64x(1, 0); 

for (size_t i=0; i<1000*1000*1000; i += 2) 
{ 
    _mm_stream_si128((__m128i *)&data[i], v); 
    v = _mm_add_epi64(v, v2); 
} 

AVX2:

#include "immintrin.h" 

const __m256i v4 = _mm256_set1_epi64x(4); 
__m256i v = _mm256_set_epi64x(3, 2, 1, 0); 

for (size_t i=0; i<1000*1000*1000; i += 4) 
{ 
    _mm256_stream_si256((__m256i *)&data[i], v); 
    v = _mm256_add_epi64(v, v4); 
} 

Lưu ý rằng data cần phải được sắp xếp phù hợp (16 byte hoặc 32 ranh giới byte).

AVX2 chỉ khả dụng trên Intel Haswell và phiên bản mới hơn, nhưng SSE2 phổ biến nhiều trong những ngày này.


FWIW Tôi đặt cùng một khai thác thử nghiệm với một vòng lặp vô hướng và trên SSE và AVX vòng biên dịch nó với kêu vang, và thử nghiệm nó trên một Haswell MacBook Air (1600MHz LPDDR3 DRAM). Tôi nhận được kết quả như sau:

# sequence_scalar: t = 0.870903 s = 8.76033 GB/s 
# sequence_SSE: t = 0.429768 s = 17.7524 GB/s 
# sequence_AVX: t = 0.431182 s = 17.6941 GB/s 

Tôi cũng đã cố gắng nó trên một máy tính để bàn Linux với một 3,6 GHz Haswell, biên dịch với gcc 4.7.2, và đã nhận như sau:

# sequence_scalar: t = 0.816692 s = 9.34183 GB/s 
# sequence_SSE: t = 0.39286 s = 19.4201 GB/s 
# sequence_AVX: t = 0.392545 s = 19.4357 GB/s 

Vì vậy, nó trông giống như việc triển khai SIMD cho phép cải thiện gấp 2 lần so với mã vô hướng 64 bit (mặc dù SIMD 256 bit dường như không cải thiện hơn 128 bit SIMD) và thông lượng tiêu biểu sẽ nhanh hơn 5 GB/giây.

Tôi đoán là có sự cố với hệ thống hoặc mã điểm chuẩn của OP, điều này dẫn đến thông lượng giảm rõ ràng.

+2

Bạn đã ... đánh giá nó để xem liệu nó có phải là _actually_ nhanh hơn không? – sehe

+2

Điều đó được để lại như một bài tập cho người đọc, và tất nhiên nó sẽ phụ thuộc vào nhiều yếu tố khác nhau. Nhưng kể từ khi băng thông DRAM được cho là hư không gần bão hòa trong trường hợp của OP, tôi sẽ mong đợi một sự cải thiện khiêm tốn. –

+0

@PaulR Những con trỏ này sẽ chuyển thành '__m256i *' vòng chuông bí danh nghiêm ngặt của tôi ... –

5

Có lý do nào khiến bạn mong đợi tất cả data[] có trong các trang RAM được hỗ trợ không?

Trình tìm nạp trước DDR3 sẽ dự đoán chính xác hầu hết các truy cập nhưng ranh giới trang x86-64 thường xuyên có thể là một vấn đề. Bạn đang ghi vào bộ nhớ ảo, do đó, tại mỗi ranh giới trang có khả năng dự đoán sai của trình tìm nạp trước. Bạn có thể giảm đáng kể điều này bằng cách sử dụng các trang lớn (ví dụ: MEM_LARGE_PAGES trên Windows).

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