Tại sao độ trễ của lệnh sqrtsd thay đổi dựa trên đầu vào? Bộ xử lý Intel


9

Vâng, theo hướng dẫn nội tại của Intel , có tuyên bố rằng lệnh "sqrtsd" có độ trễ là 18 chu kỳ.

Tôi đã thử nghiệm nó với chương trình của riêng tôi và nó là chính xác nếu, ví dụ, chúng tôi lấy 0,15 làm đầu vào. Nhưng khi chúng ta lấy 256 (hoặc bất kỳ số 2 ^ x) thì độ trễ chỉ là 13. Tại sao lại như vậy?

Một giả thuyết tôi có là vì 13 là độ trễ của "sqrtss" giống như "sqrtsd" nhưng được thực hiện trên các điểm nổi 32 bit nên có lẽ bộ xử lý đủ thông minh để hiểu taht 256 có thể phù hợp với 32 bit và do đó sử dụng phiên bản đó trong khi 0,15 cần 64 bit đầy đủ vì nó không thể biểu diễn theo cách hữu hạn.

Tôi đang thực hiện nó bằng cách sử dụng lắp ráp nội tuyến, đây là phần tương ứng được biên dịch với gcc -O3 và -fno-tree-vectorize.

static double sqrtsd (double x) {
    double r;
    __asm__ ("sqrtsd %1, %0" : "=x" (r) : "x" (x));
    return r;
}

3
Cho chúng tôi xem mã của bài kiểm tra. Tôi có thể tưởng tượng việc thực hiện trong đó tối ưu hóa được thực hiện bởi trình biên dịch chứ không phải bộ xử lý.
Robert Navado

Bộ xử lý không thông minh: họ thực hiện các hướng dẫn được đưa ra.
Thời tiết

Điều này có trả lời câu hỏi của bạn không? Tại sao SSE vô hướng sqrt (x) chậm hơn rsqrt (x) * x?
Tarek Dakhran

2
Bạn không tưởng tượng mọi thứ: instlatx64 cho skylake cũng liệt kê 18 (trường hợp xấu nhất) và 13 (giá trị đơn giản)
harold

1
Mã thông báo nội tuyến của bạn không có ý nghĩa và sẽ không biên dịch: godbolt.org/z/rJA6nS . "i"chỉ định là ngay lập tức và không thể là một hạn chế đầu ra. sqrtsdchỉ chấp nhận đầu vào reg / mem, không phải ngay lập tức, vì vậy sẽ không lắp ráp ngay cả khi nó đã biên dịch. Ngoài ra, sử dụng các hằng số thời gian biên dịch không cho phép bạn kiểm tra độ trễ, chỉ thông lượng. Nhưng con số của bạn trông có vẻ lành mạnh vì vậy bất cứ điều gì bạn thực sự có thể đã kiểm tra độ trễ sqrtsd.
Peter Cordes

Câu trả lời:


10

SQRT * và DIV * là hai hướng dẫn ALU "đơn giản" duy nhất (uop đơn lẻ, không phân nhánh / vòng lặp được mã hóa) có thông lượng hoặc độ trễ phụ thuộc dữ liệu trên CPU Intel / AMD hiện đại. (Không tính microcode hỗ trợ cho các giá trị FP không bình thường hay không bình thường trong add / Multiply / fma). Mọi thứ khác đều được sửa chữa khá nhiều, vì vậy máy móc lập lịch uop không theo thứ tự không cần chờ xác nhận rằng kết quả đã sẵn sàng một số chu kỳ, nó chỉ biết rằng nó sẽ được.

Như thường lệ, hướng dẫn nội tại của Intel đưa ra một bức tranh đơn giản hóa về hiệu suất. Độ trễ thực tế không phải là 18 chu kỳ cố định cho độ chính xác kép trên Skylake. (Dựa trên những con số bạn chọn để trích dẫn, tôi giả sử bạn có Skylake.)

div / sqrt khó thực hiện; ngay cả trong phần cứng, điều tốt nhất chúng ta có thể làm là một quá trình sàng lọc lặp lại. Tinh chỉnh nhiều bit cùng một lúc (bộ chia radix-1024 kể từ Broadwell) tăng tốc độ (xem phần Hỏi & Đáp về phần cứng này ). Nhưng nó vẫn đủ chậm để sử dụng sớm để tăng tốc các trường hợp đơn giản (Hoặc có thể cơ chế tăng tốc chỉ bỏ qua bước thiết lập cho các mantissas hoàn toàn không trên các CPU hiện đại với các đơn vị div / sqrt được đường ống một phần. = độ trễ cho FP div / sqrt; đơn vị thực thi đó khó đường ống hơn.)


https://www.uops.info/html-instr/VSQRTSD_XMM_XMM_XMM.html cho thấy Skylake SQRTSD có thể thay đổi từ 13 đến 19 độ trễ chu kỳ. Các số SKL (máy khách) chỉ hiển thị độ trễ 13 chu kỳ, nhưng chúng ta có thể thấy từ trang SKL vsqrtsd chi tiết mà chúng chỉ kiểm tra với đầu vào = 0. Số SKX (máy chủ) hiển thị độ trễ 13-19 chu kỳ. ( Trang này có phân tích chi tiết về mã kiểm tra mà họ đã sử dụng, bao gồm các mẫu bit nhị phân cho các thử nghiệm.) Thử nghiệm tương tự (chỉ có 0 đối với lõi máy khách) đã được thực hiện trên trang không phải VEXsqrtsd xmm, xmm . : /

