所以我有一个网格,我需要计算一些信息 - computeInfo(triangle)
。在我的顺序版本中,我只使用迭代器来遍历整个网格。
为了获得一些时间,我正在尝试将此部分与OpenMP并行化。诀窍是computeInfo(T)
访问并修改三角形T
周围的一些三角形。
我的想法如下:首先计算网格的边界框。然后创建一个足够的3D网格(单元格足够大,使computeInfo(T)
不会引起任何问题)并将每个三角形分配给相应的网格单元格。
然后每个线程处理一个单元格中的所有三元组,其坐标可以表示为(2*i, 2*j, 2*k)
:这可以确保不会因另一个线程而出现修改。我们等待处理所有相应的单元格,然后处理(2*i+1, 2*j, 2*k)
,(2*i, 2*j+1, 2*k)
,依此类推,直到我们处理(2*i+1, 2*j+1, 2*k+1)
。
显然,我的并行代码几乎和顺序代码一样快(我做的最好的速度是2倍,使用8个线程......)。我认为这是由于我用于存储网格的结构,要处理的方面等等。
这是我的代码的简化版本:
vector<set<Index> > vsGrid(nX*nY*nZ); // vector that contains each "cells"
// a cell is a set of the facet index
// it contains
// nX, nY, nZ = size of the grid
vector<vector<set<Index> > > vvsGrid(iNbOfThreads);
// one vector for each thread
#pragma omp parallel for
for(int i = 0; i < iNbOfThreads; ++i)
{
vector<set<Index> > vsGrid(nX*nY*nZ);
vvsGrid[i] = vsGrid;
}
#pragma omp parallel
{
const int iThrdId = omp_get_thread_num();
// each thread process a part of the total triangles (called facet)
for(PlaneFinderAPI::Polyhedron::Facet_iterator f = vFStart[iThrdId]; f != vFEnd[iThrdId]; ++f)
{
Point_3d p = barycenterOf(f);
int X = int((p.x() - minX)/(12*meanEdgeSize));
int Y = int((p.y() - minY)/(12*meanEdgeSize));
int Z = int((p.z() - minZ)/(12*meanEdgeSize));
vvsGrid[iThrdId][X+nX*Y+nX*nY*Z].insert(f->index());
}
#pragma omp barrier
for(int col = iThrdId; col < nX*nY*nZ; col+=iNbOfThreads)
{
for(int j = 0; j < iNbOfThreads; ++j)
{
// we merge the cells of all the threads
vsGrid[col].insert(vvsGrid[j][col].begin(), vvsGrid[j][col].end());
}
}
}
for(int i = 0; i < vvCellToProcess.size(); ++i)
{
#pragma omp parallel for
for(int j = 0; j < vvCellToProcess[i].size(); ++j)
// vvCellToProcess contains the cells to process, first vector contains all
// the cells (2*i, 2*j, 2*k) and so on
{
const int iCellToProcess = vvCellToProcess[i][j];
for(set<Index>::iterator it = vsGrid[iCellToProcess].begin(); it != vsGrid[iCellToProcess].end(); ++it)
{
PlaneFinderAPI::Polyhedron::Facet_iterator f = facetMap.at(*it);
computeInfo(f);
}
}
}
我认为主要问题在于过度使用集合向量。我不认为内存是有效分配的,这就是为什么它很慢。那么我应该使用什么结构?有没有更有效的方法来处理我的问题?
序列号:
for (PlaneFinderAPI::Polyhedron::Facet_iterator f = P.facets_begin() ; f != P.facets_end() ; ++f)
{
computeInfo(f);
}
computeInfo
使用网格的标准halfedge数据结构查看f周围的顶点。为了避免多次查看同一个顶点,每个顶点都与布尔值visited
相关联。这就是为什么我不能简单地并行化for循环,因为在visited
布尔值的读/写中会出现问题。
技术信息:我使用的是带有Visual Studio 2010的Windows 7,带有8个线程和12GB内存的i7 960 @ 3.20GHz。
答案 0 :(得分:0)
我建议您在猜测什么是慢速和什么是快速之前对代码进行基准测试。同样取决于索引是什么,每次分配和读取向量时,您可能会有一个昂贵的副本。您可以尝试存储Index的指针。
这一行例如:
vvsGrid[i] = vsGrid;
将为向量中的每个集合生成多个索引的副本,然后将每个集合的副本和每个集合中的每个索引设置到新向量中。