FLOP đếm cho các chức năng thư viện


13

Khi đánh giá số lượng FLOP trong một hàm đơn giản, người ta thường có thể đi xuống biểu thức kiểm tra các toán tử số học cơ bản. Tuy nhiên, trong trường hợp các câu lệnh toán học liên quan đến phép chia, người ta không thể làm điều này và hy vọng có thể so sánh với số FLOP từ các hàm chỉ bằng phép cộng và phép nhân. Tình hình thậm chí còn tồi tệ hơn khi hoạt động được thực hiện trong một thư viện. Do đó, bắt buộc phải có một số khái niệm hợp lý về hiệu suất của các chức năng đặc biệt.

Theo các chức năng đặc biệt, chúng tôi có nghĩa là những thứ như:

  • điểm kinh nghiệm
  • sqrt ()
  • tội lỗi / cos / tan ()

thường được cung cấp bởi các thư viện hệ thống.

Việc xác định độ phức tạp của những điều này còn bị nhầm lẫn hơn nữa bởi thực tế là nhiều trong số chúng có khả năng thích ứng và có độ phức tạp phụ thuộc vào đầu vào. Ví dụ, các triển khai ổn định về số của exp () thường được điều chỉnh lại một cách thích ứng và sử dụng các tra cứu. Ấn tượng ban đầu của tôi ở đây là điều tốt nhất có thể làm trong trường hợp này là xác định hành vi trung bình của các hàm.

Toàn bộ cuộc thảo luận này, tất nhiên, phụ thuộc nhiều vào kiến ​​trúc. Đối với cuộc thảo luận này, chúng tôi có thể giới hạn bản thân mình vào các kiến ​​trúc mục đích chung truyền thống và loại trừ những kiến ​​trúc có đơn vị chức năng đặc biệt (GPU, v.v.)

Người ta có thể tìm thấy những nỗ lực khá đơn giản để chuẩn hóa những điều này cho các kiến ​​trúc cụ thể vì lợi ích của hệ thống so với hệ thống, nhưng điều này không được chấp nhận nếu người ta quan tâm đến phương pháp so với hiệu suất phương pháp. Phương pháp nào để xác định độ phức tạp FLOP của các hàm này được coi là chấp nhận được? Có những cạm bẫy lớn?


Peter, chỉ là một nhận xét nhanh chóng. Mặc dù bạn cung cấp một số ví dụ hay về các hàm được cung cấp bởi các thư viện toán học, các phép chia dấu phẩy động thường được thực hiện bởi đơn vị dấu phẩy động.
Aron Ahmadia

Cảm ơn! Tôi đã không đủ rõ ràng. Tôi chỉ chỉnh sửa để cung cấp độ tương phản tốt hơn.
Peter Brunei

Tôi đã rất ngạc nhiên khi thấy rằng sin, cos và sqrt đều thực sự được triển khai trong tập con dấu phẩy động x87 của hướng dẫn x86. Tôi nghĩ rằng tôi hiểu ý của bạn, nhưng tôi nghĩ rằng thực tiễn được chấp nhận chỉ là coi những hoạt động này là các phép toán dấu phẩy động với các hằng số lớn hơn một chút :)
Aron Ahmadia

@AronAhmadia Không có lý do để sử dụng x87 trong hơn một thập kỷ. Phân chia và sqrt()ở trong SSE / AVX, nhưng chúng mất nhiều thời gian hơn so với bổ sung và đa cấp. Ngoài ra, chúng được vector hóa kém trên Sandy Bridge AVX, mất gấp đôi so với hướng dẫn SSE (với một nửa chiều rộng). Ví dụ, AVX có độ chính xác gấp đôi (rộng gấp đôi) có thể nhân bội và đóng gói thêm mỗi chu kỳ (giả sử không có phụ thuộc hoặc lưu trữ trên bộ nhớ) là 8 flops mỗi chu kỳ. Việc phân chia mất từ ​​20 đến 44 chu kỳ để thực hiện các "4 flops" đó.
Jed Brown

sqrt () là tùy chọn trên PowerPC. Nhiều chip nhúng của kiến ​​trúc này không thực hiện hướng dẫn, ví dụ loạt MPC5xxx của Freescale.
Damien

Câu trả lời:


10

