From 9b0d8c7e629597fd8e6dfb91a6b8f625b34ab274 Mon Sep 17 00:00:00 2001 From: Runitai Linden Date: Mon, 22 Nov 2021 18:42:56 -0600 Subject: SL-16094 More profile hooks for threading code, remove redundant wglCreateContextAttribs call --- indra/llcommon/llthreadsafequeue.h | 18 ++++++++++++++++++ indra/llcommon/threadpool.cpp | 6 +++++- indra/llcommon/threadsafeschedule.h | 34 ++++++++++++++++++++++++++++++---- 3 files changed, 53 insertions(+), 5 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h index 5c934791fe..2806506550 100644 --- a/indra/llcommon/llthreadsafequeue.h +++ b/indra/llcommon/llthreadsafequeue.h @@ -275,6 +275,7 @@ template template bool LLThreadSafeQueue::tryLock(CALLABLE&& callable) { + LL_PROFILE_ZONE_SCOPED; lock_t lock1(mLock, std::defer_lock); if (!lock1.try_lock()) return false; @@ -291,6 +292,7 @@ bool LLThreadSafeQueue::tryLockUntil( const std::chrono::time_point& until, CALLABLE&& callable) { + LL_PROFILE_ZONE_SCOPED; lock_t lock1(mLock, std::defer_lock); if (!lock1.try_lock_until(until)) return false; @@ -304,6 +306,7 @@ template template bool LLThreadSafeQueue::push_(lock_t& lock, T&& element) { + LL_PROFILE_ZONE_SCOPED; if (mStorage.size() >= mCapacity) return false; @@ -319,6 +322,7 @@ template template bool LLThreadSafeQueue::pushIfOpen(T&& element) { + LL_PROFILE_ZONE_SCOPED; lock_t lock1(mLock); while (true) { @@ -341,6 +345,7 @@ template template void LLThreadSafeQueue::push(T&& element) { + LL_PROFILE_ZONE_SCOPED; if (! pushIfOpen(std::forward(element))) { LLTHROW(LLThreadSafeQueueInterrupt()); @@ -352,6 +357,7 @@ template template bool LLThreadSafeQueue::tryPush(T&& element) { + LL_PROFILE_ZONE_SCOPED; return tryLock( [this, element=std::move(element)](lock_t& lock) { @@ -368,6 +374,7 @@ bool LLThreadSafeQueue::tryPushFor( const std::chrono::duration& timeout, T&& element) { + LL_PROFILE_ZONE_SCOPED; // Convert duration to time_point: passing the same timeout duration to // each of multiple calls is wrong. return tryPushUntil(std::chrono::steady_clock::now() + timeout, @@ -381,6 +388,7 @@ bool LLThreadSafeQueue::tryPushUntil( const std::chrono::time_point& until, T&& element) { + LL_PROFILE_ZONE_SCOPED; return tryLockUntil( until, [this, until, element=std::move(element)](lock_t& lock) @@ -413,6 +421,7 @@ template typename LLThreadSafeQueue::pop_result LLThreadSafeQueue::pop_(lock_t& lock, ElementT& element) { + LL_PROFILE_ZONE_SCOPED; // If mStorage is empty, there's no head element. if (mStorage.empty()) return mClosed? DONE : EMPTY; @@ -434,6 +443,7 @@ LLThreadSafeQueue::pop_(lock_t& lock, ElementT& element) template ElementT LLThreadSafeQueue::pop(void) { + LL_PROFILE_ZONE_SCOPED; lock_t lock1(mLock); ElementT value; while (true) @@ -462,6 +472,7 @@ ElementT LLThreadSafeQueue::pop(void) template bool LLThreadSafeQueue::tryPop(ElementT & element) { + LL_PROFILE_ZONE_SCOPED; return tryLock( [this, &element](lock_t& lock) { @@ -479,6 +490,7 @@ bool LLThreadSafeQueue::tryPopFor( const std::chrono::duration& timeout, ElementT& element) { + LL_PROFILE_ZONE_SCOPED; // Convert duration to time_point: passing the same timeout duration to // each of multiple calls is wrong. return tryPopUntil(std::chrono::steady_clock::now() + timeout, element); @@ -491,6 +503,7 @@ bool LLThreadSafeQueue::tryPopUntil( const std::chrono::time_point& until, ElementT& element) { + LL_PROFILE_ZONE_SCOPED; return tryLockUntil( until, [this, until, &element](lock_t& lock) @@ -510,6 +523,7 @@ LLThreadSafeQueue::tryPopUntil_( const std::chrono::time_point& until, ElementT& element) { + LL_PROFILE_ZONE_SCOPED; while (true) { pop_result popped = pop_(lock, element); @@ -536,6 +550,7 @@ LLThreadSafeQueue::tryPopUntil_( template size_t LLThreadSafeQueue::size(void) { + LL_PROFILE_ZONE_SCOPED; lock_t lock(mLock); return mStorage.size(); } @@ -544,6 +559,7 @@ size_t LLThreadSafeQueue::size(void) template void LLThreadSafeQueue::close() { + LL_PROFILE_ZONE_SCOPED; lock_t lock(mLock); mClosed = true; lock.unlock(); @@ -557,6 +573,7 @@ void LLThreadSafeQueue::close() template bool LLThreadSafeQueue::isClosed() { + LL_PROFILE_ZONE_SCOPED; lock_t lock(mLock); return mClosed; } @@ -565,6 +582,7 @@ bool LLThreadSafeQueue::isClosed() template bool LLThreadSafeQueue::done() { + LL_PROFILE_ZONE_SCOPED; lock_t lock(mLock); return mClosed && mStorage.empty(); } diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp index cf25cc838e..06e0dc5bfc 100644 --- a/indra/llcommon/threadpool.cpp +++ b/indra/llcommon/threadpool.cpp @@ -28,7 +28,11 @@ LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capac for (size_t i = 0; i < threads; ++i) { std::string tname{ STRINGIZE(mName << ':' << (i+1) << '/' << threads) }; - mThreads.emplace_back(tname, [this, tname](){ run(tname); }); + mThreads.emplace_back(tname, [this, tname]() + { + LL_PROFILER_SET_THREAD_NAME(tname.c_str()); + run(tname); + }); } // Listen on "LLApp", and when the app is shutting down, close the queue // and join the workers. diff --git a/indra/llcommon/threadsafeschedule.h b/indra/llcommon/threadsafeschedule.h index c8ad23532b..601681d550 100644 --- a/indra/llcommon/threadsafeschedule.h +++ b/indra/llcommon/threadsafeschedule.h @@ -98,12 +98,14 @@ namespace LL // we could minimize redundancy by breaking out a common base class... void push(const DataTuple& tuple) { + LL_PROFILE_ZONE_SCOPED; push(tuple_cons(Clock::now(), tuple)); } /// individually pass each component of the TimeTuple void push(const TimePoint& time, Args&&... args) { + LL_PROFILE_ZONE_SCOPED; push(TimeTuple(time, std::forward(args)...)); } @@ -114,6 +116,7 @@ namespace LL // and call that overload. void push(Args&&... args) { + LL_PROFILE_ZONE_SCOPED; push(Clock::now(), std::forward(args)...); } @@ -124,18 +127,21 @@ namespace LL /// DataTuple with implicit now bool tryPush(const DataTuple& tuple) { + LL_PROFILE_ZONE_SCOPED; return tryPush(tuple_cons(Clock::now(), tuple)); } /// individually pass components bool tryPush(const TimePoint& time, Args&&... args) { + LL_PROFILE_ZONE_SCOPED; return tryPush(TimeTuple(time, std::forward(args)...)); } /// individually pass components with implicit now bool tryPush(Args&&... args) { + LL_PROFILE_ZONE_SCOPED; return tryPush(Clock::now(), std::forward(args)...); } @@ -148,6 +154,7 @@ namespace LL bool tryPushFor(const std::chrono::duration& timeout, const DataTuple& tuple) { + LL_PROFILE_ZONE_SCOPED; return tryPushFor(timeout, tuple_cons(Clock::now(), tuple)); } @@ -156,6 +163,7 @@ namespace LL bool tryPushFor(const std::chrono::duration& timeout, const TimePoint& time, Args&&... args) { + LL_PROFILE_ZONE_SCOPED; return tryPushFor(TimeTuple(time, std::forward(args)...)); } @@ -164,6 +172,7 @@ namespace LL bool tryPushFor(const std::chrono::duration& timeout, Args&&... args) { + LL_PROFILE_ZONE_SCOPED; return tryPushFor(Clock::now(), std::forward(args)...); } @@ -176,6 +185,7 @@ namespace LL bool tryPushUntil(const std::chrono::time_point& until, const DataTuple& tuple) { + LL_PROFILE_ZONE_SCOPED; return tryPushUntil(until, tuple_cons(Clock::now(), tuple)); } @@ -184,6 +194,7 @@ namespace LL bool tryPushUntil(const std::chrono::time_point& until, const TimePoint& time, Args&&... args) { + LL_PROFILE_ZONE_SCOPED; return tryPushUntil(until, TimeTuple(time, std::forward(args)...)); } @@ -192,6 +203,7 @@ namespace LL bool tryPushUntil(const std::chrono::time_point& until, Args&&... args) { + LL_PROFILE_ZONE_SCOPED; return tryPushUntil(until, Clock::now(), std::forward(args)...); } @@ -209,12 +221,14 @@ namespace LL // haven't yet jumped through those hoops. DataTuple pop() { + LL_PROFILE_ZONE_SCOPED; return tuple_cdr(popWithTime()); } /// pop TimeTuple by value TimeTuple popWithTime() { + LL_PROFILE_ZONE_SCOPED; lock_t lock(super::mLock); // We can't just sit around waiting forever, given that there may // be items in the queue that are not yet ready but will *become* @@ -254,6 +268,7 @@ namespace LL /// tryPop(DataTuple&) bool tryPop(DataTuple& tuple) { + LL_PROFILE_ZONE_SCOPED; TimeTuple tt; if (! super::tryPop(tt)) return false; @@ -264,6 +279,7 @@ namespace LL /// for when Args has exactly one type bool tryPop(typename std::tuple_element<1, TimeTuple>::type& value) { + LL_PROFILE_ZONE_SCOPED; TimeTuple tt; if (! super::tryPop(tt)) return false; @@ -275,6 +291,7 @@ namespace LL template bool tryPopFor(const std::chrono::duration& timeout, Tuple& tuple) { + LL_PROFILE_ZONE_SCOPED; // It's important to use OUR tryPopUntil() implementation, rather // than delegating immediately to our base class. return tryPopUntil(Clock::now() + timeout, tuple); @@ -285,6 +302,7 @@ namespace LL bool tryPopUntil(const std::chrono::time_point& until, TimeTuple& tuple) { + LL_PROFILE_ZONE_SCOPED; // super::tryPopUntil() wakes up when an item becomes available or // we hit 'until', whichever comes first. Thing is, the current // head of the queue could become ready sooner than either of @@ -304,20 +322,25 @@ namespace LL pop_result tryPopUntil_(lock_t& lock, const TimePoint& until, TimeTuple& tuple) { + LL_PROFILE_ZONE_SCOPED; TimePoint adjusted = until; if (! super::mStorage.empty()) { + LL_PROFILE_ZONE_NAMED("tpu - adjust"); // use whichever is earlier: the head item's timestamp, or // the caller's limit adjusted = min(std::get<0>(super::mStorage.front()), adjusted); } // now delegate to base-class tryPopUntil_() pop_result popped; - while ((popped = pop_result(super::tryPopUntil_(lock, adjusted, tuple))) == WAITING) { - // If super::tryPopUntil_() returns WAITING, it means there's - // a head item, but it's not yet time. But it's worth looping - // back to recheck. + LL_PROFILE_ZONE_NAMED("tpu - super"); + while ((popped = pop_result(super::tryPopUntil_(lock, adjusted, tuple))) == WAITING) + { + // If super::tryPopUntil_() returns WAITING, it means there's + // a head item, but it's not yet time. But it's worth looping + // back to recheck. + } } return popped; } @@ -327,6 +350,7 @@ namespace LL bool tryPopUntil(const std::chrono::time_point& until, DataTuple& tuple) { + LL_PROFILE_ZONE_SCOPED; TimeTuple tt; if (! tryPopUntil(until, tt)) return false; @@ -339,6 +363,7 @@ namespace LL bool tryPopUntil(const std::chrono::time_point& until, typename std::tuple_element<1, TimeTuple>::type& value) { + LL_PROFILE_ZONE_SCOPED; TimeTuple tt; if (! tryPopUntil(until, tt)) return false; @@ -362,6 +387,7 @@ namespace LL // considering whether to deliver the current head element bool canPop(const TimeTuple& head) const override { + LL_PROFILE_ZONE_SCOPED; // an item with a future timestamp isn't yet ready to pop // (should we add some slop for overhead?) return std::get<0>(head) <= Clock::now(); -- cgit v1.2.3