Disabled external gits

This commit is contained in:
2022-04-07 18:46:57 +02:00
parent 88cb3426ad
commit 15e7120d6d
5316 changed files with 4563444 additions and 6 deletions

View File

@@ -0,0 +1,52 @@
# Copyright (c) 2005-2020 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Common Makefile that builds and runs example.
PROG=convex_hull_bench
ARGS=
PERF_RUN_ARGS = silent auto 40000000
LIGHT_ARGS = 4 400
# Trying to find if icl.exe is set
CXX1 = $(TBB_CXX)-
CXX2 = $(CXX1:icl.exe-=icl.exe)
CXX = $(CXX2:-=cl.exe)
# The C++ compiler options
# Below, _SECURE_SCL=0 is for VC9 and earlier, and _ITERATOR_DEBUG_LEVEL=0 is for VC10 and later
MYCXXFLAGS = /TP /EHsc /W3 /nologo /D _CONSOLE /D _MBCS /D WIN32 /D _ITERATOR_DEBUG_LEVEL=0 /D _SECURE_SCL=0 $(CXXFLAGS)
MYLDFLAGS =/INCREMENTAL:NO /NOLOGO /DEBUG /FIXED:NO $(LDFLAGS)
all: release test
release: compiler_check
$(CXX) convex_hull_sample.cpp /MD /O2 /D NDEBUG $(MYCXXFLAGS) /link tbb.lib $(LIBS) $(MYLDFLAGS) /OUT:convex_hull_sample.exe
$(CXX) convex_hull_bench.cpp /MD /O2 /D NDEBUG $(MYCXXFLAGS) /link tbb.lib $(LIBS) $(MYLDFLAGS) /OUT:convex_hull_bench.exe
debug: compiler_check
$(CXX) convex_hull_sample.cpp /MDd /Od /Zi /D TBB_USE_DEBUG /D _DEBUG $(MYCXXFLAGS) /link tbb_debug.lib $(LIBS) $(MYLDFLAGS) /OUT:convex_hull_sample.exe
$(CXX) convex_hull_bench.cpp /MDd /Od /Zi /D TBB_USE_DEBUG /D _DEBUG $(MYCXXFLAGS) /link tbb_debug.lib $(LIBS) $(MYLDFLAGS) /OUT:convex_hull_bench.exe
clean:
@cmd.exe /C del convex_hull*.exe *.obj *.?db *.manifest
test:
$(PROG) $(ARGS)
perf_build: release
perf_run:
convex_hull_sample $(PERF_RUN_ARGS)
light_test:
$(PROG) $(LIGHT_ARGS)
compiler_check:
@echo compiler_test>compiler_test && @$(CXX) /E compiler_test >nul 2>&1 || echo "$(CXX) command not found. Check if CXX=$(CXX) is set properly"
@cmd.exe /C del compiler_test

View File

@@ -0,0 +1,184 @@
/*
Copyright (c) 2005-2020 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef __CONVEX_HULL_H__
#define __CONVEX_HULL_H__
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <string>
#include <cstring>
#include <algorithm>
#include <functional>
#include <climits>
#include "tbb/tick_count.h"
#include "tbb/global_control.h"
#include "../../common/utility/utility.h"
#include "../../common/utility/get_default_num_threads.h"
#include "../../common/utility/fast_random.h"
using namespace std;
namespace cfg {
// convex hull problem user set parameters
long numberOfPoints = 5000000; // problem size
// convex hull grain sizes for 3 subproblems. Be sure 16*GS < 512Kb
const size_t generateGrainSize = 25000;
const size_t findExtremumGrainSize = 25000;
const size_t divideGrainSize = 25000;
};
namespace util {
bool silent = false;
bool verbose = false;
vector<string> OUTPUT;
// utility functionality
void ParseInputArgs(int argc, char* argv[], utility::thread_number_range& threads) {
utility::parse_cli_arguments(
argc,argv,
utility::cli_argument_pack()
//"-h" option for displaying help is present implicitly
.positional_arg(threads,"n-of-threads",utility::thread_number_range_desc)
.positional_arg(cfg::numberOfPoints,"n-of-points","number of points")
.arg(silent,"silent","no output except elapsed time")
.arg(verbose,"verbose","turns verbose ON")
);
//disabling verbose if silent is specified
if (silent) verbose = false;;
}
template <typename T>
struct point {
T x;
T y;
//According to subparagraph 4 of paragraph 12.6.2 "Initializing bases and members" [class.base.init]
//of ANSI-ISO-IEC C++ 2003 standard, POD members will _not_ be initialized if they are not mentioned
//in the base-member initializer list.
//For more details why this needed please see comment in FillRNDPointsVector_buf
point() {}
point(T _x, T _y) : x(_x), y(_y) {}
};
std::ostream& operator<< (std::ostream& o, point<double> const& p) {
return o << "(" << p.x << "," << p.y << ")";
}
struct rng {
static const size_t max_rand = USHRT_MAX;
utility::FastRandom my_fast_random;
rng (size_t seed):my_fast_random(seed) {}
unsigned short operator()(){return my_fast_random.get();}
unsigned short operator()(size_t& seed){return my_fast_random.get(seed);}
};
template < typename T ,typename rng_functor_type>
point<T> GenerateRNDPoint(size_t& count, rng_functor_type random, size_t rand_max) {
/* generates random points on 2D plane so that the cluster
is somewhat circle shaped */
const size_t maxsize=500;
T x = random()*2.0/(double)rand_max - 1;
T y = random()*2.0/(double)rand_max - 1;
T r = (x*x + y*y);
if(r>1) {
count++;
if(count>10) {
if (random()/(double)rand_max > 0.5)
x /= r;
if (random()/(double)rand_max > 0.5)
y /= r;
count = 0;
}
else {
x /= r;
y /= r;
}
}
x = (x+1)*0.5*maxsize;
y = (y+1)*0.5*maxsize;
return point<T>(x,y);
}
template <typename Index>
struct edge {
Index start;
Index end;
edge(Index _p1, Index _p2) : start(_p1), end(_p2) {};
};
template <typename T>
ostream& operator <<(ostream& _ostr, point<T> _p) {
return _ostr << '(' << _p.x << ',' << _p.y << ')';
}
template <typename T>
istream& operator >>(istream& _istr, point<T> _p) {
return _istr >> _p.x >> _p.y;
}
template <typename T>
bool operator ==(point<T> p1, point<T> p2) {
return (p1.x == p2.x && p1.y == p2.y);
}
template <typename T>
bool operator !=(point<T> p1, point<T> p2) {
return !(p1 == p2);
}
template <typename T>
double cross_product(const point<T>& start, const point<T>& end1, const point<T>& end2) {
return ((end1.x-start.x)*(end2.y-start.y)-(end2.x-start.x)*(end1.y-start.y));
}
// Timing functions are based on TBB to always obtain wall-clock time
typedef tbb::tick_count my_time_t;
my_time_t gettime() {
return tbb::tick_count::now();
}
double time_diff(my_time_t start, my_time_t end) {
return (end-start).seconds();
}
void WriteResults(int nthreads, double initTime, double calcTime) {
if(verbose) {
cout << " Step by step hull construction:" << endl;
for(size_t i = 0; i < OUTPUT.size(); ++i)
cout << OUTPUT[i] << endl;
}
if (!silent){
cout
<< " Number of nodes:" << cfg::numberOfPoints
<< " Number of threads:" << nthreads
<< " Initialization time:" << setw(10) << setprecision(3) << initTime
<< " Calculation time:" << setw(10) << setprecision(3) << calcTime
<< endl;
}
}
};
#endif // __CONVEX_HULL_H__

