Performance Doubles vs Floats

Pagina: 1
Acties:

  • Mischa_NL
  • Registratie: Mei 2004
  • Laatst online: 01-02-2023
Hallo Allemaal!

Na veel gelezen te hebben kwam ik tot de conclusie dat de XNA Vector2 class niet voldeed. Daarom heb ik een DoubleVector class geschreven die zoals de naam al zegt werkt met doubles.

Tot mijn grote verbazing zijn doubles in de meeste gevallen sneller dan floats (singles).
Ik compile mijn programma naar 32bit, en dan lijkt het me dat doubles (64bit) 2 cycles nodig heeft en een single 1.

Toch blijkt niks minder waar!
Hier de testresultaten:

Optellen 100.000.000 keer:
Vector2: 1,5215385s
dVec2: 4,1205239

Vermenigvuldigen 10.000.000 keer:
Vector2: 6,6963624s2,5680953s
dVec2: 3,0714592s

BaryCentre 10.000.000 keer:
Vector2: 16,3185189s13,2084785s
dVec2: 6,4234776s

Bij optellen zijn de resultaten zoals verwacht, bij vermenigvuldigen en het barycentre uitrekenen (een vrij zware) is het echter compleet omgekeerd.

Ik gebruik de stopwatch class in c# en hoewel die (geen idee) misschien niet zeer precies is, zijn de resultaten zodanig verschillend dat er duidelijk een performance verschil is!

De baryCentric functie is overigens als volgt:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
    public static dVec2 Barycentric(dVec2 a, dVec2 b, dVec2 c, double b2, double b3)
    {
        a.X = ((1 - b2 - b3) * a.X) + (b2 * b.X) + (b3 * c.X);
        a.Y = ((1 - b2 - b3) * a.Y) + (b2 * b.Y) + (b3 * c.Y);
        return a;
    }

    public static Vector2 Barycentric(Vector2 a, Vector2 b, Vector2 c, float b2, float b3)
    {
        a.X = ((1 - b2 - b3) * a.X) + (b2 * b.X) + (b3 * c.X);
        a.Y = ((1 - b2 - b3) * a.Y) + (b2 * b.Y) + (b3 * c.Y);
        return a;
    }


Nu de vraag:
Hoe kan het dat dit het geval is? Heeft het wellicht te maken met casting wat intern gebeurd?

[ Voor 20% gewijzigd door Mischa_NL op 11-02-2010 18:21 ]


  • OMX2000
  • Registratie: Januari 2001
  • Laatst online: 01:03

OMX2000

By any means necessary...

ik ben geen expert, maar ik denk dat het ook te maken kan hebben met de FPU.

Dè developers podcast in je moerstaal : CodeKlets Podcast


  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
Omdat je XNA gebruikt, moet je even opletten dat alle code die geschreven is in het framework (Vector2 dus) op de XBOX360 wel gebruikt maakt van de FPU. Maar je eigen code op geen manier gebruik kan maken van de FPU.

Verder snap ik niet waarom jouw dVec2 barycentric functie sneller is als een double. Immers heb je aangetoond dat floats sneller + - en * doen. En barycentric is slechts een combinatie van die functies.

Edit: oops

~ Mijn prog blog!


  • Mischa_NL
  • Registratie: Mei 2004
  • Laatst online: 01-02-2023
roy-t schreef op donderdag 11 februari 2010 @ 18:39:
Omdat je XNA gebruikt, moet je even opletten dat alle code die geschreven is in het framework (Vector2 dus) op de XBOX360 wel gebruikt maakt van de FPU. Maar je eigen code op geen manier gebruik kan maken van de FPU.

Verder snap ik niet waarom jouw dVec2 barycentric functie sneller is als een double. Immers heb je aangetoond dat floats sneller + - en * doen. En barycentric is slechts een combinatie van die functies.
Ik heb de barycentre functie recht van mdsn maar na wat meer test lijkt het erop dat daar het een en ander extra gebeurt in die functie... Dat zou het verschil zomaar eens kunnen maken...
Een normalize echter scheelt ook maar honderdsten om 10.000.000 iteraties... Ik vind het vrij onverklaarbaar dat de double niet gewoon 2X zo traag is maar in sommige gevallen bijna net zo snel of soms zelfs iets sneller is...

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 12-09 15:31
Mischa_NL schreef op donderdag 11 februari 2010 @ 18:14:
Ik compile mijn programma naar 32bit, en dan lijkt het me dat doubles (64bit) 2 cycles nodig heeft en een single 1.
Dat is met de huidige processorarchitecturen zeker niet het geval. Als je alleen op pure geheugensnelheid van de RAM geheugenbanken moet afgaan zou je misschien een factor twee verwachten, maar bij de snelheid van het uitvoeren van instructies spelen nog veel meer factoren een rol, zoals out-of-order execution, pipelining, caching, branch prediction, verschillende soorten instructies, memory alignment, etc.
Mischa_NL schreef op donderdag 11 februari 2010 @ 18:59:
[...]
Een normalize echter scheelt ook maar honderdsten om 10.000.000 iteraties... Ik vind het vrij onverklaarbaar dat de double niet gewoon 2X zo traag is maar in sommige gevallen bijna net zo snel of soms zelfs iets sneller is...
Er zijn een heleboel oorzaken te verzinnen. Een simpele is bijvoorbeeld dat als je 10.000.000 keer met dezelfde vector aan het rekenen bent je 100% in de CPU cache bezig bent. Of dat je de memory allocater aan het benchmarken bent bijvoorbeeld. De manier waarop je benchmarkt maakt dus nogal veel uit.

Daarnaast kan er ook een verschil zijn in de uiteindelijke machinecode die voor beide versies wordt gegenereerd. Post die anders eens :)

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 12-09 15:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zou het kunnen zijn dat de dVec2 structure intern te groot is om by value op de stack mee te geven, en de JIT compiler dus eigenlijk gewoon references rondpassed, waardoor je dus feitelijk overhead aan het meten bent (je berekening is immers ook niet zo heel erg ingewikkeld en tijdrovend).

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1