2009-12-21 10 views
26

Gibt es eine wesentliche Optimierung, wenn der Rahmenzeiger weggelassen wird? Wenn ich richtig verstanden habe durch Lesen this Seite, wird verwendet, wenn wir speichern, Einrichten und Wiederherstellen von Frame-Zeigern vermeiden wollen.Wann sollte ich den Rahmenzeiger weglassen?

Wird dies nur für jeden Funktionsaufruf durchgeführt und wenn ja, lohnt es sich wirklich, ein paar Anweisungen für jede Funktion zu vermeiden? Ist es nicht trivial für eine Optimierung? Was sind die tatsächlichen Auswirkungen der Verwendung dieser Option abgesehen von den Debugging-Einschränkungen?

ich die folgende C-Code mit und ohne diese Option kompiliert

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 die beiden Dateien ergab folgende Assembler-Code:


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

Könnte jemand bitte ein Licht auf die Schlüssel Punkte des obigen Codes Schuppen, wo -fomit-frame-pointer tatsächlich den Unterschied gemacht hat ?

Edit:objdump 's Ausgabe ersetzt mit gcc -S' s

+2

Probieren Sie das Diff erneut aus, indem Sie mit -S kompilieren. Vergleichen Sie die Assemblersprache: Es wird viel besser lesbar sein. –

+0

@Richard: Fertig! Danke für das Aufzeigen! – PetrosB

+0

Siehe auch [ARM: Link-Register und Frame-Zeiger] (http://stackoverflow.com/q/15752188). – jww

Antwort

24

ermöglicht ein zusätzliches Register für allgemeine Anwendungen zur Verfügung zu stehen. Ich würde annehmen, das ist wirklich nur eine große Sache auf 32-Bit-x86, die ein wenig für Register ausgehungert ist. *

Man würde erwarten zu sehen, EBP nicht mehr gespeichert und bei jedem Funktionsaufruf eingestellt und wahrscheinlich einige zusätzliche Verwendung von EBP in normalem Code und weniger Stapeloperationen bei Gelegenheiten, bei denen EBP als ein Allzweckregister verwendet wird.

Ihr Code ist viel zu einfach, um einen Nutzen aus dieser Art der Optimierung zu ziehen - Sie verwenden nicht genügend Register. Außerdem haben Sie den Optimierer nicht eingeschaltet, der notwendig sein könnte, um einige dieser Effekte zu sehen.

* ISA-Register, keine Mikroarchitekturregister.

+0

Wenn ich explizit andere Optimierungsoptionen einstellen muss, welche Bedeutung hat diese Option? Ihr Argument, dass mein Code einfach ist, scheint jedoch gültig zu sein! – PetrosB

+0

Diese Option ist separat, da es erhebliche Nachteile für das Debuggen hat. –

+0

Es ist separat, da es funktionale Auswirkungen auf andere Dinge hat, z. B. Ausführen des Codes in einem Debugger oder Verknüpfen mit anderem Code. Ich nehme an, dass Sie selbst bei ausgeschaltetem Optimierer eine Verringerung der Registerausfälle sehen würden, aber da ich nicht sicher bin, hecke ich meine Wetten ab. –

9

Der einzige Nachteil des Weglassens ist, dass das Debugging viel schwieriger ist.

Der große Vorteil ist, dass es ein zusätzliches Allzweckregister gibt, das die Leistung erheblich verbessern kann. Offensichtlich wird dieses zusätzliche Register nur benutzt, wenn es gebraucht wird (wahrscheinlich in Ihrer einfachen Funktion nicht); in einigen Funktionen macht es mehr Unterschied als in anderen.

+1

Es macht nicht nur das Debuggen viel mehr dufficult. Gnu Docsonline sagt, dass es Debugging unmöglich macht – PetrosB

+16

Sie sind falsch. 'printf()' debugging (das ** IS ** noch Debugging) ist zum Beispiel sehr gut möglich. –

+8

Sie können immer noch auf der Befehlsebene (Assemblersprache) debuggen, unabhängig von den verwendeten Compileroptionen. Nicht so einfach wie das Debuggen auf Quellniveau, aber "unmöglich" ist definitiv das falsche Wort. –

4

Profilieren Sie Ihr Programm, um festzustellen, ob es einen signifikanten Unterschied gibt.

Als nächstes, profilieren Sie Ihren Entwicklungsprozess. Ist das Debuggen einfacher oder schwieriger? Verbringst du mehr Zeit oder weniger?

Optimierungen ohne Profilierung sind eine Verschwendung von Zeit und Geld.

+0

Ich wünschte, Downvoters würde eine Erklärung hinterlassen. –

7

Sie können oft sinnvoller Assembler-Code von GCC erhalten, indem mit dem -S Argumente zur Ausgabe der Montage:

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

GCC nicht über die Adresse schert, so können wir die tatsächlichen Anweisungen direkt erzeugt vergleichen. Für Ihre Blattfunktion ergibt dies:

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 erzeugen den Code nicht den Rahmen-Pointer auf den Stapel zu schieben, und dies ändert sich die relative Adresse der Argumente der Funktion auf dem Stack übergeben.

Verwandte Themen