Kết quả InstLatx64 cho thấy độ trễ trường hợp tốt nhất / xấu nhất từ ​​13 đến 18 chu kỳ trên Skylake-X (sử dụng cùng lõi với Skylake-client, nhưng đã bật AVX512).

Các bảng hướng dẫn của Agner Fog cho thấy độ trễ chu kỳ 15-16 trên Skylake. (Agner thường kiểm tra với một loạt các giá trị đầu vào khác nhau.) Các thử nghiệm của anh ta ít tự động hơn và đôi khi không khớp chính xác với các kết quả khác.

Điều gì làm cho một số trường hợp nhanh chóng?

Lưu ý rằng hầu hết các ISA (bao gồm x86) sử dụng dấu phẩy động nhị phân :
các bit biểu thị các giá trị dưới dạng ý nghĩa tuyến tính (hay còn gọi là mantissa) lần 2 exp và một bit dấu.

Có vẻ như chỉ có 2 tốc độ trên Intel hiện đại (ít nhất là Haswell) (Xem thảo luận với @harold trong các nhận xét.), Ví dụ như các quyền hạn của 2 đều nhanh, như 0,25, 1, 4 và 16. Những thứ này có tầm thường mantissa = 0x0 đại diện cho 1.0. https://www.h-schmidt.net/FloatConverter/IEEE754.html có một công cụ chuyển đổi mô hình bit <-> thập phân tương tác đẹp cho độ chính xác đơn, với các hộp kiểm cho các bit được đặt và chú thích về những gì mantissa và số mũ biểu thị.

Trên Skylake, các trường hợp nhanh duy nhất tôi tìm thấy trong một kiểm tra nhanh thậm chí là các quyền hạn của 2 như 4.0 nhưng không phải là 2.0. Những con số này có kết quả sqrt chính xác với cả đầu vào và đầu ra có 1.0 mantissa (chỉ bộ 1 bit ẩn). 9.0không nhanh, mặc dù nó chính xác có thể đại diện và 3.0kết quả cũng vậy. 3.0 có mantissa = 1.5 chỉ với bit đáng kể nhất của mantissa được đặt trong biểu diễn nhị phân. Giá trị của 9.0 là 1.125 (0b00100 ...). Vì vậy, các bit khác không rất gần với đỉnh, nhưng dường như điều đó đủ để loại bỏ nó.

( +-InfNaN. Đang nhanh chóng, quá Vậy là số âm bình thường: kết quả = -NaN . Tôi đo 13 chu kỳ độ trễ cho những ngày i7-6700k, tương tự như đối 4.0vs 18 chu kỳ độ trễ đối với trường hợp chậm..)

x = sqrt(x)chắc chắn là rất nhanh với x = 1.0(mantissa hoàn toàn bằng không ngoại trừ 1 bit dẫn đầu ngầm). Nó có một đầu vào đơn giản và đầu ra đơn giản.

Với 2.0, đầu vào cũng đơn giản (mantissa hoàn toàn bằng 0 và số mũ 1 cao hơn) nhưng đầu ra không phải là số tròn. sqrt (2) là không hợp lý và do đó có các bit khác không vô hạn trong bất kỳ cơ sở nào. Điều này rõ ràng làm cho nó chậm trên Skylake.

Các bảng hướng dẫn của Agner Fog nói rằng divhiệu suất lệnh số nguyên của AMD K10 phụ thuộc vào số lượng bit đáng kể trong cổ tức (đầu vào), chứ không phải thương số, nhưng tìm kiếm bảng microarch pdf và bảng hướng dẫn của Agner không tìm thấy bất kỳ chú thích hay thông tin nào về cách thức cụ thể của sqrt phụ thuộc dữ liệu.

Trên các CPU cũ hơn với FP sqrt chậm hơn, có thể có nhiều chỗ hơn cho một loạt tốc độ. Tôi nghĩ rằng số lượng bit đáng kể trong lớp phủ của đầu vào có thể sẽ có liên quan. Ít bit đáng kể hơn (nhiều số 0 ở cuối có nghĩa) làm cho nó nhanh hơn, nếu điều này là chính xác. Nhưng một lần nữa, trên Haswell / Skylake, các trường hợp nhanh duy nhất dường như thậm chí là sức mạnh của 2.


Bạn có thể kiểm tra điều này với thứ gì đó kết hợp đầu ra trở lại đầu vào mà không phá vỡ sự phụ thuộc dữ liệu, ví dụ andps xmm0, xmm1/ orps xmm0, xmm2để đặt giá trị cố định trong xmm0 phụ thuộc vào đầu ra sqrtsd.

