summaryrefslogtreecommitdiffstats
path: root/tools/memory-profiler/MemoryProfiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/memory-profiler/MemoryProfiler.cpp')
-rw-r--r--tools/memory-profiler/MemoryProfiler.cpp324
1 files changed, 0 insertions, 324 deletions
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