diff options
Diffstat (limited to 'tools/memory-profiler')
-rw-r--r-- | tools/memory-profiler/GCHeapProfilerImpl.cpp | 168 | ||||
-rw-r--r-- | tools/memory-profiler/GCHeapProfilerImpl.h | 53 | ||||
-rw-r--r-- | tools/memory-profiler/MemoryProfiler.cpp | 324 | ||||
-rw-r--r-- | tools/memory-profiler/MemoryProfiler.h | 159 | ||||
-rw-r--r-- | tools/memory-profiler/NativeProfilerImpl.cpp | 82 | ||||
-rw-r--r-- | tools/memory-profiler/NativeProfilerImpl.h | 43 | ||||
-rw-r--r-- | tools/memory-profiler/UncensoredAllocator.cpp | 121 | ||||
-rw-r--r-- | tools/memory-profiler/UncensoredAllocator.h | 48 | ||||
-rw-r--r-- | tools/memory-profiler/moz.build | 21 | ||||
-rw-r--r-- | tools/memory-profiler/nsIMemoryProfiler.idl | 72 | ||||
-rw-r--r-- | tools/memory-profiler/nsMemoryProfilerFactory.cpp | 32 |
11 files changed, 0 insertions, 1123 deletions
diff --git a/tools/memory-profiler/GCHeapProfilerImpl.cpp b/tools/memory-profiler/GCHeapProfilerImpl.cpp deleted file mode 100644 index 528a05501..000000000 --- a/tools/memory-profiler/GCHeapProfilerImpl.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=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/. */ - -#include "GCHeapProfilerImpl.h" - -#include "UncensoredAllocator.h" - -namespace mozilla { - -GCHeapProfilerImpl::GCHeapProfilerImpl() -{ - mLock = PR_NewLock(); - mMarking = false; -} - -GCHeapProfilerImpl::~GCHeapProfilerImpl() -{ - if (mLock) { - PR_DestroyLock(mLock); - } -} - -nsTArray<nsCString> -GCHeapProfilerImpl::GetNames() const -{ - return mTraceTable.GetNames(); -} - -nsTArray<TrieNode> -GCHeapProfilerImpl::GetTraces() const -{ - return mTraceTable.GetTraces(); -} - -const nsTArray<AllocEvent>& -GCHeapProfilerImpl::GetEvents() const -{ - return mAllocEvents; -} - -void -GCHeapProfilerImpl::reset() -{ - mTraceTable.Reset(); - mAllocEvents.Clear(); - mNurseryEntries.Clear(); - mTenuredEntriesFG.Clear(); - mTenuredEntriesBG.Clear(); -} - -void -GCHeapProfilerImpl::sampleTenured(void* addr, uint32_t size) -{ - SampleInternal(addr, size, mTenuredEntriesFG); -} - -void -GCHeapProfilerImpl::sampleNursery(void* addr, uint32_t size) -{ - SampleInternal(addr, size, mNurseryEntries); -} - -void -GCHeapProfilerImpl::markTenuredStart() -{ - AutoUseUncensoredAllocator ua; - AutoMPLock lock(mLock); - if (!mMarking) { - mMarking = true; - mTenuredEntriesFG.SwapElements(mTenuredEntriesBG); - MOZ_ASSERT(mTenuredEntriesFG.Count() == 0); - } -} - -void -GCHeapProfilerImpl::markTenured(void* addr) -{ - AutoUseUncensoredAllocator ua; - AutoMPLock lock(mLock); - if (mMarking) { - AllocEntry entry; - if (mTenuredEntriesBG.Get(addr, &entry)) { - entry.mMarked = true; - mTenuredEntriesBG.Put(addr, entry); - } - } -} - -void -GCHeapProfilerImpl::sweepTenured() -{ - AutoUseUncensoredAllocator ua; - AutoMPLock lock(mLock); - if (mMarking) { - mMarking = false; - for (auto iter = mTenuredEntriesBG.Iter(); !iter.Done(); iter.Next()) { - if (iter.Data().mMarked) { - iter.Data().mMarked = false; - mTenuredEntriesFG.Put(iter.Key(), iter.Data()); - } else { - AllocEvent& oldEvent = mAllocEvents[iter.Data().mEventIdx]; - AllocEvent newEvent(oldEvent.mTraceIdx, -oldEvent.mSize, TimeStamp::Now()); - mAllocEvents.AppendElement(newEvent); - } - } - mTenuredEntriesBG.Clear(); - } -} - -void -GCHeapProfilerImpl::sweepNursery() -{ - AutoUseUncensoredAllocator ua; - AutoMPLock lock(mLock); - for (auto iter = mNurseryEntries.Iter(); !iter.Done(); iter.Next()) { - AllocEvent& oldEvent = mAllocEvents[iter.Data().mEventIdx]; - AllocEvent newEvent(oldEvent.mTraceIdx, -oldEvent.mSize, TimeStamp::Now()); - mAllocEvents.AppendElement(newEvent); - } - mNurseryEntries.Clear(); -} - -void -GCHeapProfilerImpl::moveNurseryToTenured(void* addrOld, void* addrNew) -{ - AutoUseUncensoredAllocator ua; - AutoMPLock lock(mLock); - AllocEntry entryOld; - if (!mNurseryEntries.Get(addrOld, &entryOld)) { - return; - } - - // Because the tenured heap is sampled, the address might already be there. - // If not, the address is inserted with the old event. - AllocEntry tenuredEntryOld; - if (!mTenuredEntriesFG.Get(addrNew, &tenuredEntryOld)) { - mTenuredEntriesFG.Put(addrNew, AllocEntry(entryOld.mEventIdx)); - } else { - // If it is already inserted, the insertion above will fail and the - // iterator of the already-inserted element is returned. - // We choose to ignore the the new event by setting its size zero and point - // the newly allocated address to the old event. - // An event of size zero will be skipped when reporting. - mAllocEvents[entryOld.mEventIdx].mSize = 0; - tenuredEntryOld.mEventIdx = entryOld.mEventIdx; - mTenuredEntriesFG.Put(addrNew, tenuredEntryOld); - } - mNurseryEntries.Remove(addrOld); -} - -void -GCHeapProfilerImpl::SampleInternal(void* aAddr, uint32_t aSize, AllocMap& aTable) -{ - AutoUseUncensoredAllocator ua; - AutoMPLock lock(mLock); - size_t nSamples = AddBytesSampled(aSize); - if (nSamples > 0) { - nsTArray<nsCString> trace = GetStacktrace(); - AllocEvent ai(mTraceTable.Insert(trace), nSamples * mSampleSize, TimeStamp::Now()); - aTable.Put(aAddr, AllocEntry(mAllocEvents.Length())); - mAllocEvents.AppendElement(ai); - } -} - -} // namespace mozilla diff --git a/tools/memory-profiler/GCHeapProfilerImpl.h b/tools/memory-profiler/GCHeapProfilerImpl.h deleted file mode 100644 index e84e97017..000000000 --- a/tools/memory-profiler/GCHeapProfilerImpl.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=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 memory_profiler_GCHeapProfilerImpl_h -#define memory_profiler_GCHeapProfilerImpl_h - -#include "CompactTraceTable.h" -#include "MemoryProfiler.h" - -#include "jsfriendapi.h" - -namespace mozilla { - -class GCHeapProfilerImpl final : public GCHeapProfiler - , public ProfilerImpl -{ -public: - GCHeapProfilerImpl(); - ~GCHeapProfilerImpl() override; - - nsTArray<nsCString> GetNames() const override; - nsTArray<TrieNode> GetTraces() const override; - const nsTArray<AllocEvent>& GetEvents() const override; - - void reset() override; - void sampleTenured(void* addr, uint32_t size) override; - void sampleNursery(void* addr, uint32_t size) override; - void markTenuredStart() override; - void markTenured(void* addr) override; - void sweepTenured() override; - void sweepNursery() override; - void moveNurseryToTenured(void* addrOld, void* addrNew) override; - -private: - void SampleInternal(void* addr, uint32_t size, AllocMap& table); - - PRLock* mLock; - bool mMarking; - - AllocMap mNurseryEntries; - AllocMap mTenuredEntriesFG; - AllocMap mTenuredEntriesBG; - - nsTArray<AllocEvent> mAllocEvents; - CompactTraceTable mTraceTable; -}; - -} // namespace mozilla - -#endif // memory_profiler_GCHeapProfilerImpl_h diff --git a/tools/memory-profiler/MemoryProfiler.cpp b/tools/memory-profiler/MemoryProfiler.cpp deleted file mode 100644 index c2b8cbd1d..000000000 --- a/tools/memory-profiler/MemoryProfiler.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=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/. */ - -#include "MemoryProfiler.h" - -#include <cmath> -#include <cstdlib> - -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/Move.h" -#include "mozilla/TimeStamp.h" -#include "mozilla/UniquePtr.h" - -#include "GCHeapProfilerImpl.h" -#include "GeckoProfiler.h" -#include "NativeProfilerImpl.h" -#include "UncensoredAllocator.h" -#include "js/TypeDecls.h" -#include "jsfriendapi.h" -#include "nsIDOMClassInfo.h" -#include "nsIGlobalObject.h" -#include "prtime.h" -#include "xpcprivate.h" - -namespace mozilla { - -#define MEMORY_PROFILER_SAMPLE_SIZE 65536 -#define BACKTRACE_BUFFER_SIZE 16384 - -ProfilerImpl::ProfilerImpl() - : mSampleSize(MEMORY_PROFILER_SAMPLE_SIZE) -{ - mLog1minusP = std::log(1.0 - 1.0 / mSampleSize); - mRemainingBytes = std::floor(std::log(1.0 - DRandom()) / mLog1minusP); -} - -nsTArray<nsCString> -ProfilerImpl::GetStacktrace() -{ - nsTArray<nsCString> trace; - auto output = MakeUnique<char[]>(BACKTRACE_BUFFER_SIZE); - - profiler_get_backtrace_noalloc(output.get(), BACKTRACE_BUFFER_SIZE); - for (const char* p = output.get(); *p; p += strlen(p) + 1) { - trace.AppendElement()->Assign(p); - } - - return trace; -} - -// Generate a random number in [0, 1). -double -ProfilerImpl::DRandom() -{ - return double(((uint64_t(std::rand()) & ((1 << 26) - 1)) << 27) + - (uint64_t(std::rand()) & ((1 << 27) - 1))) - / (uint64_t(1) << 53); -} - -size_t -ProfilerImpl::AddBytesSampled(uint32_t aBytes) -{ - size_t nSamples = 0; - while (mRemainingBytes <= aBytes) { - mRemainingBytes += std::floor(std::log(1.0 - DRandom()) / mLog1minusP); - nSamples++; - } - mRemainingBytes -= aBytes; - return nSamples; -} - -NS_IMPL_ISUPPORTS(MemoryProfiler, nsIMemoryProfiler) - -PRLock* MemoryProfiler::sLock; -uint32_t MemoryProfiler::sProfileContextCount; -StaticAutoPtr<NativeProfilerImpl> MemoryProfiler::sNativeProfiler; -StaticAutoPtr<JSContextProfilerMap> MemoryProfiler::sJSContextProfilerMap; -TimeStamp MemoryProfiler::sStartTime; - -void -MemoryProfiler::InitOnce() -{ - MOZ_ASSERT(NS_IsMainThread()); - - static bool initialized = false; - - if (!initialized) { - MallocHook::Initialize(); - sLock = PR_NewLock(); - sProfileContextCount = 0; - sJSContextProfilerMap = new JSContextProfilerMap(); - ClearOnShutdown(&sJSContextProfilerMap); - ClearOnShutdown(&sNativeProfiler); - std::srand(PR_Now()); - bool ignored; - sStartTime = TimeStamp::ProcessCreation(ignored); - initialized = true; - } -} - -NS_IMETHODIMP -MemoryProfiler::StartProfiler() -{ - InitOnce(); - AutoUseUncensoredAllocator ua; - AutoMPLock lock(sLock); - JSContext* context = XPCJSContext::Get()->Context(); - ProfilerForJSContext profiler; - if (!sJSContextProfilerMap->Get(context, &profiler) || - !profiler.mEnabled) { - if (sProfileContextCount == 0) { - js::EnableContextProfilingStack(context, true); - if (!sNativeProfiler) { - sNativeProfiler = new NativeProfilerImpl(); - } - MemProfiler::SetNativeProfiler(sNativeProfiler); - } - GCHeapProfilerImpl* gp = new GCHeapProfilerImpl(); - profiler.mEnabled = true; - profiler.mProfiler = gp; - sJSContextProfilerMap->Put(context, profiler); - MemProfiler::GetMemProfiler(context)->start(gp); - if (sProfileContextCount == 0) { - MallocHook::Enable(sNativeProfiler); - } - sProfileContextCount++; - } - return NS_OK; -} - -NS_IMETHODIMP -MemoryProfiler::StopProfiler() -{ - InitOnce(); - AutoUseUncensoredAllocator ua; - AutoMPLock lock(sLock); - JSContext* context = XPCJSContext::Get()->Context(); - ProfilerForJSContext profiler; - if (sJSContextProfilerMap->Get(context, &profiler) && - profiler.mEnabled) { - MemProfiler::GetMemProfiler(context)->stop(); - if (--sProfileContextCount == 0) { - MallocHook::Disable(); - MemProfiler::SetNativeProfiler(nullptr); - js::EnableContextProfilingStack(context, false); - } - profiler.mEnabled = false; - sJSContextProfilerMap->Put(context, profiler); - } - return NS_OK; -} - -NS_IMETHODIMP -MemoryProfiler::ResetProfiler() -{ - InitOnce(); - AutoUseUncensoredAllocator ua; - AutoMPLock lock(sLock); - JSContext* context = XPCJSContext::Get()->Context(); - ProfilerForJSContext profiler; - if (!sJSContextProfilerMap->Get(context, &profiler) || - !profiler.mEnabled) { - delete profiler.mProfiler; - profiler.mProfiler = nullptr; - sJSContextProfilerMap->Put(context, profiler); - } - if (sProfileContextCount == 0) { - sNativeProfiler = nullptr; - } - return NS_OK; -} - -struct MergedTraces -{ - nsTArray<nsCString> mNames; - nsTArray<TrieNode> mTraces; - nsTArray<AllocEvent> mEvents; -}; - -// Merge events and corresponding traces and names. -static MergedTraces -MergeResults(const nsTArray<nsCString>& names0, - const nsTArray<TrieNode>& traces0, - const nsTArray<AllocEvent>& events0, - const nsTArray<nsCString>& names1, - const nsTArray<TrieNode>& traces1, - const nsTArray<AllocEvent>& events1) -{ - NodeIndexMap<nsCStringHashKey, nsCString> names; - NodeIndexMap<nsGenericHashKey<TrieNode>, TrieNode> traces; - nsTArray<AllocEvent> events; - - nsTArray<size_t> names1Tonames0(names1.Length()); - nsTArray<size_t> traces1Totraces0(traces1.Length()); - - // Merge names. - for (auto& i: names0) { - names.Insert(i); - } - for (auto& i: names1) { - names1Tonames0.AppendElement(names.Insert(i)); - } - - // Merge traces. Note that traces1[i].parentIdx < i for all i > 0. - for (auto& i: traces0) { - traces.Insert(i); - } - traces1Totraces0.AppendElement(0); - for (size_t i = 1; i < traces1.Length(); i++) { - TrieNode node = traces1[i]; - node.parentIdx = traces1Totraces0[node.parentIdx]; - node.nameIdx = names1Tonames0[node.nameIdx]; - traces1Totraces0.AppendElement(traces.Insert(node)); - } - - // Merge the events according to timestamps. - auto p0 = events0.begin(); - auto p1 = events1.begin(); - - while (p0 != events0.end() && p1 != events1.end()) { - if (p0->mTimestamp < p1->mTimestamp) { - events.AppendElement(*p0++); - } else { - events.AppendElement(*p1++); - events.LastElement().mTraceIdx = - traces1Totraces0[events.LastElement().mTraceIdx]; - } - } - - while (p0 != events0.end()) { - events.AppendElement(*p0++); - } - - while (p1 != events1.end()) { - events.AppendElement(*p1++); - events.LastElement().mTraceIdx = - traces1Totraces0[events.LastElement().mTraceIdx]; - } - - return MergedTraces{names.Serialize(), traces.Serialize(), Move(events)}; -} - -NS_IMETHODIMP -MemoryProfiler::GetResults(JSContext* cx, JS::MutableHandle<JS::Value> aResult) -{ - InitOnce(); - AutoUseUncensoredAllocator ua; - AutoMPLock lock(sLock); - JSContext* context = XPCJSContext::Get()->Context(); - // Getting results when the profiler is running is not allowed. - if (sProfileContextCount > 0) { - return NS_OK; - } - // Return immediately when native profiler does not exist. - if (!sNativeProfiler) { - return NS_OK; - } - // Return immediately when there's no result in current context. - ProfilerForJSContext profiler; - if (!sJSContextProfilerMap->Get(context, &profiler) || - !profiler.mProfiler) { - return NS_OK; - } - GCHeapProfilerImpl* gp = profiler.mProfiler; - - auto results = MergeResults(gp->GetNames(), gp->GetTraces(), gp->GetEvents(), - sNativeProfiler->GetNames(), - sNativeProfiler->GetTraces(), - sNativeProfiler->GetEvents()); - const nsTArray<nsCString>& names = results.mNames; - const nsTArray<TrieNode>& traces = results.mTraces; - const nsTArray<AllocEvent>& events = results.mEvents; - - JS::RootedObject jsnames(cx, JS_NewArrayObject(cx, names.Length())); - JS::RootedObject jstraces(cx, JS_NewArrayObject(cx, traces.Length())); - JS::RootedObject jsevents(cx, JS_NewArrayObject(cx, events.Length())); - - for (size_t i = 0; i < names.Length(); i++) { - JS::RootedString name(cx, JS_NewStringCopyZ(cx, names[i].get())); - JS_SetElement(cx, jsnames, i, name); - } - - for (size_t i = 0; i < traces.Length(); i++) { - JS::RootedObject tn(cx, JS_NewPlainObject(cx)); - JS::RootedValue nameIdx(cx, JS_NumberValue(traces[i].nameIdx)); - JS::RootedValue parentIdx(cx, JS_NumberValue(traces[i].parentIdx)); - JS_SetProperty(cx, tn, "nameIdx", nameIdx); - JS_SetProperty(cx, tn, "parentIdx", parentIdx); - JS_SetElement(cx, jstraces, i, tn); - } - - int i = 0; - for (auto ent: events) { - if (ent.mSize == 0) { - continue; - } - MOZ_ASSERT(!sStartTime.IsNull()); - double time = (ent.mTimestamp - sStartTime).ToMilliseconds(); - JS::RootedObject tn(cx, JS_NewPlainObject(cx)); - JS::RootedValue size(cx, JS_NumberValue(ent.mSize)); - JS::RootedValue traceIdx(cx, JS_NumberValue(ent.mTraceIdx)); - JS::RootedValue timestamp(cx, JS_NumberValue(time)); - JS_SetProperty(cx, tn, "size", size); - JS_SetProperty(cx, tn, "traceIdx", traceIdx); - JS_SetProperty(cx, tn, "timestamp", timestamp); - JS_SetElement(cx, jsevents, i++, tn); - } - JS_SetArrayLength(cx, jsevents, i); - - JS::RootedObject result(cx, JS_NewPlainObject(cx)); - JS::RootedValue objnames(cx, ObjectOrNullValue(jsnames)); - JS_SetProperty(cx, result, "names", objnames); - JS::RootedValue objtraces(cx, ObjectOrNullValue(jstraces)); - JS_SetProperty(cx, result, "traces", objtraces); - JS::RootedValue objevents(cx, ObjectOrNullValue(jsevents)); - JS_SetProperty(cx, result, "events", objevents); - aResult.setObject(*result); - return NS_OK; -} - -} // namespace mozilla diff --git a/tools/memory-profiler/MemoryProfiler.h b/tools/memory-profiler/MemoryProfiler.h deleted file mode 100644 index 85a378fb2..000000000 --- a/tools/memory-profiler/MemoryProfiler.h +++ /dev/null @@ -1,159 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=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 tools_profiler_MemoryProfiler_h -#define tools_profiler_MemoryProfiler_h - -#include "nsIMemoryProfiler.h" - -#include "mozilla/StaticPtr.h" -#include "mozilla/TimeStamp.h" - -#include "CompactTraceTable.h" -#include "nsTArray.h" -#include "prlock.h" - -#define MEMORY_PROFILER_CID \ - { 0xf976eaa2, 0xcc1f, 0x47ee, \ - { 0x81, 0x29, 0xb8, 0x26, 0x2a, 0x3d, 0xb6, 0xb2 } } - -#define MEMORY_PROFILER_CONTRACT_ID "@mozilla.org/tools/memory-profiler;1" - -struct PRLock; - -namespace mozilla { - -class NativeProfilerImpl; -class GCHeapProfilerImpl; - -struct ProfilerForJSContext -{ - ProfilerForJSContext() - : mProfiler(nullptr) - , mEnabled(false) - {} - GCHeapProfilerImpl* mProfiler; - bool mEnabled; -}; -using JSContextProfilerMap = - nsDataHashtable<nsClearingPtrHashKey<JSContext>, ProfilerForJSContext>; - -class MemoryProfiler final : public nsIMemoryProfiler -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIMEMORYPROFILER - -private: - static void InitOnce(); - ~MemoryProfiler() {} - - // The accesses to other static member are guarded by sLock and - // sProfileContextCount. - static PRLock* sLock; - static uint32_t sProfileContextCount; - - static StaticAutoPtr<NativeProfilerImpl> sNativeProfiler; - static StaticAutoPtr<JSContextProfilerMap> sJSContextProfilerMap; - static TimeStamp sStartTime; -}; - -// Allocation events to be reported. -struct AllocEvent { - TimeStamp mTimestamp; - // index to a stacktrace singleton. - uint32_t mTraceIdx; - // Allocation size - int32_t mSize; - - AllocEvent(uint32_t aTraceIdx, int32_t aSize, TimeStamp aTimestamp) - : mTimestamp(aTimestamp) - , mTraceIdx(aTraceIdx) - , mSize(aSize) - {} -}; - -// Index to allocation events but also a mark bit to be GC-able. -struct AllocEntry { - uint32_t mEventIdx : 31; - bool mMarked : 1; - - // Default constructor for uninitialized stack value required by - // getter methods. - AllocEntry() - : mEventIdx(0) - , mMarked(false) - {} - explicit AllocEntry(int aEventIdx) - : mEventIdx(aEventIdx) - , mMarked(false) - {} -}; - -using AllocMap = nsDataHashtable<nsClearingVoidPtrHashKey, AllocEntry>; - -class ProfilerImpl -{ -public: - static nsTArray<nsCString> GetStacktrace(); - static double DRandom(); - - ProfilerImpl(); - virtual nsTArray<nsCString> GetNames() const = 0; - virtual nsTArray<TrieNode> GetTraces() const = 0; - virtual const nsTArray<AllocEvent>& GetEvents() const = 0; - -protected: - /** - * The sampler generates a random variable which conforms to a geometric - * distribution of probability p = 1 / mSampleSize to calculate the - * next-to-be-sampled byte directly; It avoids rolling a dice on each byte. - * - * Let Bn denote a Bernoulli process with first success on n-th trial, the - * cumulative distribution function of Bn is Cn = 1 - (1 - p) ^ n. - * Let U denote a uniformly distributed random variable in [0, 1). - * A geometric random variable can be generated by Cn's reverse function: - * G = floor(log(1 - U) / log(1 - p)). - * - * @param aSize the number of bytes seen - * @return the number of events sampled - */ - size_t AddBytesSampled(uint32_t aBytes); - - uint32_t mSampleSize; - -private: - uint32_t mRemainingBytes; - double mLog1minusP; -}; - -/* - * This class is used to make sure the profile data is only accessed - * on one thread at a time. Don't use mozilla::Mutex because we don't - * want to allocate memory. - */ -class AutoMPLock -{ -public: - explicit AutoMPLock(PRLock* aLock) - { - MOZ_ASSERT(aLock); - mLock = aLock; - PR_Lock(mLock); - } - - ~AutoMPLock() - { - PR_Unlock(mLock); - } - -private: - PRLock* mLock; -}; - -} // namespace mozilla - -#endif diff --git a/tools/memory-profiler/NativeProfilerImpl.cpp b/tools/memory-profiler/NativeProfilerImpl.cpp deleted file mode 100644 index 48c684c72..000000000 --- a/tools/memory-profiler/NativeProfilerImpl.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=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/. */ - -#include "NativeProfilerImpl.h" - -#include "UncensoredAllocator.h" - -namespace mozilla { - -NativeProfilerImpl::NativeProfilerImpl() -{ - mLock = PR_NewLock(); -} - -NativeProfilerImpl::~NativeProfilerImpl() -{ - if (mLock) { - PR_DestroyLock(mLock); - } -} - -nsTArray<nsCString> -NativeProfilerImpl::GetNames() const -{ - return mTraceTable.GetNames(); -} - -nsTArray<TrieNode> -NativeProfilerImpl::GetTraces() const -{ - return mTraceTable.GetTraces(); -} - -const nsTArray<AllocEvent>& -NativeProfilerImpl::GetEvents() const -{ - return mAllocEvents; -} - -void -NativeProfilerImpl::reset() -{ - mTraceTable.Reset(); - mAllocEvents.Clear(); - mNativeEntries.Clear(); -} - -void -NativeProfilerImpl::sampleNative(void* addr, uint32_t size) -{ - AutoUseUncensoredAllocator ua; - AutoMPLock lock(mLock); - size_t nSamples = AddBytesSampled(size); - if (nSamples > 0) { - nsTArray<nsCString> trace = GetStacktrace(); - AllocEvent ai(mTraceTable.Insert(trace), nSamples * mSampleSize, TimeStamp::Now()); - mNativeEntries.Put(addr, AllocEntry(mAllocEvents.Length())); - mAllocEvents.AppendElement(ai); - } -} - -void -NativeProfilerImpl::removeNative(void* addr) -{ - AutoUseUncensoredAllocator ua; - AutoMPLock lock(mLock); - - AllocEntry entry; - if (!mNativeEntries.Get(addr, &entry)) { - return; - } - - AllocEvent& oldEvent = mAllocEvents[entry.mEventIdx]; - AllocEvent newEvent(oldEvent.mTraceIdx, -oldEvent.mSize, TimeStamp::Now()); - mAllocEvents.AppendElement(newEvent); - mNativeEntries.Remove(addr); -} - -} // namespace mozilla diff --git a/tools/memory-profiler/NativeProfilerImpl.h b/tools/memory-profiler/NativeProfilerImpl.h deleted file mode 100644 index 95cc2ec13..000000000 --- a/tools/memory-profiler/NativeProfilerImpl.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=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 memory_profiler_NativeProfilerImpl_h -#define memory_profiler_NativeProfilerImpl_h - -#include "CompactTraceTable.h" -#include "MemoryProfiler.h" - -#include "jsfriendapi.h" - -struct PRLock; - -namespace mozilla { - -class NativeProfilerImpl final : public NativeProfiler - , public ProfilerImpl -{ -public: - NativeProfilerImpl(); - ~NativeProfilerImpl() override; - - nsTArray<nsCString> GetNames() const override; - nsTArray<TrieNode> GetTraces() const override; - const nsTArray<AllocEvent>& GetEvents() const override; - - void reset() override; - void sampleNative(void* addr, uint32_t size) override; - void removeNative(void* addr) override; - -private: - PRLock* mLock; - AllocMap mNativeEntries; - nsTArray<AllocEvent> mAllocEvents; - CompactTraceTable mTraceTable; -}; - -} // namespace mozilla - -#endif // memory_profiler_NativeProfilerImpl_h diff --git a/tools/memory-profiler/UncensoredAllocator.cpp b/tools/memory-profiler/UncensoredAllocator.cpp deleted file mode 100644 index 92caeb633..000000000 --- a/tools/memory-profiler/UncensoredAllocator.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=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/. */ - -#include "UncensoredAllocator.h" - -#include "mozilla/Assertions.h" -#include "mozilla/Unused.h" - -#include "MainThreadUtils.h" -#include "jsfriendapi.h" -#include "nsDebug.h" -#include "prlock.h" -#ifdef MOZ_REPLACE_MALLOC -#include "replace_malloc_bridge.h" -#endif - -namespace mozilla { - -#ifdef MOZ_REPLACE_MALLOC -MOZ_THREAD_LOCAL(bool) MallocHook::mEnabledTLS; -NativeProfiler* MallocHook::mNativeProfiler; -malloc_hook_table_t MallocHook::mMallocHook; -#endif - -AutoUseUncensoredAllocator::AutoUseUncensoredAllocator() -{ -#ifdef MOZ_REPLACE_MALLOC - MallocHook::mEnabledTLS.set(false); -#endif -} - -AutoUseUncensoredAllocator::~AutoUseUncensoredAllocator() -{ -#ifdef MOZ_REPLACE_MALLOC - MallocHook::mEnabledTLS.set(true); -#endif -} - -bool -MallocHook::Enabled() -{ -#ifdef MOZ_REPLACE_MALLOC - return mEnabledTLS.get() && mNativeProfiler; -#else - return false; -#endif -} - -void* -MallocHook::SampleNative(void* aAddr, size_t aSize) -{ -#ifdef MOZ_REPLACE_MALLOC - if (MallocHook::Enabled()) { - mNativeProfiler->sampleNative(aAddr, aSize); - } -#endif - return aAddr; -} - -void -MallocHook::RemoveNative(void* aAddr) -{ -#ifdef MOZ_REPLACE_MALLOC - if (MallocHook::Enabled()) { - mNativeProfiler->removeNative(aAddr); - } -#endif -} - -void -MallocHook::Initialize() -{ -#ifdef MOZ_REPLACE_MALLOC - MOZ_ASSERT(NS_IsMainThread()); - mMallocHook.free_hook = RemoveNative; - mMallocHook.malloc_hook = SampleNative; - ReplaceMallocBridge* bridge = ReplaceMallocBridge::Get(3); - if (bridge) { - mozilla::Unused << bridge->RegisterHook("memory-profiler", nullptr, nullptr); - } - - bool success = mEnabledTLS.init(); - if (NS_WARN_IF(!success)) { - return; - } -#endif -} - -void -MallocHook::Enable(NativeProfiler* aNativeProfiler) -{ -#ifdef MOZ_REPLACE_MALLOC - MOZ_ASSERT(NS_IsMainThread()); - ReplaceMallocBridge* bridge = ReplaceMallocBridge::Get(3); - if (bridge) { - const malloc_table_t* alloc_funcs = - bridge->RegisterHook("memory-profiler", nullptr, &mMallocHook); - if (alloc_funcs) { - mNativeProfiler = aNativeProfiler; - } - } -#endif -} - -void -MallocHook::Disable() -{ -#ifdef MOZ_REPLACE_MALLOC - MOZ_ASSERT(NS_IsMainThread()); - ReplaceMallocBridge* bridge = ReplaceMallocBridge::Get(3); - if (bridge) { - bridge->RegisterHook("memory-profiler", nullptr, nullptr); - mNativeProfiler = nullptr; - } -#endif -} - -} // namespace mozilla diff --git a/tools/memory-profiler/UncensoredAllocator.h b/tools/memory-profiler/UncensoredAllocator.h deleted file mode 100644 index b9074c738..000000000 --- a/tools/memory-profiler/UncensoredAllocator.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=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 memory_profiler_UncensoredAllocator_h -#define memory_profiler_UncensoredAllocator_h - -#include "mozilla/Attributes.h" -#include "mozilla/ThreadLocal.h" - -#ifdef MOZ_REPLACE_MALLOC -#include "replace_malloc_bridge.h" -#endif - -class NativeProfiler; - -namespace mozilla { - -class MallocHook final -{ -public: - static void Initialize(); - static void Enable(NativeProfiler* aNativeProfiler); - static void Disable(); - static bool Enabled(); -private: - static void* SampleNative(void* aAddr, size_t aSize); - static void RemoveNative(void* aAddr); -#ifdef MOZ_REPLACE_MALLOC - static MOZ_THREAD_LOCAL(bool) mEnabledTLS; - static NativeProfiler* mNativeProfiler; - static malloc_hook_table_t mMallocHook; -#endif - friend class AutoUseUncensoredAllocator; -}; - -class MOZ_RAII AutoUseUncensoredAllocator final -{ -public: - AutoUseUncensoredAllocator(); - ~AutoUseUncensoredAllocator(); -}; - -} // namespace mozilla - -#endif // memory_profiler_UncensoredAllocator_h diff --git a/tools/memory-profiler/moz.build b/tools/memory-profiler/moz.build index be2fe7432..cd37ffdb2 100644 --- a/tools/memory-profiler/moz.build +++ b/tools/memory-profiler/moz.build @@ -4,26 +4,5 @@ # 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/. -if CONFIG['MOZ_ENABLE_PROFILER_SPS']: - XPIDL_MODULE = 'memory_profiler' - XPIDL_SOURCES += [ - 'nsIMemoryProfiler.idl', - ] - - UNIFIED_SOURCES += [ - 'GCHeapProfilerImpl.cpp', - 'MemoryProfiler.cpp', - 'NativeProfilerImpl.cpp', - 'nsMemoryProfilerFactory.cpp', - 'UncensoredAllocator.cpp', - ] - - LOCAL_INCLUDES += [ - '/js/xpconnect/src', - '/xpcom/base', - ] - - FINAL_LIBRARY = 'xul' - if CONFIG['GNU_CXX']: CXXFLAGS += ['-Wno-error=shadow'] diff --git a/tools/memory-profiler/nsIMemoryProfiler.idl b/tools/memory-profiler/nsIMemoryProfiler.idl deleted file mode 100644 index 4ca386f9d..000000000 --- a/tools/memory-profiler/nsIMemoryProfiler.idl +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#include "nsISupports.idl" - -/** - * The memory profiler samples allocation events. An allocation event - * includes a type (what and at where is going to be allocated), a - * size, a timestamp and the corresponding stack trace. Free events - * are also tracked. For managed languages, namely languages relying - * on garbage collection, a free event is generated when an object is - * reclaimed by the garbage collector. These sampled events can be - * used to approximate the full history of allocations afterwards. - * That means we can get various memory profiles of a program in - * different perspectives by post-processing the history in different - * ways. The profiler is designed at the very beginning to support not - * only JavaScript but also native codes. Naturally, not only - * JavaScript objects but also native allocations are tracked. - * - * The result returned is the sampled allocation event traces in a - * compact format. The events is sorted according to the timestamp - * when the event happened. Each event has a trace index pointing to - * the traces table. Each trace entry has a name index pointing to the - * names table and a parent index pointing to the parent trace in the - * traces table. By following the trace index one could rebuild the - * complete backtrace of an allocation event. - * - * [ Events ] - * +-------+-------+ +-------+ - * | Size | Size | | Size | - * |-------|-------| |-------| - * | Time | Time |......| Time | - * |-------|-------| |-------| - * +-- Trace | Trace | | Trace | - * | +-------+-------+ +-------+ - * | - * | [ Traces ] - * +->--------+--------+ +--------+ +--------+ - * -| Name | Name | | Name | | Name | - * / |--------|--------|...|--------|...|--------| - * | | Parent | Parent | | Parent | | Parent | - * | +---|----+----^--++ +--^--|--+ +---^----+ - * | | | | | | | - * | +---------+ +-------+ +----------+ - * | [ Names ] - * | +-----------------+-----------------+ - * +-> Function name | Function name | - * | & line numbers | & line numbers |...... - * +-----------------+-----------------+ - * - */ -[scriptable, uuid(1e10e7a9-bc05-4878-a687-36c9ea4428b1)] -interface nsIMemoryProfiler : nsISupports -{ - void startProfiler(); - void stopProfiler(); - void resetProfiler(); - - /** - * Get results in an object which contains three tables: - * { - * names, // an array of function names and positions - * traces, // an array of {nameIdx, parentIdx} - * events, // an array of {size, timestamp, traceIdx} - * } - * Should only be called after stopProfiler. - */ - [implicit_jscontext] - jsval getResults(); -}; diff --git a/tools/memory-profiler/nsMemoryProfilerFactory.cpp b/tools/memory-profiler/nsMemoryProfilerFactory.cpp deleted file mode 100644 index b962a6604..000000000 --- a/tools/memory-profiler/nsMemoryProfilerFactory.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#include "mozilla/ModuleUtils.h" -#include "nsCOMPtr.h" -#include "MemoryProfiler.h" - -using mozilla::MemoryProfiler; - -NS_GENERIC_FACTORY_CONSTRUCTOR(MemoryProfiler) - -NS_DEFINE_NAMED_CID(MEMORY_PROFILER_CID); - -static const mozilla::Module::CIDEntry kMemoryProfilerCIDs[] = { - { &kMEMORY_PROFILER_CID, false, nullptr, MemoryProfilerConstructor }, - { nullptr } -}; - -static const mozilla::Module::ContractIDEntry kMemoryProfilerContracts[] = { - { MEMORY_PROFILER_CONTRACT_ID, &kMEMORY_PROFILER_CID }, - { nullptr } -}; - -static const mozilla::Module kMemoryProfilerModule = { - mozilla::Module::kVersion, - kMemoryProfilerCIDs, - kMemoryProfilerContracts -}; - -NSMODULE_DEFN(nsMemoryProfilerModule) = &kMemoryProfilerModule; |