Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Mo Jul 14, 2025 23:42

Foren-Übersicht » Programmierung » Allgemein
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 17 Beiträge ]  Gehe zu Seite 1, 2  Nächste
Autor Nachricht
BeitragVerfasst: Fr Okt 22, 2010 15:20 
Offline
DGL Member

Registriert: Mo Aug 31, 2009 13:19
Beiträge: 151
Gleich vorweg - das hier ist kein Problem oder ähnliches, was einer dringenden Lösung betrifft, darum stehts auch im OT. Ich hab nur ne seltsame (aber auch winzigkleine) Beobachtung gemacht, als ich gerade meinen Code optimiert hab, die ich mir als nicht-Informatiker nicht erklären kann. Vllt. klärt mir jemand das Miraculum auf :)

Ich hab mir nen kleinen Raytracer geschrieben, und bin wie oben beschrieben also gerade dabei meinen Code zu optimieren. Die Zeitmessungen mach ich alle mehrmals und mittele dann, um zufällige Schwankungen auszuschließen. Meine Test-Szene renderte vor meiner "Optimierung" in ~5800ms. Dann hab ich mich an folgende Codestelle gemacht:
Code:
for i := 0 to Scene.SceneCount - 1 do
  begin
  if not Scene[i].InheritsFrom(TVisibleObject) then Continue;
  Hit := Scene[i].Intersect(a_Ray, Distance);
  if Hit <> 0 then Primitive := Scene[i];
  end;


Durch Änderungen am Scene-Objekt hab ich sichergestellt, dass die default-Eigenschaft nur TVisibleObject-Nachfolger enthält und dachte mir dann "Gut, jezze brauchste die dritte Zeile wohl nimmer, wo du das prüfst - nimmste sie raus, is immerhin eine if-Abfrage weniger pro Strahl", gesagt, getan: Auskommentiert, Zeitmessung, uuuund - der Rendervorgang dauert länger. Und zwar sagenhafte 30-40ms länger (wie gesagt, es sind schon gemittelte Werte). Ja, ich weiß, die Änderung is winzig, aber sie ist da und ich kann sie mir partout nich erklären - ich spare der CPU doch Arbeit, wieso also dauert die Sache plötzlich länger?

Nochmal: Ich weiß es is nich weltbewegend, ich finds auch nich dringend und weils wahrscheinlich nix ist, was die Welt (außer mich) interessiert stehts ja auch im OT ^^

Edit:
Ich sammel hier einfach mal weiter, worüber ich noch so stoße...
Warum ist der berühmte FastInvSQRT in Delphi:
Code:
Function FastInvSQRT(v: Single): Single;
Var
   XHalf: Single;
   I: Integer Absolute v;
   X2: Single Absolute I;
Begin
  XHalf:= 0.5 * v;
  I:= $5f3759df - (I SHR 1);
  Result := X2 * (1.5 - XHalf * X2 * X2);
end;

langsamer als ein "1 / Math.Sqrt"? (50-60ms)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 22, 2010 15:54 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Kann ich mir spontan nicht erklären, nur mit einer (ungeprüften!) Hypothese. InheritsFrom könnte eventuell nur testen, ob Vorfahrenklassen TVisibleObject sind, nicht aber ob das Objekt selbst eine Instanz von TVisibleObject ist. Damit würden eventuell (ich kenne deine Szene nicht) einige Objekte, die direkt von TVisibleObject erben, rausfallen. Aber wie gesagt, das ist nur eine Hypothese und ich kenne die genaue Funktion von InheritsFrom nicht. Der "is" Operator prüft auf jeden Fall auch ob die aktuelle Klasse gleich ist, das aber nur am Rande.

Der "is"-Test oder auch InheritsFrom sind auf jeden fall etwas komplexere Tests (will sagen, mehr als nur ein Integer-Vergleich z.B.), also ists schon erstaunlich, wenn du durch die einsparung kosten erzeugst.

Hast du eventuell im Getter, der hinter Scene[i] steht, irgendwas dazu gebaut?