View File

@@ -0,0 +1,631 @@
/*
Copyright (c) 2005-2020 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
This file contains a few implementations, so it may look overly complicated.
The most efficient implementation is also separated into convex_hull_sample.cpp
*/
#include "convex_hull.h"
typedef util::point<double> point_t;
#ifndef USETBB
#define USETBB 1
#endif
#ifndef USECONCVEC
#define USECONCVEC 1
#endif
#if !USETBB // Serial implementation of Quick Hull algorithm
typedef std::vector< point_t > pointVec_t;
void serial_initialize(pointVec_t &points);
// C++ style serial code
class FindXExtremum : public std::unary_function<const point_t&, void> {
public:
typedef enum {
minX, maxX
} extremumType;
FindXExtremum(const point_t& frstPoint, extremumType exType_)
: extrXPoint(frstPoint), exType(exType_) {}
void operator()(const point_t& p) {
if(closerToExtremum(p))
extrXPoint = p;
}
operator point_t () {
return extrXPoint;
}
private:
const extremumType exType;
point_t extrXPoint;
bool closerToExtremum(const point_t &p) const {
switch(exType) {
case minX:
return p.x<extrXPoint.x; break;
case maxX:
return p.x>extrXPoint.x; break;
}
return false; // avoid warning
}
};
template <FindXExtremum::extremumType type>
point_t extremum(const pointVec_t &points) {
assert(!points.empty());
return std::for_each(points.begin(), points.end(), FindXExtremum(points[0], type));
}
class SplitByCP : public std::unary_function<const point_t&, void> {
pointVec_t &reducedSet;
point_t p1, p2;
point_t farPoint;
double howFar;
public:
SplitByCP( point_t _p1, point_t _p2, pointVec_t &_reducedSet)
: p1(_p1), p2(_p2), reducedSet(_reducedSet), howFar(0), farPoint(p1) {}
void operator()(const point_t& p) {
double cp;
if( (p != p1) && (p != p2) ) {
cp = util::cross_product(p1, p2, p);
if(cp>0) {
reducedSet.push_back(p);
if(cp>howFar) {
farPoint = p;
howFar = cp;
}
}
}
}
operator point_t (){
return farPoint;
}
};
point_t divide(const pointVec_t &P, pointVec_t &P_reduced, const point_t &p1, const point_t &p2) {
SplitByCP splitByCP(p1, p2, P_reduced);
point_t farPoint = std::for_each(P.begin(), P.end(), splitByCP);
if(util::verbose) {
std::stringstream ss;
ss << P.size() << " nodes in bucket"<< ", "
<< "dividing by: [ " << p1 << ", " << p2 << " ], "
<< "farthest node: " << farPoint;
util::OUTPUT.push_back(ss.str());
}
return farPoint;
}
void divide_and_conquer(const pointVec_t &P, pointVec_t &H, point_t p1, point_t p2) {
assert(P.size() >= 2);
pointVec_t P_reduced;
pointVec_t H1, H2;
point_t p_far = divide(P, P_reduced, p1, p2);
if (P_reduced.size()<2) {
H.push_back(p1);
H.insert(H.end(), P_reduced.begin(), P_reduced.end());
}
else {
divide_and_conquer(P_reduced, H1, p1, p_far);
divide_and_conquer(P_reduced, H2, p_far, p2);
H.insert(H.end(), H1.begin(), H1.end());
H.insert(H.end(), H2.begin(), H2.end());
}
}
void quickhull(const pointVec_t &points, pointVec_t &hull) {
if (points.size() < 2) {
hull.insert(hull.end(), points.begin(), points.end());
return;
}
point_t p_maxx = extremum<FindXExtremum::maxX>(points);
point_t p_minx = extremum<FindXExtremum::minX>(points);
pointVec_t H;
divide_and_conquer(points, hull, p_maxx, p_minx);
divide_and_conquer(points, H, p_minx, p_maxx);
hull.insert(hull.end(), H.begin(), H.end());
}
int main(int argc, char* argv[]) {
util::ParseInputArgs(argc, argv);
pointVec_t points;
pointVec_t hull;
util::my_time_t tm_init, tm_start, tm_end;
std::cout << "Starting serial version of QUICK HULL algorithm" << std::endl;
tm_init = util::gettime();
serial_initialize(points);
tm_start = util::gettime();
std::cout << "Init time: " << util::time_diff(tm_init, tm_start) << " Points in input: " << points.size() << "\n";
tm_start = util::gettime();
quickhull(points, hull);
tm_end = util::gettime();
std::cout << "Serial time: " << util::time_diff(tm_start, tm_end) << " Points in hull: " << hull.size() << "\n";
}
#else // USETBB - parallel version of Quick Hull algorithm
#include "tbb/parallel_for.h"
#include "tbb/parallel_reduce.h"
#include "tbb/blocked_range.h"
typedef tbb::blocked_range<size_t> range_t;
#if USECONCVEC
#include "tbb/concurrent_vector.h"
typedef tbb::concurrent_vector<point_t> pointVec_t;
void appendVector(const point_t* src, size_t srcSize, pointVec_t& dest) {
std::copy(src, src + srcSize, dest.grow_by(srcSize));
}
void appendVector(const pointVec_t& src, pointVec_t& dest) {
std::copy(src.begin(), src.end(), dest.grow_by(src.size()));
}
void grow_vector_to_at_least(pointVec_t& vect, size_t size) {
vect.grow_to_at_least(size);
}
#else // USE STD::VECTOR - include spin_mutex.h and lock vector operations
#include "tbb/spin_mutex.h"
typedef tbb::spin_mutex mutex_t;
typedef std::vector<point_t> pointVec_t;
void appendVector(mutex_t& insertMutex, const pointVec_t& src, pointVec_t& dest) {
mutex_t::scoped_lock lock(insertMutex);
dest.insert(dest.end(), src.begin(), src.end());
}
void appendVector(mutex_t& insertMutex, const point_t* src, size_t srcSize,
pointVec_t& dest) {
mutex_t::scoped_lock lock(insertMutex);
dest.insert(dest.end(), src, src + srcSize);
}
void grow_vector_to_at_least(mutex_t& mutex, pointVec_t& vect, size_t size) {
mutex_t::scoped_lock lock(mutex);
if (vect.size()< size){
vect.resize(size);
}
}
#endif // USECONCVEC
class FillRNDPointsVector {
pointVec_t &points;
public:
static const size_t grainSize = cfg::generateGrainSize;
#if !USECONCVEC
static mutex_t pushBackMutex;
#endif // USECONCVEC
explicit FillRNDPointsVector(pointVec_t& _points)
: points(_points){}
void operator()(const range_t& range) const {
util::rng the_rng(range.begin());
const size_t i_end = range.end();
size_t count = 0;
#if USECONCVEC
points.grow_to_at_least(i_end);
#else // Locked enlarge to a not thread-safe STD::VECTOR
grow_vector_to_at_least(pushBackMutex,points,i_end);
#endif // USECONCVEC
for(size_t i = range.begin(); i != i_end; ++i) {
points[i]=util::GenerateRNDPoint<double>(count,the_rng,util::rng::max_rand);
}
}
};
class FillRNDPointsVector_buf {
pointVec_t &points;
public:
static const size_t grainSize = cfg::generateGrainSize;
#if !USECONCVEC
static mutex_t insertMutex;
#endif // USECONCVEC
explicit FillRNDPointsVector_buf(pointVec_t& _points)
: points(_points){}
void operator()(const range_t& range) const {
util::rng the_rng(range.begin());
const size_t i_end = range.end();
size_t count = 0, j = 0;
point_t tmp_vec[grainSize];
for(size_t i=range.begin(); i!=i_end; ++i) {
tmp_vec[j++] = util::GenerateRNDPoint<double>(count,the_rng,util::rng::max_rand);
}
#if USECONCVEC
grow_vector_to_at_least(points,range.end());
#else // USE STD::VECTOR
grow_vector_to_at_least(insertMutex,points,range.end());
#endif // USECONCVEC
std::copy(tmp_vec, tmp_vec+j,points.begin()+range.begin());
}
};
#if !USECONCVEC
mutex_t FillRNDPointsVector::pushBackMutex = mutex_t();
mutex_t FillRNDPointsVector_buf::insertMutex = mutex_t();
#endif
template<typename BodyType>
void initialize(pointVec_t &points) {
//This function generate the same series of point on every call.
//Reproducibility is needed for benchmarking to produce reliable results.
//It is achieved through the following points:
// - FillRNDPointsVector_buf instance has its own local instance
// of random number generator, which in turn does not use any global data
// - tbb::simple_partitioner produce the same set of ranges on every call to
// tbb::parallel_for
// - local RNG instances are seeded by the starting indexes of corresponding ranges
// - grow_to_at_least() enables putting points into the resulting vector in deterministic order
// (unlike concurrent push_back or grow_by).
// In the buffered version, a temporary storage for as much as grainSize elements
// is allocated inside the body. Since auto_partitioner may increase effective
// range size which would cause a crash, simple partitioner has to be used.
tbb::parallel_for(range_t(0, cfg::numberOfPoints, BodyType::grainSize),
BodyType(points), tbb::simple_partitioner());
}
class FindXExtremum {
public:
typedef enum {
minX, maxX
} extremumType;
static const size_t grainSize = cfg::findExtremumGrainSize;
FindXExtremum(const pointVec_t& points_, extremumType exType_)
: points(points_), exType(exType_), extrXPoint(points[0]) {}
FindXExtremum(const FindXExtremum& fxex, tbb::split)
: points(fxex.points), exType(fxex.exType), extrXPoint(fxex.extrXPoint) {}
void operator()(const range_t& range) {
const size_t i_end = range.end();
if(!range.empty()) {
for(size_t i = range.begin(); i != i_end; ++i) {
if(closerToExtremum(points[i])) {
extrXPoint = points[i];
}
}
}
}
void join(const FindXExtremum &rhs) {
if(closerToExtremum(rhs.extrXPoint)) {
extrXPoint = rhs.extrXPoint;
}
}
point_t extremeXPoint() {
return extrXPoint;
}
private:
const pointVec_t &points;
const extremumType exType;
point_t extrXPoint;
bool closerToExtremum(const point_t &p) const {
switch(exType) {
case minX:
return p.x<extrXPoint.x; break;
case maxX:
return p.x>extrXPoint.x; break;
}
return false; // avoid warning
}
};
template <FindXExtremum::extremumType type>
point_t extremum(const pointVec_t &P) {
FindXExtremum fxBody(P, type);
tbb::parallel_reduce(range_t(0, P.size(), FindXExtremum::grainSize), fxBody);
return fxBody.extremeXPoint();
}
class SplitByCP {
const pointVec_t &initialSet;
pointVec_t &reducedSet;
point_t p1, p2;
point_t farPoint;
double howFar;
public:
static const size_t grainSize = cfg::divideGrainSize;
#if !USECONCVEC
static mutex_t pushBackMutex;
#endif // USECONCVEC
SplitByCP( point_t _p1, point_t _p2,
const pointVec_t &_initialSet, pointVec_t &_reducedSet)
: p1(_p1), p2(_p2),
initialSet(_initialSet), reducedSet(_reducedSet),
howFar(0), farPoint(p1) {
}
SplitByCP( SplitByCP& sbcp, tbb::split )
: p1(sbcp.p1), p2(sbcp.p2),
initialSet(sbcp.initialSet), reducedSet(sbcp.reducedSet),
howFar(0), farPoint(p1) {}
void operator()( const range_t& range ) {
const size_t i_end = range.end();
double cp;
for(size_t i=range.begin(); i!=i_end; ++i) {
if( (initialSet[i] != p1) && (initialSet[i] != p2) ) {
cp = util::cross_product(p1, p2, initialSet[i]);
if(cp>0) {
#if USECONCVEC
reducedSet.push_back(initialSet[i]);
#else // Locked push_back to a not thread-safe STD::VECTOR
{
mutex_t::scoped_lock lock(pushBackMutex);
reducedSet.push_back(initialSet[i]);
}
#endif // USECONCVEC
if(cp>howFar) {
farPoint = initialSet[i];
howFar = cp;
}
}
}
}
}
void join(const SplitByCP& rhs) {
if(rhs.howFar>howFar) {
howFar = rhs.howFar;
farPoint = rhs.farPoint;
}
}
point_t farthestPoint() const {
return farPoint;
}
};
class SplitByCP_buf {
const pointVec_t &initialSet;
pointVec_t &reducedSet;
point_t p1, p2;
point_t farPoint;
double howFar;
public:
static const size_t grainSize = cfg::divideGrainSize;
#if !USECONCVEC
static mutex_t insertMutex;
#endif // USECONCVEC
SplitByCP_buf( point_t _p1, point_t _p2,
const pointVec_t &_initialSet, pointVec_t &_reducedSet)
: p1(_p1), p2(_p2),
initialSet(_initialSet), reducedSet(_reducedSet),
howFar(0), farPoint(p1) {}
SplitByCP_buf(SplitByCP_buf& sbcp, tbb::split)
: p1(sbcp.p1), p2(sbcp.p2),
initialSet(sbcp.initialSet), reducedSet(sbcp.reducedSet),
howFar(0), farPoint(p1) {}
void operator()(const range_t& range) {
const size_t i_end = range.end();
size_t j = 0;
double cp;
point_t tmp_vec[grainSize];
for(size_t i = range.begin(); i != i_end; ++i) {
if( (initialSet[i] != p1) && (initialSet[i] != p2) ) {
cp = util::cross_product(p1, p2, initialSet[i]);
if(cp>0) {
tmp_vec[j++] = initialSet[i];
if(cp>howFar) {
farPoint = initialSet[i];
howFar = cp;
}
}
}
}
#if USECONCVEC
appendVector(tmp_vec, j, reducedSet);
#else // USE STD::VECTOR
appendVector(insertMutex, tmp_vec, j, reducedSet);
#endif // USECONCVEC
}
void join(const SplitByCP_buf& rhs) {
if(rhs.howFar>howFar) {
howFar = rhs.howFar;
farPoint = rhs.farPoint;
}
}
point_t farthestPoint() const {
return farPoint;
}
};
#if !USECONCVEC
mutex_t SplitByCP::pushBackMutex = mutex_t();
mutex_t SplitByCP_buf::insertMutex = mutex_t();
#endif
template <typename BodyType>
point_t divide(const pointVec_t &P, pointVec_t &P_reduced,
const point_t &p1, const point_t &p2) {
BodyType body(p1, p2, P, P_reduced);
// Must use simple_partitioner (see the comment in initialize() above)
tbb::parallel_reduce(range_t(0, P.size(), BodyType::grainSize),
body, tbb::simple_partitioner() );
if(util::verbose) {
std::stringstream ss;
ss << P.size() << " nodes in bucket"<< ", "
<< "dividing by: [ " << p1 << ", " << p2 << " ], "
<< "farthest node: " << body.farthestPoint();
util::OUTPUT.push_back(ss.str());
}
return body.farthestPoint();
}
void divide_and_conquer(const pointVec_t &P, pointVec_t &H,
point_t p1, point_t p2, bool buffered) {
assert(P.size() >= 2);
pointVec_t P_reduced;
pointVec_t H1, H2;
point_t p_far;
if(buffered) {
p_far = divide<SplitByCP_buf>(P, P_reduced, p1, p2);
} else {
p_far = divide<SplitByCP>(P, P_reduced, p1, p2);
}
if (P_reduced.size()<2) {
H.push_back(p1);
#if USECONCVEC
appendVector(P_reduced, H);
#else // insert into STD::VECTOR
H.insert(H.end(), P_reduced.begin(), P_reduced.end());
#endif
}
else {
divide_and_conquer(P_reduced, H1, p1, p_far, buffered);
divide_and_conquer(P_reduced, H2, p_far, p2, buffered);
#if USECONCVEC
appendVector(H1, H);
appendVector(H2, H);
#else // insert into STD::VECTOR
H.insert(H.end(), H1.begin(), H1.end());
H.insert(H.end(), H2.begin(), H2.end());
#endif
}
}
void quickhull(const pointVec_t &points, pointVec_t &hull, bool buffered) {
if (points.size() < 2) {
#if USECONCVEC
appendVector(points, hull);
#else // STD::VECTOR
hull.insert(hull.end(), points.begin(), points.end());
#endif // USECONCVEC
return;
}
point_t p_maxx = extremum<FindXExtremum::maxX>(points);
point_t p_minx = extremum<FindXExtremum::minX>(points);
pointVec_t H;
divide_and_conquer(points, hull, p_maxx, p_minx, buffered);
divide_and_conquer(points, H, p_minx, p_maxx, buffered);
#if USECONCVEC
appendVector(H, hull);
#else // STD::VECTOR
hull.insert(hull.end(), H.begin(), H.end());
#endif // USECONCVEC
}
int main(int argc, char* argv[]) {
utility::thread_number_range threads(utility::get_default_num_threads);
util::ParseInputArgs(argc, argv, threads);
int nthreads;
util::my_time_t tm_init, tm_start, tm_end;
#if USECONCVEC
std::cout << "Starting TBB unbuffered push_back version of QUICK HULL algorithm" << std::endl;
#else
std::cout << "Starting STL locked unbuffered push_back version of QUICK HULL algorithm" << std::endl;
#endif // USECONCVEC
for(nthreads=threads.first; nthreads<=threads.last; nthreads=threads.step(nthreads)) {
pointVec_t points;
pointVec_t hull;
tbb::global_control c(tbb::global_control::max_allowed_parallelism, nthreads);
tm_init = util::gettime();
initialize<FillRNDPointsVector>(points);
tm_start = util::gettime();
std::cout << "Parallel init time on " << nthreads << " threads: " << util::time_diff(tm_init, tm_start) << " Points in input: " << points.size() << "\n";
tm_start = util::gettime();
quickhull(points, hull, false);
tm_end = util::gettime();
std::cout << "Time on " << nthreads << " threads: " << util::time_diff(tm_start, tm_end) << " Points in hull: " << hull.size() << "\n";
}
#if USECONCVEC
std::cout << "Starting TBB buffered version of QUICK HULL algorithm" << std::endl;
#else
std::cout << "Starting STL locked buffered version of QUICK HULL algorithm" << std::endl;
#endif
for(nthreads=threads.first; nthreads<=threads.last; nthreads=threads.step(nthreads)) {
pointVec_t points;
pointVec_t hull;
tbb::global_control c(tbb::global_control::max_allowed_parallelism, nthreads);
tm_init = util::gettime();
initialize<FillRNDPointsVector_buf>(points);
tm_start = util::gettime();
std::cout << "Init time on " << nthreads << " threads: " << util::time_diff(tm_init, tm_start) << " Points in input: " << points.size() << "\n";
tm_start = util::gettime();
quickhull(points, hull, true);
tm_end = util::gettime();
std::cout << "Time on " << nthreads << " threads: " << util::time_diff(tm_start, tm_end) << " Points in hull: " << hull.size() << "\n";
}
return 0;
}
#endif // USETBB
void serial_initialize(pointVec_t &points) {
points.reserve(cfg::numberOfPoints);
unsigned int rseed=1;
for(size_t i=0, count=0; long(i)<cfg::numberOfPoints; ++i) {
points.push_back(util::GenerateRNDPoint<double>(count,&std::rand,RAND_MAX ));
}
}