Hoặc một cách đơn giản hơn để kiểm tra độ trễ là tận dụng "lợi thế" của sự phụ thuộc đầu ra sai củasqrtsd xmm0, xmm1 - nó và sqrtssđể lại 64/32 bit trên (tương ứng) của đích không được sửa đổi, do đó thanh ghi đầu ra cũng là đầu vào cho việc hợp nhất đó. Tôi giả sử đây là cách mà nỗ lực nội tuyến ngây thơ của bạn đã kết thúc việc tắc nghẽn về độ trễ thay vì thông lượng với trình biên dịch chọn một thanh ghi khác cho đầu ra để nó có thể đọc lại cùng một đầu vào trong một vòng lặp. Mã asm nội tuyến mà bạn đã thêm vào câu hỏi của mình hoàn toàn bị hỏng và thậm chí sẽ không biên dịch, nhưng có lẽ mã thực của bạn được sử dụng "x"(thanh ghi xmm) ràng buộc thay vì "i"(ngay lập tức)?

Nguồn NASM này cho một vòng kiểm tra thực thi tĩnh (để chạy bên dưới perf stat) sử dụng sự phụ thuộc sai đó với mã hóa không phải VEX của sqrtsd.

Mụn cóc thiết kế này là nhờ Intel tối ưu hóa trong thời gian ngắn với SSE1 trên Pentium III. P3 xử lý các thanh ghi 128 bit bên trong như hai nửa 64 bit. Để nửa trên không thay đổi, hãy để các hướng dẫn vô hướng giải mã thành một uop duy nhất. (Nhưng điều đó vẫn mang lại cho PIII sqrtssmột sự phụ thuộc sai). AVX cuối cùng cũng cho phép chúng tôi tránh điều này với vsqrtsd dst, src,srcít nhất là đối với các nguồn đăng ký, và tương tự vcvtsi2sd dst, cold_reg, eaxđối với các hướng dẫn vô hướng được thiết kế gần tương tự int-> fp chuyển đổi. (GCC bỏ lỡ tối ưu hóa các báo cáo: 80.586 , 89.071 , 80.571 ).


Trên nhiều CPU trước đó, thông lượng thậm chí có thể thay đổi, nhưng Skylake đã tăng cường các bộ chia đủ để bộ lập lịch luôn biết rằng nó có thể bắt đầu một chu kỳ div / sqrt 3 mới sau lần nhập chính xác đơn cuối cùng.

Ngay cả thông lượng chính xác kép của Skylake cũng có thể thay đổi: 4 đến 6 chu kỳ sau lần đầu vào chính xác kép cuối cùng, nếu bảng hướng dẫn của Agner Fog là đúng. https://uops.info/ cho thấy một 6c phẳng đối ứng thông. (Hoặc gấp đôi thời gian cho các vectơ 256 bit; 128 bit và vô hướng có thể sử dụng một nửa các dải phân cách SIMD rộng để có thông lượng cao hơn nhưng cùng độ trễ.) Xem thêm Phân chia điểm nổi so với phép nhân điểm nổi cho một số số thông lượng / độ trễ được trích xuất từ bảng hướng dẫn của Agner Fog.


Nhân tiện, còn độ trễ giữa hai thái cực thì sao? Họ có xảy ra không? Tôi không thể làm điều đó xảy ra trên Haswell của mình, nhưng điều đó không có kết luận
quấy rối

@harold: IDK, tôi đoán rằng nếu có thể, điều đó sẽ xảy ra với một số lượng nhỏ hơn các số 0 ở cuối lớp phủ. Nhưng có lẽ chỉ có một trường hợp phát hiện sớm trường hợp đặc biệt cho những trường hợp đơn giản nhất. Bộ chia cơ số thấp hơn của Haswell sẽ giúp bạn có lợi hơn khi tìm kiếm sớm hơn sớm, nhưng có lẽ đó là vấn đề của ước tính ban đầu (từ cùng một bảng sử dụng rsqrt) là chính xác hay không, và nếu không thì nó cần phải sàng lọc lặp lại tất cả đường đến cuối cùng.
Peter Cordes

rsqrtkhông chính xác cho quyền hạn của hai mặc dù (trên Haswell dù sao), nhưng quyền hạn của hai và số 0 cho đến nay là đầu vào duy nhất tôi tìm thấy nơi căn bậc hai nhanh, sau đó một lần nữa các rsqrthướng dẫn dường như không chỉ là một tra cứu được đưa ra độ trễ của chúng thực sự là bao lâu
harold

@harold: rsqrtcó thể không phải là đầu ra thô của LUT (vâng như bạn đã chỉnh sửa, độ trễ cao có thể là một số công việc). Hoặc có thể nó dẫn đến câu trả lời chính xác cho các đầu vào đơn giản (mantissa hoàn toàn bằng không). Hoặc có lẽ mantissa hoàn toàn có thể bỏ qua việc tra cứu LUT trước khi bắt đầu sàng lọc. Tôi không biết đủ về các bộ chia CTNH để loại trừ bất kỳ dự đoán nào trong số này. : /
Peter Cordes

1
sqrtsdnhanh cho sức mạnh của hai với số mũ lẻ? Hay chỉ cho sức mạnh của hai với số mũ chẵn? Hay đấy.
fuz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.