grüße
(ps: Eine andere Optimierung wäre übrigens, Scene[i] zwischenzuspeichern. Propertyzugriffe sind immer etwas teurer als normale Variablenzugriffe, vorallem, wenn da hinter den Kulissen noch auf eine Liste zugegriffen wird, wo Range Checks etc. vorkommen)

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 22, 2010 15:57 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Zum FastInvSQRT: Rechnest du außerhalb eventuell mit Double oder Extended (oder auch dem Metatyp "float" der entweder Double oder Extended ist)? Dann muss danach eine Umwandlung Double<>Extended gemacht werden, was Zeit kostet. Außerdem haben heutige CPUs bei Floating-Point-Operationen schon mächtig Zahn drauf, irgendwer hat hier im Forum auch mal geschrieben, dass die sogar eher auf Float als auf Integer optimiert werden, was eventuell erklärt, warum die Int-Lösung langsamer ist.

// Edit: Nach Allgemein verschoben. Darf ruhig gefunden werden und passt hier trotz mangelnder Dringlichkeit besser rein.

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 22, 2010 16:47 
Offline
DGL Member

Registriert: Mo Aug 31, 2009 13:19
Beiträge: 151
Vorab: Ich könnt mich köstlich amüsieren über das, was meine Zeiten so sagen...

Nacheinander:
Lord Horazont hat geschrieben:
Kann ich mir spontan nicht erklären, nur mit einer (ungeprüften!) Hypothese. InheritsFrom könnte eventuell nur testen, ob Vorfahrenklassen TVisibleObject sind, nicht aber ob das Objekt selbst eine Instanz von TVisibleObject ist. Damit würden eventuell (ich kenne deine Szene nicht) einige Objekte, die direkt von TVisibleObject erben, rausfallen. Aber wie gesagt, das ist nur eine Hypothese und ich kenne die genaue Funktion von InheritsFrom nicht. Der "is" Operator prüft auf jeden Fall auch ob die aktuelle Klasse gleich ist, das aber nur am Rande.

Der "is"-Test oder auch InheritsFrom sind auf jeden fall etwas komplexere Tests (will sagen, mehr als nur ein Integer-Vergleich z.B.), also ists schon erstaunlich, wenn du durch die einsparung kosten erzeugst.

Hast du eventuell im Getter, der hinter Scene[i] steht, irgendwas dazu gebaut?


TVisibleObject ist nur eine abstrakte Klasse, die die Funktionen Intersect und GetNormal (als abstract) einführt - die gibts in der Szene nicht. Hab auch mal statt dem "Continue" ein "Beep" reingeschrieben, um zu testen, ob da vielleicht doch mal gesprungen wird - nein, es wird nicht gesprungen. Aber mit dem "Is"-Operator hast du mich auf ne Idee gebracht - ich hab das .InheritsFrom mal durch ein "is" ersetzt - bringt tatsächlich nen paar ms.
Der Getter für Scene[i] sieht wie folgt aus:

Code:
function TScene.GetScene(Index: Integer): TVisibleObject;
begin
Result := nil;
if Index > High(FScene) then Exit;
Result := FScene[Index];
end;


Is also auch eher komisch, dass ich Zeit spare, wenn ich ihn aufrufe...aber dazu später ;)

Lord Horazont hat geschrieben:
grüße
(ps: Eine andere Optimierung wäre übrigens, Scene[i] zwischenzuspeichern. Propertyzugriffe sind immer etwas teurer als normale Variablenzugriffe, vorallem, wenn da hinter den Kulissen noch auf eine Liste zugegriffen wird, wo Range Checks etc. vorkommen)


Die Idee fand ich gut, also hab ich mich auf die Suche nach Codestellen gemacht, wo mir das was bringen könnte (das Scene[i] von oben landet nach dem Intersection-Test sofort in ner anderen Variable, da brachte es also sicher nichts) und bin bei meinen Lichtern fündig geworden - die stehen in Scene.Lights[Index: Integer], also auch in ner Liste, der Getter sieht exakt aus wie der oben angegebene - nur halt für TLight statt für TVisibleObject und ich guck natürlich auch in nem andern Array. Also hab ich der Raytracingprozedur eine neue Variable verpasst (Light: TLight), und das aktuelle Licht (Scene.Lights[j]) brav zwischengespeichert. Noch fix alle "Scene.Lights[j]" durch "Light" ersetzt, Raytracer angeworfen, zurückgelehnt, Ergebnis gesehen, aufgelacht: Langsamer.
Das hat mich dann dazu bewogen, den Kompilierungsmodus von "Debug" mal auf "Release" zu stellen - wollts nur erwähnen, geändert hats nichts. Dabei sollte das doch eigentlich nen Geschwindigkeitszuwachs bringen, meine ich mal gehört zu haben...

