diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index e44dfb742..e2bd6ef65 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -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 -#include -#include // 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, 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. diff --git a/src/libslic3r/Thread.cpp b/src/libslic3r/Thread.cpp index 4fe07fb59..22d4cb419 100644 --- a/src/libslic3r/Thread.cpp +++ b/src/libslic3r/Thread.cpp @@ -4,6 +4,9 @@ #else // any posix system #include + #ifdef __APPLE__ + #include + #endif // __APPLE__ #endif #include @@ -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 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; + } +} + } diff --git a/src/libslic3r/Thread.hpp b/src/libslic3r/Thread.hpp index 9afe13b42..252116ea7 100644 --- a/src/libslic3r/Thread.hpp +++ b/src/libslic3r/Thread.hpp @@ -6,6 +6,9 @@ #include #include +#include +#include + 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 inline boost::thread create_thread(Fn &&fn) return create_thread(attrs, std::forward(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, tbb::ets_key_usage_type::ets_key_per_instance> m_is_locales_sets{ false }; +}; + } #endif // GUI_THREAD_HPP diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 173d34570..275fcdc98 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -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 lck(m_mutex);