2010-06-29 43 views
8

Tôi đã gặp phải vấn đề tò mò. Một thuật toán tôi đang làm việc trên bao gồm rất nhiều tính toán như thế nàyHiệu suất dấu phẩy động 32 bit so với 64 bit

q = x(0)*y(0)*z(0) + x(1)*y(1)*z(1) + ... 

nơi chiều dài của tổng là giữa 4 và 7.

Các tính toán ban đầu đều được thực hiện sử dụng chính xác 64-bit. Để thử nghiệm, tôi đã thử sử dụng độ chính xác 32 bit cho các giá trị đầu vào x, y, z (để tính toán được thực hiện bằng cách sử dụng 32 bit) và lưu trữ kết quả cuối cùng dưới dạng giá trị 64 bit (đúc đơn giản).

Tôi dự kiến ​​hiệu suất 32 bit sẽ tốt hơn (kích thước bộ nhớ cache, kích thước SIMD, v.v.), nhưng với sự ngạc nhiên của tôi không có sự khác biệt về hiệu suất, thậm chí có thể giảm.

Kiến trúc được đề cập là Intel 64, Linux và GCC. Cả hai mã dường như sử dụng SSE và mảng trong cả hai trường hợp đều được căn chỉnh với ranh giới 16 byte.

Tại sao lại như vậy? Dự đoán của tôi cho đến nay là độ chính xác 32 bit chỉ có thể sử dụng SSE trên bốn phần tử đầu tiên, với phần còn lại được thực hiện một cách nghiêm túc bằng cách cast overhead.

+0

Bạn đã thêm tiền thưởng - bạn không thích gì về câu trả lời của dsimcha? Nó cũng có thể là giá trị cố gắng GCC gần đây nhất bạn có thể hoặc trình biên dịch của Intel http://software.intel.com/en-us/articles/non-commercial-software-download/ để xem họ làm một công việc tốt hơn biên dịch/vectorising . – Rup

+0

@Rup Tôi thích câu trả lời của anh ấy, tuy nhiên cũng thích các ý kiến ​​khác, vì vậy tôi đặt một số tiền thưởng – Anycorn

Trả lời

24

Trên x87 ít nhất, mọi thứ thực sự được thực hiện với độ chính xác 80 bit trong nội bộ. Độ chính xác thực sự chỉ xác định số lượng các bit được lưu trữ trong bộ nhớ. Đây là một phần lý do tại sao các cài đặt tối ưu hóa khác nhau có thể thay đổi kết quả một chút: Chúng thay đổi số lượng làm tròn từ 80 bit đến 32 hoặc 64 bit. Trong thực tế, sử dụng điểm nổi 80-bit (long double trong C và C++, real trong D) thường chậm vì không có cách hiệu quả để tải và lưu trữ 80 bit từ bộ nhớ. 32 và 64 bit thường được cung cấp nhanh chóng với điều kiện băng thông bộ nhớ không phải là nút cổ chai, tức là nếu mọi thứ đều nằm trong bộ đệm ẩn. 64 bit có thể chậm hơn nếu một trong các điều sau xảy ra:

  1. Băng thông bộ nhớ là nút cổ chai.
  2. Số 64 bit không được căn chỉnh chính xác trên các ranh giới 8 byte. Các số 32 bit chỉ yêu cầu căn chỉnh 4 byte để đạt hiệu quả tối ưu, vì vậy chúng ít khó tính hơn. Một số trình biên dịch (trình biên dịch Digital Mars D xuất hiện trong đầu) không phải lúc nào cũng nhận được quyền này cho các cặp đôi 64 bit được lưu trữ trên ngăn xếp. Điều này gây ra gấp đôi số lượng hoạt động bộ nhớ cần thiết để tải một, trong thực tế dẫn đến khoảng một hit hiệu suất 2x so với phù hợp 64-bit nổi phù hợp hoặc nổi 32-bit.

Theo như tối ưu hóa SIMD, cần lưu ý rằng hầu hết các trình biên dịch đều rất kinh khủng khi tự động mã hóa vectơ. Nếu bạn không muốn viết trực tiếp trong ngôn ngữ assembly, cách tốt nhất để tận dụng các hướng dẫn này là sử dụng những thứ như hoạt động mảng, có sẵn, ví dụ, trong D, và được thực hiện theo các chỉ lệnh SSE. Tương tự như vậy, trong C hoặc C++, bạn có thể muốn sử dụng một thư viện mức cao của các hàm được tối ưu hóa SSE, mặc dù tôi không biết một hàm nào tốt ngoài đầu bởi vì tôi chủ yếu là chương trình trong D.

+4

"x87" - Hơi tốt hơn các bộ vi xử lý x86 cũ. :-) – Thanatos

+4

http://en.wikipedia.org/wiki/X87 – Adam

0

Có thể do bộ xử lý của bạn vẫn thực hiện đếm 64 bit và sau đó cắt bớt số. Có một số cờ CPU mà bạn có thể thay đổi, nhưng tôi không thể nhớ ...

0

Đầu tiên kiểm tra ASM được sản xuất. Nó có thể không phải là những gì bạn mong đợi.

Cũng cố gắng viết nó như một vòng lặp:

typedef float fp; 
fp q = 0 
for(int i = 0; i < N; i++) 
    q += x[i]*y[i]*z[i] 

Một số trình biên dịch có thể nhận thấy các vòng lặp và không phải là hình thức trải ra.

Cuối cùng, mã của bạn được sử dụng () thay vì []. Nếu mã của bạn đang thực hiện nhiều cuộc gọi hàm (12 đến 21), điều đó sẽ làm giảm chi phí FP và thậm chí loại bỏ tính toán fp cùng nhau sẽ không tạo ra nhiều khác biệt. Inlineing OTOH có thể.

+0

cảm ơn, thực sự 'q()' là macro chuyển đổi trực tiếp sang truy cập con trỏ thô – Anycorn

+0

@aaa: Vâng, nếu có bất kỳ toán học nào, nó vẫn có thể là một tỷ lệ lớn. Ngoài ra, tôi không biết làm thế nào tốt trình biên dịch đối phó với trộn FP và các công cụ khác. Điều đó có thể đủ để ngăn chặn nó bằng cách sử dụng ops vector. – BCS

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