Là phân tích thuật toán bằng cách đếm flop lỗi thời?


43

Trong các khóa học phân tích số của mình, tôi đã học cách phân tích hiệu quả của các thuật toán bằng cách đếm số lượng các phép toán dấu phẩy động (flops) mà chúng yêu cầu, liên quan đến kích thước của vấn đề. Ví dụ, trong văn bản của Trefethen & Bau về Đại số tuyến tính số, thậm chí có những hình ảnh trông giống 3D của số đếm flop.

Bây giờ thật thời trang để nói rằng "flop là miễn phí" bởi vì độ trễ bộ nhớ để tìm nạp bất cứ thứ gì không có trong bộ nhớ cache lớn hơn nhiều so với chi phí của một flop. Nhưng chúng tôi vẫn đang dạy sinh viên đếm flops, ít nhất là trong các khóa học phân tích số. Thay vào đó chúng ta có nên dạy họ đếm số lượt truy cập bộ nhớ không? Chúng ta có cần viết sách giáo khoa mới không? Hoặc là truy cập bộ nhớ quá cụ thể để dành thời gian trên? Xu hướng dài hạn sẽ là gì về việc liệu flops hoặc truy cập bộ nhớ là nút cổ chai?

Lưu ý: một số câu trả lời dưới đây dường như đang trả lời một câu hỏi khác như "Tôi có nên viết lại một cách ám ảnh việc thực hiện của mình để lưu một vài flops hoặc cải thiện hiệu suất bộ đệm không?" Nhưng những gì tôi đang hỏi là nhiều hơn theo dòng " Có hữu ích hơn khi ước tính độ phức tạp thuật toán về mặt hoạt động số học hoặc truy cập bộ nhớ không?"


1
> "Có hữu ích hơn khi ước tính độ phức tạp thuật toán về các hoạt động số học hoặc truy cập bộ nhớ không?" . Từ quan điểm thực tế, các hệ thống nhúng vẫn bị giới hạn bởi tốc độ FPU thay vì băng thông bộ nhớ. Do đó, ngay cả khi việc đếm flops được coi là lỗi thời bởi các tiêu chuẩn HPC, nó vẫn được sử dụng thực tế cho các cộng đồng khác.
Damien

Câu trả lời:


31

Tôi nghĩ rằng điều đúng (thứ tự đầu tiên) cần làm là xem xét tỷ lệ flop so với byte cần thiết trong thuật toán, mà tôi gọi là . Đặt là tốc độ flop tối đa của bộ xử lý và băng thông tối đa. Nếu , thì thuật toán sẽ bị giới hạn băng thông. Nếu , thuật toán bị giới hạn.F m một x B m một x F m một xβFmaxBmaxBmmộtxβ>FmmộtxFmaxβ>BmaxBmaxβ>Fmax

Tôi nghĩ rằng việc truy cập bộ nhớ là bắt buộc, nhưng chúng ta cũng nên suy nghĩ về:

  • Cần bao nhiêu bộ nhớ cục bộ

  • Chúng ta có bao nhiêu đồng thời

Sau đó, bạn có thể bắt đầu phân tích các thuật toán cho phần cứng hiện đại.


3
Tôi đồng ý với Matt, nhưng tôi muốn chỉ ra rằng hiện được tìm thấy một cách hợp lý được định nghĩa trong tài liệu là "cường độ số học" và "cường độ số". Tôi nghĩ rằng mô hình mái nhà của Williams, Waterman và Patterson có lẽ là một khởi đầu tốt để suy nghĩ về những vấn đề này. Tôi nghĩ rằng điều này nên được mở rộng theo tỷ lệ truy cập bộ nhớ / flop của thuật toán theo thời gian. β
Aron Ahmadia

2
David làm hơn 8 năm trước.
Matt Knepley

3
Được rồi, do đó, có một mô hình tốt hơn, phức tạp hơn (như mọi khi). Nhưng mô hình này đưa ra một câu trả lời phụ thuộc vào máy móc. Những gì chúng ta nên dạy học sinh sử dụng như là một phân tích đầu tiên?
David Ketcheson

3
Điểm đáng chú ý là máy đã được giảm xuống một con số duy nhất, tỷ lệ flops đỉnh với băng thông cực đại, cũng như thuật toán. Điều này là đơn giản như nó được. Không có một mô hình tính toán, bất kỳ ước tính phức tạp nào cũng vô dụng và đây là mô hình thực tế đơn giản nhất.
Matt Knepley

