Parallel PCL Operations

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Parallel PCL Operations

Pooky
Is it possible to run PCL operations in parallel? Something like this:

std::thread t1(poisson_recon_task1)
std::thread t1(poisson_recon_task2)

void poisson_recon_task1()
{
        pcl::PointCloud<PCNorm> pc_recon;
        std::vector<pcl::Vertices> polygons_recon;

        pcl::Poisson<PCNorm> surf_con;
        surf_con.setInputCloud(cloud_1);
        surf_con.performReconstruction(pc_recon, polygons_recon);
}

void poisson_recon_task2()
{
        pcl::PointCloud<PCNorm> pc_recon;
        std::vector<pcl::Vertices> polygons_recon;

        pcl::Poisson<PCNorm> surf_con;
        surf_con.setInputCloud(cloud_2);
        surf_con.performReconstruction(pc_recon, polygons_recon);
}

I get an access violation exception which makes me think I don't have 2
separate instances of pcl::Poission.

I had the same issues with QHull... but I saw in another thread that it's
not thread-safe



--
Sent from: http://www.pcl-users.org/
_______________________________________________
[hidden email] / http://pointclouds.org
http://pointclouds.org/mailman/listinfo/pcl-users
Reply | Threaded
Open this post in threaded view
|

Re: Parallel PCL Operations

ROZAR Fabien
Hello,

I never try this kind of parallelisation with PCL, but in your example
it seems that you don't share any thing between poisson_recon_task1
and poisson_recon_task2 (not even the InputCloud), so it's reasonable
to think that it should work.

Can you copy/paste the exact error message you get please?

frozar

PS : which version of PCL to you use? The master branch in github
repository?
The one that come from Ubuntu package?

Le 08/12/2017 à 16:39, Pooky a écrit :

> Is it possible to run PCL operations in parallel? Something like this:
>
> std::thread t1(poisson_recon_task1)
> std::thread t1(poisson_recon_task2)
>
> void poisson_recon_task1()
> {
> pcl::PointCloud<PCNorm> pc_recon;
> std::vector<pcl::Vertices> polygons_recon;
>
>          pcl::Poisson<PCNorm> surf_con;
> surf_con.setInputCloud(cloud_1);
> surf_con.performReconstruction(pc_recon, polygons_recon);
> }
>
> void poisson_recon_task2()
> {
> pcl::PointCloud<PCNorm> pc_recon;
> std::vector<pcl::Vertices> polygons_recon;
>
>          pcl::Poisson<PCNorm> surf_con;
> surf_con.setInputCloud(cloud_2);
> surf_con.performReconstruction(pc_recon, polygons_recon);
> }
>
> I get an access violation exception which makes me think I don't have 2
> separate instances of pcl::Poission.
>
> I had the same issues with QHull... but I saw in another thread that it's
> not thread-safe
>
>
>
> --
> Sent from: http://www.pcl-users.org/
> _______________________________________________
> [hidden email] / http://pointclouds.org
> http://pointclouds.org/mailman/listinfo/pcl-users

_______________________________________________
[hidden email] / http://pointclouds.org
http://pointclouds.org/mailman/listinfo/pcl-users
Reply | Threaded
Open this post in threaded view
|

Re: Parallel PCL Operations

Sérgio Agostinho
In reply to this post by Pooky

On 08-12-2017 15:39, Pooky wrote:

Is it possible to run PCL operations in parallel? Something like this:
Normally, yes. Our classes are not usually attached to a global state or anything of the sort. PCLVisualizer is an exception though.
I had the same issues with QHull... but I saw in another thread that it's
not thread-safe
We have plans to start linking against the "new" reentrant version of QHull but were deterred by some issues in ubuntu. More info here.

Cheers

_______________________________________________
[hidden email] / http://pointclouds.org
http://pointclouds.org/mailman/listinfo/pcl-users
Reply | Threaded
Open this post in threaded view
|

Re: Parallel PCL Operations

MarkL
In reply to this post by Pooky
Poisson reconstruction uses a static memory allocator.

You can disable it by setting MEMORY_ALLOCATOR_BLOCK_SIZE to zero, at:
https://github.com/PointCloudLibrary/pcl/blob/abf77fffd5b05140ebeb4cb71c204ad7458ae7c5/surface/include/pcl/surface/impl/poisson.hpp#L55

Not sure if this will be enough to make it work, but worth a try.