View File

@@ -0,0 +1,293 @@
/*
Copyright (c) 2005-2020 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
This file contains the TBB-based implementation of convex hull algortihm.
It corresponds to the following settings in convex_hull_bench.cpp:
- USETBB defined to 1
- USECONCVEC defined to 1
- INIT_ONCE defined to 0
- only buffered version is used
*/
#include "convex_hull.h"
#include "tbb/parallel_for.h"
#include "tbb/parallel_reduce.h"
#include "tbb/blocked_range.h"
#include "tbb/tick_count.h"
#include "tbb/concurrent_vector.h"
typedef util::point<double> point_t;
typedef tbb::concurrent_vector< point_t > pointVec_t;
typedef tbb::blocked_range<size_t> range_t;
void appendVector(const point_t* src, size_t srcSize, pointVec_t& dest) {
std::copy(src, src + srcSize, dest.grow_by(srcSize));
}
void appendVector(const pointVec_t& src, pointVec_t& dest) {
std::copy(src.begin(), src.end(), dest.grow_by(src.size()));
}
class FillRNDPointsVector_buf {
pointVec_t &points;
public:
static const size_t grainSize = cfg::generateGrainSize;
explicit FillRNDPointsVector_buf(pointVec_t& _points)
: points(_points) {}
void operator()(const range_t& range) const {
util::rng the_rng(range.begin());
const size_t i_end = range.end();
size_t count = 0, j = 0;
point_t tmp_vec[grainSize];
for(size_t i=range.begin(); i!=i_end; ++i) {
tmp_vec[j++] = util::GenerateRNDPoint<double>(count, the_rng, util::rng::max_rand);
}
//Here we have race condition. Elements being written to may be still under construction.
//For C++ 2003 it is workarounded by vector element type which default constructor does not touch memory,
//it being constructed on. See comments near default ctor of point class for more details.
//Strictly speaking it is UB.
//TODO: need to find more reliable/correct way
points.grow_to_at_least(range.end());
std::copy(tmp_vec, tmp_vec+j,points.begin()+range.begin());
}
};
void initialize(pointVec_t &points) {
//This function generate the same series of point on every call.
//Reproducibility is needed for benchmarking to produce reliable results.
//It is achieved through the following points:
// - FillRNDPointsVector_buf instance has its own local instance
// of random number generator, which in turn does not use any global data
// - tbb::simple_partitioner produce the same set of ranges on every call to
// tbb::parallel_for
// - local RNG instances are seeded by the starting indexes of corresponding ranges
// - grow_to_at_least() enables putting points into the resulting vector in deterministic order
// (unlike concurrent push_back or grow_by).
// In the buffered version, a temporary storage for as much as grainSize elements
// is allocated inside the body. Since auto_partitioner may increase effective
// range size which would cause a crash, simple partitioner has to be used.
tbb::parallel_for(range_t(0, cfg::numberOfPoints, FillRNDPointsVector_buf::grainSize),
FillRNDPointsVector_buf(points), tbb::simple_partitioner());
}
class FindXExtremum {
public:
typedef enum {
minX, maxX
} extremumType;
static const size_t grainSize = cfg::findExtremumGrainSize;
FindXExtremum(const pointVec_t& points_, extremumType exType_)
: points(points_), exType(exType_), extrXPoint(points[0]) {}
FindXExtremum(const FindXExtremum& fxex, tbb::split)
// Can run in parallel with fxex.operator()() or fxex.join().
// The data race reported by tools is harmless.
: points(fxex.points), exType(fxex.exType), extrXPoint(fxex.extrXPoint) {}
void operator()(const range_t& range) {
const size_t i_end = range.end();
if(!range.empty()) {
for(size_t i = range.begin(); i != i_end; ++i) {
if(closerToExtremum(points[i])) {
extrXPoint = points[i];
}
}
}
}
void join(const FindXExtremum &rhs) {
if(closerToExtremum(rhs.extrXPoint)) {
extrXPoint = rhs.extrXPoint;
}
}
point_t extremeXPoint() {
return extrXPoint;
}
private:
const pointVec_t &points;
const extremumType exType;
point_t extrXPoint;
bool closerToExtremum(const point_t &p) const {
switch(exType) {
case minX:
return p.x<extrXPoint.x; break;
case maxX:
return p.x>extrXPoint.x; break;
}
return false; // avoid warning
}
};
template <FindXExtremum::extremumType type>
point_t extremum(const pointVec_t &P) {
FindXExtremum fxBody(P, type);
tbb::parallel_reduce(range_t(0, P.size(), FindXExtremum::grainSize), fxBody);
return fxBody.extremeXPoint();
}
class SplitByCP_buf {
const pointVec_t &initialSet;
pointVec_t &reducedSet;
point_t p1, p2;
point_t farPoint;
double howFar;
public:
static const size_t grainSize = cfg::divideGrainSize;
SplitByCP_buf( point_t _p1, point_t _p2,
const pointVec_t &_initialSet, pointVec_t &_reducedSet)
: p1(_p1), p2(_p2),
initialSet(_initialSet), reducedSet(_reducedSet),
howFar(0), farPoint(p1) {}
SplitByCP_buf(SplitByCP_buf& sbcp, tbb::split)
: p1(sbcp.p1), p2(sbcp.p2),
initialSet(sbcp.initialSet), reducedSet(sbcp.reducedSet),
howFar(0), farPoint(p1) {}
void operator()(const range_t& range) {
const size_t i_end = range.end();
size_t j = 0;
double cp;
point_t tmp_vec[grainSize];
for(size_t i = range.begin(); i != i_end; ++i) {
if( (initialSet[i] != p1) && (initialSet[i] != p2) ) {
cp = util::cross_product(p1, p2, initialSet[i]);
if(cp>0) {
tmp_vec[j++] = initialSet[i];
if(cp>howFar) {
farPoint = initialSet[i];
howFar = cp;
}
}
}
}
appendVector(tmp_vec, j, reducedSet);
}
void join(const SplitByCP_buf& rhs) {
if(rhs.howFar>howFar) {
howFar = rhs.howFar;
farPoint = rhs.farPoint;
}
}
point_t farthestPoint() const {
return farPoint;
}
};
point_t divide(const pointVec_t &P, pointVec_t &P_reduced,
const point_t &p1, const point_t &p2) {
SplitByCP_buf sbcpb(p1, p2, P, P_reduced);
// Must use simple_partitioner (see the comment in initialize() above)
tbb::parallel_reduce(range_t(0, P.size(), SplitByCP_buf::grainSize),
sbcpb, tbb::simple_partitioner());
if(util::verbose) {
std::stringstream ss;
ss << P.size() << " nodes in bucket"<< ", "
<< "dividing by: [ " << p1 << ", " << p2 << " ], "
<< "farthest node: " << sbcpb.farthestPoint();
util::OUTPUT.push_back(ss.str());
}
return sbcpb.farthestPoint();
}
void divide_and_conquer(const pointVec_t &P, pointVec_t &H,
point_t p1, point_t p2) {
assert(P.size() >= 2);
pointVec_t P_reduced;
pointVec_t H1, H2;
point_t p_far = divide(P, P_reduced, p1, p2);
if (P_reduced.size()<2) {
H.push_back(p1);
appendVector(P_reduced, H);
}
else {
divide_and_conquer(P_reduced, H1, p1, p_far);
divide_and_conquer(P_reduced, H2, p_far, p2);
appendVector(H1, H);
appendVector(H2, H);
}
}
void quickhull(const pointVec_t &points, pointVec_t &hull) {
if (points.size() < 2) {
appendVector(points, hull);
return;
}
point_t p_maxx = extremum<FindXExtremum::maxX>(points);
point_t p_minx = extremum<FindXExtremum::minX>(points);
pointVec_t H;
divide_and_conquer(points, hull, p_maxx, p_minx);
divide_and_conquer(points, H, p_minx, p_maxx);
appendVector(H, hull);
}
int main(int argc, char* argv[]) {
utility::thread_number_range threads(utility::get_default_num_threads);
util::my_time_t tm_main_begin = util::gettime();
util::ParseInputArgs(argc, argv, threads);
pointVec_t points;
pointVec_t hull;
int nthreads;
points.reserve(cfg::numberOfPoints);
if(!util::silent) {
std::cout << "Starting TBB-buffered version of QUICK HULL algorithm" << std::endl;
}
for(nthreads=threads.first; nthreads<=threads.last; nthreads=threads.step(nthreads)) {
tbb::global_control c(tbb::global_control::max_allowed_parallelism, nthreads);
points.clear();
util::my_time_t tm_init = util::gettime();
initialize(points);
util::my_time_t tm_start = util::gettime();
if(!util::silent) {
std::cout <<"Init time on "<<nthreads<<" threads: "<<util::time_diff(tm_init, tm_start)<<" Points in input: "<<points.size()<<std::endl;
}
tm_start = util::gettime();
quickhull(points, hull);
util::my_time_t tm_end = util::gettime();
if(!util::silent) {
std::cout <<"Time on "<<nthreads<<" threads: "<<util::time_diff(tm_start, tm_end)<<" Points in hull: "<<hull.size()<<std::endl;
}
hull.clear();
}
utility::report_elapsed_time(util::time_diff(tm_main_begin, util::gettime()));
return 0;
}

