Configuration of TBB work pool threads executed from the background

slicing process:
1) "C" locales are always enforced.
2) OSX Quality of Service level is set to make sure the slicing
  runs on fat cores on Apple Silicon if some fat cores are available.
This commit is contained in:
Vojtech Bubnik 2022-09-27 18:12:02 +02:00
parent 05a157c916
commit 9bc69efde6
4 changed files with 58 additions and 28 deletions

View File

@ -9,6 +9,7 @@
#include "GCode/WipeTower.hpp"
#include "ShortestPath.hpp"
#include "Print.hpp"
#include "Thread.hpp"
#include "Utils.hpp"
#include "ClipperUtils.hpp"
#include "libslic3r.h"
@ -34,8 +35,6 @@
#include "SVG.hpp"
#include <tbb/parallel_for.h>
#include <tbb/task_scheduler_observer.h>
#include <tbb/enumerable_thread_specific.h>
// Intel redesigned some TBB interface considerably when merging TBB with their oneAPI set of libraries, see GH #7332.
// We are using quite an old TBB 2017 U7. Before we update our build servers, let's use the old API, which is deprecated in up to date TBB.
@ -1469,32 +1468,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
print.throw_if_canceled();
}
// For unknown reasons and in sporadic cases when GCode export is processing, some participating thread
// in tbb::parallel_pipeline has not set locales to "C", probably because this thread is newly spawned.
// So in this class method on_scheduler_entry is called for every thread before it starts participating
// in tbb::parallel_pipeline to ensure that locales are set correctly
// For tbb::parallel_pipeline, it seems that on_scheduler_entry is called for every layer and every filter.
// We ensure using thread-local storage that locales will be set to "C" just once for any participating thread.
class TBBLocalesSetter : public tbb::task_scheduler_observer
{
public:
TBBLocalesSetter() { this->observe(true); }
~TBBLocalesSetter() override { this->observe(false); };
void on_scheduler_entry(bool is_worker) override
{
if (bool &is_locales_sets = m_is_locales_sets.local(); !is_locales_sets) {
// Set locales of the worker thread to "C".
set_c_locales();
is_locales_sets = true;
}
}
private:
tbb::enumerable_thread_specific<bool, tbb::cache_aligned_allocator<bool>, tbb::ets_key_usage_type::ets_key_per_instance> m_is_locales_sets{false};
};
// Process all layers of all objects (non-sequential mode) with a parallel pipeline:
// Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser
// and export G-code into file.

View File

@ -4,6 +4,9 @@
#else
// any posix system
#include <pthread.h>
#ifdef __APPLE__
#include <pthread/qos.h>
#endif // __APPLE__
#endif
#include <atomic>
@ -241,4 +244,26 @@ void name_tbb_thread_pool_threads_set_locale()
});
}
void set_current_thread_qos()
{
#ifdef __APPLE__
// OSX specific: Set Quality of Service to "user initiated", so that the threads will be scheduled to high performance
// cores if available.
pthread_set_qos_class_self_np(QOS_CLASS_USER_INITIATED, 0);
#endif // __APPLE__
}
void TBBLocalesSetter::on_scheduler_entry(bool is_worker)
{
// static std::atomic<int> cnt = 0;
// std::cout << "TBBLocalesSetter Entering " << cnt ++ << " ID " << std::this_thread::get_id() << "\n";
if (bool& is_locales_sets = m_is_locales_sets.local(); !is_locales_sets) {
// Set locales of the worker thread to "C".
set_c_locales();
// OSX specific: Elevate QOS on Apple Silicon.
set_current_thread_qos();
is_locales_sets = true;
}
}
}

View File

@ -6,6 +6,9 @@
#include <thread>
#include <boost/thread.hpp>
#include <tbb/task_scheduler_observer.h>
#include <tbb/enumerable_thread_specific.h>
namespace Slic3r {
// Set / get thread name.
@ -26,6 +29,10 @@ inline bool set_thread_name(boost::thread &thread, const std::string &thread_nam
bool set_current_thread_name(const char *thread_name);
inline bool set_current_thread_name(const std::string &thread_name) { return set_current_thread_name(thread_name.c_str()); }
// OSX specific: Set Quality of Service to "user initiated", so that the threads will be scheduled to high performance
// cores if available.
void set_current_thread_qos();
// Returns nullopt if not supported.
// Not supported by OSX.
// Naming threads is only supported on newer Windows 10.
@ -53,6 +60,25 @@ template<class Fn> inline boost::thread create_thread(Fn &&fn)
return create_thread(attrs, std::forward<Fn>(fn));
}
// For unknown reasons and in sporadic cases when GCode export is processing, some participating thread
// in tbb::parallel_pipeline has not set locales to "C", probably because this thread is newly spawned.
// So in this class method on_scheduler_entry is called for every thread before it starts participating
// in tbb::parallel_pipeline to ensure that locales are set correctly
//
// For tbb::parallel_pipeline, it seems that on_scheduler_entry is called for every layer and every filter.
// We ensure using thread-local storage that locales will be set to "C" just once for any participating thread.
class TBBLocalesSetter : public tbb::task_scheduler_observer
{
public:
TBBLocalesSetter() { this->observe(true); }
~TBBLocalesSetter() override { this->observe(false); };
void on_scheduler_entry(bool is_worker) override;
private:
tbb::enumerable_thread_specific<bool, tbb::cache_aligned_allocator<bool>, tbb::ets_key_usage_type::ets_key_per_instance> m_is_locales_sets{ false };
};
}
#endif // GUI_THREAD_HPP

View File

@ -211,6 +211,12 @@ void BackgroundSlicingProcess::thread_proc()
set_current_thread_name("slic3r_BgSlcPcs");
name_tbb_thread_pool_threads_set_locale();
// Set "C" locales and enforce OSX QoS level on all threads entering an arena.
// The cost of the callback is quite low: The callback is called once per thread
// entering a parallel loop and the callback is guarded with a thread local
// variable to be executed just once.
TBBLocalesSetter setter;
assert(m_print != nullptr);
assert(m_print == m_fff_print || m_print == m_sla_print);
std::unique_lock<std::mutex> lck(m_mutex);