diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 5934961b79a486dc501021ab458b773aca39b8a6..3cf361dc5f54b17ee4a93cbc9100d1eca84b0404 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -289,6 +289,35 @@ LLThread::id_t LLThread::getID() const return mThreadp ? mThreadp->get_id() : std::thread::id(); } + bool LLThread::setPriority(EThreadPriority thread_priority) +{ + if(!mThreadp) return false; +#if LL_WINDOWS + int thread_prio = 0; + switch (thread_priority) + { + case LOWEST: + thread_prio = THREAD_PRIORITY_LOWEST; + break; + case BELOW_NORMAL: + thread_prio = THREAD_PRIORITY_BELOW_NORMAL; + break; + default: + case NORMAL: + thread_prio = THREAD_PRIORITY_NORMAL; + break; + case ABOVE_NORMAL: + thread_prio = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case HIGHEST: + thread_prio = THREAD_PRIORITY_HIGHEST; + break; + } + SetThreadPriority(mThreadp->native_handle(), thread_prio); +#endif + return true; +} + //============================================================================ // Called from MAIN THREAD. diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 99d03708de2a5be69e08b1d567aea450360b6c3c..cbc1f42bbc8d33a0ec5cee12f8a9ec87127eab56 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -49,6 +49,15 @@ class LL_COMMON_API LLThread QUITTING= 2, // Someone wants this thread to quit CRASHED = -1 // An uncaught exception was thrown by the thread } EThreadStatus; + + typedef enum e_thread_priority + { + LOWEST = 0, + BELOW_NORMAL, + NORMAL, + ABOVE_NORMAL, + HIGHEST + } EThreadPriority; typedef std::thread::id id_t; LLThread(const std::string& name, apr_pool_t *poolp = NULL); @@ -85,6 +94,8 @@ class LL_COMMON_API LLThread id_t getID() const; + bool setPriority(EThreadPriority thread_priority); + private: bool mPaused; diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp index d5adf11264cfc25f8de690f545a2a80807355c50..5a3ef043dc7d9955d7b7c7c4ba128e21dfbfd241 100644 --- a/indra/llcommon/threadpool.cpp +++ b/indra/llcommon/threadpool.cpp @@ -21,21 +21,46 @@ #include "llevents.h" #include "stringize.h" -LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity): +LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity, EThreadPrio prio): super(name), mQueue(name, capacity), mName("ThreadPool:" + name), - mThreadCount(threads) + mThreadCount(threads), + mThreadPriority(prio) {} void LL::ThreadPool::start() { for (size_t i = 0; i < mThreadCount; ++i) { - std::string tname{ stringize(mName, ':', (i+1), '/', mThreadCount) }; - mThreads.emplace_back(tname, [this, tname]() - { - LL_PROFILER_SET_THREAD_NAME(tname.c_str()); + std::string tname{ stringize(mName, ':', (i + 1), '/', mThreadCount) }; + EThreadPrio prio = mThreadPriority; + mThreads.emplace_back(tname, [this, tname, prio]() + { + LL_PROFILER_SET_THREAD_NAME(tname.c_str()); +#if LL_WINDOWS + int thread_prio = 0; + switch (prio) + { + case E_LOWEST: + thread_prio = THREAD_PRIORITY_LOWEST; + break; + case E_BELOW_NORMAL: + thread_prio = THREAD_PRIORITY_BELOW_NORMAL; + break; + default: + case E_NORMAL: + thread_prio = THREAD_PRIORITY_NORMAL; + break; + case E_ABOVE_NORMAL: + thread_prio = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case E_HIGHEST: + thread_prio = THREAD_PRIORITY_HIGHEST; + break; + } + SetThreadPriority(GetCurrentThread(), thread_prio); +#endif run(tname); }); } diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h index f8eec3b45744d8a18532811a24901fe84271f62a..be0d856d896b73257e405af3570428a45892a9d7 100644 --- a/indra/llcommon/threadpool.h +++ b/indra/llcommon/threadpool.h @@ -27,11 +27,20 @@ namespace LL private: using super = LLInstanceTracker<ThreadPool, std::string>; public: + enum EThreadPrio + { + E_LOWEST = 0, + E_BELOW_NORMAL, + E_NORMAL, + E_ABOVE_NORMAL, + E_HIGHEST + }; + /** * Pass ThreadPool a string name. This can be used to look up the * relevant WorkQueue. */ - ThreadPool(const std::string& name, size_t threads=1, size_t capacity=1024); + ThreadPool(const std::string& name, size_t threads=1, size_t capacity=1024, EThreadPrio = E_NORMAL); virtual ~ThreadPool(); /** @@ -66,6 +75,7 @@ namespace LL std::string mName; size_t mThreadCount; std::vector<std::pair<std::string, std::thread>> mThreads; + EThreadPrio mThreadPriority; }; } // namespace LL diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index c8700fc793c2e12b0a98123f0f7bdfded43ab8f8..6397936a0c2cc8aba56e6b16c0b448315041c619 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -92,10 +92,11 @@ LLImageDecodeThread::LLImageDecodeThread(bool threaded, U32 pool_size) pool_size = 2U; // Use a sane default: 2 cores if (pool_size >= 8U) { - // Using number of (virtual) cores minus 3 for: + // Using number of (virtual) cores minus 4 for: // - main image worker // - viewer main loop thread // - mesh repo thread + // - gl image thread // further bound to a maximum of 12 threads (more than that is totally useless, even // when flying over main land with 512m draw distance). pool_size = llclamp(pool_size - 4U, 0U, 12U); @@ -124,6 +125,7 @@ LLImageDecodeThread::LLImageDecodeThread(bool threaded, U32 pool_size) { mThreadPool.push_back(std::make_unique<PoolWorkerThread>(fmt::format("Image Decode Thread {}", i))); mThreadPool[i]->start(); + mThreadPool[i]->setPriority(LLThread::BELOW_NORMAL); } } @@ -133,6 +135,10 @@ LLImageDecodeThread::~LLImageDecodeThread() if (sImageThreads > 0) { LL_INFOS() << "Requests failed to queue to pool: " << mFailedRequests << LL_ENDL; + for (auto& thread : mThreadPool) + { + thread->shutdown(); + } } delete mCreationMutex ; } @@ -344,7 +350,7 @@ bool LLImageDecodeThread::ImageRequest::tut_isOK() bool LLImageDecodeThread::enqueRequest(ImageRequest * req) { - for(size_t num_tries = 0, pool_size = mThreadPool.size(); num_tries <= pool_size; ++num_tries) + for(size_t num_tries = 0, pool_size = mThreadPool.size(); num_tries < pool_size; ++num_tries) { if (mLastPoolAllocation >= pool_size) { diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index feb4ed844d972908a10613918f9365e6a089a2c5..56d200e109a39d994b095a9f43ead37c51ab4801 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -2522,7 +2522,7 @@ LLImageGLThread::LLImageGLThread(LLWindow* window) // We want exactly one thread, but a very large capacity: we never want // anyone, especially inner-loop render code, to have to block on post() // because we're full. - : ThreadPool("LLImageGL", 1, 1024*1024) + : ThreadPool("LLImageGL", 1, 1024*1024, LL::ThreadPool::E_ABOVE_NORMAL) , mWindow(window) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 891a4d3f976c2c8643366210a16fd7cb27887730..2b524ff12ff8cdc17d9f3ff52c8d751bfcecab6c 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -4639,7 +4639,7 @@ std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList() #endif // LL_WINDOWS inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread() - : ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE) + : ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, LL::ThreadPool::E_ABOVE_NORMAL) { ThreadPool::start(); }