在 OpenCL 中对不同的数据项执行不同的任务



总之,我正在寻找处理计算的第一步是两个计算昂贵的分支之间的条件分支的情况的方法。

我本质上是在尝试实现一个对图像和掩码进行操作的图形过滤器 - 掩码是与图像大小相同的位图数组,过滤器根据掩码的值执行不同的操作。所以我基本上想为每个像素做这样的事情:

if(mask == 1) {
    foo();
} else {
    bar();
}

其中foobar都是相当昂贵的操作。据我了解,当我在GPU上运行此代码时,它必须为每个像素计算两个分支。(如果掩码有两个以上的可能值,这将变得更加昂贵。有什么办法可以避免这种情况吗?

我能想到的一个选择是,在主机代码中,根据当时掩码的值将所有像素分类为两个一维数组,然后在它们上使用完全不同的内核;然后从两个数据集重建图像。这样做的问题是,就我而言,我想迭代运行过滤器,并且图像和蒙版都会随着每次迭代而变化(蒙版实际上是从图像计算出来的(。如果我在主机代码中将图像拆分为两个存储桶,我必须将图像和掩码的每次迭代从 GPU 传输,然后将新存储桶传输回 GPU,从而引入新的瓶颈来替换旧瓶颈。

有没有其他方法可以避免这个瓶颈?

另一种方法可能是使用掩码在每个工作组内执行简单的存储桶排序。

因此,为每个掩码值添加一个本地内存数组和原子计数器。首先读取每个工作项的像素(或一组像素可能更好(,递增适当的原子计数,并将像素地址写入数组中的该位置。

然后执行工作组屏障。

然后,作为最后阶段,将一组工作项(可能是基础向量大小的倍数(分配给每个数组并循环访问它。然后,您的操作将在很大程度上是高效的,除非在末端有一些损失,并且如果您查看每个工作项的足够像素,即使您将整个组分配给一个掩码值,然后依次分配给另一个掩码值,效率损失也可能很小。

鉴于您的描述只有两个掩码值,将两个数组放入本地内存应该非常简单并且可以很好地扩展。

将线程的高要求任务推送到共享/本地内存(同步会减慢进程(并执行轻量级任务,直到所有轻量级任务完成(因此隐藏了缓慢的同步延迟(,然后执行较重的任务。

if(mask == 1) {
    uploadFoo();//heavy, upload to __local object[]
} else {
    processBar(); // compute until, then check for a foo() in local memory if any exists.
    downloadFoo();
}

也许使用生产者 - 消费者的方法。

最新更新