Durée de vie et synchronisation des ressources

Comme avec Direct3D 12, votre application DirectML doit (afin d’éviter tout comportement non défini) gérer correctement les durées de vie et la synchronisation des objets entre l’UC et le GPU. DirectML suit un modèle de durée de vie de ressource identique à celui de Direct3D 12.

  • Les dépendances de durée de vie entre deux objets UC sont conservées par DirectML à l’aide de nombres de références fortes. Votre application n’a pas besoin de gérer manuellement les dépendances de durée de vie de l’UC. Par exemple, chaque enfant d’appareil contient une référence forte à son appareil parent.
  • Les dépendances de durée de vie entre les objets GPU ou les dépendances qui s’étendent sur l’UC et le GPU ne sont pas gérées automatiquement. Il est de la responsabilité de votre application de s’assurer que les ressources GPU vivent au moins jusqu’à ce que tout le travail utilisant cette ressource soit terminé sur le GPU.

Appareils DirectML

L’appareil DirectML est un objet fabrique sans état thread-safe. Chaque enfant d’appareil (voir IDMLDeviceChild) contient une référence forte à son appareil DirectML parent (voir IDMLDevice). Cela signifie que vous pouvez toujours récupérer l’interface de l’appareil parent à partir de n’importe quelle interface d’enfant de l’appareil.

Un appareil DirectML contient à son tour une référence forte à l’appareil Direct3D 12 qui a été utilisé pour le créer (voir ID3D12Device et interfaces dérivées).

Étant donné que l’appareil DirectML est sans état, il est implicitement thread-safe. Vous pouvez appeler des méthodes sur l’appareil DirectML à partir de plusieurs threads simultanément sans avoir besoin d’une synchronisation externe.

Toutefois, contrairement à l’appareil Direct3D 12, l’appareil DirectML n’est pas un objet singleton. Vous êtes libre de créer autant d’appareils DirectML que vous le souhaitez. Toutefois, vous ne pouvez pas mélanger et faire correspondre des enfants d’appareils appartenant à différents appareils. Par exemple, IDMLBindingTable et IDMLCompiledOperator sont deux types d’enfants d’appareils (les deux interfaces dérivent directement ou indirectement de IDMLDeviceChild). Et vous ne pouvez pas utiliser une table de liaison (IDMLBindingTable) pour lier pour un opérateur (IDMLCompiledOperator) si l’opérateur et la table de liaison appartiennent à différentes instances d’appareil DirectML.

Étant donné que l’appareil DirectML n’est pas un singleton, la suppression d’appareil se produit pour chaque appareil et non pas pour l’ensemble du processus comme c’est le cas pour un appareil Direct3D 12. Pour plus d’informations, consultez Gestion des erreurs et suppression d’appareils dans DirectML.

Exigences de durée de vie des ressources GPU

Comme Direct3D 12, DirectML ne se synchronise pas automatiquement entre l’UC et le GPU. Il ne conserve pas automatiquement les ressources actives pendant qu’elles sont utilisées par le GPU non plus. Au lieu de cela, cette responsabilité incombe à votre application.

Lors de l’exécution d’une liste de commandes qui contient des répartitions DirectML, votre application doit s’assurer que les ressources GPU restent actives jusqu’à ce que toutes les ressources utilisant ces ressources soient exécutées sur le GPU.

Dans le cas de IDMLCommandRecorder::RecordDispatch pour un opérateur DirectML, cela inclut les objets suivants.

  • IDMLCompiledOperator en cours d’exécution (ou IDMLOperatorInitializer à la place, si l’initialisation d’opérateur est effectuée).
  • IDMLCompiledOperator qui sauvegarde la table de liaison utilisée pour lier l’opérateur.
  • Les objets ID3D12Resource liés en tant qu’entrées/sorties de l’opérateur.
  • Les objets ID3D12Resource liés en tant que ressources persistantes et temporaires, le cas échéant.
  • ID3D12CommandAllocator qui sauvegarde la liste de commandes elle-même.

Toutes les interfaces DirectML ne représentent pas les ressources GPU. Par exemple, une table de liaison n’a pas besoin d’être conservée active tant que toutes les distributions qui l’utilisent n’ont pas terminé l’exécution sur le GPU. Cela est dû au fait que la table de liaison elle-même ne possède aucune ressource GPU. Au lieu de cela, c’est le tas du descripteur qui en possède. Par conséquent, le tas du descripteur sous-jacent est l’objet qui doit être conservé actif tant que l’exécution n’est pas terminée. La table de liaison elle-même n’a pas à être active.

Un concept similaire existe dans Direct3D 12. Un allocateur de commandes doit être conservé actif jusqu’à ce que toutes les exécutions qui l’utilisent soient terminées sur le GPU, étant donné que c’est l’allocateur possède la mémoire GPU. Toutefois, une liste de commandes ne possède pas de mémoire GPU. Elle peut donc être réinitialisée ou libérée dès qu’elle a été envoyée pour exécution.

Dans DirectML, les opérateurs compilés (IDMLCompiledOperator) et les initialiseurs d’opérateur (IDMLOperatorInitializer) possèdent directement les ressources GPU, de sorte qu’ils doivent être conservés actifs jusqu’à ce que toutes les distributions les utilisant aient terminé leur exécution sur le GPU. En outre, toute ressource Direct3D 12 utilisée (allocateurs de commande, tas du descripteur, mémoires tampons, par exemple) doit également être conservée en vie par votre application.

Si vous libérez prématurément un objet alors qu’il est toujours utilisé par le GPU, un comportement non défini en résulte. Cela peut provoquer la suppression de l’appareil ou d’autres erreurs.

Synchronisation du processeur et du GPU

DirectML n’envoie pas lui-même de travail pour l’exécution sur le GPU. Au lieu de cela, la méthode IDMLCommandRecorder::RecordDispatchenregistre la répartition de ce travail dans une liste de commandes pour une exécution ultérieure. Votre application doit ensuite fermer et envoyer sa liste de commandes pour l’exécution en appelant ID3D12CommandQueue::ExecuteCommandLists, comme avec n’importe quelle liste de commandes Direct3D 12.

Étant donné que DirectML n’envoie pas de travail pour l’exécution sur le GPU, il ne crée pas d’isolations, ni n’effectue de synchronisation UC/GPU pour elle. Il incombe à votre application d’utiliser les primitives Direct3D 12 appropriées pour attendre que l’exécution du travail soumis soit terminée sur le GPU, si nécessaire. Pour plus d’informations, consultez ID3D12Fence et ID3D12CommandQueue::Signal.

Voir aussi