PointCloudLibrary / pcl

Point Cloud Library (PCL)
https://pointclouds.org/
Other
9.89k stars 4.61k forks source link

[gpu::NormalEstimation] Error:out of memory #6055

Closed QiuYilin closed 4 months ago

QiuYilin commented 4 months ago

Describe the bug

When creating the neighbor point index memory space, a larger wrong value will be generated, causing memory overflow.

Context

I want to use the cuda accelerated version of NormalEstimation to calculate the normals of a point cloud.

Expected behavior

The calculation process of the neighboring points of normal estimation should be to find the points within the given radius and the total number is less than maxnn.If the required space does exceed the memory, an exception will be thrown.

Current Behavior

When the number of points or maxnn is small, the program runs normally. When the number of points and maxnn are large, the memory will overflow.During debugging, the size value in the "DeviceArray::create(std::size_t size)" step of creating the memory of NeighborIndices is incorrect.

To Reproduce

My code:


#include <pcl/features/normal_3d.h>
#include <pcl/io/pcd_io.h>

#include <iostream>
#include <pcl/gpu/features/features.hpp>

int main(int, char** argv) {
  // std::string filename = argv[1];
  // std::cout << "Reading " << filename << std::endl;

  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

  if (pcl::io::loadPCDFile<pcl::PointXYZ>(
          "C:\\program_on_git\\own\\test\\pcl_test\\source\\windfield_croped_"
          "bin.pcd",
          *cloud) == -1)  // load the file
  {
    PCL_ERROR("Couldn't read file\n");
    return -1;
  }

  std::cout << "points: " << cloud->size() << std::endl;

  pcl::gpu::NormalEstimation gpu_ne;
  pcl::gpu::Feature::PointCloud gpu_cloud;
  pcl::gpu::Feature::Normals gpu_normals;

  gpu_cloud.upload(cloud->points);
  // pcl::gpu::Feature::PointCloud gpu_surface;
  // gpu_surface.upload(sphere_cloud->points);
  // gpu_ne.setSearchSurface(gpu_surface);

  gpu_ne.setInputCloud(gpu_cloud);
  gpu_ne.setRadiusSearch(2, 1000);
  gpu_ne.compute(gpu_normals);

  std::vector<pcl::gpu::Feature::NormalType> downloaded_normals;
  gpu_normals.download(downloaded_normals);

  pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
  normals->resize(downloaded_normals.size());
  for (size_t i = 0; i < downloaded_normals.size(); ++i) {
    normals->points[i].normal_x = downloaded_normals[i].x;
    normals->points[i].normal_y = downloaded_normals[i].y;
    normals->points[i].normal_z = downloaded_normals[i].z;

    normals->points[i].curvature = downloaded_normals[i].data[3];
  }
  // cloud_normals->size () should have the same size as the input cloud->size
  // ()
  std::cout << "cloud_normals->size (): " << normals->size() << std::endl;
  return 0;
}

my file: https://ufile.io/up3nb8br

Debug phenomenon:

- data.create (query_number * max_elems); (here query_number =10240000 max_elems= 1000) - DeviceMemory::create(size * elem_size); (here size somehow becomes 1650065408)

Your Environment (please complete the following information):

mvieth commented 4 months ago

There is an overflow of an int type happening. The largest value an int can represent is 2^31-1, about 2.1 billion. 10240000 1000 equals about 10 billion, so the product overflows and becomes 1650065408. But even without the overflow, you would need 10240000 1000 * 4, roughly 41GB of graphic memory (one int needs 4 bytes). The gpu normal estimation currently does not work with so many points/so high max_nn. I would recommend to reduce max_nn to 50 (which should be completely sufficient for normal estimation), or reduce the number of points.

QiuYilin commented 4 months ago

Thanks, then wouldn't it be better to determine in advance whether the maximum int value will be exceeded in setRadiusSearch? In this way, I can get exceptions instead of crashes or error values.

mvieth commented 4 months ago

The overflow could be fixed by casting to std::size_t before multiplying. If you have an idea how to prevent an out-of-memory error, feel free to make a suggestion. I think that is difficult to do because different users have different GPUs with different amounts of gpu memory.

QiuYilin commented 4 months ago

Can we simply throw an exception instead of exiting? Problems caused by uncontrollable user input fall into the category of exceptions.

mvieth commented 4 months ago

Feel free to suggest where/how to do that. While debugging you have probably developed a good understanding of the code. BTW the overflow should be fixed by this: data.create (static_cast<std::size_t>(query_number) * static_cast<std::size_t>(max_elems)); in device_format.hpp

QiuYilin commented 4 months ago

I will make a pr for it.