Einführung in die Systemprogrammierung 0C

Größe: px
Ab Seite anzeigen:

Download "Einführung in die Systemprogrammierung 0C"

Transkript

1 Einführung in die Systemprogrammierung 0C Prof. Dr. Christoph Reichenbach Fachbereich 12 / Institut für Informatik 8. Juli 2014

2 Klausur 10:00 12:00 am 22.07, Hörsaal V 80% reines Kompetenzwissen 20% Synthese (aus zwei oder mehr Kompetenzen) +10% (max.) aus Testaten Erlaubte Hilfsmittel Schreibmaterialien DIN A4-Seite mit handschriftlichen Notizen Taschenrechner (ohne Funkkommunikation oder Fähigkeit, MIPS auszuführen) Klausureinsicht 12:00-14:00 am Raum 210a, Robert-Mayer-Str. 10

3 Wiederholung: Grenzen der Optimierbarkeit Einschränkungen der Implementierung Fehlende Unterstützung Berechenbarkeit Programmgleicheit ist unentscheidbar Sprachsemantik Programmverhalten muß Sprachspezifikation entsprechen Überspezifizierung Programmierer trifft Entscheidung, die Compiler treffen könnte Beschränktes Wissen Übersetzer sieht nicht genug Informationen

4 Optimierungsproblem: Dynamisches Binden AttoL class C() { obj f() { return 1; } } class D() { obj f() { return 2; } } obj a = [C(), D()]; i =...; while (...) { x := x + a[i].f(); } Gegen welches f binden wir?

5 Optimierungsproblem: Dynamisches Laden Python eval( raw_input()) Java BufferedReader in = new BufferedReader( new InputStreamReader( System. in)); Object obj = Class.forName(in.readLine()).newInstance(); Welche Klasse / welcher Code wird geladen?

6 Just-In-Time-Übersetzung Gerade noch rechtzeitige Übersetzung: Dynamischer Lader Quellprogramm Basis- Übersetzer Optimierender Übersetzer Häufig verwendeter Code Maschinencode Optimierter Maschinencode Profiler (Statt Basis-Übersetzer wird ggf. Interpreter verwendet) Beobachten Ausführung, Optimieren anhand von beobachtetem Bedarf zur Laufzeit

7 Was wird optimiert? Basis-Übersetzung: Schnell, aber langsamer Code Opt-Übersetzung: Langsam, aber schneller Code Nicht jedes Programmstück ist die Optimierung wert Pareto-Prinzip (80/20-Regel) Unter Annahme einer Potenzverteilung beobachten wir, daß ca. 80% der Ausführungszeit in 20% des Programmcodes stattfinden. Je nach Programm beobachtet man auch 90/10 oder extremere Fokussierung

8 Wie wird optimiert? Alle üblichen Optimierungen sind denkbar Jede Optimierung kostet Optimierungszeit: Fokus auf häufig wirksame Optimierungen Schnelle Vorhersage, ob Optimierungen hilfreich sein könnten (Keine Schleife keine Schleifenabwicklung) Spekulative Optimierungen Profiler kann Laufzeiteigenschaften beobachten: Dynamisches Binden geht meistens zu bestimmter Methode? Spekulatives Inlining Parameter scheint konstant zu sein? Spekulative Konstantenpropagierung

9 Zusammenfassung Laufzeitübersetzung bei Bedarf (Just-In-Time-Übersetzung) erlaubt Optimierung von Code, der zum Programmstart unbekannt ist Strategie: Programm wird unoptimiert ausgeführt Programmverhalten von Profiler beobachtet Optimierung der performanzkritischen Elemente Optimierungsstrategie: Optimierung kostet Zeit: Abwägung nötig Spekulative Optimierungen möglich

10 Spekulative Optimierungen Kernidee: Annahme plausibel aktiviert Optimierungen Beispiel: bool-parameter ist immer false Falsche Annahmen: Erkennung: Annahme verletzt Korrektur der Ausführung: Alternativer Ausführungspfad