1
Tôi nghĩ rằng bạn hiểu sai vấn đề. Chúng tôi đã có vận chuyển quang có thể mang tải lớn. Vấn đề là nhận được điều đó trên một con chip. Bạn chỉ có rất nhiều dây và tốc độ đồng hồ hàng đầu. Vận chuyển quang sẽ chỉ làm giảm bớt vấn đề này trên một chip quang.
Matt Knepley

22

Tôi không thấy lý do tại sao một người phải là "người chiến thắng"; đây không phải là một trò chơi có tổng bằng không, trong đó số lượng flop và truy cập bộ nhớ phải nhấn chìm người khác. Bạn có thể dạy cả hai, và tôi nghĩ rằng cả hai đều có công dụng của chúng. Xét cho cùng, thật khó để nói rằng thuật toán với các truy cập bộ nhớ nhất thiết phải nhanh hơn thuật toán với các truy cập . Tất cả phụ thuộc vào chi phí tương đối của các phần khác nhau (tiền tố pesky mà chúng tôi luôn bỏ qua trong các phân tích này!).O ( N ) O ( N log N ) O ( N 2 )O(N4)O(N)O(NlogN)O(N2)

Từ góc độ rộng hơn, tôi nghĩ rằng việc phân tích hiệu suất thuật toán nên "bao gồm tất cả". Nếu chúng ta dạy mọi người trở thành nhà phát triển và người dùng HPC thực tế, thì họ cần hiểu chi phí lập trình trong thế giới thực là gì. Các mô hình phân tích trừu tượng mà chúng ta không tính đến thời gian của lập trình viên. Chúng ta nên suy nghĩ về "tổng thời gian để giải quyết", thay vì chỉ đếm số lượng và hiệu quả thuật toán. Sẽ không có ý nghĩa gì khi dành ba hoặc bốn ngày lập trình viên để viết lại một thói quen sẽ tiết kiệm một giây thời gian trên máy tính cho mỗi công việc trừ khi bạn có kế hoạch chạy vài triệu phép tính. Tương tự, đầu tư một vài ngày để tiết kiệm một hoặc hai giờ tính toán nhanh chóng được đền đáp. Thuật toán mới lạ đó có thể là tuyệt vời,


7
Một thuật toán mà thực hiện truy cập dữ liệu? :)O ( N 2 )O(NlogN)O(N2)
Andreas Klöckner

2
Tại sao không? Nếu chỉ đề cập đến ops dấu phẩy động, thì có thể có thêm một số lượng ops nguyên đáng kể khiến dữ liệu truy cập :)O ( N 2 )O(NlogN)O(N2)
kini

9

Như những người khác đã chỉ ra, câu trả lời tất nhiên phụ thuộc vào việc nút cổ chai là CPU hay băng thông bộ nhớ. Đối với nhiều thuật toán hoạt động trên một số tập dữ liệu có kích thước tùy ý, nút cổ chai thường là băng thông bộ nhớ vì tập dữ liệu không vừa với bộ đệm CPU.

Hơn nữa, Knuth đề cập rằng phân tích truy cập bộ nhớ có nhiều khả năng đứng trước thử thách của thời gian, có lẽ vì nó tương đối đơn giản (ngay cả khi tính đến tính thân thiện với bộ đệm) so với sự phức tạp của các đường ống CPU hiện đại và dự đoán nhánh.

Knuth sử dụng thuật ngữ gigamem trong Tập 4A của TAOCP, khi phân tích các BDD. Tôi không chắc anh ta có sử dụng nó trong các tập trước không. Ông đã đưa ra nhận xét đã nói ở trên về việc đứng trước thử thách của thời gian trong Bài giảng Cây Giáng sinh hàng năm vào năm 2010.

Thật thú vị, Bạn đang làm sai cho thấy rằng ngay cả việc phân tích hiệu suất dựa trên các hoạt động của bộ nhớ không phải lúc nào cũng đơn giản vì có những yếu tố như áp lực VM xuất hiện nếu dữ liệu không phù hợp với RAM vật lý cùng một lúc.


8

Cách bạn xác định chi phí của một thuật toán phụ thuộc vào "mức độ" tính toán khoa học mà bạn làm việc và loại vấn đề (hẹp hay rộng) mà bạn xem xét.

Nếu bạn nghĩ về tối ưu hóa bộ đệm, điều này rõ ràng phù hợp hơn với, ví dụ, việc triển khai các gói đại số tuyến tính số như BLAS và các thư viện tương tự. Vì vậy, điều này thuộc về tối ưu hóa ở mức độ thấp và sẽ ổn nếu bạn có một thuật toán cố định cho một vấn đề cụ thể và có đủ các ràng buộc về đầu vào. Ví dụ, tối ưu hóa bộ đệm có thể có liên quan để thực hiện nhanh việc lặp lại độ dốc liên hợp nếu ma trận được hứa là đủ thưa thớt.