Có vẻ như bạn muốn có một cách để đánh giá mã của FPU bị ràng buộc như thế nào, hoặc bạn đang sử dụng FPU hiệu quả như thế nào, thay vì đếm số lượng flop theo định nghĩa lỗi thời của "flop". Nói cách khác, bạn muốn một số liệu đạt đến cùng một đỉnh nếu mọi đơn vị điểm nổi đang chạy hết công suất mỗi chu kỳ. Chúng ta hãy nhìn vào Cầu Sandy của Intel để xem điều này có thể phát ra như thế nào.

Hoạt động điểm nổi hỗ trợ phần cứng

Con chip này hỗ trợ các hướng dẫn AVX , vì vậy các thanh ghi dài 32 byte (giữ 4 nhân đôi). Kiến trúc siêu khối cho phép các hướng dẫn trùng nhau, với hầu hết các hướng dẫn số học mất một vài chu kỳ để hoàn thành, mặc dù một hướng dẫn mới có thể có thể bắt đầu vào chu kỳ tiếp theo. Các ngữ nghĩa này thường được viết tắt bằng cách viết thông lượng độ trễ / nghịch đảo, giá trị 5/2 có nghĩa là hướng dẫn mất 5 chu kỳ để hoàn thành, nhưng bạn có thể bắt đầu một hướng dẫn mới mỗi chu kỳ khác (giả sử rằng các toán hạng có sẵn, do đó không có dữ liệu phụ thuộc và không chờ đợi bộ nhớ).

Có ba đơn vị số học dấu phẩy động trên mỗi lõi, nhưng thứ ba không liên quan đến cuộc thảo luận của chúng tôi, chúng tôi sẽ gọi hai đơn vị A và M có liên quan vì các hàm chính của chúng là phép cộng và phép nhân. Hướng dẫn ví dụ (xem bảng Agner Fog )

  • vaddpd: bổ sung đóng gói, chiếm đơn vị A trong 1 chu kỳ, thông lượng trễ / nghịch đảo là 3/1
  • vmulpd: phép nhân đóng gói, đơn vị M, 5/1
  • vmaxpd: đóng gói chọn tối đa theo cặp, đơn vị A, 3/1
  • vdivpd: phân chia đóng gói, đơn vị M (và một số A), 21/20 đến 45/44 tùy thuộc vào đầu vào
  • vsqrtpd: đóng gói căn bậc hai, một số A và M, 21/21 đến 43/43 tùy thuộc vào đầu vào
  • vrsqrtps: đóng gói căn bậc hai đối ứng có độ chính xác thấp cho đầu vào chính xác đơn (8 floats)

Các ngữ nghĩa chính xác cho những gì có thể trùng lặp vdivpdvsqrtpdrõ ràng là tinh tế và AFAIK, không được ghi lại ở bất cứ đâu. Trong hầu hết các cách sử dụng, tôi nghĩ rằng có rất ít khả năng cho sự chồng chéo, mặc dù từ ngữ trong hướng dẫn cho thấy rằng nhiều luồng có thể cung cấp nhiều khả năng hơn cho sự chồng chéo trong hướng dẫn này. Chúng ta có thể đạt được flops đỉnh nếu chúng ta bắt đầu một vaddpdvmulpdtrên mỗi chu kỳ, với tổng số 8 flops mỗi chu kỳ. Ma trận dày đặc ma trận nhân ( dgemm) có thể có được gần hợp lý với đỉnh này.

Khi đếm flops cho các hướng dẫn đặc biệt, tôi sẽ xem xét số lượng FPU bị chiếm dụng. Giả sử đối số rằng trong phạm vi đầu vào của bạn, vdivpdmất trung bình 24 chu kỳ để hoàn thành, chiếm hoàn toàn đơn vị M, nhưng việc bổ sung có thể (nếu có) được thực hiện đồng thời trong một nửa chu kỳ. FPU có khả năng thực hiện 24 bội số đóng gói và 24 bổ sung đóng gói trong các chu kỳ đó (xen kẽ hoàn hảo vaddpdvmulpd), nhưng với một vdivpd, điều tốt nhất chúng ta có thể làm là thêm 12 lần đóng gói bổ sung. Nếu chúng ta cho rằng cách tốt nhất có thể để phân chia là sử dụng phần cứng (hợp lý), chúng ta có thể tính vdivpdlà 36 "flops" được đóng gói, chỉ ra rằng chúng ta nên tính mỗi phép chia vô hướng là 36 "flops".