11 Beispiel: Inlining-Bedarf quadrat.c int quadrat(int z) { return z * z; } aktualisieren.c void aktualisiere(int *d, int l, int (*f)(int)) { for (int i = 0; i<l; i++) d[i] = f(d[i]); } main.c int main(int argc, char **argv) {... aktualisiere(daten, laenge, quadrat);... } Drei separate Module Speedup von 1.8 mit Inlining möglich

12 Spekulatives Inlining void aktualisiere(int *d, int l, int (*f)(int)) { for (int i = 0; i<l; i++) { if (f == quadrat) { d[i] = d[i] * d[i]; } else { d[i] = f(d[i]); } } } Annahme: f = quadrat Inlining mit Prüfung der Annahme und alternativem Pfad C verwendet normalerweise kein spekulatives Inlining

13 Nach Deoptimierung kann erneut spekulatives Inlining betrieben werden Deoptimierung Was, wenn die Annahme oft falsch ist? Beispiel: aktualisiere bei Programmstart mit quadrat verwendet Danach aktualisiere nur noch mit anderer Funktion (plusfuenf) Falsche Annahme: Kostet Performanz Lösung: Beobachten spekulative Optimierungen: Wie oft falsche Annahme? Wenn Annahme oft falsch: Deoptimierung Ersetzen von spekulativ optimiertem Code durch unoptimierten Code

14 Zusammenfassung Spekulative Optimierung: Mache Annahme Möglichst durch Messungen begründet Optimiere anhand von Annahme Prüfe Annahme, Korrektur bei Falschannahme Bei häufiger Korrektur: Deoptimierung

15 Was optimieren wir? Suchen heiße Funktionen: Wo wird viel Ausführungszeit verbracht? Suchen Informationen über heiße Funktionen: Wie werden die Funktionen verwendet? Was wären plausible Konstanten/Typen für spekulative Optimierung? Schätzen Nutzen ab: Laufzeitmodell: Wie lange dauert Optimierung vs. wieviel Zeit sparen wir in der Ausführung?

16 Finden wichtiger Funktionen Strategien: 1 Aufrufzähler Jede Funktion zählt Variable hoch, wenn aufgerufen Evtl. weiteres Hochzählen bei Schleifenwiederholungen Probleme: Kann kleine Funktionen verlangsamen Evtl. Auswirkungen auf Caches Sagt uns nichts genaues über Ausführungszeit 2 Profiling Unterbreche Programm regelmäßig Untersuche Aufrufstapel Probleme: Keine exakten Informationen über Häufigkeit von Aufrufen (für Inlining nützlich!) Kleine Funktionen werden u.u. übersehen

17 Ausführung mit Profiler Param: argv =... Param: argc =... Rücksprung Lader $fp Lader Lokale Variablen Param: f = quadrat Ausführungsrahmen main.c int main(int argc, char **argv) {... aktualisiere(daten, laenge, quadrat);... } Param: l = laenge aktualisieren.c Param: d = daten void aktualisiere(int *d, Rücksprung main int l, int (*f)(int)) { $fp main for (int i = 0; i<l; i++) d[i] = f(d[i]); Lokale Variable: i } Param: z = d[i] quadrat.c Rücksprung aktualisiere Signal vom Systemkern! int quadrat(int z) { $fp aktualisieren return z * z; }

18 Stapelkarten und Variablen Param: argv =... Param: argc =... Rücksprung Lader $fp Lader Lokale Variablen Param: f = quadrat Param: l = laenge Param: d = daten Rücksprung main $fp main Lokale Variable: i Param: z = d[i] Rücksprung aktualisiere $fp aktualisieren Signal wird regelmäßig ausgelöst Kernel ruft Signalbehanlung auf Signalbehandlung liest $pc und sieht: wir sind in quadrat Wir verwenden Stapelkarte zu quadrat: Erklärt Inhalt des Stapels: Welche Variablen sind wo? Erlaubt uns, $pc des Aufrufers zu finden Analog: Registerkarte Dekodieren Aufrufstapel rekursiv Identifizieren Parameter Sammeln Statistiken Stapelkarten auch von Mark&Sweep verwendet

