Professional Documents
Culture Documents
Con el fin de garantizar un cmputo uniforme entre plataformas, IEEE-754 defi nes 32 y 64 bits
Los formatos de punto flotante, que corresponden a los tipos de datos C flotan y doblan. Su
Las representaciones tienen diferentes longitudes de bits, como se ilustra en la Figura 7-2.
Dada una variable de punto flotante de 32 bits con un bit de signo s, el exponente de 8 bits e, y el significado de 23
bits v el
El valor representado se puede calcular como se muestra en la Figura 7-3.
Es importante entender que debido a este formato estndar, las variables de punto flotante pueden
Representan valores en una granularidad ms fina que las variables enteras. Sin embargo, la exactitud numrica es
An limitado. Los valores que se pueden almacenar exactamente en formato de punto flotante son discretos y
finitos.
Por ejemplo, considere el fragmento de cdigo siguiente:
Flotar a = 3,1415927f;
Flotador b = 3,1415928f;
Si (a == b) {
Printf ("a es igual a b \ n");
} Else {
Printf ("a no es igual b \ n");
Dado que el ltimo dgito de ay b difiere, se esperara que se imprimiera:
A no es igual b
Sin embargo, en arquitecturas compatibles con el estndar IEEE 754, realmente imprimir:
A es igual a b
En este ejemplo, ninguno de los valores se puede almacenar realmente en el nmero finito de bits utilizados por el
Variables de punto flotante a y b. Como resultado, estos valores se redondean al valor ms cercano que puede
Ser almacenados, lo que pasa a ser el mismo para ambos.
Los valores de punto flotante que no se pueden almacenar correctamente se redondean a valores representables
usando una
Modo de redondeo confiable. Por ejemplo, el ejemplo anterior us el comportamiento predeterminado, roundto-
closer,
Que redondea los valores no representables al valor representable ms cercano. Otros ejemplos
De los modos de redondeo incluyen redondear a cero (siempre redondo hacia el valor con una menor absoluta
Valor), redondeo y redondeo.
Otra consideracin importante en la programacin de puntos flotantes es la granularidad de la representacin
Valores de los puntos flotantes. Como se ha expuesto, los valores de punto flotante pueden representar valores a un
mximo
Granularidad que los valores enteros. Sin embargo, slo pueden almacenar valores a intervalos discretos.
Adems, a medida que los valores de los puntos flotantes se alejan de cero (tanto en lo positivo como en lo negativo
Direccin), el intervalo entre valores representables crece tambin (como se muestra en la figura 7-4).
Puede utilizar la funcin matemtica estndar C nextafterf para encontrar el siguiente flotador representable ms
alto
Valor de un valor dado. La Tabla 7-1 muestra las diferencias entre un flotador y el siguiente
Representable para algunos valores. Obsrvese la drstica prdida de precisin cuando los valores de x aumentan.
Estos grandes intervalos entre valores de punto flotante significan que la eleccin del modo de redondeo puede
tener
Un impacto significativo en la salida numrica de cualquier aplicacin en la que puedan surgir valores extremos.
Las instrucciones que funcionan con valores de punto flotante se conocen naturalmente como instrucciones de
punto flotante.
CUDA soporta todas las operaciones aritmticas habituales para puntos flotantes tales como adicin,
Multiplicacin, divisin y sustraccin.
Como se mencion anteriormente, CUDA y otros modelos de programacin que se adhieren al IEEE 754
Niveles de precisin en el punto flotante: 32 bits y 64 bits. Estos diferentes formatos se conocen tambin como
De una sola precisin y doble precisin, respectivamente. Debido a que las variables de doble precisin usan el doble
Muchos bits como variables de precisin nica, los valores de doble precisin pueden representar correctamente
muchos ms
valores. Esto significa que el conjunto de valores de precisin doble tiene una granularidad ms fina y una mayor
Rango que los valores de precisin nica. Por ejemplo, considere una versin del punto flotante anterior
Ejemplo de precisin que utiliza flotantes de doble precisin y no de precisin simple:
Doble a = 3,1415927;
Doble b = 3,1415928;
Si (a == b) {
Printf ("a es igual a b \ n");
} Else {
Printf ("a no es igual b \ n");
}
Este cdigo produce el resultado esperado:
A no es igual b
Porque los valores representables ms cercanos para a y b no son los mismos cuando se almacenan usando la
precisin doble
Variables.
Tenga en cuenta que aunque todas las GPU NVIDIA compatibles con el procesador admiten puntos de flotacin de
precisin nica,
Necesitan una GPU NVIDIA de capacidad de clculo 1.3 o superior para utilizar valores de doble precisin.
Sin embargo, incluso los valores de doble precisin tienen sus lmites. Una seccin posterior de este captulo titulada
"SinglePrecision
Vs Double-Precision "explorar ms cuantitativamente los desafos del punto flotante
La programacin y las diferencias entre el punto flotante de precisin simple y doble.
Funciones intrnsecas y estndar
Adems de la separacin entre operaciones de precisin simple y doble, CUDA tambin categoriza
Todas las funciones aritmticas como funciones intrnsecas o estndar. Las funciones estndar se utilizan para
Las operaciones de soporte que son accesibles y estandarizadas a travs del host y el dispositivo. Estndar
Las funciones incluyen operaciones aritmticas de la biblioteca de matemticas estndar C, como sqrt, exp y sin.
Las operaciones de una instruccin como la multiplicacin y la adicin tambin se incluyen como funciones estndar.
Las funciones intrnsecas de CUDA slo se pueden acceder desde el cdigo del dispositivo. En la programacin, una
funcin
Intrnseco o incorporado, implica que el compilador tiene un conocimiento especial sobre su comportamiento, que
Permite la optimizacin ms agresiva y la generacin de instrucciones especializadas. Esto es cierto para CUDA
Funciones intrnsecas. De hecho, muchas funciones trigonomtricas se implementan directamente en hardware en
GPUs porque se usan mucho en aplicaciones grficas (para realizar traducciones, rotaciones y
As sucesivamente para aplicaciones visuales 3D).
En CUDA, muchas funciones intrnsecas estn relacionadas con una funcin estndar, lo que significa que una norma
Existe una funcin que implementa la misma operacin. Por ejemplo, la funcin estndar
La realizacin de una raz cuadrada de punto de flotar de doble precisin es sqrt. La versin intrnseca que
implementa la misma funcionalidad es __dsqrt_rn. Existe incluso una funcin intrnseca para la precisin simple
Divisin de puntos flotantes, __fdividef.
Las funciones intrnsecas se descomponen en menos instrucciones que sus funciones estndar equivalentes. Como
Un resultado, las funciones intrnsecas son ms rpidas que sus funciones estndar equivalentes pero menos
numricamente
preciso. Esto le da la capacidad de usar funciones estndar e intrnsecas intercambiablemente, pero
Producen un comportamiento diferente del programa en trminos de rendimiento y exactitud numrica.
Las funciones estndar e intrnsecas aaden una cantidad significativa de fl exibilidad a cualquier aplicacin CUDA.
Sirven como mandos de granulado fino que puede convertir para ajustar el rendimiento y precisin numrica
En una operacin por operacin. En una seccin posterior de este captulo titulada "Estndar vs. Intrnseco
Funciones "tendrs experiencia prctica ajustando estas perillas para explorar sus efectos Instrucciones atmicas
Una instruccin atmica realiza una operacin matemtica, pero lo hace en una sola operacin ininterrumpida
Sin interferencias de otros hilos. Cuando un subproceso completa correctamente un
Atmica en una variable, puede estar seguro de que el cambio de estado de la variable no ha terminado
No importa cuntos otros subprocesos tengan acceso a esa variable. Debido a que las instrucciones atmicas
impiden
Mltiples hilos de interferir entre s, permiten operaciones read-modify-write para datos
Compartidos entre los subprocesos (por ejemplo, leer el valor actual, incrementarlo y escribir el nuevo valor).
Garantizar la atomicidad de las operaciones de lectura-modificacin-escritura es especialmente importante en
situaciones altamente concurrentes
Como la GPU. CUDA proporciona funciones atmicas que realizan read-modify-write
Operaciones atmicas en 32 bits o 64 bits de memoria global o memoria compartida.
Mientras que cualquier dispositivo con capacidad de clculo 1.1 o superior soporta operaciones atmicas, basado en
Kepler
Las operaciones de memoria atmica global son ms rpidas que las operaciones basadas en Fermi, lo que
Mayor rendimiento. Esto puede permitir que las aplicaciones basadas en CUDA
Considerados impracticables para la ejecucin de la GPU debido a su gran dependencia de las operaciones atmicas.
Al igual que las funciones estndar e intrnsecas, cada funcin atmica implementa una
Operacin, como suma, multiplicacin o sustraccin. A diferencia de cualquier otro tipo de instruccin
Descritas hasta ahora, las instrucciones atmicas tienen un comportamiento defi nido cuando operan en una
ubicacin de memoria
Compartida por dos hilos competidores.
Considere el siguiente kernel simple para ayudarle a entender este concepto:
__global__ void incr (int * ptr) {
Int temp = * ptr;
Temp = temp + 1;
* Ptr = temp;
}
Este kernel lee desde una ubicacin de memoria, aade uno a ese valor y luego escribe el valor calculado
Valor a la misma ubicacin. Tenga en cuenta que no se utilizan identificadores de subproceso para cambiar las
ubicaciones de memoria
Ser accedido; Cada subproceso en un lanzamiento del kernel leer y escribir desde la misma direccin. Si un solo
Bloque de 32 subprocesos se inici con este kernel, qu producto esperara? T podras
Digamos 32: Cada hilo aumentar en uno. En verdad, el valor resultante no est definido. El problema
Aqu es causada por ms de un hilo escribiendo en la misma ubicacin de memoria. Esto se llama un
Carrera de datos o acceso inseguro a la memoria. Una carrera de datos se define formalmente como dos o ms hilos
independientes de ejecucin que acceden a la misma ubicacin, donde al menos uno de esos accesos est
modificando
Esa ubicacin. Usted no tiene manera de saber que ganar la carrera para escribir hasta que el programa es
Ejecutado. Por lo tanto, el resultado de esta o cualquier aplicacin que contiene carreras de datos es ms
Difcil de determinar.
Afortunadamente, las instrucciones atmicas evitan este comportamiento indeseable. Se accede a las instrucciones
atmicas
A travs de la API CUDA como funciones. Por ejemplo:
Int atomicAdd (int * M, int V);
La mayora de las funciones atmicas son funciones binarias, realizando una operacin en dos operandos. Toman
Como entrada una posicin de memoria M y un valor V. La operacin asociada con la funcin atmica es
Ejecutado en V y el valor ya almacenado en la posicin de memoria, * M. El resultado se escribe
Volver a la misma ubicacin de memoria.
Las funciones atmicas se pueden dividir en tres grupos: funciones aritmticas, funciones bit a bit y swap
Funciones. Las funciones aritmticas atmicas realizan aritmtica simple en la ubicacin de memoria de destino
E incluyen operaciones comunes como sumar, restar, mximo, mnimo, incremento y decremento.
Las funciones atmicas bit a bit realizan una operacin bit a bit en la ubicacin de memoria destino e incluyen
Bit a bit AND, bit a bit OR, y bit a bit XOR. El intercambio atmico funciona de forma condicional o
Intercambiar incondicionalmente el valor de una ubicacin de memoria con un nuevo valor. Funciones de
intercambio atmico siempre
Devuelve el valor originalmente almacenado en la ubicacin de destino, independientemente de si el intercambio
tiene xito.
AtomicExch reemplaza incondicionalmente el valor almacenado. AtomicCAS condicionalmente reemplaza el valor
Almacenado si el valor actualmente almacenado coincide con un valor esperado especificado por el subproceso GPU
que llama.
Como ejemplo, recuerde el ncleo de incremento anterior:
__global__ void incr (int * ptr) {
Int temp = * ptr;
Temp = temp + 1;
* Ptr = temp;
}
Puede volver a escribir el ncleo incr utilizando la funcin atomicAdd. AtomicAdd agrega atmicamente una
Valor V al valor almacenado en la posicin de memoria M. El kernel incr actualizado a continuacin utiliza una
instruccin
Para incrementar el valor almacenado en la ubicacin ptr y devuelve el valor almacenado en ptr antes de la
incremento.
__global__ void incr (__ global__ int * ptr) {
Int temp = atomicAdd (ptr, 1);
}
Con estos cambios, el comportamiento de este kernel est ahora bien defi nido. Si se lanzaron 32 subprocesos,
El valor almacenado en * ptr tendra que ser 32.
Por otro lado, qu sucede si su aplicacin no requiere que todos los subprocesos incrementen con xito
el objetivo? Qu pasa si slo le importaba si uno o algunos hilos en una urdimbre tuvo xito? Como ejemplo,
considere
El ncleo siguiente:
__glob Al__ void check_threshold (int * arr, umbral int, int * flag) {si (arr [blockIdx.x * blockDim.x + threadIdx.x]>
umbral) {* flag = 1; }}
Aqu cada hilo est comprobando su valor contra un umbral. Si ese valor est por encima del umbral,
Se fija la tasa global. Debido a que todos los subprocesos estn operando en el mismo global fl ag, si varios valores
son
Por encima del umbral, entonces la asignacin a la bandera es insegura.
Sera posible eliminar estos accesos inseguros usando atomicExch:
Int atomicExch (int * M, int V);
AtomicExch reemplaza incondicionalmente el valor almacenado en M con V y devuelve el valor anterior.
Reescribiendo el kernel check_threshold con atomicExch elimina los accesos inseguros al flag:
__global__ void check_threshold (int * arr, umbral int, int * flag) {
Si (arr [blockIdx.x * blockDim.x + threadIdx.x]> umbral) {
AtomicExch (bandera, 1);
}
}
Para este ejemplo, es realmente necesario usar atomicExch? En este caso, si usa accesos inseguros,
Todava estn garantizados que al menos un hilo escribir a * flag con xito. Usar atomicExch hace
No modificar el comportamiento de este kernel. Sera posible utilizar simplemente accesos inseguros en
Check_threshold y an tienen una aplicacin funcionalmente correcta. De hecho, el uso de atomicExch y
Otras operaciones atmicas pueden degradar signifi- cativamente el rendimiento. Sin embargo, al considerar este
tipo de
Optimizacin debe ser muy cuidadoso de que la operacin no depende realmente de los resultados de
Hilo visible. Si check_threshold realizaba un incremento como forma de contar el nmero
De valores por encima del umbral, el uso de accesos inseguros no sera vlido.
Las instrucciones atmicas son potentes en un entorno altamente paralelo como la GPU. Proporcionan un
Manera segura de operar en valores compartidos por cientos o miles de hilos. Mientras que las funciones atmicas
No sufren preocupaciones adicionales de precisin (como hacen las funciones intrnsecas), su uso puede
Degradar el rendimiento. En una seccin posterior de este captulo titulada "Entender las instrucciones atmicas"
Explorar por qu.
--ftz=[true, false] Enjuaga todas las false Cuando se establece Cuando se establece
Punto flotante en true, en
denormal Esta bandera podra Falsa, esta bandera
Valores a cero. Una mejorar el Podra mejorar
descripcion rendimiento, exactitud,
De los nmeros dependiente dependiente
denormales Sobre los valores Sobre los valores
Est fuera del Procesado y Procesado y
alcance de Aritmtica realizada Aritmtica realizada
Este libro, pero su en tus en tus
presencia solicitud. solicitud.
En su aplicacin
Puede requerir todo
o algunos
Operaciones
aritmticas para
Tomar cdigo menos
eficiente
Caminos
(dependiendo de
Si tienes un
preFermi
O GPU post-Fermi).
--prec-div= Mejora el nmero true Cuando se establece Cuando se establece
[true,false] Exactitud de toda la en true, en
precisin nica Podra haber Verdadero,
Divisiones y actuacin numrico
Reciprocos degradacin compatibilidad
con el
Norma IEEE
Mejora
--prec-sqrt= Fuerzas true Cuando se establece Cuando se establece
[true,false] numricamente ms en true, en
Raz cuadrada exacta Podra haber Verdadero,
funcin actuacin numrico
degradacin compatibilidad
con el
Norma IEEE
Mejora
--fmad=[true,false] Controla si el true Habilitacin de Habilitacin de
El compilador est FMAD FMAD
autorizado a Mejora el Podra reducir
Fusionar rendimiento, La exactitud de
operaciones de previsto su aplicacin.
multiplicar y agregar Hay loco
En una sola FMAD Operaciones en
instruccin punto flotante
Variables en su
solicitud.
--use_fast _math Reemplaza todos los false Habilitacin --use_ Habilitacin --use_
Funciones en su Traje rpido Traje rpido
aplicacin Implica un nmero Podra disminuir
Con su intrnseco De optimizaciones El numrico
Funcin Habilitado, todos Exactitud de su
equivalentes. Eso De los cuales solicitud.
Tambin establece mejoran
--ftz = true, actuacin.
--prec-div = false, y
--prec-sqrt = false
Adems de la opcin --fmad, CUDA tambin incluye un par de funciones intrnsecas que se pueden utilizar
Para controlar la generacin de la instruccin FMAD: __fmul y __dmul. Estas funciones implementan el punto
flotante
Multiplicacin para los tipos flotante y doble. Si bien estas funciones no afectan el rendimiento
De la operacin de multiplicacin, llamndolos en el lugar de un operador * impide nvcc
De utilizar esa multiplicacin como parte de la optimizacin MAD. Por ejemplo, en el cdigo anterior
Sample of the kernel foo, --fmad = false se us para evitar la generacin de una instruccin mad.f32. los
El mismo efecto podra haber sido logrado insertando una llamada a __fmul:
__global__ void foo (float * ptr) {
Ptr = __fmul_rn (* ptr, * ptr) + * ptr;
}
Tenga en cuenta que __fmul y __dmul impiden la generacin de instrucciones MAD independientemente de si
--fmad = true o --fmad = false se especifica. Como resultado, es posible tener habilitada la optimizacin del
compilador MAD globalmente, al tiempo que mejora la robustez numrica de ciertos clculos por
Llamando selectivamente __fmul o __dmul.
Usted puede haber notado que cuando __fmul fue llamado en foo, la llamada fue en realidad a una funcin
__fmul_rn. Muchas funciones intrnsecas de punto flotante (incluyendo __fadd, __fsub, __fmul, etc.)
Indicar explcitamente el modo de redondeo de punto flotante en el nombre de la funcin utilizando un sufijo de dos
caracteres
X (resumido en la Tabla 7-4). Recurdese que debido a que las variables de punto flotante todava pueden
representar
Discretos aunque de grano fino, cualquier valor irrepresentable debe ser redondeado a valores representables.
El modo de redondeo de una operacin de punto flotante determina cmo se convierten los valores irrepresentables
A valores representables.
Sufij sentido
o
Rn Valores redondeados que no se pueden representar con precisin en el punto flotante actual
(Simple o doble) al valor ms cercano que se pueda representar. Esto es
El comportamiento predeterminado.
Rz Los valores siempre redondos hacia cero (es decir, los valores mayores que cero son redondeados
Abajo y los valores menos que cero se redondean hacia arriba).
Ru Siempre redondea los valores hacia el infinito positivo.
rd Siempre redondea los valores hacia abajo hacia el infinito negativo
Ahora que ha visto los cambios de nivel de instruccin causados por la habilitacin o deshabilitacin de la FMAD
Optimizacin, tambin se puede observar el efecto de estos cambios en la exactitud numrica. T
Puede descargar, construir y ejecutar el ejemplo de fmad.cu desde Wrox.com. Este ejemplo ejecuta un solo
Operacin MAD en el host y una sola operacin MAD en el dispositivo usando funciones estndar.
Compilar fmad.cu con diferentes valores para el --fmad fl ag le permite comparar los resultados de
Kernels CUDA que se ejecutan con y sin la optimizacin MAD con respecto a un valor de
anfitrin.
Primero, intente compilar fmad.cu con la optimizacin MAD CUDA activada. Tenga en cuenta que tambin podra
Deje el parmetro --fmad = true fuera, ya que por defecto es true.
$ Nvcc -arch = sm_20 --fmad = true fmad.cu -o fmad
La ejecucin de la aplicacin generada produce la siguiente salida de ejemplo:
F
El dispositivo emite un valor diferente del host, diff = 8.881784e-16.
Como era de esperar, utilizando la optimizacin MAD llev a pequeos errores numricos en el dispositivo. Fmad.cu
puede
Tambin se compilar con la optimizacin del compilador MAD explcitamente deshabilitada:
$ Nvcc -arch = sm_20 --fmad = false fmad.cu -o fmad La ejecucin de la aplicacin deshabilitada MAD produce la
siguiente salida de ejemplo:
F
El dispositivo emite el mismo valor que el host.
Con FMAD deshabilitado, los valores producidos por el host y el dispositivo son idnticos. Sin embargo, el dispositivo
El kernel ahora requerir ms instrucciones para realizar este clculo.
Resumen
Esta seccin demostr el amplio y omnipresente impacto que los estndares e intrnsecos
Funciones del programa (como se resume en la Tabla 7-5). En muchas situaciones, puede controlar
Cmo se generan las instrucciones por el compilador, lo cual es extremadamente til cuando
Aplicacin para el rendimiento y precisin numrica.
Descripcin de las instrucciones atmicas
En esta seccin, usted explorar cmo usar las operaciones atmicas y aprender sobre la implementacin correcta
Operaciones en datos compartidos en un entorno altamente concurrente. Tenga en cuenta que las GPUs de
diferentes
Capacidad de apoyo diferentes funciones atmicas. Necesitar tener acceso a una GPU con capacidad de clculo
1.0 o superior para ejecutar los ejemplos en esta seccin.
Desde el principio
Cada funcin atmica proporcionada por CUDA puede ser reintroducida usando una sola funcin atmica:
Operador de comparacin y intercambio atmico (CAS). Atomic CAS es una operacin poderosa que no slo
Le permiten defi ne sus propias funciones atmicas en CUDA, sino tambin ayuda con una comprensin ms
profunda
De las operaciones atmicas en general.
CAS toma como entrada tres elementos: Una ubicacin de memoria, un valor esperado en esa ubicacin de memoria
y
El valor que desea almacenar en esa ubicacin de memoria. A continuacin, realiza los siguientes pasos:
1. Lea la ubicacin de destino y compare el valor almacenado all con el valor esperado.
a. Si el valor almacenado es igual al valor esperado, la ubicacin de la memoria objetivo se llena con
El valor deseado.
segundo. Si el valor almacenado no es igual al valor esperado, entonces no se realiza ningn cambio en el valor
ubicacin del objetivo.
2. En cualquier caso, una operacin CAS devuelve siempre el valor que encontr almacenado en el destino
ubicacin. Tenga en cuenta que al utilizar el valor devuelto, puede comprobar si hay un intercambio satisfactorio. Si el
valor
Devuelto es igual al valor esperado pasado, entonces la operacin CAS debe haber tenido xito.
Ahora, eso es slo la operacin CAS. Un CAS atmico implica que todo el proceso CAS se realiza
Sin interferencia de otros hilos. Porque es un operador atmico, si el valor de retorno de
La operacin CAS indica que la escritura tuvo xito, entonces ese cambio se debe haber hecho visible
A todos los otros hilos tambin.
Para aprender ms sobre las operaciones atmicas, ser til para usted implementar un ejemplo atmico
Funcin desde el suelo utilizando la funcin de dispositivo CUDA atomicCAS. Para este ejemplo, usted ser
Implementando la adicin entera atmica de 32 bits. La firma de la variante pertinente de atomicCAS es:
Int atomicCAS (int * address, int compare, int val);
Aqu direccin es la ubicacin de la memoria de destino, comparar es el valor que se espera que en esa ubicacin,
Y val es el valor que desea escribir en esa ubicacin.
Entonces, cmo podras implementar una adicin atmica usando atomicCAS? Primero tendr que descomponer
Adicin en sus componentes y defi nindolo como una operacin CAS. Una tcnica til
Cuando la implementacin de operaciones atmicas personalizadas es defi nir los estados de inicio y finalizacin del
objetivo.
Con un agregado atmico, el estado inicial es el valor base que se incrementar. El acabado
Estado es la suma del estado inicial y el valor de incremento. Esta definicin se traduce directamente a
AtomicCAS: El valor esperado es el estado inicial y el valor deseado es el estado final.
Para implementar una funcin de adicin atmica personalizada, se iniciar con una firma de funcin que
Una ubicacin para agregar y un valor para aadir a ella:
__device__ int myAtomicAdd (int * direccin, int incr) {
...
}
Puede calcular un valor esperado para el objetivo simplemente leyendo la ubicacin de memoria de destino.
El valor deseado es defi nido por el valor ledo ms el valor incre que se pasa a myAtomicAdd.
Usando estos valores esperados y deseados, se puede hacer una llamada a atomicCAS que implemente una
adicin:
__device__ int myAtomicAdd (int * direccin, int incr) {
// Crea una conjetura inicial para el valor almacenado en * address.
Int esperado = * direccin;
Int oldValue = atomicCAS (direccin, esperado, esperado + incr);
...
}
Esta funcin myAtomicAdd ya puede realizar un atmico agregar! Sin embargo, la operacin slo
Tener xito si el valor ledo en esperado es tambin el valor almacenado en la direccin cuando el atomicCAS es
Realizado. Debido a que la ubicacin de destino es compartida por mltiples subprocesos (de lo contrario, las
operaciones atmicas
No es necesario), es posible que otro hilo modifique el valor en la direccin entre
Siendo ledo en esperado y modificado por atomicCAS. Si eso sucediera, la atomicCAS
Fallan porque el valor actual en la direccin y el valor de esperado seran diferentes.
Recuerde que el fallo es sealado por un valor de retorno atomicCAS que difiere del valor esperado.
Utilizando esta informacin, myAtomicAdd puede comprobar si hay un error y repetir la comparacin y el
intercambio en un
Hasta que atomicCAS tenga xito:
__device__ int myAtomicAdd (int * direccin, int incr) {
// Crea una conjetura inicial para el valor almacenado en * address.
Int esperado = * direccin;
Int oldValue = atomicCAS (direccin, esperado, esperado + incr);
// Loop while expected es incorrecto.
While (oldValue! = Esperado) {
Expected = oldValue;
OldValue = atomicCAS (direccin, esperado, esperado + incr);
}
Return oldValue;
}
Las tres primeras lneas de esta funcin son las mismas que las anteriores. Si falla la primera atomicCAS,
MyAtomicAdd ahora loops mientras el ltimo valor devuelto por atomicCAS sea diferente del
valor esperado. Una vez que esa condicin falla, el intercambio debe haber tenido xito, y myAtomicAdd sale
el lazo. De lo contrario, el valor esperado se restablece al valor ms reciente ledo y se realiza un reintento. A
Coincide con la semntica de otras funciones atmicas CUDA, myAtomicAdd tambin devuelve el valor que fue
Reemplazado en la ubicacin de destino devolviendo el valor ms reciente devuelto por atomicCAS.
Puede descargar, crear y ejecutar una copia de este cdigo en my-atomic-add.cu desde Wrox.com. Construir
como sigue:
$ Nvcc -arch = sm_11 my-atomic-add.cu
Aunque la siguiente seccin cubre las funciones atmicas que CUDA apoya nativamente, es importante
Para entender que usted no est limitado a ellos. Con atomicCAS puedes implementar una
Gama de operaciones atmicas segn lo requiera su aplicacin particular.
Funciones atmicas CUDA incorporadas
CUDA soporta una coleccin de funciones atmicas. El subconjunto de los accesibles depende de
La capacidad de clculo de su dispositivo.
El soporte para funciones atmicas comienza en la capacidad de clculo 1.1. En este nivel, usted tendr acceso a
Funciones que manipulan valores de 32 bits en la memoria global.
Compatibilidad con la manipulacin de valores de 32 bits en memoria compartida y valores de 64 bits en memoria
global
Con capacidad de clculo 1.2. Soporte para manipulaciones de 64 bits en memoria compartida comienza con
Capacidad de clculo 2.0.
La Tabla 7-6 enumera las operaciones para las que CUDA apoya una funcin atmica, la CUDA asociada
La funcin del dispositivo y los tipos soportados.