Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Seminar aus Softwareentwicklung: Programmierstil Effizienz Friedrich Priewasser.

Ähnliche Präsentationen


Präsentation zum Thema: "Seminar aus Softwareentwicklung: Programmierstil Effizienz Friedrich Priewasser."—  Präsentation transkript:

1 Seminar aus Softwareentwicklung: Programmierstil Effizienz Friedrich Priewasser

2 Übersicht Überschlagsrechnungen Profiling Code Tuning Effiziente Speichernutzung

3 Überschlagsrechnungen Ermöglichen das Abschätzen von Laufzeiten und Speicherbedarf Schon vor Implementierung kann Machbarkeit überprüft werden Für jede Operation wird die durchschnittliche Ausführungsdauer gemessen: n=... for (int i=0; i

4 Kosten für eine Operation Probleme: Compileroptimierungen verwendeter Speicher (Cache oder Hauptspeicher) Ergebnis nur für ähnliche Prozessoren einsetzbar an „sinnvollen“ Bsp. überprüfen ob Schätzung stimmt (Größenordnung) Sicherheitsfaktoren verwenden

5 Profiling Profiler: Werkzeug zum Auflisten der Häufigkeit mit der ein Programmteil ausgeführt wurde Bsp: Primzahlen bis 1000 ermitteln: int prime(int n){ int i; for (i=2; i

6 int root(int n){ return (int) sqrt((float) n); 5456 } int prime(int n) { int i; for(i=2;i<=root(n);i++) 999 if (n%i == 0) 5288 return 0; 831 return 1; 168 } main(){ int i,n; n=1000; 1 for (i=2; i<=n; i++) 1 if (prime(i)) 999 printf("%d\n", i); 168 }  5288 statt Tests Laufzeit steigt allerdings Reduzieren der Tests auf Teilbarkeit

7 %Zeit Name 82.7 sqrt 4.5 prime 4.3 root 2.6 frexp int prime(int n) { int i, bound; bound = root(n); for (i=2; i<=bound; i++) if (n%i == 0) return 0; return 1; } int prime(int n) { int i; for (i=2; i*i<=n; i++) if (n%i == 0) return 0; return 1; }  Wurzelberechnung benötigt über 4/5 der Gesamtzeit Arbeit innerhalb Schleifen minimieren Komplexe Funktion durch einfache ersetzen Verwenden eines Profilers mit Zeitmessung

8 Code Tuning Gründe die gegen Code Tuning sprechen : optimierter Code ist schwierig zu programmieren, zu lesen und zu überarbeiten fehleranfällig mit viel Zeitaufwand beim Erstellen verbunden im schlimmsten Fall Langsamer Falsche Vermutungen können die Laufzeit erhöhen das Aus für das Projekt Zu frühes Optimieren führt zu nicht korrekten, schlecht modularisierten Code Programmcode (noch) nicht optimieren

9 Methoden zur Geschwindigkeitssteigerung Programm Design überdenken (Modularisierung, Grobentwurf,...) Modul- und Methodendesign überarbeiten (Wahl geeigneter Datenstrukturen und Algorithmen) Zugriffe auf Betriebssystem reduzieren (Ausgabe auf Bildschirm, Festplatte,... Einlesen von Festplatte,...) Geeigneten Compiler wählen (Compileroptimierungen) Andere Hardware verwenden (Hardware ist billiger als Software) Code Tuning

10 Vorgehensweise beim Code-Tuning Geschwindigkeit des Programms messen ca. 5% des Codes benötigen über 50% der Laufzeit „Hot Spot“ im Programm überarbeiten, „tunen“ Erfolg der Optimierung überprüfen Ist Programm wirklich schneller geworden? Läuft es weiterhin fehlerfrei? Sinnhaftigkeit weiterer Optimierung überdenken

11 Ein Beispiel: Zweier-Logarithmus-Berechnung für Integer static uint Log2(uint n){ return (uint) (System.Math.Log(n)/System.Math.Log(2)); } static uint Log2(uint n){ return (uint) (System.Math.Log(n)/ ); } 450ns 700ns static uint Log2(uint x){ if(x<0x2) return 0; if(x<0x4) return 1; if(x<0x8) return 2; if(x<0x10) return 3;... if(x<0x ) return 28; if(x<0x ) return 29; if(x<0x ) return 30; return 31; } 120ns Ersetzen von Funktionsaufrufen durch Ergebnis Geeignete Datentypen verwenden / Algorithmus ändern

12 static uint Log2(uint x){ if(x<0x10000){ if(x<0x100){ if(x<0x10){ if(x<0x4){ if(x<0x2) return 0; else return 1; } else { if(x<0x8) return 2;... else return 29; } else { if(x<0x ) return 30; else return 31; } } } } } 40ns Vergleich:Originalversion700ns mit Konstante450ns -36% ohne Math.Log120ns -83% mit Binärsuche40ns -94% Ein Beispiel: Zweier-Logarithmus-Berechnung für Integer Algorithmus verbessern

13 Komplizierte Operationen durch einfache ersetzen Positionsbestimmung bei Zyklischer Puffer: pos=(pos+1) % n; ersetzen durch: pos++; if(pos>=n) pos=0; val=0; for(int p=0;p<=power;p++) val=val+coef[p]*Math.pow(x,p); ersetzen durch: Polynom-Auswertung val=0; powerOfX=1; for(int p=0;p<=power;p++){ val=val+coef[p]*powerOfX; powerOfX*=powerOfX; } val=0; for(int p=power;p>=0;p--) val=val*x+coef[p]; Weitere Verbesserung durch Ändern des Algorithmus:

14 Inline-Codierung Vermeidet Aufwand des Funktionsaufrufs Beliebtes Mittel in C: Makros Bsp.: max Funktion int max(int a, int b){ return a>b ? a : b; } #define max(a,b) ((a)>(b) ? (a) : (b)) Je nach Compiler bis zu 50% schneller wird ersetzt durch

15 int[] x={5,2,1,3}; int max=arrmax(4); Beispiel zur Anwendung:  Komplexität steigt durch Verwenden des Makros von O(n) auf O(2 n ) int arrmax(int n){ if (n==1) return x[0]; else return max(x[n-1],arrmax(n-1)); }

16 Loop-Unrolling for (int i=0;i<5;i++) a[i]=i; a[0]=0; a[1]=1; a[2]=2; a[3]=3; a[4]=4;  6.5 mal schneller = 85% Zeit Ersparnis Allgemein:  i=1; while (i<=Num){ a[i]=i; i++; } i=1; upper=Num-N+1; while(i<=upper){ a[i]=i; a[i+1]=i+1;... a[i+N-1]=i+N-1; i+=N; } while(i<=N){ a[i]=i; i++; } 

17 Speichern für Wiederverwendung Einmalige Berechnung von Funktionsergebnissen zur Implementierungszeit (Ergebnisse in Datei speichern) zur Initialisierungszeit bei erstem Aufruf z.B.: Tabelle mit vorberechneten Sinuswerten 0 bis 90 Grad (Rest kann berechnet werden) 0.1 Grad Schritte void InitTab(){ for(int x=0;x<=900;x++) sinTab[x]=Math.sin(x); } double SinTab(int n){ if(sinTab[n]<-1) sinTab[n]=Math.sin(n/10); return sinTab[n]; } bei Initialisierung:bei erstem Aufruf:

18 Schreiben von Programmteilen in Assembler Vorgehensweise Programm vollständig in Hochsprache schreiben Testen und feststellen ob das Programm den Anforderungen entspricht Feststellen welche Teile des Codes nicht schnell genug arbeiten (Profiler) Vom Compiler erzeugten Assembler-Code optimieren Korrektheit und Geschwindigkeitsgewinn überprüfen bzw. messen Nachteil: Portabilität geht verloren

19 Compiler Optimierungen Kosten nichts Leistungsgewinn hängt ab von Programmcode Sprache Compiler Bereich: 0 bis 50 Prozent

20 Weitere Techniken Gleich oft durchlaufene Schleifen zusammenfassen Arbeit innerhalb Schleifen minimieren Tests beenden wenn Ergebnis bekannt ist Mit break Schleife beenden „Sentinels“ verwenden beim Suchen in Arrays Letztes Element durch gesuchten Wert ersetzen Ersetzt dir Abfrage ob der Index noch gültig ist if else und switch Statements der Häufigkeit nach ordnen

21 Speichereffizienz Bsp.: Geographische Datenbank: 200x200 Felder 2000 Nachbarn geg.: x und y Position ges.: Nr. des Nachbarn Einfachste Lösung: Array mit 200x200 Einträgen  Elemente:bei 32-Bit Werten Byte bei 16-Bit Werten Byte

22 Suchaufwand:Max: über 200 Punkte Mittel:über 10 Punkte Speicherbedarf: 200*4 Byte *12 Byte = Byte durch malloc steigt der Bedarf auf das mehrfache Verwenden verketteter Listen:

23 pointnum row firstincol Suchaufwand:Max: über 200 Punkte Mittel:über 10 Punkte Speicherbedarf: bei 32-Bit Werten: 201*4 Byte *4 Byte *4 Byte = Byte bei 16-Bit Werten: 201*2 Byte *2 Byte *2 Byte = 8402 Byte find(int i,int j){ for (k=firstincol[i];k

24 find(int i,int j){ for (k=firstincol[i];k= Byte 1-dim Arrays: Byte Byte ohne „Row“ Byte Byte Platzersparnis: 75.6 kB = 94.5% Entfernen des Row-Arrays:

25 Zusammenfassung Speichereffizienz Kleinst mögliche Wert-Typen verwenden Werte neu berechnen statt speichern Geeignete Datenstrukturen verwenden Keinen Platz für Null-Werte verschwenden Menge an Hilfsdaten (Zeiger,...) reduzieren Nicht übertreiben (Jahr 2000 Problem)

26 Schlüsselpunkte beim Optimieren Performance alleine führt nicht zu guter Softwarequalität Wenige Prozent des Codes (ca. 5%) benötigen über 50% der Laufzeit Messen der Geschwindigkeit (vor und nach der "Optimierung") ist das A und O des Code Tuning Nur von Anfang an sauberer Code führt zu guten Ergebnissen


Herunterladen ppt "Seminar aus Softwareentwicklung: Programmierstil Effizienz Friedrich Priewasser."

Ähnliche Präsentationen


Google-Anzeigen