2011-10-20 33 views
8

Tôi đã đọc một số bài viết và câu hỏi/câu trả lời kết luận thực hành tốt nhất là để trình biên dịch JIT thực hiện tất cả tối ưu hóa cho các cuộc gọi hàm nội tuyến. Có ý nghĩa.Trình biên dịch JIT có tối ưu hóa các biến khai báo không cần thiết (nội tuyến) không?

Còn các khai báo biến nội tuyến thì sao? Trình biên dịch có tối ưu hóa chúng không?

Nghĩa là, sẽ này:

 Dim h = (a + b + c)/2  'Half-Perimeter 

     If maxEdgeLength/(Math.Sqrt(h * (h - a) * (h - b) * (h - c))/h) <= MaximumTriangleAspectRatio Then 
      'Do stuff here. 
     End If 

có hiệu suất tốt hơn thế này:

 Dim perimeter = a + b + c 'Perimeter 
     Dim h = perimeter/2  'Half-Perimeter 

     Dim area = Math.Sqrt(h * (h - a) * (h - b) * (h - c)) 'Heron's forumula. 
     Dim inradius = area/h 
     Dim aspectRatio = maxEdgeLength/inradius 

     If aspectRatio <= MaximumTriangleAspectRatio Then 
      'Do stuff here. 
     End If 

Tất nhiên tôi thích sau này bởi vì nó dễ dàng hơn để đọc và sửa lỗi, nhưng tôi không thể đủ khả năng sự suy giảm hiệu suất nếu nó tồn tại.

Lưu ý: Tôi đã xác định mã này là nút cổ chai - Không cần phải trả lời về tối ưu hóa sớm. :-)

+6

Bạn không thể trả thêm 20 byte RAM?Điều này rất khó có thể thúc đẩy hiệu suất của ứng dụng của bạn, đặc biệt là nếu mã này được chạy lặp đi lặp lại, nó sẽ là 20 byte giống nhau mỗi lần. –

+0

Trình biên dịch (không phải là JIT!) Sẽ là "chịu trách nhiệm" đối với loại tối ưu hóa này trong khi dịch sang MSIL? (Và nếu như vậy, trình biên dịch MS C# tối ưu hóa ở mức độ nào) Trong mọi trường hợp, nó sẽ là một cách tương đối duy nhất. –

+4

Bạn là người duy nhất ở đây có thể trả lời câu hỏi. Bạn đã viết mã cả hai cách. Chạy cả hai cách, đo thời gian, và sau đó bạn sẽ biết cái nào nhanh hơn. Những gì jitter có hoặc không làm là không thích hợp; biết những gì jitter không có cách nào trả lời câu hỏi "cái nào nhanh hơn?" –

Trả lời

16

Biến tạm thời có tên hoặc không phải là sự cố.

Nhưng bạn có thể tối ưu hóa sự bất bình đẳng đó một cách đáng kể.

Mã của bạn là:

If maxEdgeLength/(Math.Sqrt(h * (h - a) * (h - b) * (h - c))/h) <= MaximumTriangleAspectRatio Then 

Multiply cả hai bên bởi căn bậc hai, loại bỏ sự phân chia (bất bình đẳng được bảo tồn, bởi vì căn bậc hai không thể trả lại một số âm):

If maxEdgeLength <= (Math.Sqrt(h * (h - a) * (h - b) * (h - c))/h) * MaximumTriangleAspectRatio Then 

Bây giờ, hình vuông cả hai bên để loại bỏ căn bậc hai đắt tiền đó:

If maxEdgeLength * maxEdgeLength <= h * (h - a) * (h - b) * (h - c)/h/h * MaximumTriangleAspectRatio * MaximumTriangleAspectRatio Then 

Hủy, và m tối đa h.

If maxEdgeLength * maxEdgeLength * h <= (h - a) * (h - b) * (h - c) * MaximumTriangleAspectRatio * MaximumTriangleAspectRatio Then 

Điều này sẽ nhanh hơn rất nhiều. Nếu tính toán này được lặp lại, hãy xem xét lưu vào bộ nhớ đệm các kết quả của một phần của biểu thức này để cải thiện hơn nữa.

Sử dụng nhận xét để giải thích công thức. Loại bỏ một cuộc gọi Math.Sqrt trong một chức năng nút cổ chai là giá trị bằng văn bản biểu thức trong một định dạng ít hơn-đơn giản.

+1

Thay vì (chỉ) sử dụng nhận xét, hãy tính toán lại thành một hàm độc lập - quá nhiều thời gian để xảy ra trong mã như vậy. Giải thích * rằng * chức năng khi cần thiết (đặc biệt, giải thích sự biến đổi được thực hiện ở trên…). –

+6

+1 để xác định rằng một tối ưu hóa có thể được tìm thấy không phải trong mã hoặc biên dịch, nhưng chính thuật toán. –

5

Bằng cách này, chỉ để chơi ủng hộ ma quỷ, tôi cũng muốn chỉ này ra:

JIT nội tuyến của toàn bộ chức năng nhìn vào độ dài, tính bằng byte của MSIL, và không phải là phức tạp của việc tính toán. Thêm biến cục bộ (và mong đợi JIT để đăng ký chúng) có thể làm tăng kích thước MSIL của hàm đủ để làm cho toàn bộ hàm không phải là một ứng cử viên cho nội tuyến.

Điều này không có khả năng tạo sự khác biệt lớn khi sử dụng không cần thiết Math.Sqrt, nhưng đó là khả năng. Như Eric Lippert đã nói, bạn sẽ biết nhiều hơn bằng cách thực sự đo lường. Tuy nhiên, một phép đo như vậy chỉ hợp lệ cho một lần chạy chương trình cụ thể và không tổng quát hóa các bộ xử lý khác nhau hoặc các phiên bản tương lai của thời gian chạy .NET (bao gồm các gói dịch vụ) thường chỉnh sửa hành vi JIT. Vì vậy, bạn muốn có một cách tiếp cận phân tích và thực nghiệm để tối ưu hóa.

+1

Bạn thực hiện một điểm tuyệt vời Ben; ngoại trừ trong các trường hợp tầm thường, thực sự không có thứ như "tối ưu hóa". Mỗi cái gọi là "tối ưu hóa" thực sự là một sự cân bằng mà chúng tôi * hy vọng * là tốt hơn, nhưng có thể không. Bạn giao dịch nhiều hơn đăng ký sử dụng trên tính toán này cho ít đăng ký có sẵn trên tính toán đó, và hy vọng rằng bạn chọn một trong những cần thiết để được nhanh hơn. Hoặc bạn giao dịch sử dụng bộ nhớ nhiều hơn trong thời gian ít hơn, và hy vọng rằng làm như vậy không gây ra một bộ nhớ cache bỏ lỡ sau này. Và cứ thế. –

+0

@EricLippert: Có, tối ưu hóa hoàn toàn liên quan đến sự cân bằng. Nhưng đó là bên cạnh những điểm tôi đang làm. Khi sử dụng trình biên dịch JIT, bạn phải tuân thủ các thuật toán tối ưu hóa đã thay đổi, điều này tạo ra sự cân bằng khác nhau cho cùng một đầu vào MSIL. Ngay cả với các trình biên dịch gốc AOT truyền thống, cùng một chuỗi lệnh có thể thực hiện khác nhau trên các bộ vi xử lý khác nhau với các đặc tính CPI khác nhau. –

Các vấn đề liên quan