Pooky wrote

> Is it possible to run PCL operations in parallel? Something like this:
>
> std::thread t1(poisson_recon_task1)
> std::thread t1(poisson_recon_task2)
>
> void poisson_recon_task1()
> {
> pcl::PointCloud
> <PCNorm>
>  pc_recon;
> std::vector
> <pcl::Vertices>
>  polygons_recon;
>
>         pcl::Poisson
> <PCNorm>
>  surf_con;
> surf_con.setInputCloud(cloud_1);
> surf_con.performReconstruction(pc_recon, polygons_recon);
> }
>
> void poisson_recon_task2()
> {
> pcl::PointCloud
> <PCNorm>
>  pc_recon;
> std::vector
> <pcl::Vertices>
>  polygons_recon;
>
>         pcl::Poisson
> <PCNorm>
>  surf_con;
> surf_con.setInputCloud(cloud_2);
> surf_con.performReconstruction(pc_recon, polygons_recon);
> }
>
> I get an access violation exception which makes me think I don't have 2
> separate instances of pcl::Poission.





--
Sent from: http://www.pcl-users.org/
_______________________________________________
[hidden email] / http://pointclouds.org
http://pointclouds.org/mailman/listinfo/pcl-users
Reply | Threaded
Open this post in threaded view
|

Re: Parallel PCL Operations

Sérgio Agostinho
By the way, can you open an issue in the issue tracker?

Even if the suggested fix doesn’t work, it’s not a good limitation to not be able to perform a reconstruction of two independent things in parallel.

Thanks.
_______________________________________________
[hidden email] / http://pointclouds.org
http://pointclouds.org/mailman/listinfo/pcl-users

