2009-12-21 12 views
26

¿Hay alguna optimización sustancial al omitir el puntero del marco? Si lo he entendido correctamente al leer la página this, se usa cuando queremos evitar guardar, configurar y restaurar punteros de cuadros.¿Cuándo debería omitir el puntero de marco?

¿Se hace esto sólo para cada llamada a la función y si es así, ¿es realmente vale la pena para evitar unas pocas instrucciones para cada función? ¿No es trivial para una optimización? ¿Cuáles son las implicaciones reales de usar esta opción aparte de las limitaciones de depuración?

compilé el siguiente código C con y sin esta opción

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 los dos archivos reveló el siguiente código de montaje:


--- 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 

Podría alguien arrojar luz sobre los clave puntos del código anterior, donde -fomit-frame-pointer no realmente hacer la diferencia ?

Editar:objdump 's de salida sustituido por gcc -S' s

+2

Pruebe nuevamente la diferencia compilando con -S. Compare el lenguaje ensamblador: será mucho más legible. –

+0

@Richard: ¡Hecho! ¡Gracias por mencionarlo! – PetrosB

+0

Relacionados, vea [ARM: registro de enlace y puntero de marco] (http://stackoverflow.com/q/15752188). – jww

Respuesta

24

permite un registro adicional que esté disponible para su uso para fines generales. Asumiría que esto es realmente un gran problema en 32-bit x86, que es un poco hambriento para los registros. *

Uno esperaría ver que EBP ya no se guarde y ajuste en cada llamada de función, y probablemente algún uso adicional de EBP en código normal, y menos operaciones de pila en ocasiones donde EBP se usa como un registro de propósito general.

Su código es demasiado simple para ver algún beneficio de este tipo de optimization-- no se está usando suficientes registros. Además, no ha activado el optimizador, que podría ser necesario para ver algunos de estos efectos.

* Registros ISA, no registros de micro-arquitectura.

+0

Si tengo que establecer explícitamente otras opciones de optimización, ¿cuál es el significado de esta opción por separado? ¡Sin embargo, su punto de que mi código es simple parece válido! – PetrosB

+0

Esta opción es independiente porque tiene desventajas significativas para la depuración. –

+0

Está separado porque tiene implicaciones funcionales para otras cosas, como ejecutar el código en un depurador o vincularlo con otro código. Supongo que verá una reducción en los derrames de registros incluso con el optimizador desactivado, pero como no estoy seguro estoy cerrando mis apuestas. –

9

El único inconveniente de omitirlo es que la depuración es mucho más difícil.

La principal ventaja es que hay un registro de propósito general adicional que puede hacer una gran diferencia en el rendimiento. Obviamente, este registro adicional se usa solo cuando es necesario (probablemente en su función muy simple no lo es); en algunas funciones hace más diferencia que en otras.

+1

No solo hace que la depuración sea mucho más dufficult. Gnu docsonline dice que hace que la depuración sea imposible – PetrosB

+16

Están equivocados. La depuración de 'printf()' (que ** ** aún está depurando) es muy posible, por ejemplo. –

+8

Aún puede depurar a nivel de instrucción (lenguaje ensamblador) independientemente de las opciones de compilación utilizadas. No es tan fácil como la depuración a nivel de fuente para estar seguro, pero "imposible" es definitivamente la palabra incorrecta. –

4

Perfile su programa para ver si hay una diferencia significativa.

A continuación, perfile su proceso de desarrollo. ¿Es la depuración más fácil o más difícil? ¿Pasas más tiempo desarrollando o menos?

Las optimizaciones sin perfiles son una pérdida de tiempo y dinero.

+0

Ojalá los videntes me dejen una explicación. –

7

A menudo se puede obtener el código de montaje más significativo del CCG utilizando el argumento -S a la salida de la asamblea:

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

GCC no se preocupa por la dirección, por lo que puede comparar las instrucciones reales generados directamente. Para su función de hoja, esto da:

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 no genera el código para empujar el puntero de marco en la pila, y esto cambia la dirección relativa de los argumentos pasados ​​a la función en la pila.

Cuestiones relacionadas