Bug 1241096 - Add a better memory reporting system for AudioBuffers. r=erahm

MozReview-Commit-ID: GHiauyyD3R2
This commit is contained in:
Paul Adenot 2016-04-01 13:36:41 +02:00
parent ed3b71bc67
commit 352f3c7654
3 changed files with 129 additions and 3 deletions

View File

@ -12,6 +12,7 @@
#include "AudioChannelFormat.h"
#include "mozilla/PodOperations.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/MemoryReporting.h"
#include "AudioNodeEngine.h"
namespace mozilla {
@ -39,6 +40,128 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AudioBuffer, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioBuffer, Release)
/**
* AudioBuffers can be shared between AudioContexts, so we need a separate
* mechanism to track their memory usage. This thread-safe class keeps track of
* all the AudioBuffers, and gets called back by the memory reporting system
* when a memory report is needed, reporting how much memory is used by the
* buffers backing AudioBuffer objects. */
class AudioBufferMemoryTracker : public nsIMemoryReporter
{
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIMEMORYREPORTER
private:
AudioBufferMemoryTracker();
virtual ~AudioBufferMemoryTracker();
public:
/* Those methods can be called on any thread. */
static void RegisterAudioBuffer(const AudioBuffer* aAudioBuffer);
static void UnregisterAudioBuffer(const AudioBuffer* aAudioBuffer);
private:
static AudioBufferMemoryTracker* GetInstance();
/* Those methods must be called with the lock held. */
void RegisterAudioBufferInternal(const AudioBuffer* aAudioBuffer);
/* Returns the number of buffers still present in the hash table. */
uint32_t UnregisterAudioBufferInternal(const AudioBuffer* aAudioBuffer);
void Init();
/* This protects all members of this class. */
static StaticMutex sMutex;
static StaticRefPtr<AudioBufferMemoryTracker> sSingleton;
nsTHashtable<nsPtrHashKey<const AudioBuffer>> mBuffers;
};
StaticRefPtr<AudioBufferMemoryTracker> AudioBufferMemoryTracker::sSingleton;
StaticMutex AudioBufferMemoryTracker::sMutex;
NS_IMPL_ISUPPORTS(AudioBufferMemoryTracker, nsIMemoryReporter);
AudioBufferMemoryTracker* AudioBufferMemoryTracker::GetInstance()
{
sMutex.AssertCurrentThreadOwns();
if (!sSingleton) {
sSingleton = new AudioBufferMemoryTracker();
sSingleton->Init();
}
return sSingleton;
}
AudioBufferMemoryTracker::AudioBufferMemoryTracker()
{
}
void
AudioBufferMemoryTracker::Init()
{
RegisterWeakMemoryReporter(this);
}
AudioBufferMemoryTracker::~AudioBufferMemoryTracker()
{
UnregisterWeakMemoryReporter(this);
}
void
AudioBufferMemoryTracker::RegisterAudioBuffer(const AudioBuffer* aAudioBuffer)
{
StaticMutexAutoLock lock(sMutex);
AudioBufferMemoryTracker* tracker = AudioBufferMemoryTracker::GetInstance();
tracker->RegisterAudioBufferInternal(aAudioBuffer);
}
void
AudioBufferMemoryTracker::UnregisterAudioBuffer(const AudioBuffer* aAudioBuffer)
{
StaticMutexAutoLock lock(sMutex);
AudioBufferMemoryTracker* tracker = AudioBufferMemoryTracker::GetInstance();
uint32_t count;
count = tracker->UnregisterAudioBufferInternal(aAudioBuffer);
if (count == 0) {
sSingleton = nullptr;
}
}
void
AudioBufferMemoryTracker::RegisterAudioBufferInternal(const AudioBuffer* aAudioBuffer)
{
sMutex.AssertCurrentThreadOwns();
mBuffers.PutEntry(aAudioBuffer);
}
uint32_t
AudioBufferMemoryTracker::UnregisterAudioBufferInternal(const AudioBuffer* aAudioBuffer)
{
sMutex.AssertCurrentThreadOwns();
mBuffers.RemoveEntry(aAudioBuffer);
return mBuffers.Count();
}
MOZ_DEFINE_MALLOC_SIZE_OF(AudioBufferMemoryTrackerMallocSizeOf)
NS_IMETHODIMP
AudioBufferMemoryTracker::CollectReports(nsIHandleReportCallback* handleReport,
nsISupports* data, bool)
{
size_t amount = 0;
nsresult rv;
for (auto iter = mBuffers.Iter(); !iter.Done(); iter.Next()) {
amount += iter.Get()->GetKey()->SizeOfIncludingThis(AudioBufferMemoryTrackerMallocSizeOf);
}
rv = handleReport->Callback(EmptyCString(),
NS_LITERAL_CSTRING("explicit/webaudio/audiobuffer"),
KIND_HEAP, UNITS_BYTES, amount,
NS_LITERAL_CSTRING("Memory used by AudioBuffer"
" objects (Web Audio)"),
data);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
AudioBuffer::AudioBuffer(AudioContext* aContext, uint32_t aNumberOfChannels,
uint32_t aLength, float aSampleRate,
already_AddRefed<ThreadSharedFloatArrayBufferList>
@ -52,10 +175,12 @@ AudioBuffer::AudioBuffer(AudioContext* aContext, uint32_t aNumberOfChannels,
mSharedChannels->GetChannels() == aNumberOfChannels);
mJSChannels.SetLength(aNumberOfChannels);
mozilla::HoldJSObjects(this);
AudioBufferMemoryTracker::RegisterAudioBuffer(this);
}
AudioBuffer::~AudioBuffer()
{
AudioBufferMemoryTracker::UnregisterAudioBuffer(this);
ClearJSChannels();
}

View File

@ -10,6 +10,8 @@
#include "nsWrapperCache.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Attributes.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/StaticMutex.h"
#include "nsAutoPtr.h"
#include "nsTArray.h"
#include "AudioContext.h"

View File

@ -615,9 +615,8 @@ size_t
AudioBufferSourceNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
{
size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
if (mBuffer) {
amount += mBuffer->SizeOfIncludingThis(aMallocSizeOf);
}
/* mBuffer can be shared and is accounted for separately. */
amount += mPlaybackRate->SizeOfIncludingThis(aMallocSizeOf);
amount += mDetune->SizeOfIncludingThis(aMallocSizeOf);