Mặt khác, lớp vấn đề càng rộng, bạn càng ít dự đoán về tính toán thực tế (như, bạn không biết các ma trận đầu vào của việc triển khai CG của bạn sẽ thực sự như thế nào). Lớp máy của chương trình của bạn được cho là chạy càng rộng, bạn càng ít dự đoán về kiến ​​trúc Cache.

Hơn nữa, ở mức độ cao hơn của máy tính khoa học, có thể phù hợp hơn để thay đổi cấu trúc vấn đề. Ví dụ, nếu bạn dành thời gian để tìm một điều kiện tiên quyết tốt cho một hệ phương trình tuyến tính, loại tối ưu hóa này thường đánh bại bất kỳ tối ưu hóa cấp thấp nào, bởi vì số lần lặp giảm đi đáng kể.

Trong conclusio, tối ưu hóa bộ đệm chỉ hữu ích nếu không còn gì để tối ưu hóa bằng cách song song và giảm số lượng FLOP không triệu chứng.

Tôi nghĩ thật khôn ngoan khi thích nghi với lập trường của khoa học máy tính lý thuyết: Cuối cùng, việc cải thiện độ phức tạp tiệm cận của một thuật toán có nhiều lợi nhuận hơn so với tối ưu hóa vi mô của một số dòng mã hiện có. Do đó, đếm FLOP vẫn được ưa thích hơn.


"Tối ưu hóa bộ đệm chỉ hữu ích nếu không còn gì để tối ưu hóa bằng cách song song và giảm số lượng FLOP không triệu chứng". Tôi không đồng ý. Nếu bạn muốn tính một biểu thức lớn của một bó số lớn, tốt hơn là thực hiện một bước tại một thời điểm với tất cả các số hơn tất cả các bước cho mỗi số. Cả hai đều có cùng số FLOPS, nhưng một cái tốt hơn trong việc truy cập bộ nhớ. Phần thưởng nếu bạn chọn kích thước của bó để phù hợp với bộ đệm (hoặc trình biên dịch sẽ làm điều đó cho bạn). Đây là những gì numexpr làm trong Python: github.com/pydata/numexpr
Davidmh

6

Tôi luôn từ chối thậm chí nghĩ về việc đếm flop, truy cập bộ nhớ hoặc bất cứ điều gì bạn có. Đó là một khái niệm từ những năm 1960 khi những gì bạn đã làm được đưa ra khá nhiều và chỉ có cách bạn làm nó là tối ưu hóa thuật toán. Hãy suy nghĩ giải một bài toán phần tử hữu hạn trên lưới xyz đồng nhất bằng cách sử dụng phép loại bỏ Gaussian của phép lặp Jacobi.

Bây giờ, bạn có thể tối ưu hóa điều này thành địa ngục và tiết kiệm một vài flops, đạt 10% thời gian chạy. Hoặc bạn có thể suy nghĩ về việc thực hiện một phương pháp đa biến và một điều kiện tiên quyết khối tối ưu, đạt được hệ số 10 trong thời gian chạy. Đây là những gì chúng ta nên đào tạo sinh viên của mình để làm - nghĩ về những thuật toán phức tạp, bên ngoài có thể giúp bạn vượt qua việc cố gắng tìm một thuật toán bên trong tốt hơn. Sếp của bạn (Keyes) có những slide về tiến trình tính toán MHD khiến cho điều này trở nên khá rõ ràng.


Thật ra tôi đã hỏi về kiểu tư duy cấp cao mà bạn đề xuất, không phải tối ưu hóa cấp thấp. Số liệu nào bạn nên sử dụng để xác định xem multigrid và điều kiện tiên quyết của bạn sẽ nhanh hơn các lựa chọn thay thế?
David Ketcheson

Tôi sẽ không biết cách đếm - bằng tay - FLOPS hoặc bất kỳ lệnh hướng dẫn nào khác cho các thuật toán phức tạp chạy trên hàng chục hoặc hàng nghìn dòng mã. Ví dụ, hãy nghĩ rằng giai đoạn phân tích và xây dựng của các thuật toán AMG phức tạp như thế nào. Có rất nhiều phần của các thuật toán này và tất cả các thuật toán này phụ thuộc vào dữ liệu thực tế mà bạn không thể dự đoán số lượng hoạt động.
Wolfgang Bangerth

