2012-01-13 15 views
9

Tôi có một mảnh lớn của mã, một phần của mà cơ thể có chứa đoạn mã này:SSE chậm hơn FPU?

result = (nx * m_Lx + ny * m_Ly + m_Lz)/sqrt(nx * nx + ny * ny + 1); 

mà tôi đã vector hóa như sau (tất cả mọi thứ đã là một float):

__m128 r = _mm_mul_ps(_mm_set_ps(ny, nx, ny, nx), 
         _mm_set_ps(ny, nx, m_Ly, m_Lx)); 
__declspec(align(16)) int asInt[4] = { 
    _mm_extract_ps(r,0), _mm_extract_ps(r,1), 
    _mm_extract_ps(r,2), _mm_extract_ps(r,3) 
}; 
float (&res)[4] = reinterpret_cast<float (&)[4]>(asInt); 
result = (res[0] + res[1] + m_Lz)/sqrt(res[2] + res[3] + 1); 

Kết quả đúng; Tuy nhiên, điểm chuẩn của tôi cho thấy rằng phiên bản vectorized là chậm:

  • Phiên bản phi vectorized mất 3750 ms
  • Phiên bản vectorized mất 4050 ms
  • Thiết result-0 trực tiếp (và loại bỏ phần này của mã hoàn toàn) làm giảm toàn bộ quá trình đến 2500 ms

cho rằng các phiên bản vectorized chỉ chứa một tập hợp các phép nhân SSE (thay vì bốn phép nhân FPU), tại sao nó chậm hơn? FPU có thực sự nhanh hơn SSE không, hoặc có một biến nhiễu ở đây không?

(Tôi đang trên một Core i5 di động.)

+7

Đã một thời gian kể từ khi tôi nhìn thấy câu hỏi SSE trên SO. Tôi đoán mọi người đang trở về từ kỳ nghỉ.:) – Mysticial

+0

@Mysticial: LOL. xD – Mehrdad

Trả lời

15

Bạn đang dành rất nhiều thời gian di chuyển các giá trị vô hướng đến/từ SSE đăng ký với _mm_set_ps_mm_extract_ps - điều này đang tạo ra rất nhiều hướng dẫn, thời gian thực hiện trong đó sẽ vượt xa bất kỳ lợi ích nào khi sử dụng _mm_mul_ps. Hãy xem kết quả lắp ráp được tạo ra để xem có bao nhiêu mã được tạo ra ngoài lệnh MULPS đơn lẻ.

Để vector hóa đúng cách này, bạn cần sử dụng các tải và cửa hàng SSE 128 bit (_mm_load_ps/_mm_store_ps) và sau đó sử dụng lệnh trộn SSE để di chuyển các phần tử xung quanh trong sổ đăng ký khi cần.

Một điểm nữa cần lưu ý là CPU hiện đại như Core i5, Core i7, có hai FPU vô hướng và có thể phát ra 2 hệ số điểm động trên mỗi đồng hồ. Lợi ích tiềm năng của SSE đối với điểm nổi chính xác duy nhất là do đó chỉ có 2x ở mức tốt nhất. Thật dễ dàng để mất hầu hết/tất cả lợi ích 2x này nếu bạn có quá nhiều hướng dẫn "vệ sinh", như trường hợp ở đây.

+0

Huh, không nhận ra được giá trị chuyển động giữa các thanh ghi quá chậm! Tôi đã thực sự cố gắng để * tránh * hoạt động bộ nhớ. Thật tuyệt khi biết, cảm ơn rất nhiều! :) +1 – Mehrdad

+3

@Mehrdad Rất chậm vì nó di chuyển giữa các thanh ghi trong các miền khác nhau (SSE-FP so với sổ đăng ký chung). Thường có thêm một chu kỳ 1-2 chu kỳ cho chuyển động dữ liệu giữa nhiều miền. – Mysticial

+0

@Mysticial: Ooooo tốt điểm - Tôi hoàn toàn quên rằng đăng ký FPU là khá một chút khác nhau từ một mục đích chung đăng ký. :) – Mehrdad

0

Việc thực hiện của tôi là bộ xử lý có thời gian tính toán phép nhân đầu tiên khi sử dụng FPU trong khi tải các giá trị tiếp theo. SSE phải tải tất cả các giá trị trước.

3

Có một số vấn đề:

  1. Bạn sẽ không thấy lợi ích nhiều từ việc sử dụng các chỉ lệnh SSE trong các hoạt động như vậy, bởi vì các hướng dẫn SSE có nghĩa vụ phải được tốt hơn về hoạt động song song (có nghĩa là, nhân nhiều giá trị tại cùng một lúc). Việc bạn đã làm là sử dụng sai số SSE
  2. không đặt giá trị, sử dụng con trỏ đến giá trị thứ nhất trong mảng, nhưng sau đó giá trị của bạn không nằm trong mảng
  3. không trích xuất và sao chép giá trị vào mảng . Đó cũng là lạm dụng SSE. Kết quả được cho là nằm trong một mảng.