Với căn bậc hai đối ứng, đôi khi có thể đánh bại phần cứng, đặc biệt là nếu không cần độ chính xác đầy đủ hoặc nếu phạm vi đầu vào hẹp. Như đã đề cập ở trên, vrsqrtpshướng dẫn rất rẻ tiền, vì vậy (nếu ở độ chính xác đơn), bạn có thể thực hiện một lần vrsqrtpstheo sau một hoặc hai lần lặp Newton để dọn dẹp. Những lần lặp Newton này chỉ là

y *= (3 - x*y*y)*0.5;

Nếu nhiều thao tác này cần được thực hiện, việc này có thể nhanh hơn đáng kể so với đánh giá ngây thơ y = 1/sqrt(x). Trước sự sẵn có của căn bậc hai gần đúng đối xứng phần cứng, một số mã nhạy cảm hiệu năng đã sử dụng các phép toán số nguyên khét tiếng để tìm dự đoán ban đầu cho phép lặp Newton.

Các hàm toán học do thư viện cung cấp

Chúng ta có thể áp dụng một heuristic tương tự cho các hàm toán học do thư viện cung cấp. Bạn có thể lập hồ sơ để xác định số lượng hướng dẫn SSE, nhưng như chúng ta đã thảo luận, đó không phải là toàn bộ câu chuyện và một chương trình dành toàn bộ thời gian để đánh giá các chức năng đặc biệt có thể không đạt đến đỉnh điểm, điều này có thể đúng, nhưng không phải là sự thật Sẽ hữu ích cho bạn biết rằng tất cả thời gian được dành ra khỏi tầm kiểm soát của bạn trên FPU.

Tôi đề nghị sử dụng một thư viện toán học vectơ tốt làm cơ sở (ví dụ VML của Intel, một phần của MKL). Đo số lượng chu kỳ cho mỗi cuộc gọi và nhân với số lần đạt cực đại có thể đạt được trên số chu kỳ đó. Vì vậy, nếu một số mũ đóng gói mất 50 chu kỳ để đánh giá, hãy tính nó bằng 100 lần nhân với chiều rộng của thanh ghi. Thật không may, các thư viện toán học vectơ đôi khi rất khó gọi và không có tất cả các hàm đặc biệt, vì vậy bạn có thể sẽ làm toán vô hướng, trong trường hợp đó bạn sẽ tính số mũ vô hướng giả định của chúng tôi là 100 flops (mặc dù có thể nó vẫn mất 50 theo chu kỳ, do đó bạn sẽ chỉ nhận được 25% "đỉnh" nếu dành toàn bộ thời gian để đánh giá các số mũ này).

Như những người khác đã đề cập, bạn có thể đếm chu kỳ và bộ đếm sự kiện phần cứng bằng PAPI hoặc các giao diện khác nhau. Để đếm chu kỳ đơn giản, bạn có thể đọc bộ đếm chu kỳ trực tiếp bằng cách sử dụng rdtschướng dẫn với một đoạn lắp ráp nội tuyến.


7

Bạn có thể đếm chúng trên các hệ thống thực bằng PAPI , cho phép truy cập vào bộ đếm phần cứng và các chương trình thử nghiệm đơn giản. Giao diện / trình bao bọc PAPI yêu thích của tôi là IPM (Trình theo dõi hiệu suất tích hợp) nhưng các giải pháp khác tồn tại ( ví dụ TAU ). Điều này sẽ cung cấp một so sánh phương pháp-phương pháp khá ổn định.


4

Tôi sẽ trả lời câu hỏi này như thể bạn hỏi:

"Làm thế nào để tôi phân tích so sánh hoặc dự đoán hiệu suất của các thuật toán phụ thuộc nhiều vào các hàm đặc biệt, thay vì số FLOP đa nhân mang thêm truyền thống đến từ đại số tuyến tính số"

Tôi đồng ý với tiền đề đầu tiên của bạn, rằng hiệu suất của nhiều chức năng đặc biệt phụ thuộc vào kiến ​​trúc và mặc dù bạn thường có thể coi mỗi chức năng này là có chi phí không đổi, kích thước của hằng số sẽ khác nhau, thậm chí giữa hai bộ xử lý từ cùng một công ty nhưng với các kiến ​​trúc khác nhau (xem bảng thời gian hướng dẫn của Agner Fog để tham khảo).