Edit: Nachtrag zum Getter
Nachdem im Code alle Zugriffe auf Scene[Index] oder Scene.Lights[Index] nur aus Schleifen heraus erfolgen, die eh nur bis Count - 1 laufen hab ich die Tests ob der Index höher ist als der höchste Feldindex sinnvollerweise mal aus den Gettern entfernt - Ergebnis: ca. 100ms schneller.

Lord Horazont hat geschrieben:
Zum FastInvSQRT: Rechnest du außerhalb eventuell mit Double oder Extended (oder auch dem Metatyp "float" der entweder Double oder Extended ist)? Dann muss danach eine Umwandlung Double<>Extended gemacht werden, was Zeit kostet. Außerdem haben heutige CPUs bei Floating-Point-Operationen schon mächtig Zahn drauf, irgendwer hat hier im Forum auch mal geschrieben, dass die sogar eher auf Float als auf Integer optimiert werden, was eventuell erklärt, warum die Int-Lösung langsamer ist.

Alle meine Fließkommazahlen sind Singles (und machen ordentlich einen drauf, Schenkelklopfer). Aber das heutige CPUs einfach anders optimiert sind, klingt natürlich plausibel.

Neuere nützliche Beobachtungen, die auch einen Sinn ergeben (a: Single):
- a * a ist deutlich schneller als Sqr(a)
- auch wenn das Internet teilweise etwas anderes sagt ist a + a nicht schneller als 2 * a
- Um mehrere Floats durch einen Wert a zu teilen ist Floats * 1 / a schneller als Floats / a, wenn man 1 / a vorberechnet (Beispielsweise beim Vektoren normieren)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 22, 2010 16:53 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Bezüglich des zwischenspeichern von Scene[i] bzw. TLight. Du darfst dabei natürlich das TLight nicht kopieren. In C++ nutze ich für sowas gerne eine konstante Referenz:
Code:
const TLight& light = Scene[i];

In Delphi/Pascal gibt es sicher was ähnliches.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 22, 2010 17:02 
Offline
DGL Member

Registriert: Mo Aug 31, 2009 13:19
Beiträge: 151
Soviel ich weiß werden, verbergen sich bei Delphi hinter Variablen, die scheinbar Instanzen von Klassen enthalten doch sowieso immer nur Pointer auf die Instanz.

Zumindest ist es so, dass wenn ich...
Code:
type
  TFoo = class
    Bar: Integer
  end;

//Somewhere later...
var
  a, b: TFoo;
begin
a := TFoo.Create;
a.Bar := 1;
b := a;
b.Bar := 5;
Print(IntToStr(a.Bar));
end;


...mache, eine "5" erhalte.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 22, 2010 17:11 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
zoiX hat geschrieben:
- a * a ist deutlich schneller als Sqr(a)
- auch wenn das Internet teilweise etwas anderes sagt ist a + a nicht schneller als 2 * a
- Um mehrere Floats durch einen Wert a zu teilen ist Floats * 1 / a schneller als Floats / a, wenn man 1 / a vorberechnet (Beispielsweise beim Vektoren normieren)

Oh mein Gott. Ich muss das unbedingt mal überprüfen. Ich warte gerade eh auf ne Systeminstallation, ich glaube, ich mache mal einen Arithmetik-Benchmark für FreePascal.

greetings

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 22, 2010 17:14 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Soviel ich weiß werden, verbergen sich bei Delphi hinter Variablen, die scheinbar Instanzen von Klassen enthalten doch sowieso immer nur Pointer auf die Instanz.

Achso...ok...in C++ ist das anders. :)

Zitat:
a * a ist deutlich schneller als Sqr(a)

Vermutlich weil Sqr ein Funktionsaufruf ist und nicht inline abgehandelt wird.

Zitat:
auch wenn das Internet teilweise etwas anderes sagt ist a + a nicht schneller als 2 * a

Eine Addition ist schneller als eine Multiplikation. Allerdings ist 2*a ein Spezialfall den du durch einen einfachen Bit-Shift lösen kannst. => Vermutlich optimiert da der Compiler.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 22, 2010 17:19 
Offline
DGL Member

Registriert: Mo Aug 31, 2009 13:19
Beiträge: 151
Coolcat hat geschrieben:
Eine Addition ist schneller als eine Multiplikation. Allerdings ist 2*a ein Spezialfall den du durch einen einfachen Bit-Shift lösen kannst. => Vermutlich optimiert da der Compiler.


