No hay manera en CUDA (o en las GPU NVIDIA) para que un hilo interrumpa la ejecución de todos los hilos en ejecución. No se puede tener la salida inmediata del kernel tan pronto como se encuentre un resultado, simplemente no es posible hoy.
Pero puede hacer que todos los hilos salgan tan pronto como sea posible después de que un hilo encuentre un resultado. Aquí hay un modelo de cómo lo haría.
__global___ void kernel(volatile bool *found, ...)
{
while (!(*found) && workLeftToDo()) {
bool iFoundIt = do_some_work(...); // see notes below
if (iFoundIt) *found = true;
}
}
Algunas notas sobre esto.
- Tenga en cuenta el uso de
volatile
. Esto es importante.
- ¡Asegúrese de inicializar
found
— que debe ser un puntero de dispositivo — a false
antes de iniciar el kernel!
- Los hilos no se cerrarán instantáneamente cuando otro hilo actualice
found
. Saldrán solo la próxima vez que regresen a la parte superior del ciclo while.
- Cómo implementar
do_some_work
asuntos. Si es demasiado trabajo (o muy variable), entonces el retraso para salir luego de que se encuentre un resultado será largo (o variable).Si es demasiado poco trabajo, entonces sus hilos pasarán la mayor parte de su tiempo chequeando found
en lugar de hacer un trabajo útil.
do_some_work
también es responsable de asignar tareas (es decir, calcular/incrementar índices), y cómo lo hace es específico del problema.
- Si la cantidad de bloques que ejecuta es mucho mayor que la ocupación máxima del núcleo en la presente GPU, y no se encuentra una coincidencia en la primera "oleada" de bloques de hilos, entonces este kernel (y el siguiente) puede un punto muerto Si se encuentra una coincidencia en la primera oleada, los bloques posteriores solo se ejecutarán después de
found == true
, lo que significa que se iniciarán y luego saldrán inmediatamente. La solución es lanzar solo tantos bloques como puedan residir simultáneamente (también conocido como "lanzamiento máximo") y actualizar su asignación de tareas en consecuencia.
- Si el número de tareas es relativamente pequeño, puede reemplazar el
while
con un if
y ejecutar los hilos suficientes para cubrir el número de tareas. Entonces no hay posibilidad de un punto muerto (pero se aplica la primera parte del punto anterior).
workLeftToDo()
es específico de un problema, pero devolvería falso cuando no queda trabajo por hacer, para que no se interrumpa en el caso de que no se encuentre coincidencia.
Ahora, lo anterior puede dar lugar a un excesivo vaciado de particiones (todos los subprocesos golpean la misma memoria), especialmente en arquitecturas antiguas sin caché L1. Así que es posible que desee escribir una versión un poco más complicada, utilizando un estado compartido por bloque.
__global___ void kernel(volatile bool *found, ...)
{
volatile __shared__ bool someoneFoundIt;
// initialize shared status
if (threadIdx.x == 0) someoneFoundIt = *found;
__syncthreads();
while(!someoneFoundIt && workLeftToDo()) {
bool iFoundIt = do_some_work(...);
// if I found it, tell everyone they can exit
if (iFoundIt) { someoneFoundIt = true; *found = true; }
// if someone in another block found it, tell
// everyone in my block they can exit
if (threadIdx.x == 0 && *found) someoneFoundIt = true;
__syncthreads();
}
}
De esta manera, un hilo por encuestas en bloque la variable global, y sólo hilos que encontrar una coincidencia alguna vez escribir en él, por lo que el tráfico de memoria global se reduce al mínimo.
A un lado: las funciones __global__ son nulas porque es difícil definir cómo devolver valores de 1000 s de hilos en un solo subproceso de CPU. Es trivial para el usuario idear una matriz de retorno en el dispositivo o memoria de copia cero que se adapte a su propósito, pero difícil de hacer un mecanismo genérico.
Descargo de responsabilidad: Código escrito en el navegador, no probado, no verificado.
aquí hay una queja que recibí, pero todavía quiero que la función global pueda responder tan pronto como reciba la cadena correcta ... QUOTE Puede usar un indicador de memoria compartida jerárquica dentro de CTA y un indicador de memoria global para comunicarse en todas las CTA y ambos deben ser volátiles. Todos los hilos/CTA revisan periódicamente estos indicadores para ver si continúan buscando (el que encuentra que la cadena lo actualiza). CITA –