bug 1242268 record MSG memory sizes asynchronously r=padenot

This removes the one second timeout for MSG collection, extending the timeout
period to the 50 second timeout of nsMemoryReporterManager.

Also removed:

* The condition variable logic that can stop waiting without checking the
  condition set when memory reports are complete.

* Races with mAudioStreamSizes modification on two threads after wait timeout.

Memory from streams in offline graphs that are not yet running is now also
included.

MozReview-Commit-ID: FkI61iJFrZ5

--HG--
extra : rebase_source : 200d332165ef21497bcfa24b86b6ff029f8ac212
This commit is contained in:
Karl Tomlinson 2016-07-04 10:40:48 +12:00
Родитель 42c4a689dc
Коммит fc0ef5c59f
2 изменённых файлов: 114 добавлений и 70 удалений

Просмотреть файл

@ -1542,26 +1542,6 @@ MediaStreamGraphImpl::Process()
}
}
void
MediaStreamGraphImpl::MaybeProduceMemoryReport()
{
MonitorAutoLock lock(mMemoryReportMonitor);
if (mNeedsMemoryReport) {
mNeedsMemoryReport = false;
for (MediaStream* s : AllStreams()) {
AudioNodeStream* stream = s->AsAudioNodeStream();
if (stream) {
AudioNodeSizes usage;
stream->SizeOfAudioNodesIncludingThis(MallocSizeOf, usage);
mAudioStreamSizes.AppendElement(usage);
}
}
lock.Notify();
}
}
bool
MediaStreamGraphImpl::UpdateMainThreadState()
{
@ -1593,8 +1573,6 @@ MediaStreamGraphImpl::OneIteration(GraphTime aStateEnd)
// Process graph message from the main thread for this iteration.
RunMessagesInQueue();
MaybeProduceMemoryReport();
GraphTime stateEnd = std::min(aStateEnd, mEndTime);
UpdateGraph(stateEnd);
@ -3366,10 +3344,7 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
#ifdef MOZ_WEBRTC
, mFarendObserverRef(nullptr)
#endif
, mMemoryReportMonitor("MSGIMemory")
, mSelfRef(this)
, mAudioStreamSizes()
, mNeedsMemoryReport(false)
#ifdef DEBUG
, mCanRunMessagesSynchronously(false)
#endif
@ -3388,7 +3363,7 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
mLastMainThreadUpdate = TimeStamp::Now();
RegisterWeakMemoryReporter(this);
RegisterWeakAsyncMemoryReporter(this);
}
void
@ -3495,59 +3470,129 @@ MediaStreamGraph::DestroyNonRealtimeInstance(MediaStreamGraph* aGraph)
NS_IMPL_ISUPPORTS(MediaStreamGraphImpl, nsIMemoryReporter)
struct ArrayClearer
{
explicit ArrayClearer(nsTArray<AudioNodeSizes>& aArray) : mArray(aArray) {}
~ArrayClearer() { mArray.Clear(); }
nsTArray<AudioNodeSizes>& mArray;
};
NS_IMETHODIMP
MediaStreamGraphImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize)
{
if (mLifecycleState >= LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN) {
// Shutting down, nothing to report.
FinishCollectReports(aHandleReport, aData, nsTArray<AudioNodeSizes>());
return NS_OK;
}
// Clears out the report array after we're done with it.
ArrayClearer reportCleanup(mAudioStreamSizes);
{
MonitorAutoLock memoryReportLock(mMemoryReportMonitor);
mNeedsMemoryReport = true;
class Message final : public ControlMessage {
public:
Message(MediaStreamGraphImpl *aGraph,
nsIHandleReportCallback* aHandleReport,
nsISupports *aHandlerData)
: ControlMessage(nullptr)
, mGraph(aGraph)
, mHandleReport(aHandleReport)
, mHandlerData(aHandlerData) {}
void Run() override
{
// Wake up the MSG thread if it's real time (Offline graphs can't be
// sleeping).
MonitorAutoLock monitorLock(mMonitor);
if (!CurrentDriver()->AsOfflineClockDriver()) {
CurrentDriver()->WakeUp();
}
mGraph->CollectSizesForMemoryReport(mHandleReport.forget(),
mHandlerData.forget());
}
void RunDuringShutdown() override
{
// Run this message during shutdown too, so that endReports is called.
Run();
}
MediaStreamGraphImpl *mGraph;
// nsMemoryReporterManager keeps the callback and data alive only if it
// does not time out.
nsCOMPtr<nsIHandleReportCallback> mHandleReport;
nsCOMPtr<nsISupports> mHandlerData;
};
// When a non-realtime graph has not started, there is no thread yet, so
// collect sizes on this thread.
if (!(mRealtime || mNonRealtimeProcessing)) {
CollectSizesForMemoryReport(do_AddRef(aHandleReport), do_AddRef(aData));
return NS_OK;
}
AppendMessage(MakeUnique<Message>(this, aHandleReport, aData));
return NS_OK;
}
void
MediaStreamGraphImpl::CollectSizesForMemoryReport(
already_AddRefed<nsIHandleReportCallback> aHandleReport,
already_AddRefed<nsISupports> aHandlerData)
{
class FinishCollectRunnable final : public Runnable
{
public:
explicit FinishCollectRunnable(
already_AddRefed<nsIHandleReportCallback> aHandleReport,
already_AddRefed<nsISupports> aHandlerData)
: mHandleReport(aHandleReport)
, mHandlerData(aHandlerData)
{}
NS_IMETHOD Run() override
{
MediaStreamGraphImpl::FinishCollectReports(mHandleReport, mHandlerData,
Move(mAudioStreamSizes));
return NS_OK;
}
// Wait for up to one second for the report to complete.
nsresult rv;
const PRIntervalTime kMaxWait = PR_SecondsToInterval(1);
while ((rv = memoryReportLock.Wait(kMaxWait)) != NS_OK) {
if (PR_GetError() != PR_PENDING_INTERRUPT_ERROR) {
return rv;
}
nsTArray<AudioNodeSizes> mAudioStreamSizes;
private:
~FinishCollectRunnable() {}
// Avoiding nsCOMPtr because NSCAP_ASSERT_NO_QUERY_NEEDED in its
// constructor modifies the ref-count, which cannot be done off main
// thread.
RefPtr<nsIHandleReportCallback> mHandleReport;
RefPtr<nsISupports> mHandlerData;
};
RefPtr<FinishCollectRunnable> runnable =
new FinishCollectRunnable(Move(aHandleReport), Move(aHandlerData));
auto audioStreamSizes = &runnable->mAudioStreamSizes;
for (MediaStream* s : AllStreams()) {
AudioNodeStream* stream = s->AsAudioNodeStream();
if (stream) {
AudioNodeSizes* usage = audioStreamSizes->AppendElement();
stream->SizeOfAudioNodesIncludingThis(MallocSizeOf, *usage);
}
}
NS_DispatchToMainThread(runnable.forget());
}
void
MediaStreamGraphImpl::
FinishCollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
const nsTArray<AudioNodeSizes>& aAudioStreamSizes)
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIMemoryReporterManager> manager =
do_GetService("@mozilla.org/memory-reporter-manager;1");
if (!manager)
return;
#define REPORT(_path, _amount, _desc) \
do { \
nsresult rv; \
rv = aHandleReport->Callback(EmptyCString(), _path, \
KIND_HEAP, UNITS_BYTES, _amount, \
NS_LITERAL_CSTRING(_desc), aData); \
NS_ENSURE_SUCCESS(rv, rv); \
if (NS_WARN_IF(NS_FAILED(rv))) \
return; \
} while (0)
for (size_t i = 0; i < mAudioStreamSizes.Length(); i++) {
const AudioNodeSizes& usage = mAudioStreamSizes[i];
for (size_t i = 0; i < aAudioStreamSizes.Length(); i++) {
const AudioNodeSizes& usage = aAudioStreamSizes[i];
const char* const nodeType =
usage.mNodeType ? usage.mNodeType : "<unknown>";
@ -3574,7 +3619,7 @@ MediaStreamGraphImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
#undef REPORT
return NS_OK;
manager->EndReport();
}
SourceMediaStream*

Просмотреть файл

@ -193,6 +193,15 @@ public:
* Called before the thread runs.
*/
void Init();
/**
* Respond to CollectReports with sizes collected on the graph thread.
*/
static void
FinishCollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData,
const nsTArray<AudioNodeSizes>& aAudioStreamSizes);
// The following methods run on the graph thread (or possibly the main thread if
// mLifecycleState > LIFECYCLE_RUNNING)
void AssertOnGraphThreadOrNotRunning() const
@ -211,7 +220,9 @@ public:
#endif
}
void MaybeProduceMemoryReport();
void CollectSizesForMemoryReport(
already_AddRefed<nsIHandleReportCallback> aHandleReport,
already_AddRefed<nsISupports> aHandlerData);
/**
* Returns true if this MediaStreamGraph should keep running
@ -820,10 +831,6 @@ private:
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
/**
* Used to signal that a memory report has been requested.
*/
Monitor mMemoryReportMonitor;
/**
* This class uses manual memory management, and all pointers to it are raw
* pointers. However, in order for it to implement nsIMemoryReporter, it needs
@ -832,10 +839,6 @@ private:
* and Destroy() nulls this self-reference in order to trigger self-deletion.
*/
RefPtr<MediaStreamGraphImpl> mSelfRef;
/**
* Used to pass memory report information across threads.
*/
nsTArray<AudioNodeSizes> mAudioStreamSizes;
struct WindowAndStream
{
@ -846,10 +849,6 @@ private:
* Stream for window audio capture.
*/
nsTArray<WindowAndStream> mWindowCaptureStreams;
/**
* Indicates that the MSG thread should gather data for a memory report.
*/
bool mNeedsMemoryReport;
#ifdef DEBUG
/**