Như đã lưu ý trong các nhận xét, không chính xác khi tuyên bố "vụ mùa hiện tại của trình biên dịch (Bigloo, SBCL, Gambit, Chicken, v.v.) chậm hơn 20-50 lần so với mã C tương đương", mà không đủ điều kiện bạn đã kiểm tra và những gì bạn đã kiểm tra bạn đã thử nghiệm
Đối với việc sử dụng của tôi , tôi thấy rằng đối với nhiều thứ, Gambit và Chicken Scheme khá gần với mã 'C' tương đương về tốc độ, với phiên bản hiện tại của Gambit (4.7.3) thường nhanh hơn Gà (4.9.0.1) nhưng hơn trước tối ưu hóamã 'C' đầu ra (đưa ra các giả định về số lượng thanh ghi có sẵn - giả sử x686 - và buộc sử dụng bộ nhớ ngăn xếp cho bất kỳ yêu cầu bộ nhớ bổ sung nào, mà các quyết định nên để lại cho trình biên dịch 'C' như Chicken, thường loại bỏ yêu cầu về các thanh ghi bổ sung và kết hợp các bước xử lý) để ngăn trình biên dịch 'C' tự tối ưu hóa dẫn đến các vòng lặp rất nhỏ bị chậm đến khoảng hai lần so với các vòng lặp nhỏ chặt chẽ đó trong 'C' (hoặc Gà ); Chicken chỉ định nghĩa nhiều biến cục bộ cho một hàm nhất định khi nó thấy phù hợp (chủ yếu được sử dụng một cách bất biến) và sau đó phụ thuộc vào trình biên dịch để tối ưu hóa hầu hết các biến đó. Gà không '
EDIT_ADD: Tôi đã thực hiện một số nghiên cứu thêm về các phiên bản Lược đồ Gà và Gambit-C và đã tìm thấy như sau:
Gà nhanh hơn Gambit cho các vòng lặp nhỏ hẹp vì lý do trên (phụ thuộc nhiều hơn vào trình biên dịch 'C' để tối ưu hóa mà không cần thực hiện nhiều và do đó tận dụng tốt hơn các thanh ghi phụ x86-64), nhưng cũng vì nó không bao gồm kiểm tra bảo trì ngăn xếp "POLL" bên trong các vòng lặp, trong khi Gambit bao gồm kiểm tra "POLL" bên trong vòng lặp. Ngay cả khi điều này không được kích hoạt (trường hợp thông thường), sẽ mất vài chu kỳ xung nhịp CPU để xác định rằng không có gì là bắt buộc (khoảng 6 chu kỳ). Một trình biên dịch thông minh hơn trong tương lai có thể thấy rằng không cần thực hiện kiểm tra ngăn xếp khi bên trong một vòng lặp chặt chẽ và không thực hiện các hoạt động xây dựng ngăn xếp, thực hiện ngay trước hoặc sau vòng lặp và tiết kiệm thời gian này.
Macro 'G' của Gambit làm quá nhiều việc, như đã nói, trong việc xác định chính xác cách thức các hoạt động nên được thực hiện, đặc biệt là bao gồm các hoạt động kích thước ngăn xếp cố định và những trình biên dịch 'C' khó có thể tối ưu hóa hơn; sử dụng các thanh ghi hiệu quả hơn có thể giảm thời gian vòng lặp chặt chẽ có lẽ bằng 4 chu kỳ, kết hợp với những điều trên sẽ đưa nó vào sân bóng gà.
Không tối ưu hóa "đọc / sửa đổi / ghi" đầu ra cho các hoạt động vectơ được sửa đổi tại chỗ và không xuất mã để trình biên dịch thực hiện. Một phụ trợ thông minh hơn như LLVM khi được sử dụng với Haskell thực hiện loại điều này. Điều này sẽ làm giảm việc sử dụng một thanh ghi và thời gian thực hiện chỉ bằng một lệnh duy nhất thay vì đọc riêng, tính toán sửa đổi và ghi vào cùng một vị trí; điều này sẽ trở thành một phép tính sửa đổi (nói một chút hoặc), và sau đó đọc một sửa đổi (| =) viết một lệnh. Điều này có thể làm cho tốc độ nhanh hơn theo chu kỳ hoặc hơn
Cả hai đều được gõ động và xử lý các bit "thẻ" dữ liệu như là một phần của dữ liệu của chúng. Không đủ thông minh cho các vòng lặp chặt chẽ để giảm các thẻ, thực hiện vòng lặp "không có thẻ", sau đó thêm các thẻ trở lại cho bất kỳ kết quả nào từ vòng lặp, cũng không tạo ra mã mà trình biên dịch 'C' có thể thấy để làm điều này mặc dù nó kết hợp các hoạt động này cho một số trường hợp. Tối ưu hóa ở đây có thể giảm thời gian vòng lặp bằng một vài chu kỳ CPU hoặc hơn, tùy thuộc vào vòng lặp.
Các vòng lặp 'C' rất chặt chẽ có thể mất khoảng 3,5 chu kỳ xung nhịp CPU trên mỗi vòng lặp trên CPU nhanh không phải là bộ nhớ tốc độ truy cập bộ nhớ cache (như AMD Bulldozer, tốc độ chậm gấp đôi); vòng lặp tương tự trong Gà hiện mất khoảng 6 chu kỳ và Gambit mất khoảng 16,9 chu kỳ. Với tất cả các tối ưu hóa theo quy định ở trên, không có lý do gì mà các triển khai Đề án này không thể làm được điều đó, tuy nhiên một số công việc được yêu cầu:
Trong trường hợp của Gambit, công việc khó hơn có thể là cải thiện phân tích dòng chảy để nhận ra khi không cần kiểm tra "POLL" (nghĩa là điều này có thể bị gián đoạn, mặc dù trình biên dịch không cho phép ngắt để sử dụng? ); cải tiến dễ dàng hơn là chỉ thực hiện việc sử dụng thanh ghi tốt hơn (ví dụ: nhận ra các thanh ghi x86-64 tốt hơn là kiến trúc x686 mặc định). Đối với cả hai, phân tích luồng tốt hơn để nhận ra rằng họ có thể "gỡ" dữ liệu, đặc biệt là "fixnum", "flonum" và vector, dữ liệu để các thao tác này không cần thiết trong các vòng lặp chặt chẽ và kết hợp các hướng dẫn đọc / sửa đổi / ghi. Cả hai kết thúc này có thể được thực hiện bằng cách sử dụng một phụ trợ tốt hơn như LLVM (không phải là một lượng công việc không đáng kể, nhưng cả hai đều đã có một phần ở đó).
Kết luận: Gà hiện chậm hơn khoảng 50% so với 'C' trên CPU nhanh nhất (không phải là Bulldozer của tôi, với tốc độ tương đương do điều chỉnh bộ đệm của mã 'C') và Gambit chậm hơn khoảng 400% (chỉ khoảng Chậm hơn 125% trên chiếc Bulldozer chậm của tôi). Tuy nhiên, các cải tiến trong tương lai của trình biên dịch có thể làm giảm điều này để một trong hai mã không chậm hơn 'C' hoặc trong phạm vi mà OP chỉ định.
Một ngôn ngữ phức tạp hơn như Haskell, khi sử dụng phụ trợ LLVM, chú ý cẩn thận đến việc sử dụng nghiêm ngặt (không phải là vấn đề với lược đồ luôn luôn háo hức theo mặc định) và sử dụng các cấu trúc dữ liệu phù hợp (mảng ST không được đóng hộp thay vì liệt kê các vòng lặp chặt chẽ; phần nào có thể áp dụng cho Lược đồ sử dụng vectơ), chạy ở tốc độ tương đương với 'C' nếu phần phụ trợ LLVM được sử dụng với tối ưu hóa đầy đủ. Nếu nó có thể làm điều này, thì Scheme cũng có thể cải tiến trình biên dịch ở trên.
LẠI, không có cách nào mà một trong hai điều này chậm hơn 20 đến 50 lần khi được sử dụng với các cờ tối ưu hóa phù hợp. END_EDIT_ADD
Tất nhiên, tất cả các điểm chuẩn đều không hợp lệ nếu một người không sử dụng các cài đặt tối ưu hóa phù hợp cho từng người trong môi trường sản xuất ...
Tôi nghĩ rằng trình biên dịch thương mại Chez Scheme sẽ ở trong sân bóng để tạo ra hiệu suất cao như Gambit và Chicken, vì là thương mại, nó chắc chắn có một số "thời gian và tiền bạc nghiêm túc đầu tư vào nó".
Cách duy nhất tôi có thể khiến Gambit hoặc Chicken chạy chậm như "chậm hơn 20 đến 50 lần so với 'C'" là không sử dụng bất kỳ cài đặt tối ưu hóa nào, trong trường hợp chúng thường không chạy nhanh hơn nhiều so với giải thích trong REPL của chúng - Chậm hơn 10 lần so với sử dụng đúng các cài đặt đó.
Có thể OP đã không kiểm tra bằng cách sử dụng các cài đặt này đúng cách?
Nếu OP quan tâm làm rõ các quy trình thử nghiệm của mình, tôi sẽ sẵn sàng chỉnh sửa câu trả lời này để cho thấy rằng ít nhất Gambit và Gà không cần phải chậm như vậy.
(declare (optimize ...))
,(declare (<type> <var))
và(the <type> <expr>)
trong các chức năng của bạn? Nếu không, đó không phải là một so sánh công bằng :)