smime.p7s (3K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Parallel PCL Operations

Pooky
In reply to this post by ROZAR Fabien
I'm using the 1.8.1 release version.

The exception is thrown in octree_poisson.hpp

Exception thrown: read access violation.
node->parent was 0xFFFFFFFFFFFFFFF7.

The call stack:
pcl::poisson::OctNode<pcl::poisson::TreeNodeData,float>::NeighborKey3::setNeighbors(pcl::poisson::OctNode<pcl::poisson::TreeNodeData,float>
* node) Line 1254
pcl::poisson::OctNode<pcl::poisson::TreeNodeData,float>::NeighborKey3::setNeighbors(pcl::poisson::OctNode<pcl::poisson::TreeNodeData,float>
* node) Line 1264
pcl::poisson::OctNode<pcl::poisson::TreeNodeData,float>::NeighborKey3::setNeighbors(pcl::poisson::OctNode<pcl::poisson::TreeNodeData,float>
* node) Line 1264
pcl::poisson::Octree<2>::NonLinearUpdateWeightContribution(pcl::poisson::OctNode<pcl::poisson::TreeNodeData,float>
* node, const pcl::poisson::Point3D<float> & position, float weight) Line
711
pcl::poisson::Octree<2>::setTree<pcl::PointXYZRGBNormal>(boost::shared_ptr<pcl::PointCloud&lt;pcl::PointXYZRGBNormal>
const > input_, int maxDepth, int minDepth, int kernelDepth, float
samplesPerNode, float scaleFactor, pcl::poisson::Point3D<float> & center,
float & scale, int useConfidence, float constraintWeight, bool
adaptiveWeights) Line 807
pcl::Poisson<pcl::PointXYZRGBNormal>::execute<2>(pcl::poisson::CoredVectorMeshData
& mesh, pcl::poisson::Point3D<float> & center, float & scale) Line 128
pcl::Poisson<pcl::PointXYZRGBNormal>::performReconstruction(pcl::PointCloud<pcl::PointXYZRGBNormal>
& points, std::vector<pcl::Vertices,std::allocator&lt;pcl::Vertices> > &
polygons) Line 249

I don't know if this is helpful for you but the function in
octree_poisson.hpp where the exception occurs:

template< class NodeData , class Real >
    typename OctNode<NodeData,Real>::Neighbors3&
OctNode<NodeData,Real>::NeighborKey3::setNeighbors( OctNode<NodeData,Real>*
node )
    {
      int d = node->depth();
      if( node==neighbors[d].neighbors[1][1][1] )
      {
        bool reset = false;
        for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ;
k<3 ; k++ ) if( !neighbors[d].neighbors[i][j][k] ) reset = true;
        if( reset ) neighbors[d].neighbors[1][1][1] = NULL;
      }
      if( node!=neighbors[d].neighbors[1][1][1] )
      {
        neighbors[d].clear();

        if( !node->parent ) neighbors[d].neighbors[1][1][1] = node;
        else
        {
          int i,j,k,x1,y1,z1,x2,y2,z2;
          int idx=int(node-node->parent->children);   *<------ Exception is
thrown here*
          Cube::FactorCornerIndex(  idx   ,x1,y1,z1);
          Cube::FactorCornerIndex((~idx)&7,x2,y2,z2);
          for(i=0;i<2;i++){
            for(j=0;j<2;j++){
              for(k=0;k<2;k++){
               
neighbors[d].neighbors[x2+i][y2+j][z2+k]=&node->parent->children[Cube::CornerIndex(i,j,k)];
              }
            }
          }
          Neighbors3& temp=setNeighbors(node->parent);

          // Set the neighbors from across the faces
          i=x1<<1;
          if(temp.neighbors[i][1][1]){
           
if(!temp.neighbors[i][1][1]->children){temp.neighbors[i][1][1]->initChildren();}
           
for(j=0;j<2;j++){for(k=0;k<2;k++){neighbors[d].neighbors[i][y2+j][z2+k]=&temp.neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)];}}
          }
          j=y1<<1;
          if(temp.neighbors[1][j][1]){
           
if(!temp.neighbors[1][j][1]->children){temp.neighbors[1][j][1]->initChildren();}
           
for(i=0;i<2;i++){for(k=0;k<2;k++){neighbors[d].neighbors[x2+i][j][z2+k]=&temp.neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)];}}
          }
          k=z1<<1;
          if(temp.neighbors[1][1][k]){
           
if(!temp.neighbors[1][1][k]->children){temp.neighbors[1][1][k]->initChildren();}
           
for(i=0;i<2;i++){for(j=0;j<2;j++){neighbors[d].neighbors[x2+i][y2+j][k]=&temp.neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)];}}
          }

          // Set the neighbors from across the edges
          i=x1<<1; j=y1<<1;
          if(temp.neighbors[i][j][1]){
           
if(!temp.neighbors[i][j][1]->children){temp.neighbors[i][j][1]->initChildren();}
           
for(k=0;k<2;k++){neighbors[d].neighbors[i][j][z2+k]=&temp.neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)];}
          }
          i=x1<<1; k=z1<<1;
          if(temp.neighbors[i][1][k]){
           
if(!temp.neighbors[i][1][k]->children){temp.neighbors[i][1][k]->initChildren();}
           
for(j=0;j<2;j++){neighbors[d].neighbors[i][y2+j][k]=&temp.neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)];}
          }
          j=y1<<1; k=z1<<1;
          if(temp.neighbors[1][j][k]){
           
if(!temp.neighbors[1][j][k]->children){temp.neighbors[1][j][k]->initChildren();}
           
for(i=0;i<2;i++){neighbors[d].neighbors[x2+i][j][k]=&temp.neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)];}
          }

          // Set the neighbor from across the corner
          i=x1<<1; j=y1<<1; k=z1<<1;
          if(temp.neighbors[i][j][k]){
           
if(!temp.neighbors[i][j][k]->children){temp.neighbors[i][j][k]->initChildren();}
           
neighbors[d].neighbors[i][j][k]=&temp.neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)];
          }
        }
      }
      return neighbors[d];
    }




--
Sent from: http://www.pcl-users.org/
_______________________________________________
[hidden email] / http://pointclouds.org
http://pointclouds.org/mailman/listinfo/pcl-users
Reply | Threaded
Open this post in threaded view
|

Re: Parallel PCL Operations

Pooky
In reply to this post by MarkL
Thanks for the suggestion! But it doesn't work :(

I get an exception when its trying to allocate the memory.

Callstack:

