Barreras de UAV y barreras de estado de recursos en DirectML
Requisitos de barrera de vista de acceso desordenado (UAV)
Barreras de UAV en Direct3D 12
En Direct3D 12, el sombreador de cálculo adyacente se distribuye dentro de la misma lista de comandos para ejecutarse en paralelo en la GPU, a menos que se sincronicen con una barrera de vista de acceso desordenado (UAV) intermedia. Esto puede mejorar el rendimiento aumentando el uso del hardware de GPU. Sin embargo, de manera predeterminada, sin el uso de una barrera UAV, la ejecución en paralelo de dos distribuciones adyacentes puede provocar una condición de carrera si existe una dependencia de datos entre las dos distribuciones; o si ambas distribuciones realizan escrituras de UAV en las mismas regiones de memoria.
Una barrera UAV obliga a todos las distribuciones realizadas previamente a completar la ejecución en la GPU antes de que puedan comenzar las distribuciones posteriores. Las barreras UAV se usan para sincronizar entre distribuciones en la misma lista de comandos para evitar carreras de datos. Puede emitir una barrera UAV mediante el método ID3D12GraphicsCommandList::ResourceBarrier.
Barreras de UAV en DirectML
En DirectML, los operadores se distribuyen de forma similar a la manera en que los sombreadores de cálculo se distribuyen en Direct3D 12. Es decir, las distribuciones adyacentes de operadores pueden ejecutarse en paralelo en la GPU, a menos que exista una barrera de UAV intermedia entre ellos. Un modelo de Machine Learning típico contiene dependencias de datos entre sus operadores; por ejemplo, la salida de un operador se alimenta en la entrada de otra. Por lo tanto, es importante usar barreras de UAV para sincronizar correctamente las distribuciones.
DirectML garantiza que solo leerá de los tensores de entrada (y nunca escribirá en ellos). También garantiza que nunca fabricará escrituras en un tensor de salida fuera del intervalo del miembro DML_BUFFER_TENSOR_DESC::TotalTensorSizeInBytes del tensor. Esto significa que las dependencias de datos entre operadores de DirectML pueden estar sujetas a análisis examinando solo los enlaces de entrada y salida de un operador.
Por ejemplo, estas garantías permiten distribuir dos operadores que enlazan la misma región de un recurso como entrada, sin tener que emitir una barrera UAV intermedia. Esto siempre es seguro porque DirectML nunca escribe en tensores de entrada. Como otro ejemplo, siempre es seguro enlazar los tensores de salida de dos distribuciones de operadores simultáneos al mismo recurso de Direct3D 12 (siempre que sus tensores no se superpongan), ya que DirectML nunca escribe fuera de los límites de un tensor (tal como se define en el DML_BUFFER_TENSOR_DESC::TotalTensorSizeInBytes del tensor).
Dado que las barreras UAV son una forma de sincronización, el uso innecesario de barreras UAV podría afectar negativamente al rendimiento. Por lo tanto, es mejor usar el número mínimo de barreras de UAV necesarias para sincronizar correctamente las distribuciones en una lista de comandos.
Ejemplo 1
En el ejemplo siguiente, la salida de un operador de convolución se introduce en una activación ReLU, seguida de una normalización por lotes.
CONVOLUTION (conv1)
|
ACTIVATION_RELU (relu1)
|
BATCH_NORMALIZATION (batch1)
Dado que existe una dependencia de datos entre los tres operadores, necesitará una barrera UAV entre cada distribución sucesiva (consulte IDMLCommandRecorder::RecordDispatch).
dmlCommandRecorder->RecordDispatch(d3d12CommandList,
conv1)
d3d12CommandList->ResourceBarrier(
Barrera UAV)
dmlCommandRecorder->RecordDispatch(d3d12CommandList,
relu1)
d3d12CommandList->ResourceBarrier(
Barrera UAV)
dmlCommandRecorder->RecordDispatch(d3d12CommandList,
batch1)
Ejemplo 2
MAX_POOLING (pool1)
/ \
CONVOLUTION CONVOLUTION
(conv1) (conv2)
\ /
JOIN (join1)
Aquí la salida de la agrupación se introduce en dos convoluciones, cuyas salidas se concatenan mediante el operador JOIN. Existe una dependencia de datos entre pool1
y conv1
y conv2
, así como entre conv1
y conv2
y join1
. Esta es una manera válida de ejecutar este grafo.
dmlCommandRecorder->RecordDispatch(d3d12CommandList,
pool1)
d3d12CommandList->ResourceBarrier(
Barrera UAV)
dmlCommandRecorder->RecordDispatch(d3d12CommandList,
conv1)
dmlCommandRecorder->RecordDispatch(d3d12CommandList,
conv2)
d3d12CommandList->ResourceBarrier(
Barrera UAV)
dmlCommandRecorder->RecordDispatch(d3d12CommandList,
join1)
En este caso, conv1
y conv2
pueden ejecutarse simultáneamente en la GPU, lo que puede mejorar el rendimiento.
Requisitos de estado de barrera de recursos
Como autor de la llamada, es su responsabilidad asegurarse de que todos los recursos de Direct3D 12 estén en el estado de barrera de recursos correcto antes de ejecutar distribuciones de DirectML en la GPU. DirectML no realiza ninguna barrera de transición en su nombre.
Antes de la ejecución de IDMLCommandRecorder::RecordDispatch en la GPU, debe realizar la transición de todos los recursos enlazados al estado D3D12_RESOURCE_STATE_UNORDERED_ACCESS o a un estado que se pueda promover implícitamente a D3D12_RESOURCE_STATE_UNORDERED_ACCESS, como D3D12_RESOURCE_STATE_COMMON. Una vez completada esta llamada, los recursos permanecen en el estado D3D12_RESOURCE_STATE_UNORDERED_ACCESS. Para obtener más información, consulte Enlaces en DirectML.