2011-09-18 28 views
13

Dire che ho alcune funzioni, ciascuna di circa due semplici righe di codice e si chiamano in questo modo: A chiamate B chiamate C chiamate D ... chiamate K. (Quindi in pratica si tratta di una lunga serie di brevi chiamate di funzione). Quanto saranno profondi i compilatori di solito nella struttura delle chiamate per integrare queste funzioni?Quanto sono profonde le funzioni inline dei compilatori?

+0

Si potrebbe semplicemente testare e guardare l'assemblea! I tuoi documenti del compilatore dovrebbero dirti come specificare la profondità di allineamento; Penso che sia qualcosa come 50 per GCC di default. –

+2

Credo che questo dovrebbe essere specifico del compilatore e non pubblichi alcuna informazione sul tuo compilatore. –

+1

Sotto MSVC si ha il controllo parziale su questo usando '#pragma inline_depth' (http://msdn.microsoft.com/en-us/library/cx053bca.aspx) sebbene abbia avuto problemi con esso in determinate situazioni (come ad esempio ricorsivo inlining, che è pensato per essere possibile, ma non ha mai funzionato, ha finito per farlo manualmente) – Necrolis

risposta

12

La domanda non è significativa.

Se ci pensate inline, e le sue conseguenze, vi renderete conto che:

  • Evita una chiamata di funzione (con tutta la regolazione registro risparmio/telaio)
  • espone più contesto per l'ottimizzatore (negozi morti, codice morto, comune elimintation sub-espressione ...)
  • codice duplicati (gonfiore della cache istruzioni e la dimensione dell'eseguibile, tra le altre cose)

Quando decidere sia in linea che no, il compilatore esegue quindi un bilanciamento tra il potenziale rigonfiamento creato e il guadagno di velocità previsto. Questo atto di bilanciamento è influenzato dalle opzioni: per gcc -O3 significa ottimizzare per la velocità mentre -Oz significa ottimizzare per la dimensione, in linea hanno comportamenti quasi opposti!

Pertanto, ciò che importa non è il "livello di nidificazione", è il numero di istruzioni (eventualmente ponderato in quanto non tutte sono create uguali).

Ciò significa che una semplice funzione di inoltro:

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

è essenzialmente "trasparente" dal punto di vista inlining.

D'altra parte, è improbabile che una funzione che conta un centinaio di righe di codice venga attivata. Tranne che le funzioni gratuite static chiamate solo una volta sono quasi sistematicamente in linea, in quanto non crea alcuna duplicazione in questo caso.

Da questi due esempi che ottenere la sensazione di come le euristiche si comportano:

  • meno le istruzioni della funzione hanno, meglio è per inling
  • meno spesso viene chiamato, meglio è per inlining

Dopo di che, sono parametri si dovrebbe essere in grado di impostare di influenzare un modo o nell'altro (MSVC come __force_inline che allude fortemente alla inling, gcc quanto -finline-limit bandiera per "sollevare" il tresh vecchio sul conteggio di istruzioni, ecc ...)


per la tangente: ne sai di parziale inlining?

È stato introdotto in gcc in 4.6. L'idea, come suggerisce il nome, è di integrare parzialmente una funzione. Principalmente, per evitare il sovraccarico di una chiamata di funzione quando la funzione è "sorvegliata" e può (in alcuni casi) tornare quasi immediatamente.

Ad esempio:

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 
} 

potrebbe ottenere "ottimizzato", come:

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

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

Naturalmente, ancora una volta le euristiche per inlining si applicano, ma applicare più discriminately!


E, infine, a meno che non si utilizza WPO (intero programma di ottimizzazione) o LTO (Link Tempo Optimization), le funzioni possono essere inline solo se la loro definizione è nello stesso TU (unità di traduzione) che il sito di chiamata.

+0

In genere non lo faccio, ma penso che dovrei cambiare la risposta accettata. :) Non conoscevo la funzione di inlining parziale né di inlining in base al numero di chiamate. Grazie per i dettagli. –

7

Ho visto i compilatori inline più di 5 funzioni in profondità. Ma a un certo punto, diventa fondamentalmente un compromesso spazio-efficienza che il compilatore fa. Ogni compilatore è diverso in questo aspetto. Visual Studio è molto conservativo con inlining. GCC (sotto -O3) e l'Intel Compiler amano in linea ...

+0

IIRC in gcc dipende da un approssimativo "conteggio delle istruzioni" per la funzione che è in linea (ovvero quanto tempo è effettivamente); il livello di nidificazione non gioca un ruolo da quello che ho letto nei documenti ('-finline-limit' e amici), nel senso che la funzione della lunghezza 10 sarà in linea proprio come 5 + nidificata 5. – eudoxos

+1

Se le funzioni sono chiamate solo una volta non c'è motivo di evitare la linea. GCC sarà anche in linea in modo aggressivo se il feedback del profilo dice che dovrebbe. –

+3

@Zan Lynx: Questo è per lo più corretto. Ci sono alcuni casi, dove è meglio non in linea. Se la funzione si trova in un ciclo critico delle prestazioni e viene chiamata raramente (come un gestore trap), è meglio non in linea, in modo da mantenere le dimensioni del codice del ciclo ridotte. (questo a volte ti permette di usare salti corti invece di salti lunghi) – Mysticial

Problemi correlati