Entwickler-Ecke
Algorithmen, Optimierung und Assembler - Arrayzugriff entfernt -> Code langsamer??
enyaw_ecurb - Mi 12.10.05 15:22
Titel: Arrayzugriff entfernt -> Code langsamer??
Ich habe neulich eine ganz simple Mandelbrotfunktion geschrieben und wollte die dann optimieren bzw. testen. Da ich die Punkte in einem zweidimensionalen Array gespeichert hab und ich ja nur die Laufzeit der Rechnungen messen wollte hab ich die entsprechende Zeile entfernt. Als Folge darauf ist mein Code aber um ca. eine Sekunde langsamer geworden! Dabei verbraucht der Zugriff doch eigentlich Rechenzeit und die Funktion sollte schneller werden?
Für die Optimierung ist das ja eigentlich irrelevant, aber es hat mich einfach so gewundert das ich das jetzt hier poste.
Der Code:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| procedure Mandelbrot; var counterv, counterh, counteri: integer; Pointv, Pointh: Double; Stepv, Steph: Double; Sizev, Sizeh: integer; Zreal, Zimag, tmp: Double; Density: integer; Bild: array[0..767,0..1023] of Double; begin Sizev := 768; Sizeh := 1024; Steph := 3 / Sizeh; Stepv := 2 / Sizev; Pointv := 1; Density := 2000; counterv := 0;
while counterv < Sizev do begin counterh := 0; Pointh := -2; while counterh < Sizeh do begin Zreal := 0; Zimag := 0; counteri := 0; while (counteri < Density) and (sqr(Zreal) + sqr(Zimag) < 4) do begin tmp := sqr(Zreal) - sqr(Zimag) + Pointh; Zimag := Zreal*Zimag*2 + Pointv; Zreal := tmp; counteri := counteri+1; end; Bild[counterv, counterh] := counteri / Density; Pointh := Pointh + Steph; counterh := counterh+1; end; Pointv := Pointv - Stepv; Counterv := counterv+1; end; end; |
Die Zeitmessung wurde mit QueryPerformanceCounter durchgeführt und unter Delphi 5 kompiliert. Falls euch der Code oder die Variablenbezeichnungen stören...
Es geht bei meiner Frage nur um den Grund der Verlangsamung. Ich weiß selber, dass das da oben nicht so toll ist.
Also testet es am Besten mal und ich hoffe, dass einer von euch den Grund weiß und ich bedanke mich im Voraus für die Antworten.
alzaimar - Mi 12.10.05 21:04
Lach nich, bei mir verdoppelt sich die Zeit, wenn ich die Zeile rausnehme.... WENN ICH DIE ZEILE RAUSNEHME!!!
Das ist mir zu hoch :gruebel:
zemy - Mi 12.10.05 21:45
kann eigentlich nicht sein. Müsste ein Messfehler sein... wiederhohl einfach mal deine Messungen und mach gleich 4.5 und bilde das Mittel. Dürften die Ergebnisse besser werden.
alzaimar - Mi 12.10.05 21:53
Würde ich auch so sehen, aber die Routine benötigt 30 Sekunden, da sind Messfehler ausgeschlossen.
Probiers doch beim nächsten Mal selbst, bevor Du solche Ratschläge gibst. :wink:
ManuelGS - Mi 12.10.05 22:22
786.432 Arrayfelder + 786.432 FP-Operationen = viel Zeit!
Könnt ihr keine Mathe mehr? :gruebel:
Grishnak - Mi 12.10.05 22:25
Tja, würde gerne helfen, aber bei mir läuft diese Prozedur (fast) nicht!
Als VCL-Anwendung oder Consolen-Anwendung (D7) bekomme ich bei Zeile 10 ('begin') eine StackOverflow-Exception (bzw. die Consolen-Anwendung steigt einfach aus). Wenn ich Zeile 27 auskommentiere, läuft die Prozedur einwandfrei durch! Ich denke, mein Delphi "merkt", dass das Bild-Array nicht benutzt wird und lässt es komplett weg.
Das Problem liegt bestimmt an diesem Bild-Array (immerhin 6 MB groß)!
ManuelGS - Mi 12.10.05 22:34
wenn du die variabel global deklarierst geht es. bei mir braucht das ganze mit oder ohne speichern in "bild" etwa 25,5s.
Grishnak - Mi 12.10.05 22:38
@enyaw_ecurb & alzaimar: Läuft die Prozedur bei euch auch nur, wenn ihr Bild[] global deklariert? Oder läuft es genau so wie oben geposted? Und wenn ja, warum läuft es bei mir nicht?
alzaimar - Mi 12.10.05 22:46
Ich musste die Bild-Variable global deklarieren.
MIT Zuweisung zum Array werden 15 Sekunden benötigt, OHNE Zuweisung 28 Sekunden.
Grishnak - Mi 12.10.05 23:04
Ich habe "Bild: array[0..767,0..1023] of Double;" durch "Bild: array of array of Double" ersetzt, es am Anfang der Prozedur per "SetLength(Bild, 768, 1024)" die Größe angepasst und es am Schluss der Prozedur mit "SetLength(Bild, 0)" gelöscht. Ergebnis: Mit und ohne Zuweisung (Zeile 27) braucht es nun bei mir 17-18 Sekunden!
enyaw_ecurb - Mi 12.10.05 23:09
Tja, da ist mir wohl ein Fehler unterlaufen, sorry. Ich hatte die Arraydeklaration wegen der Übersichtlichkeit in die Prozedur gepackt und es natürlich ausprobiert. Leider war die Zeile von den letzten Tests noch auskommentiert...
Also ich bin auf jeden Fall vollends verwirrt denn ich hab noch ein paar Durchläufe
gemacht. Dazu hab ich die Variable Density, die innerste Iteration, auf verschiedene
Werte gestellt, die Funktion 50 mal durchlaufen lassen und den Durchschnittswert errechnet.
Density: Ohne Zeile, Mit Zeile
1: 45ms, 52ms
10: 238ms, 321ms
100: 1491ms, 1294ms
Insofern völlig normal und entgegen dem Verhalten, das ich beschrieben hab. :oops:
Wenn ich aber dann Density auf 1000 oder höher stelle - ja, ich habs keine 50 mal durchlaufen lassen, sondern nur 10 - bekomme ich falsche Durchschnittswerte, die Funktion brauch viel länger als normal, usw. Wenn ichs aber nur zwei- oder dreimal mache ist sie mit der Zeile wieder schneller. ARRGHHH :evil:
Ich hab heute auf jeden Fall nicht mehr die Nerven das nochmal zu prüfen, aber ich denke das Ganze wird schon irgendwie an einem Messfehler liegen oder zumindest damit zu tun haben.
Gute Nacht und danke für die Antworten.
Horst_H - Do 13.10.05 13:33
Hallo,
bei meinem Duron 800 tut sich da fast nichts, ob mit oder ohne diese Zeile.
Es bleiben ja nur 768*1024 Zugriffe, aber 400.576.414 Berechnungen.
Vielleicht sind modernere CPU's da ein bisschen zickiger.
Gruss Horst
P.S.
Ich habe auch Konstanten verwendet, statt Variablen, falls das einen Unterschied macht.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59:
| const Sizev = 768; Sizeh = 1024;
var Bild: array[0..SizeV-1,0..SizeH-1] of Double; {$R *.dfm} function Mandelbrot:int64; var counterv, counterh, counteri: integer; Pointv, Pointh: Double; Stepv, Steph: Double; Zreal, Zimag, tmp: Double; Density: integer;
begin result :=0; Steph := 3 / Sizeh; Stepv := 2 / Sizev; Pointv := 1; Density := 2000; counterv := 0;
while counterv < Sizev do begin counterh := 0; Pointh := -2; while counterh < Sizeh do begin Zreal := 0; Zimag := 0; counteri := 0; while (counteri < Density) and(sqr(Zreal) + sqr(Zimag) < 4) do begin tmp := sqr(Zreal) - sqr(Zimag) + Pointh; Zimag := Zreal*Zimag*2 + Pointv; Zreal := tmp; inc(Counteri); inc(result) end; Bild[counterv, counterh] := counteri / Density; Pointh := Pointh + Steph; counterh := counterh+1; end; Pointv := Pointv - Stepv; Counterv := counterv+1; end; end;
procedure TForm1.Button1Click(Sender: TObject); var t1,t0,f,Erg : int64; begin queryperformancefrequency(f); queryperformancecounter(t0); Erg :=Mandelbrot; queryperformancecounter(t1); Button1.Caption := Format('Zeit %10.5f %20d',[(t1-t0)/f,Erg]); end; |
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!