Added dependencies on the Intel Thread Building Blocks.
Changed the C++ parallelization code to Intel Thread Building Blocks.
This commit is contained in:
parent
8a42c0ad9f
commit
cb1a6eae1e
6 changed files with 158 additions and 96 deletions
140
xs/Build.PL
140
xs/Build.PL
|
@ -8,8 +8,18 @@ use ExtUtils::CppGuess;
|
|||
use Module::Build::WithXSpp;
|
||||
|
||||
my $cpp_guess = ExtUtils::CppGuess->new;
|
||||
my $lib_ext = ${$cpp_guess}{config}{lib_ext};
|
||||
my $mswin = $^O eq 'MSWin32';
|
||||
|
||||
# Library paths to search for boost, thread building blocks and such.
|
||||
# On Windows, there is really no standard. On Unices, this is a bit better.
|
||||
my @library_path_prefixes = ();
|
||||
if ($mswin) {
|
||||
@library_path_prefixes = ("C:\\", "C:\\dev\\", "C:\\local\\", "D:\\", "D:\\dev\\", "D:\\local\\");
|
||||
} else {
|
||||
@library_path_prefixes = qw(/opt/local/ /usr/local/ /opt/ /usr/);
|
||||
}
|
||||
|
||||
# _GLIBCXX_USE_C99 : to get the long long type for g++
|
||||
# HAS_BOOL : stops Perl/lib/CORE/handy.h from doing "# define bool char" for MSVC
|
||||
# NOGDI : prevents inclusion of wingdi.h which defines functions Polygon() and Polyline() in global namespace
|
||||
|
@ -76,24 +86,23 @@ if (defined $ENV{BOOST_INCLUDEDIR}) {
|
|||
# Boost library was not defined by the environment.
|
||||
# Try to guess at some default paths.
|
||||
if ($mswin) {
|
||||
for my $path (glob('C:\dev\boost*\include'), glob ('C:\boost*\include')) {
|
||||
for my $path (map glob($_ . 'boost*\include'), @library_path_prefixes) {
|
||||
push @boost_include, $path;
|
||||
}
|
||||
if (! @boost_include) {
|
||||
# No boost\include. Try to include the boost root.
|
||||
for my $path (glob('C:\dev\boost*'), glob ('C:\boost*')) {
|
||||
for my $path (map glob($_ . 'boost*'), @library_path_prefixes) {
|
||||
push @boost_include, $path;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
push @boost_include, grep { -d $_ }
|
||||
qw(/opt/local/include /usr/local/include /opt/include /usr/include);
|
||||
@boost_include = grep { -d $_ . '/boost' } map { $_ . 'include' } @library_path_prefixes;
|
||||
}
|
||||
}
|
||||
|
||||
my @boost_libs = ();
|
||||
if (defined $ENV{BOOST_LIBRARYDIR}) {
|
||||
push @boost_libs, $ENV{BOOST_LIBRARYDIR}
|
||||
push @boost_libs, $ENV{BOOST_LIBRARYDIR};
|
||||
} elsif (defined $ENV{BOOST_DIR}) {
|
||||
my $subdir = $ENV{BOOST_DIR} . ($mswin ? '\stage\lib' : '/stage/lib');
|
||||
if (-d $subdir) {
|
||||
|
@ -105,14 +114,11 @@ if (defined $ENV{BOOST_LIBRARYDIR}) {
|
|||
# Boost library was not defined by the environment.
|
||||
# Try to guess at some default paths.
|
||||
if ($mswin) {
|
||||
for my $path (
|
||||
glob('C:\dev\boost*\lib'), glob ('C:\boost*\lib'),
|
||||
glob('C:\dev\boost*\stage\lib'), glob ('C:\boost*\stage\lib')) {
|
||||
for my $path (map (glob($_ . 'boost*\lib'), glob($_ . 'boost*\stage\lib')), @library_path_prefixes) {
|
||||
push @boost_libs, $path;
|
||||
}
|
||||
} else {
|
||||
push @boost_libs, grep { -d $_ }
|
||||
qw(/opt/local/lib /usr/local/lib /opt/lib /usr/lib /lib);
|
||||
push @boost_libs, grep { -d $_ } map $_ . 'lib', @library_path_prefixes;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,7 +144,6 @@ if ($have_boost) {
|
|||
} else {
|
||||
# Either static linking, or check_lib could not be used to find the boost libraries.
|
||||
my $lib_prefix = 'libboost_';
|
||||
my $lib_ext = ${$cpp_guess}{config}{lib_ext};
|
||||
PATH: foreach my $path (@boost_libs) {
|
||||
# Try to find the boost system library.
|
||||
my @files = glob "$path/${lib_prefix}system*$lib_ext";
|
||||
|
@ -185,6 +190,110 @@ is handy, if you have built Boost libraries with mutliple settings.
|
|||
|
||||
EOF
|
||||
|
||||
# Search for the Intel Thread Building Blocks.
|
||||
my @tbb_include = ();
|
||||
if (defined $ENV{TBB_INCLUDEDIR}) {
|
||||
push @tbb_include, $ENV{TBB_INCLUDEDIR}
|
||||
} elsif (defined $ENV{TBB_DIR}) {
|
||||
my $subdir = $ENV{TBB_DIR} . (($mswin == 1) ? '\include' : '/include');
|
||||
push @tbb_include, $subdir if (-d $subdir);
|
||||
} else {
|
||||
# Thread Building Blocks library was not defined by the environment.
|
||||
# Try to guess at some default paths.
|
||||
if ($mswin) {
|
||||
for my $path (map glob($_ . 'tbb*\include'), @library_path_prefixes) {
|
||||
push @tbb_include, $path;
|
||||
}
|
||||
} else {
|
||||
@tbb_include = grep { -d $_ . '/tbb' } map { $_ . 'include' } @library_path_prefixes;
|
||||
}
|
||||
}
|
||||
|
||||
my @tbb_libs = ();
|
||||
if (defined $ENV{TBB_LIBRARYDIR}) {
|
||||
push @tbb_libs, $ENV{TBB_LIBRARYDIR}
|
||||
} elsif (defined $ENV{TBB_DIR}) {
|
||||
my $subdir = $ENV{TBB_DIR} . ($mswin ? '\lib' : '/lib');
|
||||
push @tbb_libs, $subdir if (-d $subdir);
|
||||
} else {
|
||||
# Thread Building Blocks library was not defined by the environment.
|
||||
# Try to guess at some default paths.
|
||||
if ($mswin) {
|
||||
for my $path (map { glob($_ . 'tbb*\lib') } @library_path_prefixes) {
|
||||
push @tbb_libs, $path;
|
||||
}
|
||||
} else {
|
||||
@tbb_libs = grep { -d $_ } map { $_ . 'lib' } @library_path_prefixes;
|
||||
}
|
||||
}
|
||||
|
||||
# In order to generate the -l switches we need to know how Thread Building Blocks libraries are named
|
||||
my $have_tbb = 0;
|
||||
#my @tbb_libraries = qw(tbb tbbmalloc tbbmalloc_proxy); # we need these
|
||||
my @tbb_libraries = qw(tbb); # we need these
|
||||
|
||||
if (!$ENV{SLIC3R_STATIC}) {
|
||||
# Dynamic linking of Thread Building Blocks libraries.
|
||||
if (! $mswin) {
|
||||
# Check without explicit lib path (works on Linux and OSX).
|
||||
$have_tbb = 1
|
||||
if check_lib(
|
||||
lib => [ @tbb_libraries ],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($have_tbb) {
|
||||
# The Thread Building Blocks library was detected by check_lib on Linux.
|
||||
push @LIBS, map "-l${_}", @tbb_libraries;
|
||||
} else {
|
||||
# Either static linking, or check_lib could not be used to find the Thread Building Blocks libraries.
|
||||
my $lib_prefix = $cpp_guess->is_msvc ? '' : 'lib';
|
||||
PATH: foreach my $path (@tbb_libs) {
|
||||
# Try to find the Thread Building Blocks system library.
|
||||
my @files = glob "$path/${lib_prefix}tbb*$lib_ext";
|
||||
next if !@files;
|
||||
if ($files[0] =~ /\Q${lib_prefix}tbb\E([^.]*)\Q$lib_ext\E$/) {
|
||||
# Suffix contains the version number, the build type etc.
|
||||
my $suffix = $1;
|
||||
# Verify existence of all required TBB libraries at $path.
|
||||
for my $lib (map "${lib_prefix}${_}${suffix}${lib_ext}", @tbb_libraries) {
|
||||
# If the library file does not exist, try next library path.
|
||||
-f "$path/$lib" or next PATH;
|
||||
}
|
||||
if (! $cpp_guess->is_msvc) {
|
||||
# Test the correctness of TBB libraries by linking them to a minimal C program.
|
||||
check_lib(
|
||||
lib => [ map "${_}${suffix}", @tbb_libraries ],
|
||||
INC => join(' ', map "-I$_", @INC, @tbb_include),
|
||||
LIBS => "-L$path",
|
||||
) or next;
|
||||
}
|
||||
push @INC, (map " -I$_", @tbb_include); # TODO: only use the one related to the chosen lib path
|
||||
if ($ENV{SLIC3R_STATIC} || $cpp_guess->is_msvc) {
|
||||
push @LIBS, map "${path}/${_}_static.lib", @tbb_libraries;
|
||||
} else {
|
||||
push @LIBS, " -L$path", (map " -l$_$suffix", @tbb_libraries);
|
||||
}
|
||||
$have_tbb = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
die <<'EOF' if !$have_tbb;
|
||||
Slic3r requires the Intel Thread Building Blocks libraries. Please make sure the library is installed.
|
||||
|
||||
If the Intel Thread Building Blocks library is installed, this script should be able to locate them in several
|
||||
standard locations. If this is not the case, you might want to supply a path to the library
|
||||
through the TBB_DIR environment variable:
|
||||
|
||||
TBB_DIR=/path/to/TBB perl Build.PL
|
||||
|
||||
Or you may specify TBB_INCLUDEPATH and TBB_LIBRARYPATH separatly, which
|
||||
is handy, if you have built the Thread Building Blocks libraries with mutliple settings.
|
||||
|
||||
EOF
|
||||
|
||||
# Add the OpenGL and GLU libraries.
|
||||
if ($ENV{SLIC3R_GUI}) {
|
||||
if ($mswin) {
|
||||
|
@ -206,15 +315,6 @@ if ($ENV{SLIC3R_DEBUG}) {
|
|||
# Disable asserts in the release builds.
|
||||
push @cflags, '-DNDEBUG';
|
||||
}
|
||||
if ($cpp_guess->is_gcc) {
|
||||
# check whether we're dealing with a buggy GCC version
|
||||
# see https://github.com/alexrj/Slic3r/issues/1965
|
||||
if (`cc --version` =~ m/ 4\.7\.[012]/) {
|
||||
# Workaround suggested by Boost devs:
|
||||
# https://svn.boost.org/trac/boost/ticket/8695
|
||||
push @cflags, qw(-fno-inline-small-functions);
|
||||
}
|
||||
}
|
||||
|
||||
print "\n";
|
||||
print 'With @cflags: ', join(', ', map "\"$_\"", @cflags), "\n";
|
||||
|
|
|
@ -1029,6 +1029,7 @@ GCode::needs_retraction(const Polyline &travel, ExtrusionRole role)
|
|||
|
||||
if (role == erSupportMaterial) {
|
||||
const SupportLayer* support_layer = dynamic_cast<const SupportLayer*>(this->layer);
|
||||
//FIXME support_layer->support_islands.contains should use some search structure!
|
||||
if (support_layer != NULL && support_layer->support_islands.contains(travel)) {
|
||||
// skip retraction if this is a travel move inside a support material island
|
||||
return false;
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
#include <utility>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/atomic.h>
|
||||
|
||||
#include <Shiny/Shiny.h>
|
||||
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
|
@ -632,7 +635,7 @@ PrintObject::discover_vertical_shells()
|
|||
LayerRegion &neighbor_region = *neighbor_layer.get_region(int(idx_region));
|
||||
Polygons newholes;
|
||||
for (size_t idx_region = 0; idx_region < this->_print->regions.size(); ++ idx_region)
|
||||
polygons_append(newholes, to_polygons(neighbor_layer.get_region(idx_region)->fill_expolygons));
|
||||
polygons_append(newholes, to_polygons(neighbor_layer.regions[idx_region]->fill_expolygons));
|
||||
if (hole_first) {
|
||||
hole_first = false;
|
||||
polygons_append(holes, STDMOVE(newholes));
|
||||
|
@ -1267,13 +1270,16 @@ PrintObject::_make_perimeters()
|
|||
}
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel";
|
||||
parallelize<Layer*>(
|
||||
std::queue<Layer*>(std::deque<Layer*>(this->layers.begin(), this->layers.end())), // cast LayerPtrs to std::queue<Layer*>
|
||||
boost::bind(&Slic3r::Layer::make_perimeters, _1),
|
||||
this->_print->config.threads.value
|
||||
BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - start";
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<size_t>(0, this->layers.size()),
|
||||
[this](const tbb::blocked_range<size_t>& range) {
|
||||
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx)
|
||||
this->layers[layer_idx]->make_perimeters();
|
||||
}
|
||||
);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - end";
|
||||
|
||||
/*
|
||||
simplify slices (both layer and region slices),
|
||||
we only need the max resolution for perimeters
|
||||
|
@ -1290,13 +1296,16 @@ PrintObject::_infill()
|
|||
if (this->state.is_done(posInfill)) return;
|
||||
this->state.set_started(posInfill);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel";
|
||||
parallelize<Layer*>(
|
||||
std::queue<Layer*>(std::deque<Layer*>(this->layers.begin(), this->layers.end())), // cast LayerPtrs to std::queue<Layer*>
|
||||
boost::bind(&Slic3r::Layer::make_fills, _1),
|
||||
this->_print->config.threads.value
|
||||
BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start";
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<size_t>(0, this->layers.size()),
|
||||
[this](const tbb::blocked_range<size_t>& range) {
|
||||
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx)
|
||||
this->layers[layer_idx]->make_fills();
|
||||
}
|
||||
);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - end";
|
||||
|
||||
/* we could free memory now, but this would make this step not idempotent
|
||||
### $_->fill_surfaces->clear for map @{$_->regions}, @{$object->layers};
|
||||
*/
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
|
||||
#if 0
|
||||
#define DEBUG
|
||||
#define _DEBUG
|
||||
|
@ -672,10 +674,12 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* la
|
|||
std::vector<IntersectionLines> lines(z.size());
|
||||
{
|
||||
boost::mutex lines_mutex;
|
||||
parallelize<int>(
|
||||
0,
|
||||
this->mesh->stl.stats.number_of_facets-1,
|
||||
boost::bind(&TriangleMeshSlicer::_slice_do, this, _1, &lines, &lines_mutex, z)
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<int>(0,this->mesh->stl.stats.number_of_facets),
|
||||
[&lines, &lines_mutex, &z, this](const tbb::blocked_range<int>& range) {
|
||||
for (int facet_idx = range.begin(); facet_idx < range.end(); ++ facet_idx)
|
||||
this->_slice_do(facet_idx, &lines, &lines_mutex, z);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -684,10 +688,12 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* la
|
|||
// build loops
|
||||
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::_make_loops_do";
|
||||
layers->resize(z.size());
|
||||
parallelize<size_t>(
|
||||
0,
|
||||
lines.size()-1,
|
||||
boost::bind(&TriangleMeshSlicer::_make_loops_do, this, _1, &lines, layers)
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<size_t>(0, lines.size()),
|
||||
[&lines, &layers, this](const tbb::blocked_range<size_t>& range) {
|
||||
for (size_t line_idx = range.begin(); line_idx < range.end(); ++ line_idx)
|
||||
this->make_loops(lines[line_idx], &(*layers)[line_idx]);
|
||||
}
|
||||
);
|
||||
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::slice finished";
|
||||
}
|
||||
|
@ -873,12 +879,6 @@ bool TriangleMeshSlicer::slice_facet(
|
|||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
TriangleMeshSlicer::_make_loops_do(size_t i, std::vector<IntersectionLines>* lines, std::vector<Polygons>* layers) const
|
||||
{
|
||||
this->make_loops((*lines)[i], &(*layers)[i]);
|
||||
}
|
||||
|
||||
void TriangleMeshSlicer::make_loops(std::vector<IntersectionLine> &lines, Polygons* loops) const
|
||||
{
|
||||
// Remove tangent edges.
|
||||
|
|
|
@ -132,7 +132,6 @@ private:
|
|||
std::vector<stl_vertex> v_scaled_shared;
|
||||
|
||||
void _slice_do(size_t facet_idx, std::vector<IntersectionLines>* lines, boost::mutex* lines_mutex, const std::vector<float> &z) const;
|
||||
void _make_loops_do(size_t i, std::vector<IntersectionLines>* lines, std::vector<Polygons>* layers) const;
|
||||
void make_loops(std::vector<IntersectionLine> &lines, Polygons* loops) const;
|
||||
void make_expolygons(const Polygons &loops, ExPolygons* slices) const;
|
||||
void make_expolygons_simple(std::vector<IntersectionLine> &lines, ExPolygons* slices) const;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <boost/thread.hpp>
|
||||
|
||||
#define SLIC3R_FORK_NAME "Slic3r Prusa Edition"
|
||||
#define SLIC3R_VERSION "1.31.6"
|
||||
#define SLIC3R_VERSION "1.33.8.devel"
|
||||
#define SLIC3R_BUILD "UNKNOWN"
|
||||
|
||||
//FIXME This epsilon value is used for many non-related purposes:
|
||||
|
@ -99,53 +99,6 @@ inline void append_to(std::vector<T> &dst, const std::vector<T> &src)
|
|||
dst.insert(dst.end(), src.begin(), src.end());
|
||||
}
|
||||
|
||||
template <class T> void
|
||||
_parallelize_do(std::queue<T>* queue, boost::mutex* queue_mutex, boost::function<void(T)> func)
|
||||
{
|
||||
//std::cout << "THREAD STARTED: " << boost::this_thread::get_id() << std::endl;
|
||||
while (true) {
|
||||
T i;
|
||||
{
|
||||
boost::lock_guard<boost::mutex> l(*queue_mutex);
|
||||
if (queue->empty()) return;
|
||||
i = queue->front();
|
||||
queue->pop();
|
||||
}
|
||||
//std::cout << " Thread " << boost::this_thread::get_id() << " processing item " << i << std::endl;
|
||||
func(i);
|
||||
boost::this_thread::interruption_point();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T> void
|
||||
parallelize(std::queue<T> queue, boost::function<void(T)> func,
|
||||
int threads_count = boost::thread::hardware_concurrency())
|
||||
{
|
||||
#ifdef SLIC3R_PROFILE
|
||||
while (! queue.empty()) {
|
||||
func(queue.front());
|
||||
queue.pop();
|
||||
}
|
||||
#else
|
||||
if (threads_count == 0)
|
||||
threads_count = 2;
|
||||
boost::mutex queue_mutex;
|
||||
boost::thread_group workers;
|
||||
for (int i = 0; i < std::min(threads_count, int(queue.size())); ++ i)
|
||||
workers.add_thread(new boost::thread(&_parallelize_do<T>, &queue, &queue_mutex, func));
|
||||
workers.join_all();
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T> void
|
||||
parallelize(T start, T end, boost::function<void(T)> func,
|
||||
int threads_count = boost::thread::hardware_concurrency())
|
||||
{
|
||||
std::queue<T> queue;
|
||||
for (T i = start; i <= end; ++i) queue.push(i);
|
||||
parallelize(queue, func, threads_count);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void append(std::vector<T>& dest, const std::vector<T>& src)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue