![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright 2005-2010 Intel Corporation. All Rights Reserved. 00003 00004 This file is part of Threading Building Blocks. 00005 00006 Threading Building Blocks is free software; you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License 00008 version 2 as published by the Free Software Foundation. 00009 00010 Threading Building Blocks is distributed in the hope that it will be 00011 useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00012 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with Threading Building Blocks; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 00019 As a special exception, you may use this file as part of a free software 00020 library without restriction. Specifically, if other files instantiate 00021 templates or use macros or inline functions from this file, or you compile 00022 this file and link it with other files to produce an executable, this 00023 file does not by itself cause the resulting executable to be covered by 00024 the GNU General Public License. This exception does not however 00025 invalidate any other reasons why the executable file might be covered by 00026 the GNU General Public License. 00027 */ 00028 00029 /* 00030 This file contains the TBB-based implementation of convex hull algortihm. 00031 It corresponds to the following settings in convex_hull_bench.cpp: 00032 - USETBB defined to 1 00033 - USECONCVEC defined to 1 00034 - INIT_ONCE defined to 0 00035 - only buffered version is used 00036 */ 00037 #include "convex_hull.h" 00038 00039 #include "tbb/task_scheduler_init.h" 00040 #include "tbb/parallel_for.h" 00041 #include "tbb/parallel_reduce.h" 00042 #include "tbb/blocked_range.h" 00043 #include "tbb/tick_count.h" 00044 #include "tbb/concurrent_vector.h" 00045 00046 typedef util::point<double> point_t; 00047 typedef tbb::concurrent_vector< point_t > pointVec_t; 00048 typedef tbb::blocked_range<size_t> range_t; 00049 00050 void appendVector(const point_t* src, size_t srcSize, pointVec_t& dest) { 00051 std::copy(src, src + srcSize, dest.grow_by(srcSize)); 00052 } 00053 00054 void appendVector(const pointVec_t& src, pointVec_t& dest) { 00055 std::copy(src.begin(), src.end(), dest.grow_by(src.size())); 00056 } 00057 00058 class FillRNDPointsVector_buf { 00059 pointVec_t &points; 00060 mutable unsigned int rseed; 00061 public: 00062 static const size_t grainSize = cfg::GENERATE_GS; 00063 00064 FillRNDPointsVector_buf(pointVec_t& _points) 00065 : points(_points), rseed(1) {} 00066 00067 FillRNDPointsVector_buf(const FillRNDPointsVector_buf& other) 00068 : points(other.points), rseed(other.rseed+1) {} 00069 00070 void operator()(const range_t& range) const { 00071 const size_t i_end = range.end(); 00072 size_t count = 0, j = 0; 00073 point_t tmp_vec[grainSize]; 00074 for(size_t i=range.begin(); i!=i_end; ++i) { 00075 tmp_vec[j++] = util::GenerateRNDPoint<double>(count, rseed); 00076 } 00077 appendVector(tmp_vec, j, points); 00078 } 00079 }; 00080 00081 void initialize(pointVec_t &points) { 00082 points.clear(); 00083 00084 // In the buffered version, a temporary storage for as much as grainSize elements 00085 // is allocated inside the body. Since auto_partitioner may increase effective 00086 // range size which would cause a crash, simple partitioner has to be used. 00087 tbb::parallel_for(range_t(0, cfg::MAXPOINTS, FillRNDPointsVector_buf::grainSize), 00088 FillRNDPointsVector_buf(points), tbb::simple_partitioner()); 00089 } 00090 00091 class FindXExtremum { 00092 public: 00093 typedef enum { 00094 minX, maxX 00095 } extremumType; 00096 00097 static const size_t grainSize = cfg::FINDEXT_GS; 00098 00099 FindXExtremum(const pointVec_t& points_, extremumType exType_) 00100 : points(points_), exType(exType_), extrXPoint(points[0]) {} 00101 00102 FindXExtremum(const FindXExtremum& fxex, tbb::split) 00103 // Can run in parallel with fxex.operator()() or fxex.join(). 00104 // The data race reported by tools is harmless. 00105 : points(fxex.points), exType(fxex.exType), extrXPoint(fxex.extrXPoint) {} 00106 00107 void operator()(const range_t& range) { 00108 const size_t i_end = range.end(); 00109 if(!range.empty()) { 00110 for(size_t i = range.begin(); i != i_end; ++i) { 00111 if(closerToExtremum(points[i])) { 00112 extrXPoint = points[i]; 00113 } 00114 } 00115 } 00116 } 00117 00118 void join(const FindXExtremum &rhs) { 00119 if(closerToExtremum(rhs.extrXPoint)) { 00120 extrXPoint = rhs.extrXPoint; 00121 } 00122 } 00123 00124 point_t extremeXPoint() { 00125 return extrXPoint; 00126 } 00127 00128 private: 00129 const pointVec_t &points; 00130 const extremumType exType; 00131 point_t extrXPoint; 00132 bool closerToExtremum(const point_t &p) const { 00133 switch(exType) { 00134 case minX: 00135 return p.x<extrXPoint.x; break; 00136 case maxX: 00137 return p.x>extrXPoint.x; break; 00138 } 00139 return false; // avoid warning 00140 } 00141 }; 00142 00143 template <FindXExtremum::extremumType type> 00144 point_t extremum(const pointVec_t &P) { 00145 FindXExtremum fxBody(P, type); 00146 tbb::parallel_reduce(range_t(0, P.size(), FindXExtremum::grainSize), fxBody); 00147 return fxBody.extremeXPoint(); 00148 } 00149 00150 class SplitByCP_buf { 00151 const pointVec_t &initialSet; 00152 pointVec_t &reducedSet; 00153 point_t p1, p2; 00154 point_t farPoint; 00155 double howFar; 00156 public: 00157 static const size_t grainSize = cfg::DIVIDE_GS; 00158 00159 SplitByCP_buf( point_t _p1, point_t _p2, 00160 const pointVec_t &_initialSet, pointVec_t &_reducedSet) 00161 : p1(_p1), p2(_p2), 00162 initialSet(_initialSet), reducedSet(_reducedSet), 00163 howFar(0), farPoint(p1) {} 00164 00165 SplitByCP_buf(SplitByCP_buf& sbcp, tbb::split) 00166 : p1(sbcp.p1), p2(sbcp.p2), 00167 initialSet(sbcp.initialSet), reducedSet(sbcp.reducedSet), 00168 howFar(0), farPoint(p1) {} 00169 00170 void operator()(const range_t& range) { 00171 const size_t i_end = range.end(); 00172 size_t j = 0; 00173 double cp; 00174 point_t tmp_vec[grainSize]; 00175 for(size_t i = range.begin(); i != i_end; ++i) { 00176 if( (initialSet[i] != p1) && (initialSet[i] != p2) ) { 00177 cp = util::cross_product(p1, p2, initialSet[i]); 00178 if(cp>0) { 00179 tmp_vec[j++] = initialSet[i]; 00180 if(cp>howFar) { 00181 farPoint = initialSet[i]; 00182 howFar = cp; 00183 } 00184 } 00185 } 00186 } 00187 00188 appendVector(tmp_vec, j, reducedSet); 00189 } 00190 00191 void join(const SplitByCP_buf& rhs) { 00192 if(rhs.howFar>howFar) { 00193 howFar = rhs.howFar; 00194 farPoint = rhs.farPoint; 00195 } 00196 } 00197 00198 point_t farthestPoint() const { 00199 return farPoint; 00200 } 00201 }; 00202 00203 point_t divide(const pointVec_t &P, pointVec_t &P_reduced, 00204 const point_t &p1, const point_t &p2) { 00205 SplitByCP_buf sbcpb(p1, p2, P, P_reduced); 00206 // Must use simple_partitioner (see the comment in initialize() above) 00207 tbb::parallel_reduce(range_t(0, P.size(), SplitByCP_buf::grainSize), 00208 sbcpb, tbb::simple_partitioner()); 00209 00210 if(util::VERBOSE) { 00211 std::stringstream ss; 00212 ss << P.size() << " nodes in bucket"<< ", " 00213 << "dividing by: [ " << p1 << ", " << p2 << " ], " 00214 << "farthest node: " << sbcpb.farthestPoint(); 00215 util::OUTPUT.push_back(ss.str()); 00216 } 00217 00218 return sbcpb.farthestPoint(); 00219 } 00220 00221 void divide_and_conquer(const pointVec_t &P, pointVec_t &H, 00222 point_t p1, point_t p2) { 00223 if (P.size()<2) { 00224 H.push_back(p1); 00225 appendVector(P, H); 00226 } 00227 else { 00228 pointVec_t P_reduced; 00229 pointVec_t H1, H2; 00230 00231 point_t p_far = divide(P, P_reduced, p1, p2); 00232 00233 divide_and_conquer(P_reduced, H1, p1, p_far); 00234 divide_and_conquer(P_reduced, H2, p_far, p2); 00235 00236 appendVector(H1, H); 00237 appendVector(H2, H); 00238 } 00239 } 00240 00241 void quickhull(const pointVec_t &points, pointVec_t &hull) { 00242 hull.clear(); 00243 00244 point_t p_maxx = extremum<FindXExtremum::maxX>(points); 00245 point_t p_minx = extremum<FindXExtremum::minX>(points); 00246 00247 pointVec_t H; 00248 00249 divide_and_conquer(points, hull, p_maxx, p_minx); 00250 divide_and_conquer(points, H, p_minx, p_maxx); 00251 00252 appendVector(H, hull); 00253 } 00254 00255 int main(int argc, char* argv[]) { 00256 util::ParseInputArgs(argc, argv); 00257 00258 pointVec_t points; 00259 pointVec_t hull; 00260 int nthreads; 00261 util::my_time_t tm_init, tm_start, tm_end; 00262 00263 std::cout << " Starting TBB-bufferred version of QUICK HULL algorithm" << std::endl; 00264 00265 for(nthreads=cfg::NUM_THREADS_START; nthreads<=cfg::NUM_THREADS_END; 00266 ++nthreads) { 00267 tbb::task_scheduler_init init(nthreads); 00268 tm_init = util::gettime(); 00269 initialize(points); 00270 tm_start = util::gettime(); 00271 quickhull(points, hull); 00272 tm_end = util::gettime(); 00273 00274 util::WriteResults(nthreads, util::time_diff(tm_init, tm_start), 00275 util::time_diff(tm_start, tm_end)); 00276 } 00277 00278 return 0; 00279 }
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.