Die Optimierung ist ein Programm Transformationstechnik, die um den Code indem sie verbrauchen weniger Ressourcen (CPU, Speicher) und liefern zu verbessern mit hoher Geschwindigkeit zu verbessern versucht.
In der Optimierung werden hochrangige allgemeine Programmierkonstrukte durch sehr effiziente Low-Level-Programmierung-Codes ersetzt. Ein Code Optimierung Prozess muss die drei folgenden Regeln beachtet folgen:
Der Ausgabecode muss nicht, in irgendeiner Weise zu ändern, die Bedeutung des Programms.
Die Optimierung sollte die Geschwindigkeit des Programms zu verstärken und, wenn möglich, sollte das Programm weniger Anzahl von Ressourcen verlangen.
Die Optimierung sollte sich schnell sein und sollte nicht den gesamten Zusammenstellungprozess zu verzögern.
Die Bemühungen für einen optimierten Code kann auf verschiedenen Ebenen der Zusammenstellung der Prozess gemacht werden.
Bei Beginn kann der Anwender ändern / neu ordnen Sie den Code oder nutzen bessere Algorithmen, um den Code zu schreiben.
Nach der Erzeugung von Zwischencode kann der Compiler den Zwischencode von Adressberechnungen und die Verbesserung der Schleifen zu ändern.
Während Herstellung des Zielmaschinencode kann der Compiler kann Verwendung von Speicherhierarchie und die CPU-Register zu machen.
Die Optimierung kann grob in zwei Typen unterteilt werden: Maschine unabhängige und Maschine abhängige
In dieser Optimierung, erfolgt der Compiler in den Zwischencode und wandelt einen Teil des Codes, dass tut keine beteiligen jeder CPU-Register und / oder absoluten Speicherstellen. Zum Beispiel:
do { item = 10; value = value + item; } while(value<100);
Dieser Code beinhaltet wiederholte Zuordnung der Kennung Artikel, die, wenn wir auf diese Weise:
Item = 10; do { value = value + item; } while(value<100);
sollten nicht nur speichern Sie die CPU-Zyklen, aber kann auf jedem Prozessor verwendet werden.
maschinenabhängige Optimierung wird durchgeführt, nachdem der Zielcode erzeugt worden ist, und wenn der Code entsprechend der Zielmaschinenarchitektur transformiert. Es geht um CPU-Register und kann absolute Speicherreferenzen, nicht einen relativen Referenzen haben. Maschinenabhängige Optimierer setzen Bemühungen um maximalen Nutzen aus Speicherhierarchie zu nehmen.
Quellencodes im allgemeinen eine Anzahl von Befehlen, die immer in der Reihenfolge ausgeführt werden und sind als der Basisblöcke des Codes berücksichtigt. Diese Grundbausteine keine Sprunganweisungen zwischen ihnen aufweisen, dh, wenn der erste Befehl ausgeführt wird, alle Befehle in dem gleichen Grundblock in der Reihenfolge ihrer Erscheinung, ohne die Flusssteuerung von dem Programm ausgeführt werden, zu verlieren.
Ein Programm kann verschiedene Konstrukte als Basisblöcke haben, wie IF-THEN-ELSE, SWITCH-CASE bedingte Anweisungen und Schleifen wie DO-WHILE, FOR, und REPEAT-UNTIL etc.
Wir können die folgenden Algorithmus verwenden, um die Basisblöcke in einem Programm zu finden:
Suche header Aussagen aller Basisblöcke, von wo aus ein grundlegendes Block beginnt:
Kopfzeile Rechnung sowie die Rechnung folgende ihnen bilden Basisblock.
Ein Basisblock enthält keine Kopfzeile Aussage eines anderen Basisblock.
Basisblöcken sind wichtige Konzepte aus beiden Code-Generierung und Optimierung Sicht.
Grundblöcke spielen eine wichtige Rolle bei der Identifizierung von Variablen, die mehr als einmal in einem Grundblock verwendet werden. Wenn eine Variable mehr als einmal verwendet werden, muss der Registerspeicher auf diese Variable zugewiesen nicht geleert werden, wenn der Block die Ausführung beendet.
Basisblöcke in einem Programm mit Hilfe von Steuerflussdiagramme dargestellt werden. Ein Kontrollflussgraphen zeigt, wie die Programmsteuerung, die unter den Blöcken übergeben. Es ist ein nützliches Tool, das in die Optimierung hilft durch die Hilfe Ortung unerwünschte Schleifen im Programm.
Die meisten Programme in einer Schleife in dem System ausgeführt werden. Es wird notwendig, um die Schlaufen, um die CPU-Zyklen und Speicher Speichern optimieren. Loops können durch die folgenden Techniken optimiert werden:
unveränderlichen Code : Ein Fragment der Code, der in der Schleife befindet, und berechnet den gleichen Wert bei jeder Iteration wird eine Schleife-invarianten Code bezeichnet. Dieser Code kann aus der Schleife, indem Sie sie bewegt werden, um nur einmal berechnet werden und nicht bei jeder Iteration.
Induktionsanalyse: Eine Variable wird als eine Induktionsvariable , wenn sein Wert innerhalb der Schleife durch eine Schleife unveränderlichen Wert verändert
Stärke Reduzierung: Es gibt Ausdrücke, die mehr CPU-Zyklen, die Zeit und Speicher verbrauchen. Diese Ausdrücke sollten billiger Ausdrücke, ohne die Ausgabe des Ausdrucks ersetzt werden. Zum Beispiel, Multiplikation (x * 2) ist teuer in Bezug auf CPU-Zyklen als (x << 1) und liefert das gleiche Ergebnis.
Toter Code ist einem oder mehr als ein Code-Anweisungen, die da sind:
So, spielt absolut keine Rolle Code in jedem Programmbetrieb und kann daher einfach entfernt werden.
Es gibt einige Code-Anweisungen, deren berechneten Werte sind nur unter bestimmten Umständen verwendet werden, das heißt, manchmal die Werte verwendet werden, und manchmal sind sie nicht. Solche Codes werden als teilweise Dead-Code bekannt ist.
Die obige Kontrollflussgraphen zeigt ein Stück Programm, in dem die Variable 'a' wird verwendet, um den Ausgang des Ausdrucks zuweisen 'x * y'. Nehmen wir an, dass der Wert auf 'a' wird nie in der loop.Immediately nach der Steuerung verwendet zugeordnet verlässt die Schleife 'a' wird der Wert der Variable "z", die später im Programm verwendet werden würde zugewiesen. Wir schließen hier, dass die Zuweisung von Code "a" wird nirgendwo verwendet, berechtigt, beseitigt werden daher darauf.
Auch die Abbildung oben zeigt, dass die bedingte Anweisung immer falsch ist, was bedeutet, dass der Code, in wahrer Fall geschrieben, nie ausgeführt werden, damit sie entfernt werden kann.
Redundante Ausdrücke werden mehr als einmal im Parallelpfad berechnet, ohne irgendeine Änderung in operands. Während teilweise redundante ausdrücke werden mehr als einmal in einem Pfad berechnet, ohne irgendeine Änderung in den Operanden. Zum Beispiel:
[redundante ausdrücke] |
[teilweise redundante ausdrücke] |
Schleife invarianten Code ist teilweise redundant und können mit einem Code-Motion-Technik beseitigt werden.
Ein weiteres Beispiel für eine teilweise redundanten Code können sein:
If (condition) { a = y OP z; } else { ... } c = y OP z;
Wir gehen davon aus, dass die Werte von Operanden ( y und z ) werden nicht aus Zuordnung von variablen a, um variable c geändert. Hier wird, wenn die Bedingung Anweisung wahr ist, dann y OP Zzweimal ansonsten einmal berechnet. Codebewegung kann verwendet werden, um diese Redundanz zu beseitigen, wie unten dargestellt:
If (condition) { ... tmp = y OP z; a = tmp; ... } else { ... tmp = y OP z; } c = tmp;
Hier, ob die Bedingung wahr oder falsch ist; y OP z sollte nur einmal berechnet werden.