Während eines Projekts in CUDA C stieß ich auf unerwartetes Verhalten bei Gleitkommaoperationen mit einfacher und doppelter Genauigkeit. Im Projekt fülle ich zuerst ein Array mit der Nummer in einem Kernel und in einem anderen Kernel mache ich eine Berechnung mit diesen Zahlen. Alle Variablen und Arrays sind doppelt genau, so dass ich keine Gleitkommaoperation mit einfacher Genauigkeit erwarten würde. Wenn ich jedoch die ausführbare Datei des Programms mit NVPROF analysiere, zeigt es, dass Operationen mit einfacher Genauigkeit ausgeführt werden. Wie ist das möglich?
Hier ist das kleinste Programm, das dieses Verhalten auf meiner Architektur zeigt: (behauptet und Fehler fangen wurde weggelassen). Ich benutze eine Nvidia Tesla k40 Grafikkarte.
%Vor%Die Ausgabe von NVPROF (bearbeitet, um es lesbarer zu machen, wenn Sie die volle Ausgabe benötigen, fragen Sie einfach in den Kommentaren):
%Vor%Ich habe festgestellt, dass wenn ich die Division in Zeile 16 lösche:
%Vor%Die Ausgabe ist wie erwartet: Nulloperationen mit einfacher Genauigkeit und genau 100 Operationen mit doppelter Genauigkeit werden ausgeführt. Weiß jemand, warum die Division das Programm dazu veranlasst, Flux mit einfacher Genauigkeit und 10-mal mehr Gleitkommaoperationen mit doppelter Genauigkeit zu verwenden? Ich habe auch versucht, intrinsics (__ddiv_rn) zu verwenden, aber das hat das Problem nicht gelöst.
Vielen Dank im Voraus!
Obwohl ich immer noch nicht herausgefunden habe, warum es die einfache Genauigkeit verwendet, habe ich dank @EOF eine "Lösung" für dieses Problem gefunden. Ersetzen der Division durch Multiplikation mit dem Reziprok von Rho hat die Arbeit:
%Vor%Wie bereits erwähnt, verfügen CUDA-Geräte nicht über Anweisungen zur Gleitkommadivision in Hardware. Statt dessen gehen sie von einer anfänglichen Annäherung an den Kehrwert des Nenners aus, der von einer einzigen Präzisionsfunktionseinheit geliefert wird. Das Produkt mit dem Zähler wird dann iterativ verfeinert, bis der Bruch der Maschinengenauigkeit entspricht.
Sogar die __ddiv_rn()
intrinsic wird von ptxas in diese Befehlssequenz kompiliert, so dass die Verwendung keinen Unterschied macht.
Sie können nähere Einblicke gewinnen, indem Sie den Code mit cuobjdump -sass
selbst untersuchen, obwohl dies schwierig ist, da keine offizielle Dokumentation für die Shader-Assemblierung zur Verfügung steht, außer der bare Liste von Anweisungen .
Ich werde den folgenden Rohknotenkern als Beispiel verwenden:
%Vor%Dies wird in die folgende Shader-Assembly für ein compute function 3.5-Gerät kompiliert:
%Vor% Der Befehl MUFU.RCP64H
liefert die anfängliche Annäherung des Reziproken. Es arbeitet auf den hohen 32 Bits des Nenners ( y
) und liefert die hohen 32 Bits der Doppelpräzisionsapproximation und wird deshalb als Gleitkommaoperationen (Einzelpräzisionsspecial) durch die Profiler.
Es gibt eine weitere Anweisung FFMA
mit einfacher Genauigkeit, die weiter unten als eine Hochdurchsatzversion zum Testen einer Bedingung verwendet wird, bei der keine volle Genauigkeit erforderlich ist.
Tags und Links cuda precision single-precision