std::vector<pcl::poisson::MatrixEntry&lt;float> *
__ptr64,std::allocator<pcl::poisson::MatrixEntry&lt;float> * __ptr64>
>::operator[](const unsigned __int64 _Pos) Line 1796
pcl::poisson::Allocator<pcl::poisson::MatrixEntry&lt;float> >::rollBack()
Line 87
pcl::poisson::Octree<2>::SolveFixedDepthMatrix(int depth, const
pcl::poisson::SortedTreeNodes & sNodes, float * metSolution, bool
showResidual, int minIters, double accuracy) Line 1922
pcl::poisson::Octree<2>::SolveFixedDepthMatrix(int depth, const
pcl::poisson::SortedTreeNodes & sNodes, float * metSolution, int
startingDepth, bool showResidual, int minIters, double accuracy) Line 1947
pcl::poisson::Octree<2>::LaplacianMatrixIteration(int subdivideDepth, bool
showResidual, int minIters, double accuracy) Line 1878
pcl::Poisson<pcl::PointXYZRGBNormal>::execute<2>(pcl::poisson::CoredVectorMeshData
& mesh, pcl::poisson::Point3D<float> & center, float & scale) Line 144
pcl::Poisson<pcl::PointXYZRGBNormal>::performReconstruction(pcl::PointCloud<pcl::PointXYZRGBNormal>
& points, std::vector<pcl::Vertices,std::allocator&lt;pcl::Vertices> > &
polygons) Line 249

The rollback function (i.e. where the exception is thrown):

/** This method rolls back the allocator so that it makes all of the memory
previously
          * allocated available for re-allocation. Note that it does it not
call the constructor
          * again, so after this method has been called, assumptions about
the state of the values
          * in memory are no longer valid. */
        void rollBack(void){
          if(memory.size()){
            for(size_t i=0;i<memory.size();i++){
              for(int j=0;j<blockSize;j++){
                memory[i][j].~T();
                new(&memory[i][j]) T();
              }
            }
            index=0;
            remains=blockSize;
          }
        }

In this case the size of memory is 0, while j in the for loop will go
between 0 and block size.

But if I understand this correctly, each thread should have its own static
memory allocation:

https://github.com/PointCloudLibrary/pcl/blob/abf77fffd5b05140ebeb4cb71c204ad7458ae7c5/surface/include/pcl/surface/impl/poisson.hpp#L119





--
Sent from: http://www.pcl-users.org/
_______________________________________________
[hidden email] / http://pointclouds.org
http://pointclouds.org/mailman/listinfo/pcl-users
Reply | Threaded
Open this post in threaded view
|

Re: Parallel PCL Operations

Pooky
In reply to this post by Pooky
If anyone is interested to dig deeper, I've made a simple version to test
this

#include <thread>
#include <vector>

#include <pcl/point_types.h>
#include <pcl/surface/poisson.h>
#include <pcl/io/ply_io.h>

pcl::PolygonMesh mesh_1;
pcl::PolygonMesh mesh_2;
pcl::PointCloud<pcl::PointNormal>::Ptr cloud_in_1(new
pcl::PointCloud<pcl::PointNormal>());
pcl::PointCloud<pcl::PointNormal>::Ptr cloud_in_2(new
pcl::PointCloud<pcl::PointNormal>());

void thread1Process()
{
        pcl::Poisson<pcl::PointNormal> surf_con;

        surf_con.setInputCloud(cloud_in_1);
        surf_con.performReconstruction(mesh_1);
}

int main(int argc, char* argv[])
{
        //------------------ LOAD FILES ------------------//
        std::string path_dir =
"C:\\Projects\\Snugg\\2.Development\\4.Repo\\temp\\MeasurementFinder\\build\\000Yon\\temp_m_f.ply";

        pcl::PLYReader reader;
        reader.read(path_dir, *cloud_in_1);
        reader.read(path_dir, *cloud_in_2);

        std::thread t1(thread1Process);

        pcl::Poisson<pcl::PointNormal> surf_con;

        surf_con.setInputCloud(cloud_in_2);
        surf_con.performReconstruction(mesh_2);

        t1.join();

        pcl::io::savePLYFile("mesh_1.ply", mesh_1);
        pcl::io::savePLYFile("mesh_2.ply", mesh_2);
}


The exception:

Exception thrown at 0x00007FF89E57417D (pcl_surface_debug.dll) in
MeasurementFinder.exe: 0xC0000005: Access violation reading location
0xFFFFFFFFFFFFFFFF.





--
Sent from: http://www.pcl-users.org/
_______________________________________________
[hidden email] / http://pointclouds.org
http://pointclouds.org/mailman/listinfo/pcl-users
Reply | Threaded
Open this post in threaded view
|

Re: Parallel PCL Operations

Pooky
In reply to this post by MarkL