【问题标题】:How to use CUDA tex1DFetch with cudaTextureObject_t?如何将 CUDA tex1DFetch 与 cudaTextureObject_t 一起使用?
【发布时间】:2019-03-26 01:09:31
【问题描述】:

当我注意到纹理引用已被弃用时,我正在使用它们,我尝试更新我的测试函数以使用带有 tex1Dfetch 的“新”无绑定纹理对象,但无法产生相同的结果。

我目前正在探索使用纹理内存来加速我的 aho-corasick 实现;我能够让tex1D() 使用纹理引用,但是,我注意到它们已被弃用并决定使用纹理对象。

当我尝试以任何方式使用结果时,我的内核出现了一些非常奇怪的行为;我可以毫无问题地执行results[tidx] = tidx;,但results[tidx] = temp + 1; 只返回temp 的值而不是temp * 3 或任何其他涉及temp 的数值测试。

我看不出这种行为的逻辑原因,文档示例看起来很相似,以至于我看不出哪里出错了。

我已经阅读了 CUDA tex1Dfetch() 错误行为和新 CUDA 纹理对象 — 在 2D 情况下获取错误数据,但似乎都与我遇到的问题无关。

以防万一;我正在使用带有 Nvidia GTX 980ti 的 CUDA 版本 10.0、V10.0.130。

#include <iostream>

__global__ void test(cudaTextureObject_t tex ,int* results){
    int tidx = threadIdx.y * blockDim.x + threadIdx.x;
    unsigned temp = tex1Dfetch<unsigned>(tex, threadIdx.x);
    results[tidx] = temp * 3;
}

int main(){
    int *host_arr;
    const int host_arr_size = 8;

    // Create and populate host array
    std::cout << "Host:" << std::endl;
    cudaMallocHost(&host_arr, host_arr_size*sizeof(int));
    for (int i = 0; i < host_arr_size; ++i){
        host_arr[i] = i * 2;
        std::cout << host_arr[i] << std::endl;
    }

    // Create resource description
    struct cudaResourceDesc resDesc;
    resDesc.resType = cudaResourceTypeLinear;
    resDesc.res.linear.devPtr = &host_arr;
    resDesc.res.linear.sizeInBytes = host_arr_size*sizeof(unsigned);
    resDesc.res.linear.desc = cudaCreateChannelDesc<unsigned>();
    // Create texture description
    struct cudaTextureDesc texDesc;
    texDesc.readMode = cudaReadModeElementType;
    // Create texture
    cudaTextureObject_t tex;
    cudaCreateTextureObject(&tex, &resDesc, &texDesc, NULL);

    // Allocate results array
    int * result_arr;
    cudaMalloc(&result_arr, host_arr_size*sizeof(unsigned));

    // launch test kernel
    test<<<1, host_arr_size>>>(tex, result_arr);

    // fetch results
    std::cout << "Device:" << std::endl;
    cudaMemcpy(host_arr, result_arr, host_arr_size*sizeof(unsigned), cudaMemcpyDeviceToHost);
    // print results
    for (int i = 0; i < host_arr_size; ++i){
        std::cout << host_arr[i] << std::endl;
    }

    // Tidy Up
    cudaDestroyTextureObject(tex);
    cudaFreeHost(host_arr);
    cudaFree(result_arr);
}

我希望上面的工作类似于下面的工作(确实有效):


texture<int, 1, cudaReadModeElementType> tex_ref;
cudaArray* cuda_array;

__global__ void test(int* results){
    const int tidx = threadIdx.x;
    results[tidx] = tex1D(tex_ref, tidx) * 3;
}

int main(){
    int *host_arr;
    int host_arr_size = 8;

    // Create and populate host array
    cudaMallocHost((void**)&host_arr, host_arr_size * sizeof(int));
    for (int i = 0; i < host_arr_size; ++i){
        host_arr[i] = i * 2;
        std::cout << host_arr[i] << std::endl;
    }

    // bind to texture
    cudaChannelFormatDesc cuDesc = cudaCreateChannelDesc <int >();
    cudaMallocArray(&cuda_array, &cuDesc, host_arr_size);
    cudaMemcpyToArray(cuda_array, 0, 0, host_arr , host_arr_size * sizeof(int), cudaMemcpyHostToDevice);
    cudaBindTextureToArray(tex_ref , cuda_array);
    // Allocate results array
    int * result_arr;
    cudaMalloc((void**)&result_arr, host_arr_size*sizeof(int));

    // launch kernel
    test<<<1, host_arr_size>>>(result_arr);

    // fetch results
    cudaMemcpy(host_arr, result_arr, host_arr_size * sizeof(int), cudaMemcpyDeviceToHost);
    // print results
    for (int i = 0; i < host_arr_size; ++i){
        std::cout << host_arr[i] << std::endl;
    }

    // Tidy Up
    cudaUnbindTexture(tex_ref);
    cudaFreeHost(host_arr);
    cudaFreeArray(cuda_array);
    cudaFree(result_arr);
}

预期结果:

Host:
0
2
4
6
8
10
12
14
Device:
0
6
12
18
24
30
36
42

实际结果:

Host:
0
2
4
6
8
10
12
14
Device:
0
2
4
6
8
10
12
14

有谁知道到底出了什么问题?

【问题讨论】:

    标签: cuda textures


    【解决方案1】:

    CUDA API 函数调用返回错误代码。您想检查这些错误代码。尤其是当某些事情明显出了问题某处......

    您使用相同的数组来存储初始数组数据以及从设备接收结果。您的内核启动失败并出现非法地址错误,因为您没有有效的纹理对象。您没有有效的纹理对象,因为创建纹理对象失败。内核启动后的第一个 API 调用是 cudaMemcpy() 以获取结果。由于内核启动期间出现错误,cudaMemcpy() 将失败,返回最新的错误而不是执行复制。结果,host_arr 缓冲区的内容没有改变,您最终只是再次显示原始输入数据。

    documentation(强调我的)中解释了创建纹理对象失败的原因:

    如果 cudaResourceDesc::resType 设置为 cudaResourceTypeLinear,则 cudaResourceDesc::res::linear::devPtr 必须设置为有效的设备指针,它与 cudaDeviceProp::textureAlignment 对齐。 […]

    纹理对象不能引用主机内存。您的代码中的问题出在此处:

    resDesc.res.linear.devPtr = &host_arr;
    

    您需要在设备内存中分配一个缓冲区,例如,使用cudaMalloc(),将您的数据复制到那里,并创建一个引用该设备缓冲区的纹理对象。

    此外,您的texDesc 未正确初始化。在您的情况下,只需对其进行零初始化就足够了:

    struct cudaTextureDesc texDesc = {};
    

    【讨论】:

    • 我不敢相信我错过了,感谢您的提示!我在“CUDA Pro 提示:Kepler Texture Objects 提高性能和灵活性”示例中看到了 memset 初始化,因此认为这是必要的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-29
    • 2021-07-03
    • 1970-01-01
    • 2019-07-07
    • 2015-12-18
    • 2020-12-16
    • 2022-01-25
    相关资源
    最近更新 更多