优化CUDA中的随机访问读取和随机访问写入

时间:2016-02-24 17:46:56

标签: cuda gpgpu

我想优化随机访问读取和随机访问写入以下代码:

__global__ void kernel(float* input, float* output, float* table, size_t size)
{
int x_id = blockIdx.x * blockDim.x + threadIdx.x;
if (x_id > size)
    return;

float in_f = input[x_id];
int in_i = (int)(floor(in_f));
int table_index = (int)((in_f - float(in_i)) * 1024000.0f );
float* t = table + table_index;
output[table_index] = t[0] * in_f;

}

如您所见,表和输出的索引是在运行时确定的,完全是随机的。

我知道我可以使用纹理内存或__ldg()来读取这些数据。 所以,我的问题是:

  1. 有没有更好的方法来读取随机索引的数据而不是使用纹理内存或__ldg()
  2. 上面output[table_index]的随机访问写法怎么样?
  3. 实际上,我在这里添加代码以提供随机访问读写的示例。我不需要代码优化,我只需要高级描述处理这种情况的最佳方法。

1 个答案:

答案 0 :(得分:5)

在GPU上随机访问数据没有神奇的子弹。

最好的建议是尝试执行数据重组或其他一些方法来规范数据访问。对于重复/重度访问模式,即使对数据进行排序操作等密集方法也可能导致性能整体净改善。

由于您的问题意味着随机访问是不可避免的,因此您可以做的主要是智能地使用缓存。

L2是一个设备范围的缓存,所有DRAM访问都通过它。因此,如果你有大规模的随机访问,那么L2的颠簸可能是不可避免的。没有任何函数可以禁用(有选择地或以其他方式)L2进行读或写访问。

对于较小规模的案例,您可以做的主要是通过"非L1"之一来路由访问。高速缓存,即cc3.5及更高GPU上的texture cache(在所有GPU上)和the Read-Only cache(即__ldg())。使用这些缓存可能有两种方式:

  1. 对于某些会破坏线性组织L1的访问模式,由于这些缓存使用了不同的缓存策略,您可能会在纹理或只读缓存中获得一些缓存命中。

    < / LI>
  2. 在同时使用L1缓存的设备上,路由&#34;随机&#34;通过备用缓存的流量将保持L1&#34;未受污染&#34;因此不太可能捶打。换句话说,L1可能仍然为其他访问提供缓存优势,因为它不会被随机访问所淹没。

  3. 请注意,如果使用__ldg() const __restrict__装饰volatile的适当指针,编译器可能会为您通过只读缓存路由流量,而无需明确使用volatile

    类似于上面关于保护L1的建议,它可能在某些设备上有意义,在某些情况下,可以执行加载和存储在&#34;未缓存的&#34;时尚。您通常可以通过使用volatile here让编译器为您处理此问题。您可以保持普通和-Xptxas dlcm=cg指向相同数据的指针,以便您可以规范的访问可以使用&#34;普通&#34;指针和&#34;随机&#34;访问可以使用{{1}}版本。追求未缓存访问的其他机制是使用keyword(例如{{1}}),或者通过适当使用ptxas compiler switches并使用适当的inline PTX来管理加载/存储操作。< / p>

    &#34;未缓存&#34;建议是我可以提供的主要建议&#34;随机&#34;写道。使用caching modifiers可能会为某些访问模式带来一些好处,但我认为它不可能对随机模式进行任何改进。