Ressourcenlebensdauer und -synchronisierung
Genau wie bei Direct3D 12 muss Ihre DirectML-Anwendung (um nicht definiertes Verhalten zu vermeiden) die Objektlebensdauer und die Synchronisierung zwischen CPU und GPU korrekt verwalten. DirectML folgt einem identischen Lebenszeitmodell für Ressourcen wie Direct3D 12.
- Lebenszeitabhängigkeiten zwischen zwei CPU-Objekten werden von DirectML mit Hilfe von starken Referenzzählungen gepflegt. Ihre Anwendung muss Abhängigkeiten der CPU-Lebensdauer nicht manuell verwalten. Beispielsweise enthält jedes untergeordnete Gerät einen starken Verweis auf das übergeordnete Gerät.
- Lebensdauerabhängigkeiten zwischen GPU-Objekten oder Abhängigkeiten, die sich über CPU und GPU erstrecken, werden nicht automatisch verwaltet. Es liegt in der Verantwortung Ihrer Anwendung, sicherzustellen, dass GPU-Ressourcen mindestens bis zur gesamten Arbeit, die diese Ressource verwendet, die Ausführung der GPU abgeschlossen hat.
DirectML-Geräte
Das DirectML-Gerät ist ein threadsicheres zustandsloses Zuordnungsinstanz-Objekt. Jedes untergeordnete Gerät (siehe IDMLDeviceChild) enthält einen starken Verweis auf das übergeordnete DirectML-Gerät (siehe IDMLDevice). Dies bedeutet, dass Sie immer die übergeordnete Geräteschnittstelle von jeder untergeordneten Geräteschnittstelle abrufen können.
Ein DirectML-Gerät enthält wiederum eine starke Referenz auf das Direct3D 12-Gerät, das zum Erstellen verwendet wurde (siehe ID3D12Device und abgeleitete Schnittstellen).
Da das DirectML-Gerät zustandslos ist, ist es implizit threadsicher. Sie können Methoden auf dem DirectML-Gerät von mehreren Threads gleichzeitig aufrufen, ohne dass eine externe Synchronisierung erforderlich ist.
Im Gegensatz zum Direct3D 12-Gerät ist das DirectML-Gerät jedoch kein Singleton-Objekt. Sie können beliebig viele DirectML-Geräte erstellen. Es ist jedoch nicht möglich, Gerätekinder, die zu verschiedenen Geräten gehören, zu mischen und zu kombinieren. Beispielsweise sind IDMLBindingTable und IDMLCompiledOperator zwei Arten von Gerätekindern (beide Schnittstellen werden direkt oder indirekt von IDMLDeviceChild abgeleitet). Und Sie dürfen eine Bindungstabelle (IDMLBindingTable) nicht für einen Operator (IDMLCompiledOperator) verwenden, wenn der Operator und die Bindungstabelle zu unterschiedlichen DirectML-Geräteinstanzen gehören.
Da das DirectML-Gerät kein Singleton ist, tritt die Geräteentfernung pro Gerät auf, anstatt ein prozessweites Ereignis wie für ein Direct3D 12-Gerät zu sein. Weitere Informationen finden Sie unter Behandeln von Fehlern und Entfernen von Geräten in DirectML.
Lebensdaueranforderungen von GPU-Ressourcen
Wie Direct3D 12 synchronisiert DirectML nicht automatisch zwischen CPU und GPU. Es wird auch nicht automatisch die Ressourcen aktiv gehalten, während sie von der GPU verwendet werden. Stattdessen sind diese Zuständigkeiten Ihrer Anwendung.
Wenn Sie eine Befehlsliste ausführen, die DirectML-Verteiler enthält, muss Ihre Anwendung sicherstellen, dass GPU-Ressourcen lebendig gehalten werden, bis alle Arbeiten mit diesen Ressourcen die Ausführung der GPU abgeschlossen haben.
Im Fall von IDMLCommandRecorder::RecordDispatch für einen DirectML-Operator, der die folgenden Objekte enthält.
- Der IDMLCompiledOperator wird ausgeführt (oder stattdessen IDMLOperatorInitializer , wenn die Operatorinitialisierung ausgeführt wird).
- Der IDMLCompiledOperator sichert die Bindungstabelle, die zum Binden des Operators verwendet wird.
- Die ID3D12Resource-Objekte, die als Eingaben/Ausgaben des Operators gebunden sind.
- Die ID3D12Resource-Objekte , die ggf. als persistente und temporäre Ressourcen gebunden sind.
- Der ID3D12CommandAllocator sichert die Befehlsliste selbst.
Nicht alle DirectML-Schnittstellen stellen GPU-Ressourcen dar. Beispielsweise muss eine Bindungstabelle erst aktiv bleiben, wenn alle Verteiler, die sie verwenden, die Ausführung auf der GPU abgeschlossen haben. Das liegt daran, dass die Bindungstabelle selbst keine GPU-Ressourcen besitzt. Stattdessen tut dies Deskriptorheap. Daher ist der zugrunde liegende Deskriptorheap das Objekt, das bis zur Ausführung aktiv gehalten werden muss, und nicht die Bindungstabelle selbst.
In Direct3D 12 ist ein ähnliches Konzept vorhanden. Eine Befehls-Zuweisung muss lebendig bleiben, bis alle Ausführungen, die sie verwenden, auf der GPU abgeschlossen sind, da er GPU-Speicher besitzt. Eine Befehls-Liste besitzt jedoch keinen GPU-Speicher, sodass sie daher zurückgesetzt oder freigegeben werden kann, sobald sie zur Ausführung übermittelt wurde.
In DirectML müssen kompilierte Operatoren (IDMLCompiledOperator) und Operatorinitialisierer (IDMLOperatorInitializer) beide eigene GPU-Ressourcen direkt erhalten, sodass sie lebendig bleiben müssen, bis alle Dispatcher, die sie verwenden, die Ausführung auf der GPU abgeschlossen haben. Darüber hinaus müssen alle verwendeten Direct3D 12-Ressourcen (Befehlszuweisungen, Deskriptorheaps, Puffer, als Beispiele) ebenfalls von Ihrer Anwendung lebendig gehalten werden.
Wenn Sie ein Objekt vorzeitig freigeben, während es noch von der GPU verwendet wird, ist das Ergebnis nicht definiertes Verhalten, das das Risiko hat, Geräteentfernung oder andere Fehler zu verursachen.
CPU- und GPU-Synchronisierung
DirectML sendet keine Arbeit für die Ausführung auf der GPU. Stattdessen zeichnet die IDMLCommandRecorder::RecordDispatch-Methode das Dispatch dieser Arbeit in einer Befehlsliste zur späteren Ausführung auf. Ihre Anwendung muss dann die Befehlsliste für die Ausführung schließen und übermitteln, indem ID3D12CommandQueue::ExecuteCommandLists aufgerufen wird, wie bei jeder Direct3D 12-Befehlsliste.
Da DirectML keine Arbeit für die Ausführung auf der GPU sendet, werden auch keine Umgrenzungen erstellt oder eine Form der CPU-/GPU-Synchronisierung in Ihrem Auftrag ausgeführt. Es liegt in der Zuständigkeit Ihrer Anwendung, die entsprechenden Direct3D 12-Grundtypen zu verwenden, um bei Bedarf auf die Ausführung der übermittelten Arbeit auf der GPU zu warten. Weitere Informationen finden Sie unter ID3D12Fence und ID3D12CommandQueue::Signal.