2011-09-18 32 views
13

Giả sử tôi có một số chức năng, mỗi trong khoảng hai dòng mã đơn giản và chúng gọi nhau như sau: A gọi B gọi C gọi D ... gọi K. (Vì vậy, về cơ bản nó là một chuỗi dài các cuộc gọi hàm ngắn.) Làm thế nào sâu trình biên dịch thường đi trong cây gọi để nội tuyến các chức năng này?Hàm biên dịch nội tuyến sâu bao nhiêu?

+0

Bạn chỉ cần kiểm tra và xem hội đồng! Tài liệu trình biên dịch của bạn nên cho bạn biết cách xác định độ sâu nội tuyến; Tôi nghĩ rằng nó là một cái gì đó giống như 50 cho GCC theo mặc định. –

+2

Tôi tin rằng điều này nên được trình biên dịch cụ thể và bạn đăng không có thông tin của trình biên dịch của bạn. –

+1

Theo MSVC bạn có một phần kiểm soát điều này bằng cách sử dụng '#pragma inline_depth' (http://msdn.microsoft.com/en-us/library/cx053bca.aspx) mặc dù tôi đã gặp vấn đề với nó trong một số tình huống (chẳng hạn như đệ quy inlining, có nghĩa là có thể, nhưng không bao giờ làm việc, kết thúc bằng cách thực hiện thủ công) – Necrolis

Trả lời

12

Câu hỏi này không có ý nghĩa.

Nếu bạn nghĩ về nội tuyến, và hậu quả của nó, bạn sẽ nhận ra nó:

  • Tránh một cuộc gọi chức năng (với tất cả các điều chỉnh đăng ký tiết kiệm/khung)
  • phơi bày bối cảnh nhiều hơn cho tôi ưu (cửa hàng chết, mã chết, phổ biến tiểu biểu elimintation ...)
  • Bản sao mã (đầy hơi instruction cache và kích thước thực thi, trong số những thứ khác)

Khi quyết định cho dù nội tuyến hay không, trình biên dịch do đó thực hiện một hành động cân bằng giữa các bloat tiềm năng tạo ra và đạt được tốc độ. Hành động cân bằng này bị ảnh hưởng bởi các tùy chọn: đối với gcc -O3 có nghĩa là tối ưu hóa tốc độ trong khi -Oz có nghĩa là tối ưu hóa kích thước, trên nội tuyến chúng có các hành vi trái ngược nhau!

Do đó, điều quan trọng không phải là "cấp độ làm tổ", đó là số lượng lệnh (có thể được tính là không phải tất cả đều được tạo bằng nhau).

này có nghĩa là một chức năng chuyển tiếp đơn giản:

int foo(int a, int b) { return foo(a, b, 3); } 

là về cơ bản "trong suốt" từ quan điểm nội tuyến xem.

Mặt khác, một chức năng đếm hàng trăm dòng mã không chắc sẽ được gạch chân. Ngoại trừ một hàm static miễn phí chỉ được gọi một lần được sắp xếp một cách có hệ thống, vì nó không tạo ra bất kỳ sự trùng lặp nào trong trường hợp này.

Từ hai ví dụ này, chúng ta có được một linh cảm về cách chẩn đoán xử:

  • các hướng dẫn ít chức năng có, thì càng tốt cho inling
  • ít thường nó được gọi, thì càng tốt cho nội tuyến

Sau đó, họ là những thông số bạn sẽ có thể thiết lập để ảnh hưởng một cách này hay cách khác (MSVC như __force_inline mà gợi ý mạnh mẽ tại inling, gcc khi họ -finline-limit cờ để "nâng cao" các tresh cũ vào số lượng hướng dẫn, vv ...)


Trên một tiếp tuyến: Bạn có biết về phần nội tuyến?

Nó được giới thiệu trong gcc trong 4.6. Ý tưởng, như tên cho thấy, là một phần nội tuyến một chức năng. Chủ yếu là, để tránh các chi phí của một cuộc gọi chức năng khi chức năng được "bảo vệ" và có thể (trong một số trường hợp) trở lại gần như ngay lập tức.

Ví dụ:

void foo(Bar* x) { 
    if (not x) { return; } // null pointer, pfff! 

    // ... BIG BLOC OF STATEMENTS ... 
} 

void bar(Bar* x) { 
    // DO 1 
    foo(x); 
    // DO 2 
} 

có thể nhận được "tối ưu hóa" như:

void [email protected](Bar* x) { 
    // ... BIG BLOC OF STATEMENTS ... 
} 

void bar(Bar* x) { 
    // DO 1 
    if (x) { [email protected](x); } 
    // DO 2 
} 

Tất nhiên, một lần nữa các công nghệ tự động cho nội tuyến được áp dụng, nhưng họ áp dụng đối xử phân biệt nhiều hơn nữa!


Và cuối cùng, trừ khi bạn sử dụng WPO (Whole Tối ưu hóa chương trình) hoặc LTO (Link Time Optimization), chức năng chỉ có thể được inlined nếu định nghĩa của họ là trong cùng TU (Dịch Unit) rằng trang web của cuộc gọi.

+0

Tôi không thường làm điều này, nhưng tôi nghĩ tôi nên thay đổi câu trả lời được chấp nhận. :) Tôi không biết về nội tuyến một phần và không phải về nội tuyến dựa trên số lượng cuộc gọi. Cảm ơn các chi tiết. –

7

Tôi đã thấy các trình biên dịch nội tuyến sâu hơn 5 hàm. Nhưng tại một số điểm, về cơ bản nó trở thành một thương mại không gian hiệu quả mà trình biên dịch tạo ra. Mỗi trình biên dịch là khác nhau trong khía cạnh này. Visual Studio rất bảo thủ với nội tuyến. GCC (dưới -O3) và Trình biên dịch Intel thích nội tuyến ...

+0

IIRC trong gcc nó phụ thuộc vào một số "chỉ số" gần đúng cho hàm được inlined (tức là nó thực sự là bao lâu); mức lồng nhau không đóng vai trò gì từ những gì tôi đọc trong tài liệu ('giới hạn -finline' và bạn bè), theo nghĩa là độ dài 10 sẽ được inline giống như 5 + lồng nhau 5. – eudoxos

+1

Nếu các hàm được gọi chỉ một lần không có lý do gì để tránh nội tuyến. GCC cũng sẽ rất tích cực nếu phản hồi hồ sơ cho biết. –

+3

@Zan Lynx: Đó là chủ yếu là chính xác. Có một số trường hợp, nơi tốt hơn là không nội tuyến. Nếu hàm nằm trong một vòng lặp hiệu năng quan trọng và hiếm khi được gọi (giống như một trình xử lý bẫy), thì tốt hơn là không inline nó để giữ cho kích thước mã của vòng lặp nhỏ. (điều này đôi khi sẽ cho phép bạn sử dụng các bước nhảy ngắn thay vì nhảy dài) – Mysticial

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