Seit dem Release von .Net 4.6 am 20 Juli ist neben vielen anderen neuen Features auch der neue 64-Bit Jit Compiler RyuJIT und damit neue SIMD-Befehle (Single Instruction Multiple Data) verfügbar. Einige offizielle Infos dazu finden sich z. B. auf dem .Net Blog unter den Punkten RyuJIT und SIMD [1]. Was versteckt sich nun konkret hinter dem Stichwort SIMD bei .Net? Es handelt sich um den Namensraum System.Numerics [2]. Die darin enthaltenen Strukturen ähneln dem Vector3, Vector2, der Matrix4x4 und weiteren Strukturen, wie man sie auch in SharpDX, SlimDX oder bei mir in Seeing# wiederfindet. Der Unterschied ist, dass bei den verschiedenen Methoden – falls verfügbar – speziell optimierte Prozessorfunktionen angesprochen werden und diese damit entsprechend schneller ausgeführt werden.
Ein erster Blick über die Strukturen im Namensraum System.Numerics offenbart aber auch schon einen relativ großen Unterschied zu SharpDX: Die meisten Methoden bieten keine Überladungen mit ref/out Parametern. Dadurch wird bei den Vektor- und Matrix-Methoden tendenziell mehr am Stack hin und her kopiert. Wie in der Diskussion hier [3] und hier [4] zu sehen, ist das auch der Grund, warum SharpDX noch nicht auf die neuen Funktionen wechselt und bei dem bisherigen, eigenen Coding bleibt.
Unabhängig von dieser Diskussion wollte ich die Auswirkungen auf Seeing# testen und habe mich heute hingesetzt, und die Vektor/Matrix-Funktionen auf den neuen Namensraum System.Numerics umgestellt. Hierzu ist noch zu sagen, dass diese Sachen auch bei mir ursprünglich aus dem SharpDX Projekt kommen. Die Umstellung an sich habe ich eigentlich auf einen relativ einfachen Weg gemacht:
- Die Strukturen Vector4, Vector3, Vector2, Matrix4x4, Matrix3x2 und Quaternion auskommentiert
- Alle vorherigen Verweise auf System.Numerics umgestellt
- Div. Methodenaufrufe und abweichende Methodennamen / Parameter geändert
- Die nun fehlenden Methoden in statischen Klassen Vector4Ex, Vector3Ex, usw. implementiert
Das ganze Prozedere hat insgesamt ca. 3-4 Stunden gedauert, war also nicht einmal so wild, wie ich es mir anfangs vorgestellt habe.
Das Ergebnis ist relativ gut. Insgesamt bin ich bei einer Szene mit 8000 animierten Objekten ca. 3 Millisekunden pro Frame schneller als vorher (bei insgesamt knapp über 30 Millisekunden), also um ca. 10%. Bei einer Szene mit 8000 statischen Objekten ist praktisch kein Unterschied zu erkennen – klar, hier laufen auch nicht wirklich viele Berechnungen. Getestet habe ich n 64-Bit, .Net 4.6, aktivierter Codeoptimierung und innerhalb des Windows Desktops. Insgesamt sieht es also gut aus und ich denke auch, dass ich die Funktionen so drin lasse.
Das Coding befindet sich aktuell noch in der Branch simd_instructions von Seeing# [5], werde aber relativ bald in den Hauptzweig mergen.
Verweise
- http://blogs.msdn.com/b/dotnet/archive/2015/07/20/announcing-net-framework-4-6.aspx
- https://msdn.microsoft.com/en-us/library/system.numerics(v=vs.111).aspx
- http://forums.paradox3d.net/t/using-system-numerics/219
- https://github.com/dotnet/corefx/issues/157
- https://github.com/RolandKoenig/SeeingSharp/tree/simd_instructions/SeeingSharp