2009-12-21 10 views
26

Esiste una ottimizzazione sostanziale quando si omette il puntatore del frame? Se ho capito correttamente leggendo la pagina this, è usato quando vogliamo evitare di salvare, impostare e ripristinare i puntatori di fotogramma.Quando dovrei omettere il puntatore del frame?

Questo è fatto solo per ogni chiamata di funzione e se sì, vale davvero la pena di evitare alcune istruzioni per ogni funzione? Non è banale per un'ottimizzazione. Quali sono le reali implicazioni dell'utilizzo di questa opzione oltre ai limiti di debug?

ho compilato il seguente codice C con e senza questa opzione

int main(void) 
{ 
     int i; 

     i = myf(1, 2); 
} 

int myf(int a, int b) 
{ 
     return a + b; 
} 

,

# gcc -S -fomit-frame-pointer code.c -o withoutfp.s 
# gcc -S code.c -o withfp.s 

.

diff -u 'ing i due file ha rivelato il seguente codice assembly:


--- withfp.s 2009-12-22 00:03:59.000000000 +0000 
+++ withoutfp.s 2009-12-22 00:04:17.000000000 +0000 
@@ -7,17 +7,14 @@ 
     leal 4(%esp), %ecx 
     andl $-16, %esp 
     pushl -4(%ecx) 
-  pushl %ebp 
-  movl %esp, %ebp 
     pushl %ecx 
-  subl $36, %esp 
+  subl $24, %esp 
     movl $2, 4(%esp) 
     movl $1, (%esp) 
     call myf 
-  movl %eax, -8(%ebp) 
-  addl $36, %esp 
+  movl %eax, 20(%esp) 
+  addl $24, %esp 
     popl %ecx 
-  popl %ebp 
     leal -4(%ecx), %esp 
     ret 
     .size main, .-main 
@@ -25,11 +22,8 @@ 
.globl myf 
     .type myf, @function 
myf: 
-  pushl %ebp 
-  movl %esp, %ebp 
-  movl 12(%ebp), %eax 
-  addl 8(%ebp), %eax 
-  popl %ebp 
+  movl 8(%esp), %eax 
+  addl 4(%esp), %eax 
     ret 
     .size myf, .-myf 
     .ident "GCC: (GNU) 4.2.1 20070719 

Qualcuno potrebbe far luce sulle chiave punti del codice di cui sopra in cui -fomit-frame-pointer ha in realtà fanno la differenza ?

Edit: 'uscita s sostituito con gcc -S' objdump s

+2

Provare nuovamente il diff compilando con -S. Confronta il linguaggio dell'assemblaggio: sarà molto più leggibile. –

+0

@Richard: fatto! Grazie per segnalarlo! – PetrosB

+0

Correlati, vedere [ARM: link register and frame pointer] (http://stackoverflow.com/q/15752188). – jww

risposta

24

permette un registro in più per essere disponibile per l'uso generico. Suppongo che questo sia davvero un grosso problema su x86 a 32 bit, un po 'affamato di registri. *

Ci si aspetterebbe di vedere EBP non più salvato e regolato su ogni chiamata di funzione, e probabilmente qualche uso aggiuntivo di EBP in codice normale e meno operazioni di stack in occasioni in cui EBP viene utilizzato come registro generico.

Il tuo codice è troppo semplice per vedere i vantaggi di questo tipo di ottimizzazione: non stai utilizzando abbastanza registri. Inoltre, non hai attivato l'ottimizzatore, che potrebbe essere necessario per vedere alcuni di questi effetti.

* Registri ISA, non registri di microarchitettura.

+0

Se devo impostare esplicitamente altre opzioni di ottimizzazione, qual è il significato di questa opzione separata? Il tuo punto di vista sul fatto che il mio codice sia semplice sembra comunque valido! – PetrosB

+0

Questa opzione è separata perché ha svantaggi significativi per il debug. –

+0

È separato perché ha implicazioni funzionali per altre cose, come l'esecuzione del codice in un debugger o il collegamento con altro codice. Presumo che vedresti una riduzione delle perdite di registro anche con l'ottimizzatore disattivato, ma dal momento che non so per certo, sto proteggendo le mie scommesse. –

9

L'unico lato negativo di ometterlo è che il debug è molto più difficile.

Il principale vantaggio è che esiste un registro generale extra che può fare una grande differenza sulle prestazioni. Ovviamente questo registro extra viene utilizzato solo quando necessario (probabilmente nella tua funzione molto semplice non lo è); in alcune funzioni fa più differenza rispetto ad altre.

+1

Non solo rende il debug molto più efficace. Gnu docsonline dice che rende impossibile il debug – PetrosB

+16

Hanno torto. 'printf()' debugging (che ** IS ** sta ancora eseguendo il debug) è molto possibile, per esempio. –

+8

È ancora possibile eseguire il debug al livello di istruzioni (linguaggio assembly) indipendentemente dalle opzioni del compilatore utilizzate. Non è facile come fare il debug a livello di sorgente, ma "impossibile" è sicuramente la parola sbagliata. –

4

Verifica il tuo programma per vedere se c'è una differenza significativa.

Successivamente, profilo il processo di sviluppo. Il debug è più facile o più difficile? Trascorri più tempo a sviluppare o meno?

Le ottimizzazioni senza profiling sono uno spreco di tempo e denaro.

+0

Vorrei che i downvoters lasciassero una spiegazione. –

7

spesso è possibile ottenere codice assembly più significativo dal GCC utilizzando l'argomento -S per emettere l'assemblea:

$ gcc code.c -S -o withfp.s 
$ gcc code.c -S -o withoutfp.s -fomit-frame-pointer 
$ diff -u withfp.s withoutfp.s 

GCC non si preoccupa per l'indirizzo in modo da poter confrontare le istruzioni vere e proprie generate direttamente. Per la vostra funzione di foglia, questo dà:

myf: 
-  pushl %ebp 
-  movl %esp, %ebp 
-  movl 12(%ebp), %eax 
-  addl 8(%ebp), %eax 
-  popl %ebp 
+  movl 8(%esp), %eax 
+  addl 4(%esp), %eax 
    ret 

GCC non genera il codice per spingere il puntatore riquadro nello stack, e questo cambia l'indirizzo relativo degli argomenti passati alla funzione nello stack.

Problemi correlati