2011-10-06 6 views
11

A diferencia de barrier() (que creo que entiendo), mem_fence() no afecta a todos los elementos del grupo de trabajo. La especificación OpenCL dice (sección 6.11.10), por mem_fence():En OpenCL, ¿qué hace mem_fence(), a diferencia de barrier()?

Ordenes cargas y almacenamientos de un elemento de trabajo ejecutando un kernel.

(por lo que se aplica a un elemento de trabajo simple).

Pero, al mismo tiempo, en la sección 3.3.1, se dice que:

Dentro de una memoria de elemento de trabajo tiene carga/almacenamiento consistencia.

así dentro de un elemento de trabajo la memoria es constante.

¿Para qué sirve el mem_fence()? No funciona en todos los artículos, pero no es necesario en un artículo ...

Tenga en cuenta que no he usado operaciones atómicas (sección 9.5, etc.). ¿La idea de que mem_fence() se utiliza junto con ésos? Si es así, me gustaría ver un ejemplo.

Gracias.

The spec, for reference.

actualización: Puedo ver lo que es útil cuando se utiliza con barrier() (implícitamente, ya que la barrera llama mem_fence()) - pero seguro que debe haber más, ya que existe por separado?

+0

Esta presentación proporciona un ejemplo para vallas de memoria: previene e. gramo. un reordenamiento de '' '' shared_var = value; lock = false; '' '' (https://people.maths.ox.ac.uk/gilesm/cuda/new_lectures/lec3.pdf) Para un solo elemento de trabajo aislado, este reordenamiento no importaría, porque para el trabajo individual parece que no hay ninguna dependencia entre estas variables => la consistencia requerida se da dentro del elemento de trabajo. Además, este artículo demostró ser útil: https://en.wikipedia.org/wiki/Memory_barrier. –

Respuesta

6

Para tratar de poner más claramente (con suerte),

mem_fence() espera hasta que todas las lecturas/escrituras a la memoria local y/o global hecha por el elemento de trabajo llamando antes de mem_fence() son visibles para todos los hilos en el grupo de trabajo.

que proviene de: http://developer.download.nvidia.com/presentations/2009/SIGGRAPH/asia/3_OpenCL_Programming.pdf

operaciones de memoria se pueden reordenar para que se adapte al dispositivo que se están ejecutando en. La especificación establece (básicamente) que cualquier reordenación de las operaciones de memoria debe garantizar que la memoria esté en un estado constante dentro de un único elemento de trabajo. Sin embargo, ¿qué sucede si (por ejemplo) realiza una operación de tienda y el valor decide vivir en un caché específico de un elemento de trabajo por ahora hasta que se presente un tiempo mejor para escribir en la memoria local/global? Si intenta cargar desde esa memoria, el elemento de trabajo que escribió el valor lo tiene en su caché, por lo que no hay problema. Pero otros elementos de trabajo dentro del grupo de trabajo no lo hacen, por lo que pueden leer el valor incorrecto. Colocar una valla de memoria garantiza que, en el momento de la llamada a la valla de memoria, la memoria local/global (según los parámetros) se hará coherente (cualquier caché se vacíe, y cualquier reordenamiento tendrá en cuenta que usted espera que otros hilos puedan necesidad de acceder a estos datos después de este punto).

Admito que todavía es confuso, y no juraré que mi comprensión es 100% correcta, pero creo que es al menos la idea general.

Seguimiento:

me encontré con este enlace que habla sobre las cercas de memoria CUDA, pero la misma idea general se aplica a OpenCL:

http://developer.download.nvidia.com/compute/cuda/2_3/toolkit/docs/NVIDIA_CUDA_Programming_Guide_2.3.pdf

Comprobar la sección de memoria B.5 Funciones de valla.

Tienen un ejemplo de código que calcula la suma de una matriz de números en una llamada. El código está configurado para calcular una suma parcial en cada grupo de trabajo. Luego, si hay más suma que hacer, el código tiene el último grupo de trabajo que hace el trabajo.

Por lo tanto, básicamente se hacen 2 cosas en cada grupo de trabajo: Una suma parcial, que actualiza una variable global, luego el incremento atómico de una variable global de contador.

Después de eso, si queda trabajo por hacer, el grupo de trabajo que incrementó el contador al valor de ("tamaño de grupo de trabajo" - 1) se considera el último grupo de trabajo. Ese grupo de trabajo continúa para terminar.

Ahora, el problema (como lo explican) es que, debido a la reordenación de la memoria y/o el almacenamiento en caché, el contador puede aumentar y el último grupo de trabajo puede comenzar a hacer su trabajo antes de esa suma parcial global variable ha tenido su valor más reciente escrito en la memoria global.

Una valla de memoria asegurará que el valor de esa variable de suma parcial sea consistente para todos los hilos antes de pasar la valla.

Espero que esto tenga algún sentido. Es confuso.

+0

pero en el ejemplo que das, el otro hilo no puede estar seguro de que los datos estén almacenados sin una barrera. así que necesitas la barrera de todos modos. Supongo que no puse eso en la pregunta original, pero no veo cómo la mem_fence tiene sentido solo (cuando no se utiliza con una barrera). lo siento si me falta algo y gracias por el comentario ... –

+0

Agregué más detalles arriba. Espero que esto ayude. –

+0

bien, entonces el ejemplo de cuda incluye una operación atómica, que es lo que sospechaba que era necesario para que mem_fence fuera útil. para referencia futura, la equivalencia entre las funciones opencl y cuda se describe aquí - http://developer.amd.com/documentation/articles/pages/OpenCL-and-the-AMD-APP-SDK.aspx#four –

0

La cerca asegura que las cargas y/o las tiendas emitidas antes de que la cerca se complete antes de cualquier carga y/o tiendas emitidas después de la cerca. No se implica nada solo en las vallas. La operación de barrera admite una valla de lectura/escritura en uno o ambos espacios de memoria, así como el bloqueo hasta que todos los elementos de trabajo en un grupo de trabajo de dador lleguen a ella.

0

Así es como yo lo entiendo (todavía estoy tratando de verificarlo)

memory_fence sólo hará que la memoria es consistente y visible para todos los hilos en el grupo, es decir, la ejecución no se detiene, hasta hay otra transacción de memoria (local o global). Lo que significa que si hay una instrucción de movimiento o una instrucción de agregar después de memory_fence, el dispositivo continuará ejecutando estas instrucciones de "transacción sin memoria".

barrier por el otro lado se detendrá la ejecución, punto. Y solo continuará después de que todos los hilos lleguen a ese punto Y se hayan borrado todas las transacciones de memoria.

En otras palabras, barrier es un superconjunto de mem_fence. barrier puede resultar más costoso en términos de rendimiento que mem_fence.