Tut er eher nich, denn BitShifts bei Floats sind doch...nich so gut, oder?
Ich glaub ich geh jezze mal einkaufen und komm dann mal im IRC vorbei,wenn der Thread gerade eh hochfrequentiert is xD


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 22, 2010 17:33 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Tut er eher nich, denn BitShifts bei Floats sind doch...nich so gut, oder?

Da wäre es ein +1 im Exponenten...auch sehr schnell.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 22, 2010 17:56 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Ich hab den Benchmark mal umgesetzt und ausgeführt. Jeder Test wird 10000000 mal ausgeführt. Im Anhang die Ausgabe des Programms einmal mit -O1 (normale, debuggerfreundliche Optimierung) und einmal mit -O3 (sehr starke Optimierung).

Getestet auf einem 64-Bit System. Die Werte sind relativ zu betrachten, also ist die Geschwindigkeit der CPU irrelevant.

Für die faulen gibts auch noch mal die Tests kurz ausgeschrieben, soweit nicht selbsterklärt:
Code:
SquareDirect: A * A
SquareFunc: Sqr(A)
SquarePower: Power(A, 2)
DoubleAdd: A + A
DoubleMult: 2 * A

(Nachtrag: hab gerade shl 1 für verdopplung von Ints ausprobiert, zumindest der FPC macht das schon automatisch (dauert genauso lange))

grüße


Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 22, 2010 18:13 
Offline
DGL Member

Registriert: Mo Aug 31, 2009 13:19
Beiträge: 151
Bis auf den letzten Punkt liegen meine Feststellungen also entweder am Compiler (Codegear RAD Studio hier), oder sind "subjektiv" - wie auch immer das passiert ist. Aber das Divisionen teilweise so extrem viel langsamer sind als Multiplikationen hatte ich offen gestanden nicht erwartet...

Kannst du vielleicht noch gerade benchmarken wieviel schneller ein Test auf > 0 gegen über > 0.x ist? Ich hab nämlich bei meinem Specular-Licht mal vor die Berechnung der Lichtintensität (in der ja ein Power(Single, 20 (oder irgendwas anderes großes als Exponent halt)) vorkommt, abgefragt, ob das zur zwanzigsten Potenz erhobene Skalarprodukt überhaupt groß genug ist, um nach der Rechenoperation noch wahrnehmbar zu sein. Hatte mir dadurch offen gestanden einiges an Gewinn erhofft, aber dem war nicht so (der Code war schon schneller, aber nich allzu signifikant). Vorher stand da nur die Frage, ob das Skalarprodukt größer als 0 sei.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 22, 2010 18:20 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Jup, neue Ergebnisse angehangen (Source auf anfrage).

Nop tut exakt garnichts, ist einfach eine leere Methode um den Overhead durch einen Methodenaufruf herauszubekommen. Was mir dabei auffällt ist, dass Zero ( A = 0) teilweise weniger braucht als das, was darauf hinweisen könnte, dass der Test wegoptimiert wird. Ist möglicherweise aber auch einfach Abweichung.

greetings


Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 22, 2010 20:06 
Offline
DGL Member
Benutzeravatar

Registriert: So Sep 26, 2010 12:54
Beiträge: 238
Wohnort: wieder in Berlin
Programmiersprache: Englisch
das FastInvSqrt ist deswegen so "lahm" weil es "damals" zu zeiten von lahmen rechnern schnell war........ die recheneinheiten von heute, können mittlerweile viel viel viel schneller wurzeln ziehen und quadrate bilden... würde mich auch nicht wundern wenns nicht auch bei den multimedia erweiterungen solche "funktionen" fürs invertiertewurzeln gibt.

berüchtigt ist es auch nur weil carmack genaue werte nicht interessierten und ihm einfach ein näherungswert reichte - und eben diese lassen sich per pi mal daumen schneller errechnen.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 22, 2010 20:18 
Offline
DGL Member

Registriert: Mo Aug 31, 2009 13:19
Beiträge: 151
Naja, Artikel / Blogeinträge berichten auch von mehr als 600% Geschwindigkeitsgewinn mit dem FastInvSqrt-Algorithmus gegenüber 1 / Sqrt(x), so mies war das also nich...und die Quake 3-Engine hat ja auch schon recht lang Anwendung gefunden ;)


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 17 Beiträge ]  Gehe zu Seite 1, 2  Nächste
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.010s | 15 Queries | GZIP : On ]