了解浮点数减少OpenCL的方法

时间:2017-01-30 05:59:46

标签: opencl atomic

this link之后,我尝试理解内核代码的操作(此内核代码有两个版本,一个版本为volatile local float *source,另一个版本为volatile global float *source,即{{1 }和local版本)。我在下面采用global版本:

local

如果我理解的话,由于限定符“float sum=0; void atomic_add_local(volatile local float *source, const float operand) { union { unsigned int intVal; float floatVal; } newVal; union { unsigned int intVal; float floatVal; } prevVal; do { prevVal.floatVal = *source; newVal.floatVal = prevVal.floatVal + operand; } while (atomic_cmpxchg((volatile local unsigned int *)source, prevVal.intVal, newVal.intVal) != prevVal.intVal); } ”,每个工作项共享对source变量的访问权限,不是吗?

之后,如果我拿一个工作项,代码会将volatile值添加到operand变量。然后,在此操作之后,我调用newVal.floatVal函数,该函数检查先前的分配(atomic_cmpxchgpreVal.floatVal = *source;)是否已完成,即通过比较地址newVal.floatVal = prevVal.floatVal + operand;中存储的值source

在此原子操作期间(根据定义不可中断),由于preVal.intVal存储的值与source不同,prevVal.intVal存储的新值为source ,实际上是一个浮点数(因为它像整数一样编码在4个字节上)。

我们可以说每个工作项都有一个互斥锁访问权限(我的意思是锁定访问权限),位于newVal.intVal

但是对于source address线程,只有一次迭代进入each work-item

我认为会有一次迭代,因为比较“while loop”会始终将*source== prevVal.int ? newVal.intVal : newVal.intVal值分配给存储在newVal.intVal的值,不是吗?

欢迎任何帮助,因为我还没有理解这个内核代码的所有细微之处。

更新1:

抱歉,我几乎了解所有的细微差别,尤其是source address

第一种情况:对于给定的单个线程,在调用atomic_cmpxchg之前,如果while loop仍然等于prevVal.floatVal,则*source将更改atomic_cmpxchg指针中包含的值,并返回source中包含的值,该值等于old pointer,因此我们从prevVal.intVal中断。

第二种情况:如果在while loop指令和prevVal.floatVal = *source;的调用之间,值atomic_cmpxchg已经改变(由另一个线程??),那么atomic_cmpxchg返回*source值不再等于old,因此prevVal.floatVal中的条件为真,我们将保持此循环,直到不再检查先前条件为止。

我的解释是对的?

由于

1 个答案:

答案 0 :(得分:1)

  

如果我理解的话,由于限定符“volatile”,每个工作项共享对源变量的访问权限,不是吗?

volatile是C语言的关键字,它阻止编译器优化对内存中特定位置的访问(换句话说,在每次读/写所述内存位置时强制加载/存储)。它对底层存储的所有权没有影响。这里,它用于强制编译器在每次循环迭代时从内存中重新读取source(否则编译器将被允许将该负载移出循环,这会破坏算法)。

do {
    prevVal.floatVal = *source; // Force read, prevent hoisting outside loop.
    newVal.floatVal = prevVal.floatVal + operand;
} while(atomic_cmpxchg((volatile local unsigned int *)source, prevVal.intVal, newVal.intVal) != prevVal.intVal)

删除限定符(为简单起见)和重命名参数后,atomic_cmpxchg的签名如下:

int atomic_cmpxchg(int *ptr, int expected, int new)

它的作用是:

atomically {
    int old = *ptr;

    if (old == expected) {
        *ptr = new;
    }

    return old;
}

总结一下,每个线程分别执行:

  1. *source的当前值从内存加载到preVal.floatVal
  2. *source
  3. 中计算newVal.floatVal的所需值
  4. 执行上述原子比较交换(使用类型惩罚值)
  5. 如果atomic_cmpxchg == newVal.intVal的结果,则表示比较交换成功,中断。否则,交换没有发生,请转到1再试一次。
  6. 上面的循环最终终止,因为最终,每个线程成功完成atomic_cmpxchg

      

    我们可以说每个工作项都有一个互斥锁访问(我的意思是一个锁定的访问权限)到位于源地址的值。

    互斥锁是锁,而这是一种无锁算法。 OpenCL可以用自旋锁模拟互斥锁(也用原子实现),但这不是一个。