Bug 1862556: Allow LongTask markers to be generated for any nsThread r=nika

Differential Revision: https://phabricator.services.mozilla.com/D192532
This commit is contained in:
Randell Jesup 2023-12-07 04:15:44 +00:00
parent 9c00b13451
commit e47f68f60e
8 changed files with 39 additions and 27 deletions

View File

@ -411,8 +411,7 @@ void StorageDBThread::SetDefaultPriority() {
void StorageDBThread::ThreadFunc(void* aArg) {
{
auto queue = MakeRefPtr<ThreadEventQueue>(MakeUnique<EventQueue>());
Unused << nsThreadManager::get().CreateCurrentThread(
queue, nsThread::NOT_MAIN_THREAD);
Unused << nsThreadManager::get().CreateCurrentThread(queue);
}
AUTO_PROFILER_REGISTER_THREAD("localStorage DB");

View File

@ -152,8 +152,7 @@ void Thread::ThreadMain() {
loopType == MessageLoop::TYPE_MOZILLA_NONMAINUITHREAD) {
auto queue = mozilla::MakeRefPtr<mozilla::ThreadEventQueue>(
mozilla::MakeUnique<mozilla::EventQueue>());
xpcomThread = nsThreadManager::get().CreateCurrentThread(
queue, nsThread::NOT_MAIN_THREAD);
xpcomThread = nsThreadManager::get().CreateCurrentThread(queue);
} else {
xpcomThread = NS_GetCurrentThread();
}

View File

@ -381,8 +381,7 @@ void CacheIOThread::ThreadFunc() {
auto queue =
MakeRefPtr<ThreadEventQueue>(MakeUnique<mozilla::EventQueue>());
nsCOMPtr<nsIThread> xpcomThread =
nsThreadManager::get().CreateCurrentThread(queue,
nsThread::NOT_MAIN_THREAD);
nsThreadManager::get().CreateCurrentThread(queue);
threadInternal = do_QueryInterface(xpcomThread);
if (threadInternal) threadInternal->SetObserver(this);

View File

@ -13,6 +13,10 @@ interface nsIEventTarget;
interface nsIRunnable;
interface nsIThread;
%{ C++
#include "mozilla/Maybe.h"
%}
[scriptable, function, uuid(039a227d-0cb7-44a5-a8f9-dbb7071979f2)]
interface nsINestedEventLoopCondition : nsISupports
{
@ -72,6 +76,11 @@ interface nsIThreadManager : nsISupports
// (Windows-only) Whether the thread should have a MessageLoop capable of
// processing native UI events. Defaults to false.
bool isUiThread = false;
// If set, long task markers will be collected for tasks
// longer than longTaskLength ms when profiling is enabled.
// See https://www.w3.org/TR/longtasks
mozilla::Maybe<uint32_t> longTaskLength;
};
%}

View File

@ -550,7 +550,8 @@ nsThread::nsThread(NotNull<SynchronizedEventQueue*> aQueue,
#ifdef EARLY_BETA_OR_EARLIER
mLastWakeupCheckTime(TimeStamp::Now()),
#endif
mPerformanceCounterState(mNestedEventLoopDepth, mIsMainThread) {
mPerformanceCounterState(mNestedEventLoopDepth, mIsMainThread,
aOptions.longTaskLength) {
#if !(defined(XP_WIN) || defined(XP_MACOSX))
MOZ_ASSERT(!mIsUiThread,
"Non-main UI threads are only supported on Windows and macOS");
@ -581,7 +582,7 @@ nsThread::nsThread()
#ifdef EARLY_BETA_OR_EARLIER
mLastWakeupCheckTime(TimeStamp::Now()),
#endif
mPerformanceCounterState(mNestedEventLoopDepth, mIsMainThread) {
mPerformanceCounterState(mNestedEventLoopDepth) {
MOZ_ASSERT(!NS_IsMainThread());
}
@ -1458,9 +1459,11 @@ void nsThreadShutdownContext::MarkCompleted() {
namespace mozilla {
PerformanceCounterState::Snapshot PerformanceCounterState::RunnableWillRun(
TimeStamp aNow, bool aIsIdleRunnable) {
if (IsNestedRunnable()) {
if (mIsMainThread && IsNestedRunnable()) {
// Flush out any accumulated time that should be accounted to the
// current runnable before we start running a nested runnable.
// current runnable before we start running a nested runnable. Don't
// do this for non-mainthread threads that may be running their own
// event loops, like SocketThread.
MaybeReportAccumulatedTime("nested runnable"_ns, aNow);
}
@ -1482,10 +1485,10 @@ void PerformanceCounterState::RunnableDidRun(const nsCString& aName,
// We may not need the current timestamp; don't bother computing it if we
// don't.
TimeStamp now;
if (mIsMainThread || IsNestedRunnable()) {
if (mLongTaskLength.isSome() || IsNestedRunnable()) {
now = TimeStamp::Now();
}
if (mIsMainThread) {
if (mLongTaskLength.isSome()) {
MaybeReportAccumulatedTime(aName, now);
}
@ -1505,9 +1508,7 @@ void PerformanceCounterState::MaybeReportAccumulatedTime(const nsCString& aName,
TimeStamp aNow) {
MOZ_ASSERT(mCurrentTimeSliceStart,
"How did we get here if we're not in a timeslice?");
if (!mIsMainThread) {
// No one cares about this timeslice.
if (!mLongTaskLength.isSome()) {
return;
}
@ -1520,7 +1521,7 @@ void PerformanceCounterState::MaybeReportAccumulatedTime(const nsCString& aName,
#endif
// Long tasks only matter on the main thread.
if (mIsMainThread && duration.ToMilliseconds() > LONGTASK_BUSY_WINDOW_MS) {
if (duration.ToMilliseconds() >= mLongTaskLength.value()) {
// Idle events (gc...) don't *really* count here
if (!mCurrentRunnableIsIdleRunnable) {
mLastLongNonIdleTaskEnd = aNow;

View File

@ -46,7 +46,7 @@ class nsIRunnable;
class nsThreadShutdownContext;
// See https://www.w3.org/TR/longtasks
#define LONGTASK_BUSY_WINDOW_MS 50
#define W3_LONGTASK_BUSY_WINDOW_MS 50
// Time a Runnable executes before we accumulate telemetry on it
#define LONGTASK_TELEMETRY_MS 30
@ -55,10 +55,12 @@ class nsThreadShutdownContext;
namespace mozilla {
class PerformanceCounterState {
public:
explicit PerformanceCounterState(const uint32_t& aNestedEventLoopDepthRef,
bool aIsMainThread)
explicit PerformanceCounterState(
const uint32_t& aNestedEventLoopDepthRef, bool aIsMainThread = false,
const Maybe<uint32_t>& aLongTaskLength = Nothing())
: mNestedEventLoopDepth(aNestedEventLoopDepthRef),
mIsMainThread(aIsMainThread),
mLongTaskLength(aLongTaskLength),
// Does it really make sense to initialize these to "now" when we
// haven't run any tasks?
mLastLongTaskEnd(TimeStamp::Now()),
@ -130,6 +132,9 @@ class PerformanceCounterState {
// Whether we're attached to the mainthread nsThread.
const bool mIsMainThread;
// what is considered a LongTask (in ms)
const Maybe<uint32_t> mLongTaskLength;
// The timestamp from which time to be accounted for should be measured. This
// can be the start of a runnable running or the end of a nested runnable
// running.

View File

@ -308,8 +308,9 @@ nsresult nsThreadManager::Init() {
RefPtr<ThreadEventQueue> synchronizedQueue =
new ThreadEventQueue(std::move(queue), true);
mMainThread = new nsThread(WrapNotNull(synchronizedQueue),
nsThread::MAIN_THREAD, {.stackSize = 0});
mMainThread = new nsThread(
WrapNotNull(synchronizedQueue), nsThread::MAIN_THREAD,
{.stackSize = 0, .longTaskLength = Some(W3_LONGTASK_BUSY_WINDOW_MS)});
nsresult rv = mMainThread->InitCurrentThread();
if (NS_FAILED(rv)) {
@ -490,8 +491,8 @@ void nsThreadManager::UnregisterCurrentThread(nsThread& aThread) {
// Ref-count balanced via ReleaseThread
}
nsThread* nsThreadManager::CreateCurrentThread(
SynchronizedEventQueue* aQueue, nsThread::MainThreadFlag aMainThread) {
// Not to be used for MainThread!
nsThread* nsThreadManager::CreateCurrentThread(SynchronizedEventQueue* aQueue) {
// Make sure we don't have an nsThread yet.
MOZ_ASSERT(!PR_GetThreadPrivate(mCurThreadIndex));
@ -499,8 +500,8 @@ nsThread* nsThreadManager::CreateCurrentThread(
return nullptr;
}
RefPtr<nsThread> thread =
new nsThread(WrapNotNull(aQueue), aMainThread, {.stackSize = 0});
RefPtr<nsThread> thread = new nsThread(
WrapNotNull(aQueue), nsThread::NOT_MAIN_THREAD, {.stackSize = 0});
if (NS_FAILED(thread->InitCurrentThread())) {
return nullptr;
}

View File

@ -69,8 +69,7 @@ class nsThreadManager : public nsIThreadManager {
// the thread that was created. GetCurrentThread() will also create a thread
// (lazily), but it doesn't allow the queue or main-thread attributes to be
// specified.
nsThread* CreateCurrentThread(mozilla::SynchronizedEventQueue* aQueue,
nsThread::MainThreadFlag aMainThread);
nsThread* CreateCurrentThread(mozilla::SynchronizedEventQueue* aQueue);
nsresult DispatchToBackgroundThread(nsIRunnable* aEvent,
uint32_t aDispatchFlags);