Как увеличить скорость больших петель - PullRequest
0 голосов
/ 07 января 2019

Сейчас я пытаюсь выполнить очень большие циклы для какой-то задачи, около 8e + 12 итераций. Я попытался использовать многопоточность c ++ 11, но, похоже, она работает не так быстро, как требуется. Я использую систему с 8 ГБ оперативной памяти, процессором i5 и картой Intel Graphics 4000. Если бы я использовал openmp, было бы лучше, или я должен использовать NVIDIA GPU и использовать CUDA для этой задачи? Мой код, как показано ниже:

#include <ros/ros.h>
// PCL specific includes
#include <sensor_msgs/PointCloud2.h>
#include <pcl_conversions/pcl_conversions.h>
#include <pcl/point_types.h>
#include <pcl/filters/voxel_grid.h>
#include <visualization_msgs/Marker.h>
#include <rosbag/bag.h>
#include <std_msgs/Int32.h>
#include <rosbag/view.h>
#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH
#include <fstream>

#include <pcl/point_cloud.h>
#include <pcl/octree/octree_pointcloud_changedetector.h>
#include <pcl/io/pcd_io.h>
#include <iostream>
#include <vector>
#include <ctime>
#include <thread>
ros::Publisher marker_publisher;
int frame_index = 0;
using namespace std;
int x[200000];
void thread_function(pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr cloudB,vector<int> v,int p0) {
    for(size_t p1=0;p1<v.size() && ros::ok();++p1) {
        int p0p1 = sqrt( pow(cloudB->points[v[p1]].x-cloudB->points[v[p0]].x,2)                
        +pow(cloudB->points[v[p1]].y-cloudB->points[v[p0]].y,2)
        +pow(cloudB->points[v[p1]].z-cloudB->points[v[p0]].z,2) ) * 1000;
        if(p0p1>10) {
            for(size_t p2=0;p2<v.size() && ros::ok();++p2) {
                int p0p2 = sqrt( pow(cloudB->points[v[p2]].x-cloudB->points[v[p0]].x,2)                
                +pow(cloudB->points[v[p2]].y-cloudB->points[v[p0]].y,2)
                +pow(cloudB->points[v[p2]].z-cloudB->points[v[p0]].z,2) ) * 1000;
                int p1p2 = sqrt( pow(cloudB->points[v[p2]].x-cloudB->points[v[p1]].x,2)                
                +pow(cloudB->points[v[p2]].y-cloudB->points[v[p1]].y,2)
                +pow(cloudB->points[v[p2]].z-cloudB->points[v[p1]].z,2) ) * 1000;
                if(p0p2>10 && p1p2>10) {
                }    
            }    
        }       
    }    
    x[p0] = 3;
    cout<<"ended thread="<<p0<<endl;
}