View File

@@ -0,0 +1,400 @@
<!DOCTYPE html>
<html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882">
<head>
<meta charset="UTF-8">
<style>
::selection {
background: #b7ffb7;
}
::-moz-selection {
background: #b7ffb7;
}
body {
font-family: Arial, Helvetica, sans-serif;
font-size: 16px;
width: 800px;
margin: 0 auto;
}
#banner {
/* Div for banner */
float:left;
margin: 0px;
margin-bottom: 10px;
width: 100%;
background-color: #0071C5;
z-index: 0;
}
#banner .logo {
/* Apply to logo in banner. Add as class to image tag. */
float: left;
margin-right: 20px;
margin-left: 20px;
margin-top: 15px;
padding-bottom: 5px;
}
h1 {
text-align: center;
font-size: 36px;
}
h1.title {
/* Add as class to H1 in banner */
font-family: "Intel Clear", Verdana, Arial, sans-serif;
font-weight:normal;
color: #FFFFFF;
font-size: 170%;
margin-right: 40px;
margin-left: 40px;
padding-right: 20px;
text-indent: 20px;
}
.h3-alike {
display:inline;
font-size: 1.17em;
font-weight: bold;
color: #0071C5;
}
h3 {
font-size: 1.17em;
font-weight: bold;
color: #0071C5;
}
.h4-alike {
display:inline;
font-size: 1.05em;
font-weight: bold;
}
pre {
font-family: "Consolas", Monaco, monospace;
font-size:small;
background: #fafafa;
margin: 0;
padding-left:20px;
}
#footer {
font-size: small;
}
code {
font-family: "Consolas", Monaco, monospace;
}
.code-block
{
padding-left:20px;
}
.changes {
margin: 1em 0;
}
.changes input:active {
position: relative;
top: 1px;
}
.changes input:hover:after {
padding-left: 16px;
font-size: 10px;
content: 'More';
}
.changes input:checked:hover:after {
content: 'Less';
}
.changes input + .show-hide {
display: none;
}
.changes input:checked + .show-hide {
display: block;
}
ul {
margin: 0;
padding: 0.5em 0 0.5em 2.5em;
}
ul li {
margin-bottom: 3px;
}
ul li:last-child {
margin-bottom: 0;
}
.disc {
list-style-type:disc
}
.circ {
list-style-type:circle
}
.single {
padding: 0 0.5em;
}
/* ------------------------------------------------- */
/* Table styles */
table{
margin-bottom:5pt;
border-collapse:collapse;
margin-left:0px;
margin-top:0.3em;
font-size:10pt;
}
tr{
vertical-align:top;
}
th,
th h3{
padding:4px;
text-align:left;
background-color:#0071C5;
font-weight:bold;
margin-top:1px;
margin-bottom:0;
color:#FFFFFF;
font-size:10pt;
vertical-align:middle;
}
th{
border:1px #dddddd solid;
padding-top:2px;
padding-bottom:0px;
padding-right:3px;
padding-left:3px;
}
td{
border:1px #dddddd solid;
vertical-align:top;
font-size:100%;
text-align:left;
margin-bottom:0;
}
td,
td p{
margin-top:0;
margin-left:0;
text-align:left;
font-size:inherit;
line-height:120%;
}
td p{
margin-bottom:0;
padding-top:5px;
padding-bottom:5px;
padding-right:5px;
padding-left:1px;
}
.noborder{
border:0px none;
}
.noborder1stcol{
border:0px none;
padding-left:0pt;
}
td ol{
font-size:inherit;
margin-left:28px;
}
td ul{
font-size:inherit;
margin-left:24px;
}
.DefListTbl{
width:90%;
margin-left:-3pt;
}
.syntaxdiagramtbl{
margin-left:-3pt;
}
.sdtbl{
}
.sdrow{
}
.sdtblp{
border:0px none;
font-size:inherit;
line-height:120%;
margin-bottom:0;
padding-bottom:0px;
padding-top:5px;
padding-left:0px;
padding-right:5px;
vertical-align:top;
}
.idepara, .ide_para{
border:0px none;
font-size:inherit;
line-height:120%;
margin-bottom:0;
padding-bottom:0px;
padding-top:5px;
padding-left:0px;
padding-right:5px;
vertical-align:top;
}
.specs {
border-collapse:collapse;
}
.specs td, .specs th {
font-size: 14px;
}
.specs td {
border: 1px solid black;
}
.specs td td, .specs td th {
border: none;
}
.specs td, .specs td td, .specs td th {
padding: 0 0.2em 0.2em;
text-align: center;
}
.specs td tr:last-child td,
.specs td tr:last-child th {
padding: 0 0.2em;
}
.serial-time {
}
.modified-time {
width: 6.5em;
}
.compiler {
}
.comp-opt {
}
.sys-specs {
width: 18em;
}
.note {
font-size:small;
font-style: italic;
}
</style>
<title>Intel&reg; Threading Building Blocks. Convex_hull sample</title>
</head>
<body>
<div id="banner">
<img class="logo" src="data:image/png;base64,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
9Or1LzUmVVz+HJXDAAAAAElFTkSuQmCC">
<h1 class="title">Intel&reg; Threading Building Blocks.<br>Convex_hull sample</h1>
</div>
<p>
Parallel version of convex hull algorithm (quick hull).
</p>
<div class="changes">
<div class="h3-alike">System Requirements</div>
<input type="checkbox">
<div class="show-hide">
<p>
For the most up to date system requirements, see the <a href="http://software.intel.com/en-us/articles/intel-threading-building-blocks-release-notes">release notes.</a>
</p>
</div>
</div>
<div class="changes">
<div class="h3-alike">Files</div>
<input type="checkbox" checked="checked">
<div class="show-hide">
<dl>
<dt><a href="convex_hull_sample.cpp">convex_hull_sample.cpp</a>
<dd>Source code for parallel version of the example which uses parallel_reduce, parallel_for and concurrent_vector.
<dt><a href="convex_hull_bench.cpp">convex_hull_bench.cpp</a>
<dd>Source code for the version of the example that compares serial and parallel buffered and unbuffered implementations.
<dt><a href="convex_hull.h">convex_hull.h</a>
<dd>Include file for the example.
<dt><a href="Makefile">Makefile</a>
<dd>Makefile for building the example.
</dl>
</div>
</div>
<div class="changes">
<div class="h3-alike">Directories</div>
<input type="checkbox" checked="checked">
<div class="show-hide">
<dl>
<dt><a href="msvs/">msvs</a>
<dd>Contains Microsoft* Visual Studio* workspace for building and running the example (Windows* systems only).
<dt><a href="xcode/">xcode</a>
<dd>Contains Xcode* IDE workspace for building and running the example (macOS* systems only).
</dl>
<p>For information about the minimum supported version of IDE, see <a href="http://software.intel.com/en-us/articles/intel-threading-building-blocks-release-notes">release notes.</a></p>
</div>
</div>
<div class="changes">
<div class="h3-alike">Build instructions</div>
<input type="checkbox" checked="checked">
<div class="show-hide">
<p>General build directions can be found <a href="../../index.html">here</a>.</p>
</div>
</div>
<div class="changes">
<div class="h3-alike">Usage</div>
<input type="checkbox" checked="checked">
<div class="show-hide">
<dl>
<dt><tt>convex_hull_sample [<i>S</i>] [<i>M</i>[:<i>N</i>]] [-v]</tt>
<dd><i>S</i> is the number of points (problem size).
<i>M:N</i> are a range of numbers of threads to be used.
Use the -v option to turn on verbose output.
<dt>To run a short version of this example, e.g., for use with Intel&reg; Threading Tools:
<dd>Build a <i>debug</i> version of the example
(see the <a href="../../index.html">build instructions</a>).
<br>Run it with a small problem size and the desired number of threads, e.g., <tt>convex_hull_sample&nbsp;4&nbsp;500000</tt>.
</dl>
</div>
</div>
<br>
<a href="../index.html">Up to parent directory</a>
<hr>
<div class="changes">
<div class="h3-alike">Legal Information</div>
<input type="checkbox">
<div class="show-hide">
<p>
Intel and the Intel logo are trademarks of Intel Corporation in the U.S. and/or other countries.
<br>* Other names and brands may be claimed as the property of others.
<br>&copy; 2020, Intel Corporation
</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,350 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
A146114A0B94631F000C6B18 /* convex_hull_bench.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A14611490B94631F000C6B18 /* convex_hull_bench.cpp */; };
A1F593A60B8F042A00073279 /* convex_hull_sample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A1F593A50B8F042A00073279 /* convex_hull_sample.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXBuildRule section */
C3C5895A218B677B00DAC94C /* PBXBuildRule */ = {
isa = PBXBuildRule;
compilerSpec = com.intel.compilers.icc.latest;
fileType = sourcecode.cpp;
isEditable = 1;
outputFiles = (
);
script = "# Type a script or drag a script file from your workspace to insert its path.\n";
};
/* End PBXBuildRule section */
/* Begin PBXCopyFilesBuildPhase section */
8DD76F690486A84900D96B5E /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 12;
dstPath = "";
dstSubfolderSpec = 16;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
A1F594F40B8F4E7700073279 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 16;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
A14611490B94631F000C6B18 /* convex_hull_bench.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = convex_hull_bench.cpp; path = ../convex_hull_bench.cpp; sourceTree = SOURCE_ROOT; };
A146114C0B9463CB000C6B18 /* convex_hull.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = convex_hull.h; path = ../convex_hull.h; sourceTree = SOURCE_ROOT; };
A1F593A50B8F042A00073279 /* convex_hull_sample.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = convex_hull_sample.cpp; path = ../convex_hull_sample.cpp; sourceTree = SOURCE_ROOT; };
A1F594EB0B8F4B5600073279 /* convex_hull_bench */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = convex_hull_bench; sourceTree = BUILT_PRODUCTS_DIR; };
A1F594FA0B8F4EE000073279 /* convex_hull_sample */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = convex_hull_sample; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
8DD76F660486A84900D96B5E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
A1F594E90B8F4B5600073279 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
08FB7794FE84155DC02AAC07 /* convex_hull */ = {
isa = PBXGroup;
children = (
08FB7795FE84155DC02AAC07 /* Source */,
1AB674ADFE9D54B511CA2CBB /* Products */,
);
name = convex_hull;
sourceTree = "<group>";
};
08FB7795FE84155DC02AAC07 /* Source */ = {
isa = PBXGroup;
children = (
A146114C0B9463CB000C6B18 /* convex_hull.h */,
A14611490B94631F000C6B18 /* convex_hull_bench.cpp */,
A1F593A50B8F042A00073279 /* convex_hull_sample.cpp */,
);
name = Source;
sourceTree = "<group>";
};
1AB674ADFE9D54B511CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
A1F594EB0B8F4B5600073279 /* convex_hull_bench */,
A1F594FA0B8F4EE000073279 /* convex_hull_sample */,
);
name = Products;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
8DD76F620486A84900D96B5E /* convex_hull_sample */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "convex_hull_sample" */;
buildPhases = (
8DD76F640486A84900D96B5E /* Sources */,
8DD76F660486A84900D96B5E /* Frameworks */,
8DD76F690486A84900D96B5E /* CopyFiles */,
);
buildRules = (
C3C5895A218B677B00DAC94C /* PBXBuildRule */,
);
dependencies = (
);
name = convex_hull_sample;
productInstallPath = "$(HOME)/bin";
productName = convex_hull;
productReference = A1F594FA0B8F4EE000073279 /* convex_hull_sample */;
productType = "com.apple.product-type.tool";
};
A1F594EA0B8F4B5600073279 /* convex_hull_bench */ = {
isa = PBXNativeTarget;
buildConfigurationList = A1F594EE0B8F4B8200073279 /* Build configuration list for PBXNativeTarget "convex_hull_bench" */;
buildPhases = (
A1F594E80B8F4B5600073279 /* Sources */,
A1F594E90B8F4B5600073279 /* Frameworks */,
A1F594F40B8F4E7700073279 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = convex_hull_bench;
productName = convex_hull_bench;
productReference = A1F594EB0B8F4B5600073279 /* convex_hull_bench */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1000;
};
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "convex_hull" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
en,
);
mainGroup = 08FB7794FE84155DC02AAC07 /* convex_hull */;
projectDirPath = "";
projectRoot = "";
targets = (
8DD76F620486A84900D96B5E /* convex_hull_sample */,
A1F594EA0B8F4B5600073279 /* convex_hull_bench */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
8DD76F640486A84900D96B5E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A1F593A60B8F042A00073279 /* convex_hull_sample.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A1F594E80B8F4B5600073279 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A146114A0B94631F000C6B18 /* convex_hull_bench.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
A1F593C60B8F0E6E00073279 /* Debug64 */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_VERSION = "";
HEADER_SEARCH_PATHS = "$(inherited)";
ICC_CXX_LANG_DIALECT = "c++11";
INSTALL_PATH = "$(HOME)/bin";
LD_RUNPATH_SEARCH_PATHS = "$(inherited)";
LIBRARY_SEARCH_PATHS = "$(inherited)";
PRODUCT_NAME = convex_hull_sample;
ZERO_LINK = NO;
};
name = Debug64;
};
A1F593C70B8F0E6E00073279 /* Release64 */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_VERSION = "";
HEADER_SEARCH_PATHS = "$(inherited)";
ICC_CXX_LANG_DIALECT = "c++11";
INSTALL_PATH = "$(HOME)/bin";
LD_RUNPATH_SEARCH_PATHS = "$(inherited)";
LIBRARY_SEARCH_PATHS = "$(inherited)";
PRODUCT_NAME = convex_hull_sample;
ZERO_LINK = NO;
};
name = Release64;
};
A1F593C80B8F0E6E00073279 /* Debug64 */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ENABLE_TESTABILITY = YES;
GCC_ENABLE_CPP_RTTI = YES;
GCC_MODEL_TUNING = "";
GCC_VERSION = "";
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(TBBROOT)/include",
/opt/intel/tbb/include,
);
ICC_CXX_LANG_DIALECT = "c++11";
LD_RUNPATH_SEARCH_PATHS = "$(TBBROOT)/lib /opt/intel/tbb/lib";
LIBRARY_SEARCH_PATHS = (
"$(TBBROOT)/lib",
/opt/intel/tbb/lib,
);
MACOSX_DEPLOYMENT_TARGET = 10.11;
ONLY_ACTIVE_ARCH = YES;
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-m64",
);
OTHER_LDFLAGS = (
"-m64",
"-ltbb_debug",
);
PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
SYMROOT = "/tmp/tbb-$(USER)";
VALID_ARCHS = x86_64;
};
name = Debug64;
};
A1F593C90B8F0E6E00073279 /* Release64 */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
GCC_ENABLE_CPP_RTTI = YES;
GCC_MODEL_TUNING = "";
GCC_VERSION = "";
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(TBBROOT)/include",
/opt/intel/tbb/include,
);
ICC_CXX_LANG_DIALECT = "c++11";
LD_RUNPATH_SEARCH_PATHS = "$(TBBROOT)/lib /opt/intel/tbb/lib";
LIBRARY_SEARCH_PATHS = (
"$(TBBROOT)/lib",
/opt/intel/tbb/lib,
);
MACOSX_DEPLOYMENT_TARGET = 10.11;
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-m64",
);
OTHER_LDFLAGS = (
"-m64",
"-ltbb",
);
PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
SYMROOT = "/tmp/tbb-$(USER)";
VALID_ARCHS = x86_64;
};
name = Release64;
};
A1F594F00B8F4B8200073279 /* Debug64 */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_VERSION = "";
HEADER_SEARCH_PATHS = "$(inherited)";
INSTALL_PATH = "$(HOME)/bin";
LD_RUNPATH_SEARCH_PATHS = "$(inherited)";
LIBRARY_SEARCH_PATHS = "$(inherited)";
PRODUCT_NAME = convex_hull_bench;
ZERO_LINK = NO;
};
name = Debug64;
};
A1F594F20B8F4B8200073279 /* Release64 */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_VERSION = "";
HEADER_SEARCH_PATHS = "$(inherited)";
INSTALL_PATH = "$(HOME)/bin";
LD_RUNPATH_SEARCH_PATHS = "$(inherited)";
LIBRARY_SEARCH_PATHS = "$(inherited)";
PRODUCT_NAME = convex_hull_bench;
ZERO_LINK = NO;
};
name = Release64;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "convex_hull_sample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A1F593C60B8F0E6E00073279 /* Debug64 */,
A1F593C70B8F0E6E00073279 /* Release64 */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release64;
};
1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "convex_hull" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A1F593C80B8F0E6E00073279 /* Debug64 */,
A1F593C90B8F0E6E00073279 /* Release64 */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release64;
};
A1F594EE0B8F4B8200073279 /* Build configuration list for PBXNativeTarget "convex_hull_bench" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A1F594F00B8F4B8200073279 /* Debug64 */,
A1F594F20B8F4B8200073279 /* Release64 */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release64;
};
/* End XCConfigurationList section */
};
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
}