19 Laufzeitprofile Wir beobachten mehrfach quadrat(z) als Parameter zu aktualisieren(d, l, f) f = quadrat könnte nützliche Annahme sein Lohnt sich die Optimierung? Modell Basis Opt Ausführungszeit: t eb t eo Übersetzungszeit: t cb t co Anzahl der Ausführungen: n Optimierung lohnt sich wenn: t co + t eo n < t eb n Variablen werden anhand alter Beobachtungen geschätzt

20 Laufzeitprofile im Vergleich Laufzeitprofile haben wir schon traditioneller Optimierung gesehen: Mit statischer Übersetzung Mit Laufzeit-Übersetzung (JIT) Einmalig vor Programmausführung gemessen Repräsentiert im Voraus gewählte Programmausführungen Messung verlangsamt Übersetzung/Bindeprozeß vor Ausführung Kontinuierlich während Programmausführung gemessen Repräsentiert aktuelle Programmausführung Messung verlangsamt Ausführung

21 Zusammenfassung: Messungen Bestimmen die zu optimierenden Funktionen durch: Zähler und/oder Profiler Bestimmen ggf. interessante Variableninhalte Berechnen Laufzeitprofil der interessanten Funktionen Profiler verwendet Stapelkarten, um Inhalte des Ausführungsstapels zu inspizieren Schätzen Nutzen einer Optimierung ab Optimieren, wenn merklicher Nutzen wahrscheinlich

22 Implementierung der Übersetzung TD(C) class C() { f g f g Basis- Übersetzer obj f() {...} obj g() {...} h Virtuelle Methodentabelle mit Typdeskriptor h h-opt Opt- Übersetzer } obj h() {...} Ersetzen Einträge in virtueller Methodentabelle nach Optimierung

23 Beispiel AttoVM: Übersetzung bei Bedarf TD(C) f, selektor:6 g, selektor:7 h, selektor:8 li jal $v0, 0x6 u0 u0: subiu $sp, 0x30 sd $a0, 0x0($sp) sd $a1, 0x8($sp)... sd $a5, 0x28($sp) move $a0, $v0 move $a1, $sp addiu $a1, 0x30 jal uebersetzer ld $a0, 0($sp) ld $a1, 0x8($sp)... ld $a5, 0x28($sp) addiu $sp, 0x30 jreturn Initialer Code für Methode sagt: Übersetze mich!

24 Globale/statische Funktionen Bisherige Strategie funktioniert für Methoden, aber nicht für Funktionen Lösungen: 1 Umbinden: (Relozierungstabelle) Verfolgen, wo Funktion aufgerufen werden Alle Sprungbefehle überschreiben (Umbinden) Benötigt Relozierungstabelle 2 Prozedurbindungstabelle: Indirekte Sprünge, wie in dynamischen Bibliotheken Zwischensprung wird überschrieben

25 Zusammenfassung Übersetzung benötigt Mechanismen, um übersetzten Code gegen Programm zu binden Klassen: Virtuelle Methodentabelle Globale Operationen: Indirekte Sprünge Relozierungstabellen (unüblich) Strategie auch wirksam, um Basis-Übersetzung zu verzögern

26 Zusammenfassung: JIT Laufzeit-Übersetzung bei Bedarf (Just-In-Time-Übersetzung) Übersetzen zunächst ohne Optimierung Profiling/Zähler: Beobachten Bedarf für Optimierungen Suchen interessante Annahmen für Optimierungen Optimieren heiße Funktionen Spekulative Optimierungen anhand von Annahmen Umsetzung: Tauschen optimierte Einträge in virtueller Funktionstabelle aus Indirekte Aufrufe von statischen Operationen

27 Weiterführende Veranstaltungen im WS 2014/15 Bachelor B-RA/B-CA (Computer Architecture) Mehr Hintergrund zu Rechnerarchitektur B-HL (Hochleistungsrechnerarchitektur) Rechnerarchitektur mit Fokus auf moderne Hochleistungsarchitekturen und parallele Berechnungen Master M-RA/M-CA (Computer Architecture) M-HL (Hochleistungsrechnerarchitektur) M-PS (Konzepte der Programmiersprachen) Programmanalysen, Laufzeitsysteme, Bauen von Software-Werkzeuge M-SAFP (Semantik und Analyse von funktionalen Programmen)

28 Wiederholung