1
Tôi nghĩ lúc đầu tôi đã hiểu nhầm những gì bạn đang nhận được, nhưng tôi vẫn không đồng ý với quan điểm của bạn. "Các thuật toán bên ngoài" có thể (và tôi sẽ tranh luận, nên) vẫn được thiết kế với sự phức tạp tiệm cận trong tâm trí. Chắc chắn bạn sẽ không cho rằng việc giảm từ thuật toán bậc hai sang thuật toán gần tuyến tính sẽ dẫn đến việc giảm 10% thời gian chạy; chưa, làm thế nào khác để định lượng độ phức tạp tiệm cận hơn thông qua flops và / hoặc op-memory?
Jack Poulson

7
Tôi nghĩ rằng cách tiếp cận "giơ tay lên" đối với các thuật toán là tào lao. Bạn cần đơn giản hóa việc phân tích bằng cách chỉ xem chi phí đơn hàng đầu tiên, và bằng cách đơn giản hóa mô hình sao cho dễ điều khiển, nhưng để nói rằng bạn không thể phân tích một cái gì đó như MG hoặc Cholesky vì nó quá phức tạp là sai hoàn toàn.
Matt Knepley

1
Chà, nhưng việc phân tích MG hay Cholesky có nghĩa là gì khi mỗi FLOP bạn đếm được ẩn sau một số lớp độ trễ gây ra bởi bộ xử lý siêu phân luồng, bộ nhớ cache, RAM chậm, bộ xử lý đa phương tiện và vector hóa tự động? Điểm tôi đang đưa ra là trong phạm vi 5-10, bạn không thể dự đoán thời gian chạy của thuật toán của mình nữa mà không tính thời gian. Điều đó hoàn toàn khác biệt vào những năm 50 và 60 khi mọi người bắt đầu đếm FLOP này.
Wolfgang Bangerth

1

Vâng, lỗi thời. Phân tích thuật toán bằng flops, hoặc bất kỳ phương pháp nào khác, chỉ hữu ích như mô hình trừu tượng của máy khi xem xét kích thước của vấn đề trong tay. Hiệu suất thực tế phụ thuộc cả vào việc triển khai và phần cứng, và khả năng ứng dụng của bất kỳ mô hình trừu tượng nào cho sau này vào thực tế đang giảm dần theo thời gian. Ví dụ, khi bạn tiếp tục song song hóa việc thực hiện một thuật toán phức tạp, như động lực phân tử, các khía cạnh khác nhau trở thành giới hạn tốc độ trên các phần cứng khác nhau và phân tích thuật toán không liên quan gì đến các quan sát. Theo một nghĩa nào đó, điều quan trọng duy nhất là đo lường hiệu suất của việc thực hiện (các) thuật toán trên (các) loại phần cứng được đề cập.

Là trừu tượng như vậy hữu ích như một công cụ học tập? Vâng, giống như nhiều mô hình được sử dụng cho giảng dạy, chúng rất hữu ích miễn là chúng được đặt bên cạnh sự hiểu biết về các hạn chế của mô hình. Cơ học cổ điển là tốt miễn là bạn đánh giá cao rằng nó sẽ không hoạt động trên quy mô khoảng cách nhỏ hoặc vận tốc lớn ...


-1

Không thực sự trả lời câu hỏi của bạn, nhưng thêm một biến khác để xem xét: một điều cần tính đến là các tính năng của ngôn ngữ lập trình. Ví dụ: Python sortsử dụng thuật toán Timsort , được thiết kế (trong số các thuộc tính tốt khác) để giảm thiểu số lượng so sánh, có thể có khả năng chậm đối với các đối tượng Python. Mặt khác, so sánh hai số float trong C ++ rất nhanh, nhưng việc hoán đổi chúng tốn kém hơn, vì vậy chúng sử dụng các thuật toán khác .

Các ví dụ khác là cấp phát bộ nhớ động (tầm thường trong danh sách Python, nhanh về cả thời gian chạy và thời gian dành cho nhà phát triển .append(), so với FORTRAN hoặc C, trong đó, dù có thể và nhanh hơn khi được thực hiện đúng cách, nó cần nhiều thời gian lập trình và bộ não hơn. Xem Python nhanh hơn FORTRAN.


Điều này đúng, nhưng, như bạn nói, không trả lời câu hỏi. Đó là về một chủ đề khác nhau.
David Ketcheson

Vâng, trong một phân tích thích hợp, đó là điều cần tính đến khi quyết định thực hiện thuật toán nào.
Davidmh
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.