void cloud_cb (const sensor_msgs::PointCloud2ConstPtr& input)
{
    frame_index++;
    pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudB (new pcl::PointCloud<pcl::PointXYZRGB> );
    pcl::fromROSMsg(*input,*cloudB);

    // Initializing Marker parameters which will be used in rviz
    vector<visualization_msgs::Marker> line_list, marker, text_view_facing;
    line_list.resize(4); marker.resize(4); text_view_facing.resize(4);
    for(int i=0;i<line_list.size();i++) {
        marker[i].header.frame_id = line_list[i].header.frame_id = text_view_facing[i].header.frame_id = "/X3/base_link";
        marker[i].header.stamp = line_list[i].header.stamp = text_view_facing[i].header.stamp =ros::Time();
        marker[i].ns = line_list[i].ns = text_view_facing[i].ns ="lines";
        marker[i].action = line_list[i].action = text_view_facing[i].action = visualization_msgs::Marker::ADD;
        marker[i].pose.orientation.w = line_list[i].pose.orientation.w = text_view_facing[i].pose.orientation.w = 1;
        marker[i].id = i+4;
        line_list[i].id = i;
        marker[i].type = visualization_msgs::Marker::POINTS;
        line_list[i].type = visualization_msgs::Marker::LINE_LIST;
        line_list[i].color.r = 1; line_list[i].color.g = 1; line_list[i].color. b = 1; line_list[i].color.a = 1;
        marker[i].scale.x = 0.003;
        marker[i].scale.y = 0.003;
        marker[i].scale.z = 0.003;
        text_view_facing[i].id = i+8;
        text_view_facing[i].type = visualization_msgs::Marker::TEXT_VIEW_FACING;
        text_view_facing[i].color.b = 1; text_view_facing[i].color.a = 1.0; text_view_facing[i].color.g = 1.0; text_view_facing[i].color.r = 1.0;
        text_view_facing[i].scale.z = 0.015;
    }
    marker[3].scale.x = 0.05;
    marker[3].scale.y = 0.05;
    marker[3].scale.z = 0.05;

    if(frame_index==10) // Saving the point cloud for only one time to find moved object in it
    {
      pcl::io::savePCDFileASCII ("test_pcd.pcd", *cloudB);
    }
    if(frame_index>10) // Reading above point cloud file after saving for once to compare it with newly arriving point clouds
    {
        pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGB>);

        if (pcl::io::loadPCDFile<pcl::PointXYZRGB> ("test_pcd.pcd", *cloud) == -1) //* load the file
        {
            PCL_ERROR ("Couldn't read file test_pcd.pcd \n");
        }
        else {

            srand ((unsigned int) time (NULL));

            // Octree resolution - side length of octree voxels
            double resolution = 0.1;

            // Instantiate octree-based point cloud change detection class
            pcl::octree::OctreePointCloudChangeDetector<pcl::PointXYZRGB> octree (resolution);

            // Add points from cloudA to octree
            octree.setInputCloud (cloud);
            octree.addPointsFromInputCloud ();

            // Switch octree buffers: This resets octree but keeps previous tree structure in memory.
            octree.switchBuffers ();

            // Add points from cloudB to octree
            octree.setInputCloud (cloudB);
            octree.addPointsFromInputCloud ();

            std::vector<int> newPointIdxVector;

            // Get vector of point indices from octree voxels which did not exist in previous buffer
            octree.getPointIndicesFromNewVoxels (newPointIdxVector);

            geometry_msgs::Point p; std_msgs::ColorRGBA c;
            for (size_t i = 0; i < newPointIdxVector.size (); ++i)
            {                        
                p.x = cloudB->points[newPointIdxVector[i]].x;
                p.y = cloudB->points[newPointIdxVector[i]].y;
                p.z = cloudB->points[newPointIdxVector[i]].z;
                c.r = cloudB->points[newPointIdxVector[i]].r/255.0; 
                c.g = cloudB->points[newPointIdxVector[i]].g/255.0; 
                c.b = cloudB->points[newPointIdxVector[i]].b/255.0; 
                c.a = 1;

                //cout<<newPointIdxVector.size()<<"\t"<<p.x<<"\t"<<p.y<<"\t"<<p.z<<endl;   

                if(!isnan(p.x) && !isnan(p.y) && !isnan(p.z)) {

                    marker[3].points.push_back(p);
                    marker[3].colors.push_back(c);
                }
            }
            marker_publisher.publish(marker[3]);

            pcl::PointCloud<pcl::PointXYZRGB> P;
            thread t[newPointIdxVector.size()];

            for(int p0=0;p0<newPointIdxVector.size();++p0) { // For each voxel in moved object 
                t[p0] = thread(thread_function,cloudB,newPointIdxVector,p0);  
            }   
            for(int p0=0;p0<newPointIdxVector.size();++p0) { // For each voxel in moved object 
                t[p0].join();
                cout<<"joined"<<"\t"<<p0<<"\t"<<x[p0]<<endl;
            }
        } 

    }    


}

int main (int argc, char** argv)
{
  ros::init (argc, argv, "training");
  ros::NodeHandle nh;

  ros::Subscriber sub = nh.subscribe<sensor_msgs::PointCloud2> ("input", 1, cloud_cb);
  marker_publisher = nh.advertise<visualization_msgs::Marker> ("visualization_marker",1);

  // Spin
  ros::spin ();
}

Эта задача действительно важна для выполнения моего алгоритма. Мне нужно предложение, как заставить эти циклы работать очень быстро. В приведенном выше коде функция thread_function является основной функцией, в которую я помещаю циклы for. Есть ли какой-нибудь способ увеличить его производительность в приведенном выше коде?

Ответы [ 2 ]

0 голосов
/ 16 января 2019

Резьба сама по себе не обязательно является гарантией скорости. Если ваш процесс в основном линейный, параллельно ничего не нужно делать. В вашем случае, похоже, у вас есть цикл, и каждую итерацию можно было бы выполнять независимо параллельно, но поскольку каждый цикл настолько мал и состоит в основном из простых математических операций, накладные расходы на создание каждого элемента в отдельном потоке могут не спасти вас. много (если есть) времени. Самому алгоритму может потребоваться пересмотр (т.е. сделать это совершенно другим способом), но многопоточность потенциально может решить вашу проблему, если ваш цикл огромен, и вы можете разбить его, скажем, на 4 блока и параллельно обработать 4 блока (т.е. один поток делает пункты 0-100, еще 101-200 и т. д.). Просто знайте, что один процесс может завершиться раньше другого, и если какой-то другой процесс полагается на завершение всего набора данных, то перед продолжением вам необходимо убедиться, что вы завершили все 4 потока. И если вы выполняете какие-либо манипуляции с данными (т. Е. Смещаете элементы, добавляете, удаляете) в параллельных процессах, то в итоге вы можете испортить параллельный поток. Надеюсь, это поможет!

0 голосов
/ 14 января 2019

OpenMP проще всего реализовать и попробовать. Просто добавьте пару строк в ваш CMakeLists.txt, включающую и знаменитую строку #pragma omp parallel for непосредственно перед циклом for.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...