Added dependencies on the Intel Thread Building Blocks.

Changed the C++ parallelization code to Intel Thread Building Blocks.
This commit is contained in:
bubnikv 2017-03-07 13:03:14 +01:00
parent 8a42c0ad9f
commit cb1a6eae1e
6 changed files with 158 additions and 96 deletions

View file

@ -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";

View file

@ -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;

View file

@ -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};
*/

View file

@ -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.

View file

@ -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;

View file

@ -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)
{