author | Edgar Chen <echen@mozilla.com> |
Wed, 27 Nov 2019 23:22:27 +0000 | |
changeset 505565 | 9eeb03a503fb86df387049e878c0c5dd76e0387c |
parent 505564 | 4989bb2f4f69eae11fa05cc9386edf3d65ccb0c6 |
child 505566 | 95b8b6b94213f4549642f0137d6e3ff0129ef68a |
push id | 102347 |
push user | echen@mozilla.com |
push date | Wed, 04 Dec 2019 23:23:46 +0000 |
treeherder | autoland@2dfc53add3de [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bzbarsky |
bugs | 1202706 |
milestone | 73.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/base/UseCounter.h +++ b/dom/base/UseCounter.h @@ -54,11 +54,24 @@ enum UseCounter : int16_t { #define COUNTED_UNKNOWN_PROPERTY(name_, method_) \ eUseCounter_unknown_property_##method_, #include "mozilla/CountedUnknownProperties.h" #undef COUNTED_UNKNOWN_PROPERTY eUseCounter_Count }; +enum class UseCounterWorker : int16_t { + Unknown = -1, +#define USE_COUNTER_DOM_METHOD(interface_, name_) interface_##_##name_, +#define USE_COUNTER_DOM_ATTRIBUTE(interface_, name_) \ + interface_##_##name_##_getter, interface_##_##name_##_setter, +#define USE_COUNTER_CUSTOM(name_, desc_) Custom_##name_, +#include "mozilla/dom/UseCounterWorkerList.h" +#undef USE_COUNTER_DOM_METHOD +#undef USE_COUNTER_DOM_ATTRIBUTE +#undef USE_COUNTER_CUSTOM + Count +}; + } // namespace mozilla #endif
--- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -131,16 +131,17 @@ EXPORTS.mozilla += [ 'ScriptableContentIterator.h', 'SelectionChangeEventDispatcher.h', 'TextInputProcessor.h', 'UseCounter.h', ] EXPORTS.mozilla.dom += [ '!UseCounterList.h', + '!UseCounterWorkerList.h', 'AbstractRange.h', 'AnonymousContent.h', 'Attr.h', 'BarProps.h', 'BindContext.h', 'BodyConsumer.h', 'BodyStream.h', 'BodyUtil.h', @@ -538,10 +539,13 @@ if CONFIG['MOZ_BUILD_APP'] in ['browser' DEFINES['HAVE_SIDEBAR'] = True if CONFIG['MOZ_X11']: CXXFLAGS += CONFIG['TK_CFLAGS'] GeneratedFile('UseCounterList.h', script='gen-usecounters.py', entry_point='use_counter_list', inputs=['UseCounters.conf']) +GeneratedFile('UseCounterWorkerList.h', script='gen-usecounters.py', + entry_point='use_counter_list', inputs=['UseCountersWorker.conf']) + if CONFIG['CC_TYPE'] in ('clang', 'gcc'): CXXFLAGS += ['-Wno-error=shadow']
--- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -2138,16 +2138,17 @@ WorkerPrivate::WorkerPrivate( mWorkerHybridEventTarget( new WorkerEventTarget(this, WorkerEventTarget::Behavior::Hybrid)), mParentStatus(Pending), mStatus(Pending), mBusyCount(0), mLoadingWorkerScript(false), mCreationTimeStamp(TimeStamp::Now()), mCreationTimeHighRes((double)PR_Now() / PR_USEC_PER_MSEC), + mReportedUseCounters(false), mAgentClusterId(aAgentClusterId), mWorkerThreadAccessible(aParent), mPostSyncLoopOperations(0), mParentWindowPaused(false), mCancelAllPendingRunnables(false), mWorkerScriptExecutedSuccessfully(false), mFetchHandlerWasAdded(false), mMainThreadObjectsForgotten(false), @@ -3438,16 +3439,19 @@ void WorkerPrivate::ClearMainEventQueue( RefPtr<WorkerRunnable> runnable = mPreStartRunnables[index].forget(); static_cast<nsIRunnable*>(runnable.get())->Run(); } } else { nsIThread* currentThread = NS_GetCurrentThread(); MOZ_ASSERT(currentThread); NS_ProcessPendingEvents(currentThread); + + // We are about to destroy worker, report all use counters. + ReportUseCounters(); } MOZ_ASSERT(mCancelAllPendingRunnables); mCancelAllPendingRunnables = false; } void WorkerPrivate::ClearDebuggerEventQueue() { while (!mDebuggerQueue.IsEmpty()) { @@ -3856,16 +3860,83 @@ void WorkerPrivate::DispatchCancelingRun // At the same time, we want to be sure that we interrupt infinite loops. // The following runnable starts a timer that cancel the worker, from the // parent thread, after CANCELING_TIMEOUT millseconds. RefPtr<CancelingWithTimeoutOnParentRunnable> rr = new CancelingWithTimeoutOnParentRunnable(this); rr->Dispatch(); } +void WorkerPrivate::ReportUseCounters() { + AssertIsOnWorkerThread(); + + static const bool kDebugUseCounters = false; + + if (mReportedUseCounters) { + return; + } + mReportedUseCounters = true; + + if (Telemetry::HistogramUseCounterWorkerCount <= 0 || IsChromeWorker()) { + return; + } + + const size_t type = Type(); + switch (type) { + case WorkerTypeDedicated: + Telemetry::Accumulate(Telemetry::DEDICATED_WORKER_DESTROYED, 1); + break; + case WorkerTypeShared: + Telemetry::Accumulate(Telemetry::SHARED_WORKER_DESTROYED, 1); + break; + case WorkerTypeService: + Telemetry::Accumulate(Telemetry::SERVICE_WORKER_DESTROYED, 1); + break; + default: + MOZ_ASSERT(false, "Unknown worker type"); + return; + } + + if (kDebugUseCounters) { + nsAutoCString path(Domain()); + path.AppendLiteral("("); + NS_ConvertUTF16toUTF8 script(ScriptURL()); + path.Append(script); + path.AppendPrintf(", 0x%p)", static_cast<void*>(this)); + printf("-- Worker use counters for %s --\n", path.get()); + } + + static_assert( + static_cast<size_t>(UseCounterWorker::Count) * 3 == + static_cast<size_t>(Telemetry::HistogramUseCounterWorkerCount), + "There should be three histograms (dedicated and shared and " + "servie) for each worker use counter"); + const size_t count = static_cast<size_t>(UseCounterWorker::Count); + const size_t factor = + static_cast<size_t>(Telemetry::HistogramUseCounterWorkerCount) / count; + MOZ_ASSERT(factor > type); + + for (size_t c = 0; c < count; ++c) { + // Histograms for worker use counters use the same order as the worker types + // , so we can use the worker type to index to corresponding histogram. + Telemetry::HistogramID id = static_cast<Telemetry::HistogramID>( + Telemetry::HistogramFirstUseCounterWorker + c * factor + type); + MOZ_ASSERT(id <= Telemetry::HistogramLastUseCounterWorker); + + if (bool value = GetUseCounter(static_cast<UseCounterWorker>(c))) { + Telemetry::Accumulate(id, 1); + + if (kDebugUseCounters) { + const char* name = Telemetry::GetHistogramName(id); + printf(" %s #%d: %d\n", name, id, value); + } + } + } +} + void WorkerPrivate::StopSyncLoop(nsIEventTarget* aSyncLoopTarget, bool aResult) { AssertIsOnWorkerThread(); AssertValidSyncLoop(aSyncLoopTarget); MOZ_ASSERT(!mSyncLoopStack.IsEmpty()); for (uint32_t index = mSyncLoopStack.Length(); index > 0; index--) {
--- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -1,8 +1,9 @@ + /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_workers_workerprivate_h__ #define mozilla_dom_workers_workerprivate_h__ @@ -11,16 +12,17 @@ #include "mozilla/dom/WorkerStatus.h" #include "mozilla/Attributes.h" #include "mozilla/CondVar.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/MozPromise.h" #include "mozilla/RelativeTimeline.h" #include "mozilla/StorageAccess.h" #include "mozilla/ThreadSafeWeakPtr.h" +#include "mozilla/UseCounter.h" #include "nsContentUtils.h" #include "nsIContentSecurityPolicy.h" #include "nsIEventTarget.h" #include "nsTObserverArray.h" #include "js/ContextOptions.h" #include "mozilla/dom/RemoteWorkerChild.h" #include "mozilla/dom/Worker.h" @@ -32,17 +34,18 @@ class nsIThreadInternal; namespace mozilla { class ThrottledEventQueue; namespace dom { // If you change this, the corresponding list in nsIWorkerDebugger.idl needs -// to be updated too. +// to be updated too. And histograms enum for worker use counters uses the same +// order of worker type. Please also update dom/base/usecounters.py. enum WorkerType { WorkerTypeDedicated, WorkerTypeShared, WorkerTypeService }; class ClientInfo; class ClientSource; class Function; class MessagePort; class UniqueMessagePortId; class PerformanceStorage; @@ -895,16 +898,23 @@ class WorkerPrivate : public RelativeTim const nsID& AgentClusterId() const { return mAgentClusterId; } bool IsSharedMemoryAllowed() const; // https://whatpr.org/html/4734/structured-data.html#cross-origin-isolated bool CrossOriginIsolated() const; + void SetUseCounter(UseCounterWorker aUseCounter) { + MOZ_ASSERT(!mReportedUseCounters); + MOZ_ASSERT(aUseCounter > UseCounterWorker::Unknown); + AssertIsOnWorkerThread(); + mUseCounters[static_cast<size_t>(aUseCounter)] = true; + } + private: WorkerPrivate( WorkerPrivate* aParent, const nsAString& aScriptURL, bool aIsChromeWorker, WorkerType aWorkerType, const nsAString& aWorkerName, const nsACString& aServiceWorkerScope, WorkerLoadInfo& aLoadInfo, nsString&& aId, const nsID& aAgentClusterId, const nsILoadInfo::CrossOriginOpenerPolicy aAgentClusterOpenerPolicy); @@ -990,16 +1000,24 @@ class WorkerPrivate : public RelativeTim // This method dispatches a simple runnable that starts the shutdown procedure // after a self.close(). This method is called after a ClearMainEventQueue() // to be sure that the canceling runnable is the only one in the queue. We // need this async operation to be sure that all the current JS code is // executed. void DispatchCancelingRunnable(); + bool GetUseCounter(UseCounterWorker aUseCounter) { + MOZ_ASSERT(aUseCounter > UseCounterWorker::Unknown); + AssertIsOnWorkerThread(); + return mUseCounters[static_cast<size_t>(aUseCounter)]; + } + + void ReportUseCounters(); + class EventTarget; friend class EventTarget; friend class AutoSyncLoopHolder; struct TimeoutInfo; class MemoryReporter; friend class MemoryReporter; @@ -1106,16 +1124,24 @@ class WorkerPrivate : public RelativeTim // thread before crashing because hanging. Atomic<uint64_t> mBusyCount; Atomic<bool> mLoadingWorkerScript; TimeStamp mCreationTimeStamp; DOMHighResTimeStamp mCreationTimeHighRes; + // Flags for use counters used directly by this worker. + static_assert(sizeof(UseCounterWorker) <= sizeof(size_t), + "UseCounterWorker is too big"); + static_assert(UseCounterWorker::Count >= static_cast<UseCounterWorker>(0), + "Should be non-negative value and safe to cast to unsigned"); + std::bitset<static_cast<size_t>(UseCounterWorker::Count)> mUseCounters; + bool mReportedUseCounters; + // This is created while creating the WorkerPrivate, so it's safe to be // touched on any thread. const nsID mAgentClusterId; // Things touched on worker thread only. struct WorkerThreadAccessible { explicit WorkerThreadAccessible(WorkerPrivate* aParent);