【问题标题】:CUDA - Separate min/max of (x,y,z) components of float3 array?CUDA - float3数组的(x,y,z)分量的最小/最大值?
【发布时间】:2018-09-21 20:38:18
【问题描述】:

我在 CUDA 设备上有一个 float3 点数组。我想快速找到 x、y 和 z 分量的最小值和最大值(分别)。

我知道已经存在大量使用归约算法来查找数组的最小值/最大值的实现,但我找不到任何对多分量变量执行相同操作的实现,或者提供提供的选项一大步。

有谁知道可以执行此操作的任何现有实现?

【问题讨论】:

    标签: c++ cuda max min minmax


    【解决方案1】:

    我想出了一个使用推力和自定义比较器的方法,

    对于任何希望做类似事情的人,您可以执行以下操作。在我的机器上,超过 1000 万个元素的数据集的性能要好 10 倍以上:

    // Comparators
    struct comp_float3_x{
        __host__ __device__
            bool operator()(const float3& lhs, const float3& rhs){
            return lhs.x < rhs.x;
        } 
    };
    
    struct comp_float3_y {
        __host__ __device__
            bool operator()(const float3& lhs, const float3& rhs) {
            return lhs.y < rhs.y;
        }
    };
    
    struct comp_float3_z {
        __host__ __device__
            bool operator()(const float3& lhs, const float3& rhs) {
            return lhs.z < rhs.z;
        }
    };
    
    void getMinMaxDeviceFloat3(Vec3i& min, Vec3i& max, const DeviceArray<float3>& points)
    {
        // Thrust does not deal with raw pointers well, wrapping is necessary
        thrust::device_ptr<float3> ptr = thrust::device_pointer_cast(points.ptr());
        thrust::pair<thrust::device_ptr<float3>, thrust::device_ptr<float3>> minmax_x = thrust::minmax_element(thrust::device, ptr, ptr + occupied_voxels, comp_float3_x());
        thrust::pair<thrust::device_ptr<float3>, thrust::device_ptr<float3>> minmax_y = thrust::minmax_element(thrust::device, ptr, ptr + occupied_voxels, comp_float3_y());
        thrust::pair<thrust::device_ptr<float3>, thrust::device_ptr<float3>> minmax_z = thrust::minmax_element(thrust::device, ptr, ptr + occupied_voxels, comp_float3_z());
    
        // Host buffers
        float3  min_x_host, min_y_host, min_z_host, max_x_host, max_y_host, max_z_host;
    
        // Copy data to host
        cudaMemcpy(&min_x_host, minmax_x.first.get(), sizeof(float3), cudaMemcpyDeviceToHost);
        cudaMemcpy(&min_y_host, minmax_y.first.get(), sizeof(float3), cudaMemcpyDeviceToHost);
        cudaMemcpy(&min_z_host, minmax_z.first.get(), sizeof(float3), cudaMemcpyDeviceToHost);
        cudaMemcpy(&max_x_host, minmax_x.second.get(), sizeof(float3), cudaMemcpyDeviceToHost);
        cudaMemcpy(&max_y_host, minmax_y.second.get(), sizeof(float3), cudaMemcpyDeviceToHost);
        cudaMemcpy(&max_z_host, minmax_z.second.get(), sizeof(float3), cudaMemcpyDeviceToHost);
    
        // Assign output
        min[0] = (int)min_x_host.x;
        min[1] = (int)min_y_host.y;
        min[2] = (int)min_z_host.z;
        max[0] = (int)max_x_host.x;
        max[1] = (int)max_y_host.y;
        max[2] = (int)max_z_host.z;
    }
    

    【讨论】:

    • 三个单独的调用和三个数据传递似乎非常低效
    • 嗯,这比在 CPU 上执行要快一个数量级,但您是对的,它比可能的要慢。我只是使用来自推力的内置模板,但可能可以编写一个自定义方法来输出 3 对向量。
    • 经过推力代码,没有别的办法了。要获得 3 个不同的 min-max 对,您必须执行 3 个单独的并行归约。
    • 您可以使用 thrust::reduce 将 3 个算法调用转换为 2 个算法调用,并让第一个找到所有 3 个组件的最大值,第二个找到所有 3 个组件的最小值。稍加努力,就有可能将其归结为一个算法调用。您的问题似乎没有指定使用推力,因此对于普通的 CUDA,在单个内核调用中完成所有操作会很简单。
    • 问题是二元谓词只会产生一个分量 X、Y 或 Z 之间的比较。据我所知,不可能将三个独立的二元谓词传递给一个并行归约,或者至少很容易使用现成的推力功能/组件。但是常规的 CUDA,我确信有时间我可以实现一些东西。只是希望有更多的交钥匙。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 2018-08-08
    • 2010-10-04
    • 1970-01-01
    相关资源
    最近更新 更多