Tuy nhiên, tôi không đồng ý rằng trọng tâm của việc so sánh nên tập trung vào chi phí của các hoạt động điểm nổi riêng lẻ. Tôi nghĩ rằng việc đếm FLOP ở một mức độ nào đó vẫn hữu ích, nhưng có một số cân nhắc quan trọng hơn nhiều có thể làm cho chi phí của các hàm đặc biệt ít liên quan hơn khi so sánh hai thuật toán tiềm năng và chúng nên được kiểm tra rõ ràng trước khi đi đến so sánh hoạt động điểm nổi:

  1. Khả năng mở rộng - Các thuật toán có các nhiệm vụ có thể được thực hiện hiệu quả trên các kiến ​​trúc song song sẽ thống trị lĩnh vực điện toán khoa học trong tương lai gần. Một thuật toán có "khả năng mở rộng" tốt hơn, thông qua giao tiếp thấp hơn, ít cần đồng bộ hóa hơn hoặc cân bằng tải tự nhiên tốt hơn, có thể sử dụng các hàm đặc biệt chậm hơn và do đó chậm hơn đối với số lượng nhỏ các quy trình, nhưng cuối cùng sẽ bắt kịp như số của bộ xử lý được tăng lên.

  2. Địa phương tham chiếu tạm thời - Thuật toán có sử dụng lại dữ liệu giữa các tác vụ, cho phép bộ xử lý tránh lưu lượng bộ nhớ không cần thiết không? Mỗi cấp độ của hệ thống phân cấp bộ nhớ mà thuật toán đi qua sẽ thêm một mức chi phí cường độ khác (khoảng) cho mỗi lần truy cập bộ nhớ. Kết quả là, một thuật toán có mật độ hoạt động đặc biệt cao có thể sẽ nhanh hơn đáng kể so với thuật toán có số lượng hoạt động chức năng đơn giản tương đương trên một vùng bộ nhớ lớn hơn.

  3. Dấu chân bộ nhớ - Điều này liên quan mật thiết đến các điểm trước đó, nhưng khi máy tính phát triển ngày càng lớn hơn, lượng bộ nhớ trên mỗi lõi thực sự có xu hướng giảm. Có hai lợi ích cho một dấu chân bộ nhớ nhỏ. Đầu tiên là một lượng nhỏ dữ liệu chương trình có thể sẽ phù hợp hoàn toàn trong bộ đệm của bộ xử lý. Thứ hai là, đối với các vấn đề rất lớn, một thuật toán có dung lượng bộ nhớ nhỏ hơn có thể phù hợp với bộ nhớ của bộ xử lý, cho phép giải quyết các vấn đề vượt quá khả năng của máy tính.


Tôi sẽ tuyên bố rằng việc biết FLOPS / giây cho phép bạn phân tách chế độ tắc nghẽn nào (bộ nhớ, giao tiếp) mà bạn đang làm khá tốt. Ví dụ, hãy xem xét các phương pháp Newton-Krylov, chúng dành rất nhiều thời gian để làm matvec. Matvec thực hiện FLOP hoặc hai cho mỗi mục nhập ma trận và đó là nó. Máy làm mịn không lắp ráp có tiềm năng để làm tốt hơn. Jed và tôi cũng đã nói về điều này, và một khái niệm khác là xem bạn đã chi bao nhiêu chu kỳ trong tính toán ràng buộc FLOP. Tuy nhiên, điều này có thể yêu cầu giám sát khá chi tiết và tổng FLOPS / giây có thể thực tế hơn.
Peterangu

Aron, hầu hết câu trả lời này dường như phá vỡ câu hỏi của Peter để trả lời câu hỏi khác này: scicomp.stackexchange.com/questions/114
Jed Brown

@JedBrown, tôi đồng ý, cảm ơn vì đã dành thời gian để đưa ra một câu trả lời chắc chắn hơn nhiều.
Aron Ahmadia

0

Tại sao phải đếm flops? Chỉ cần đếm chu kỳ cho mọi hoạt động và bạn sẽ có một cái gì đó là phổ quát.

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.