This commit is contained in:
enricoturri1966 2020-10-22 13:54:45 +02:00
commit be73962699
12 changed files with 219 additions and 38 deletions

View file

@ -46,6 +46,7 @@
#include "libslic3r/Format/SL1.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/AppConfig.hpp"
#include "libslic3r/Thread.hpp"
#include "PrusaSlicer.hpp"
@ -62,6 +63,9 @@ using namespace Slic3r;
int CLI::run(int argc, char **argv)
{
// Mark the main thread for the debugger and for runtime checks.
set_current_thread_name("slic3r_main");
#ifdef __WXGTK__
// On Linux, wxGTK has no support for Wayland, and the app crashes on
// startup if gtk3 is used. This env var has to be set explicitly to

View file

@ -201,6 +201,8 @@ add_library(libslic3r STATIC
Utils.hpp
Time.cpp
Time.hpp
Thread.cpp
Thread.hpp
TriangleSelector.cpp
TriangleSelector.hpp
MTUtils.hpp

View file

@ -10,6 +10,7 @@
#include "I18N.hpp"
#include "ShortestPath.hpp"
#include "SupportMaterial.hpp"
#include "Thread.hpp"
#include "GCode.hpp"
#include "GCode/WipeTower.hpp"
#include "Utils.hpp"
@ -1604,6 +1605,8 @@ void Print::auto_assign_extruders(ModelObject* model_object) const
// Slicing process, running at a background thread.
void Print::process()
{
name_tbb_thread_pool_threads();
BOOST_LOG_TRIVIAL(info) << "Starting the slicing process." << log_memory_info();
for (PrintObject *obj : m_objects)
obj->make_perimeters();

View file

@ -1688,12 +1688,6 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
m_typed_slices = false;
#ifdef SLIC3R_PROFILE
// Disable parallelization so the Shiny profiler works
static tbb::task_scheduler_init *tbb_init = nullptr;
tbb_init = new tbb::task_scheduler_init(1);
#endif
// 1) Initialize layers and their slice heights.
std::vector<float> slice_zs;
{

View file

@ -4,6 +4,7 @@
#include "ClipperUtils.hpp"
#include "Geometry.hpp"
#include "MTUtils.hpp"
#include "Thread.hpp"
#include <unordered_set>
#include <numeric>
@ -689,7 +690,10 @@ bool SLAPrint::invalidate_step(SLAPrintStep step)
void SLAPrint::process()
{
if(m_objects.empty()) return;
if (m_objects.empty())
return;
name_tbb_thread_pool_threads();
// Assumption: at this point the print objects should be populated only with
// the model objects we have to process and the instances are also filtered

158
src/libslic3r/Thread.cpp Normal file
View file

@ -0,0 +1,158 @@
#ifdef _WIN32
#include <windows.h>
#include <processthreadsapi.h>
#include <boost/nowide/convert.hpp>
#else
// any posix system
#include <pthread.h>
#endif
#include <condition_variable>
#include <mutex>
#include <tbb/parallel_for.h>
#include <tbb/tbb_thread.h>
#define SLIC3R_THREAD_NAME_WIN32_MODERN
#include "Thread.hpp"
#ifdef _WIN32
namespace Slic3r {
#ifdef SLIC3R_THREAD_NAME_WIN32_MODERN
static void WindowsSetThreadName(HANDLE hThread, const char *thread_name)
{
size_t len = strlen(thread_name);
if (len < 1024) {
// Allocate the temp string on stack.
wchar_t buf[1024];
::SetThreadDescription(hThread, boost::nowide::widen(buf, 1024, thread_name));
} else {
// Allocate dynamically.
::SetThreadDescription(hThread, boost::nowide::widen(thread_name).c_str());
}
}
#else // SLIC3R_THREAD_NAME_WIN32_MODERN
// use the old way by throwing an exception
const DWORD MS_VC_EXCEPTION=0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)
static void WindowsSetThreadName(HANDLE hThread, const char *thread_name)
{
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = threadName;
info.dwThreadID = ::GetThreadId(hThread);
info.dwFlags = 0;
__try
{
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
}
#endif // SLIC3R_THREAD_NAME_WIN32_MODERN
// posix
void set_thread_name(std::thread &thread, const char *thread_name)
{
WindowsSetThreadName(static_cast<HANDLE>(thread.native_handle()), thread_name);
}
void set_thread_name(boost::thread &thread, const char *thread_name)
{
WindowsSetThreadName(static_cast<HANDLE>(thread.native_handle()), thread_name);
}
void set_current_thread_name(const char *thread_name)
{
WindowsSetThreadName(::GetCurrentThread(), thread_name);
}
#else // _WIN32
// posix
void set_thread_name(std::thread &thread, const char *thread_name)
{
pthread_setname_np(thread->native_handle(), thread_name);
}
void set_thread_name(boost::thread &thread, const char *thread_name)
{
pthread_setname_np(thread->native_handle(), thread_name);
}
void set_current_thread_name(const char *thread_name)
{
set_thread_name(pthread_self(), thread_name);
}
#endif // _WIN32
// Spawn (n - 1) worker threads on Intel TBB thread pool and name them by an index and a system thread ID.
void name_tbb_thread_pool_threads()
{
static bool initialized = false;
if (initialized)
return;
initialized = true;
const size_t nthreads_hw = std::thread::hardware_concurrency();
size_t nthreads = nthreads_hw;
#ifdef SLIC3R_PROFILE
// Shiny profiler is not thread safe, thus disable parallelization.
nthreads = 1;
#endif
if (nthreads != nthreads_hw) {
static tbb::task_scheduler_init *tbb_init = nullptr;
tbb_init = new tbb::task_scheduler_init(nthreads);
}
std::atomic<size_t> nthreads_running(0);
std::condition_variable cv;
std::mutex cv_m;
auto master_thread_id = tbb::this_tbb_thread::get_id();
tbb::parallel_for(
tbb::blocked_range<size_t>(0, nthreads, 1),
[&nthreads_running, nthreads, &master_thread_id, &cv, &cv_m](const tbb::blocked_range<size_t> &range) {
assert(range.begin() + 1 == range.end());
if (nthreads_running.fetch_add(1) + 1 == nthreads) {
// All threads are spinning.
// Wake them up.
cv.notify_all();
} else {
// Wait for the last thread to wake the others.
std::unique_lock<std::mutex> lk(cv_m);
cv.wait(lk, [&nthreads_running, nthreads]{return nthreads_running == nthreads;});
}
auto thread_id = tbb::this_tbb_thread::get_id();
if (thread_id == master_thread_id) {
// The calling thread runs the 0'th task.
assert(range.begin() == 0);
} else {
assert(range.begin() > 0);
std::ostringstream name;
name << "slic3r_tbbpool_" << range.begin() << "_" << thread_id;
set_current_thread_name(name.str());
}
});
}
}

40
src/libslic3r/Thread.hpp Normal file
View file

@ -0,0 +1,40 @@
#ifndef GUI_THREAD_HPP
#define GUI_THREAD_HPP
#include <utility>
#include <thread>
#include <boost/thread.hpp>
namespace Slic3r {
void set_thread_name(std::thread &thread, const char *thread_name);
inline void set_thread_name(std::thread &thread, const std::string &thread_name) { set_thread_name(thread, thread_name.c_str()); }
void set_thread_name(boost::thread &thread, const char *thread_name);
inline void set_thread_name(boost::thread &thread, const std::string &thread_name) { set_thread_name(thread, thread_name.c_str()); }
void set_current_thread_name(const char *thread_name);
inline void set_current_thread_name(const std::string &thread_name) { set_current_thread_name(thread_name.c_str()); }
// To be called somewhere before the TBB threads are spinned for the first time, to
// give them names recognizible in the debugger.
void name_tbb_thread_pool_threads();
template<class Fn>
inline boost::thread create_thread(boost::thread::attributes &attrs, Fn &&fn)
{
// Duplicating the stack allocation size of Thread Building Block worker
// threads of the thread pool: allocate 4MB on a 64bit system, allocate 2MB
// on a 32bit system by default.
attrs.set_stack_size((sizeof(void*) == 4) ? (2048 * 1024) : (4096 * 1024));
return boost::thread{attrs, std::forward<Fn>(fn)};
}
template<class Fn> inline boost::thread create_thread(Fn &&fn)
{
boost::thread::attributes attrs;
return create_thread(attrs, std::forward<Fn>(fn));
}
}
#endif // GUI_THREAD_HPP

View file

@ -204,7 +204,6 @@ set(SLIC3R_GUI_SOURCES
Utils/UndoRedo.hpp
Utils/HexFile.cpp
Utils/HexFile.hpp
Utils/Thread.hpp
)
if (APPLE)

View file

@ -23,6 +23,7 @@
#include "libslic3r/GCode/PreviewData.hpp"
#endif // !ENABLE_GCODE_VIEWER
#include "libslic3r/Format/SL1.hpp"
#include "libslic3r/Thread.hpp"
#include "libslic3r/libslic3r.h"
#include <cassert>
@ -36,7 +37,6 @@
#include "I18N.hpp"
#include "RemovableDriveManager.hpp"
#include "slic3r/Utils/Thread.hpp"
#include "slic3r/GUI/Plater.hpp"
namespace Slic3r {
@ -224,6 +224,9 @@ void BackgroundSlicingProcess::process_sla()
void BackgroundSlicingProcess::thread_proc()
{
set_current_thread_name("slic3r_BackgroundSlicingProcess");
name_tbb_thread_pool_threads();
assert(m_print != nullptr);
assert(m_print == m_fff_print || m_print == m_sla_print);
std::unique_lock<std::mutex> lck(m_mutex);

View file

@ -1,6 +1,7 @@
#include <algorithm>
#include "Job.hpp"
#include <libslic3r/Thread.hpp>
#include <boost/log/trivial.hpp>
namespace Slic3r {

View file

@ -3,7 +3,8 @@
#include <atomic>
#include <slic3r/Utils/Thread.hpp>
#include "libslic3r/libslic3r.h"
#include <slic3r/GUI/I18N.hpp>
#include "ProgressIndicator.hpp"

View file

@ -1,28 +0,0 @@
#ifndef GUI_THREAD_HPP
#define GUI_THREAD_HPP
#include <utility>
#include <boost/thread.hpp>
namespace Slic3r {
template<class Fn>
inline boost::thread create_thread(boost::thread::attributes &attrs, Fn &&fn)
{
// Duplicating the stack allocation size of Thread Building Block worker
// threads of the thread pool: allocate 4MB on a 64bit system, allocate 2MB
// on a 32bit system by default.
attrs.set_stack_size((sizeof(void*) == 4) ? (2048 * 1024) : (4096 * 1024));
return boost::thread{attrs, std::forward<Fn>(fn)};
}
template<class Fn> inline boost::thread create_thread(Fn &&fn)
{
boost::thread::attributes attrs;
return create_thread(attrs, std::forward<Fn>(fn));
}
}
#endif // GUI_THREAD_HPP