TheGhostInc schreef op zondag 22 maart 2009 @ 13:59:
Elke generatie processoren/ontwikkeltalen verder is de kans dat je nog iets zinnigs kunt maken van wat de processor intern doet een stapje minder. Want het woord brancheprediction is hier nog niet gevallen, en met de huidige pipeline lengtes van 12 of meer, is de penalty voor een foute voorspelling al fors groter dan de enkele instructie extra die hier wordt genoemd.
Akkoord dat door alle extra abstractielagen het moeilijker wordt om in alle situaties te gaan voorspellen wat er intern gebeurd. Gooi daar ook nog de Just-in-time compiler bij en het wordt zeker moeilijk.
Het zou me echter wel heel sterk verwonderen dat dit voor de branchpredictor ook maar iets uitmaakt.
Aangezien je vaak iets doet met de uitkomst van je byte berekeningen, zou je de branchepredictor weleens volledig op het verkeerde been kunnen zetten door bytes ipv integers te gebruiken. Voorbeeldje:
code:
1
2
3
4
5
| byte a = 129
byte b = 64
a = a + a (= 258 -> 2)
intern komt er nu een stap van integer naar byte, dus a gaat van 258 naar 2
if (a > b) (=FALSE) |
De branchepredictor had a waarschijnlijk gegokt op de uitkomst uit de integer vergelijking, wat 258 was (=TRUE), maar door het omzetten naar een byte klapt de if statement om.
Ik moet toegeven dat ik niet perfect op de hoogte ben van hoe alle moderne branch-predictors werken, maar vziw gebruiken ze allemaal een soort van geschiedenis. (Behalve de heel simpele die gezoon altijd true veronderstellen.)
Welke conditie er dan ook geëvalueerd wordt, de predictor maakt zijn beslissing gebaseerd op vorige beslissingen. Het maakt dus doorgaans niets uit welke parameters er juist geëvalueerd worden, wel de geheugenadressen waarop die parameters staan en de voorgaande beslissingen die op basis daarvan genomen worden. Typisch op basis van een waarde in een tabel, en die waarde wordt aangepast bij de branch zelf.
Het voorbeeld dat je geeft suggereert ergens dat de branchpredictor weet welke logica juist uitgevoerd wordt en met welke parameters, maar meestal heeft dat geen betekenis voor de branchpredictor. Die rekent zelf immers niets uit. Indien die dat wel zou doen kan je bijna net zo goed geen branch-prediction doen.
Maar indien je hier meer van weet leer ik graag bij

Afhankelijk hoe de omzetting van integer naar byte wordt gedaan, kan de branchepredictor dit mogelijk niet aan zien komen (bijvoorbeeld als de laatste 3 bytes van de integer naar 0 worden gezet).
Bespaar je misschien 3 bytes, maar is de code 10-100x langzamer.
Zelfs indien het toch zo zo zijn dat dit een invloed heeft, dan wil dit nog steeds niet zeggen dat de code veel langzamer wordt, dat hangt te sterk af van de code in kwestie. Typisch wanneer je met bytes werkt zijn de getallen waarmee je werkt ook kleiner dan 256 of 127 indien signed. Vertrouwen op overflow-gedrag lijkt me zowiezo een beetje verkeerd want het maakt de code er niet duidelijker op.
Maar zelfs al maakt je branch-predictor in dit geval iedere keer de verkeerde beslissing, als je in dat geval van die byte-array telkens 1000 keer een kopie maakt zal het wel degelijk veel sneller zijn dan wanneer je al die data in een int-array zou stoppen.
Maar het blijft natuurlijk onmogelijk om er in het algemene geval uitspraken over te doen, want het is al redelijk low level performance tuning. De laatste keer dat ik zelf voordeel gehaald heb uit deze details was bij de GoT programming contest