зеркало из https://github.com/mozilla/pjs.git
Bug 714264 - Part c: Move IterateData / CollectCompartmentStatsForRuntime / GetExplicitNonHeapForRuntime to js/MemoryMetrics.h; r=njn
This patch also removes those APIs exposed in js/MemoryMetrics.h that aren't used anymore.
This commit is contained in:
Родитель
4dabf76c50
Коммит
555fdc26d7
|
@ -59,6 +59,8 @@
|
|||
#include "jscntxt.h"
|
||||
#include "jsdbgapi.h"
|
||||
#include "jsprf.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
|
||||
#include "nsAlgorithm.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
|
@ -93,7 +95,7 @@ using mozilla::MutexAutoLock;
|
|||
using mozilla::TimeDuration;
|
||||
using mozilla::TimeStamp;
|
||||
using mozilla::dom::workers::exceptions::ThrowDOMExceptionForCode;
|
||||
using mozilla::xpconnect::memory::IterateData;
|
||||
using mozilla::xpconnect::memory::ReportJSRuntimeStats;
|
||||
|
||||
USING_WORKERS_NAMESPACE
|
||||
|
||||
|
@ -223,7 +225,8 @@ public:
|
|||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
IterateData data;
|
||||
JS::IterateData data(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
|
||||
xpc::DestroyCompartmentName);
|
||||
nsresult rv = CollectForRuntime(/* isQuick = */false, &data);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -1475,9 +1478,9 @@ public:
|
|||
{
|
||||
JSAutoSuspendRequest asr(aCx);
|
||||
|
||||
*mSucceeded = mIsQuick ?
|
||||
mozilla::xpconnect::memory::GetExplicitNonHeapForRuntime(JS_GetRuntime(aCx), mData) :
|
||||
mozilla::xpconnect::memory::CollectCompartmentStatsForRuntime(JS_GetRuntime(aCx), mData);
|
||||
*mSucceeded = mIsQuick
|
||||
? JS::GetExplicitNonHeapForRuntime(JS_GetRuntime(aCx), static_cast<int64_t*>(mData), xpc::JsMallocSizeOf)
|
||||
: JS::CollectCompartmentStatsForRuntime(JS_GetRuntime(aCx), static_cast<JS::IterateData*>(mData));
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
|
|
@ -69,16 +69,6 @@ class nsIURI;
|
|||
class nsPIDOMWindow;
|
||||
class nsITimer;
|
||||
|
||||
namespace mozilla {
|
||||
namespace xpconnect {
|
||||
namespace memory {
|
||||
|
||||
struct IterateData;
|
||||
|
||||
} // namespace memory
|
||||
} // namespace xpconnect
|
||||
} // namespace mozilla
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class WorkerPrivate;
|
||||
|
|
|
@ -44,9 +44,11 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include "jsalloc.h"
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "js/Utility.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
namespace JS {
|
||||
|
||||
|
@ -59,6 +61,7 @@ struct TypeInferenceMemoryStats
|
|||
int64_t temporary;
|
||||
};
|
||||
|
||||
typedef void* (* GetNameCallback)(JSContext *cx, JSCompartment *c);
|
||||
typedef void (* DestroyNameCallback)(void *string);
|
||||
|
||||
struct CompartmentStats
|
||||
|
@ -112,6 +115,81 @@ struct CompartmentStats
|
|||
TypeInferenceMemoryStats typeInferenceMemory;
|
||||
};
|
||||
|
||||
struct IterateData
|
||||
{
|
||||
IterateData(JSMallocSizeOfFun mallocSizeOf, GetNameCallback getNameCb,
|
||||
DestroyNameCallback destroyNameCb)
|
||||
: runtimeObject(0)
|
||||
, runtimeAtomsTable(0)
|
||||
, runtimeContexts(0)
|
||||
, runtimeThreadsNormal(0)
|
||||
, runtimeThreadsTemporary(0)
|
||||
, runtimeThreadsRegexpCode(0)
|
||||
, runtimeThreadsStackCommitted(0)
|
||||
, gcHeapChunkTotal(0)
|
||||
, gcHeapChunkCleanUnused(0)
|
||||
, gcHeapChunkDirtyUnused(0)
|
||||
, gcHeapChunkCleanDecommitted(0)
|
||||
, gcHeapChunkDirtyDecommitted(0)
|
||||
, gcHeapArenaUnused(0)
|
||||
, gcHeapChunkAdmin(0)
|
||||
, gcHeapUnusedPercentage(0)
|
||||
, totalObjects(0)
|
||||
, totalShapes(0)
|
||||
, totalScripts(0)
|
||||
, totalStrings(0)
|
||||
#ifdef JS_METHODJIT
|
||||
, totalMjit(0)
|
||||
#endif
|
||||
, totalTypeInference(0)
|
||||
, totalAnalysisTemp(0)
|
||||
, compartmentStatsVector()
|
||||
, currCompartmentStats(NULL)
|
||||
, mallocSizeOf(mallocSizeOf)
|
||||
, getNameCb(getNameCb)
|
||||
, destroyNameCb(destroyNameCb)
|
||||
{}
|
||||
|
||||
int64_t runtimeObject;
|
||||
int64_t runtimeAtomsTable;
|
||||
int64_t runtimeContexts;
|
||||
int64_t runtimeThreadsNormal;
|
||||
int64_t runtimeThreadsTemporary;
|
||||
int64_t runtimeThreadsRegexpCode;
|
||||
int64_t runtimeThreadsStackCommitted;
|
||||
int64_t gcHeapChunkTotal;
|
||||
int64_t gcHeapChunkCleanUnused;
|
||||
int64_t gcHeapChunkDirtyUnused;
|
||||
int64_t gcHeapChunkCleanDecommitted;
|
||||
int64_t gcHeapChunkDirtyDecommitted;
|
||||
int64_t gcHeapArenaUnused;
|
||||
int64_t gcHeapChunkAdmin;
|
||||
int64_t gcHeapUnusedPercentage;
|
||||
int64_t totalObjects;
|
||||
int64_t totalShapes;
|
||||
int64_t totalScripts;
|
||||
int64_t totalStrings;
|
||||
#ifdef JS_METHODJIT
|
||||
int64_t totalMjit;
|
||||
#endif
|
||||
int64_t totalTypeInference;
|
||||
int64_t totalAnalysisTemp;
|
||||
|
||||
js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> compartmentStatsVector;
|
||||
CompartmentStats *currCompartmentStats;
|
||||
|
||||
JSMallocSizeOfFun mallocSizeOf;
|
||||
GetNameCallback getNameCb;
|
||||
DestroyNameCallback destroyNameCb;
|
||||
};
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
GetExplicitNonHeapForRuntime(JSRuntime *rt, int64_t *amount,
|
||||
JSMallocSizeOfFun mallocSizeOf);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
SizeOfCompartmentTypeInferenceData(JSContext *cx, JSCompartment *compartment,
|
||||
TypeInferenceMemoryStats *stats,
|
||||
|
@ -122,32 +200,9 @@ SizeOfObjectTypeInferenceData(/*TypeObject*/ void *object,
|
|||
TypeInferenceMemoryStats *stats,
|
||||
JSMallocSizeOfFun mallocSizeOf);
|
||||
|
||||
extern JS_PUBLIC_API(size_t)
|
||||
SizeOfObjectDynamicSlots(JSObject *obj, JSMallocSizeOfFun mallocSizeOf);
|
||||
|
||||
extern JS_PUBLIC_API(size_t)
|
||||
SizeOfCompartmentShapeTable(JSCompartment *c, JSMallocSizeOfFun mallocSizeOf);
|
||||
|
||||
extern JS_PUBLIC_API(size_t)
|
||||
SizeOfCompartmentMjitCode(const JSCompartment *c);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsShapeInDictionary(const void *shape);
|
||||
|
||||
extern JS_PUBLIC_API(size_t)
|
||||
SizeOfShapePropertyTable(const void *shape, JSMallocSizeOfFun mallocSizeOf);
|
||||
|
||||
extern JS_PUBLIC_API(size_t)
|
||||
SizeOfShapeKids(const void *shape, JSMallocSizeOfFun mallocSizeOf);
|
||||
|
||||
extern JS_PUBLIC_API(size_t)
|
||||
SizeOfScriptData(JSScript *script, JSMallocSizeOfFun mallocSizeOf);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
extern JS_PUBLIC_API(size_t)
|
||||
SizeOfScriptJitData(JSScript *script, JSMallocSizeOfFun mallocSizeOf);
|
||||
#endif
|
||||
|
||||
extern JS_PUBLIC_API(size_t)
|
||||
SystemCompartmentCount(const JSRuntime *rt);
|
||||
|
||||
|
|
|
@ -171,6 +171,7 @@ CPPSRCS = \
|
|||
SemanticAnalysis.cpp \
|
||||
TokenStream.cpp \
|
||||
LifoAlloc.cpp \
|
||||
MemoryMetrics.cpp \
|
||||
RegExpObject.cpp \
|
||||
RegExpStatics.cpp \
|
||||
RegExp.cpp \
|
||||
|
|
|
@ -0,0 +1,382 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is about:memory glue.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ms2ger <ms2ger@gmail.com>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "js/MemoryMetrics.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jscompartment.h"
|
||||
#include "jsgc.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsscope.h"
|
||||
#include "jsscript.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
namespace JS {
|
||||
|
||||
using namespace js;
|
||||
|
||||
static void
|
||||
CompartmentMemoryCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
|
||||
{
|
||||
// Append a new CompartmentStats to the vector.
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
|
||||
// CollectCompartmentStatsForRuntime reserves enough space.
|
||||
MOZ_ALWAYS_TRUE(data->compartmentStatsVector.growBy(1));
|
||||
CompartmentStats &curr = data->compartmentStatsVector.back();
|
||||
curr.init(data->getNameCb(cx, compartment), data->destroyNameCb);
|
||||
data->currCompartmentStats = &curr;
|
||||
|
||||
// Get the compartment-level numbers.
|
||||
#ifdef JS_METHODJIT
|
||||
curr.mjitCode = compartment->sizeOfMjitCode();
|
||||
#endif
|
||||
SizeOfCompartmentTypeInferenceData(cx, compartment,
|
||||
&curr.typeInferenceMemory,
|
||||
data->mallocSizeOf);
|
||||
curr.shapesCompartmentTables =
|
||||
SizeOfCompartmentShapeTable(compartment, data->mallocSizeOf);
|
||||
}
|
||||
|
||||
static void
|
||||
ExplicitNonHeapCompartmentCallback(JSContext *cx, void *data, JSCompartment *compartment)
|
||||
{
|
||||
#ifdef JS_METHODJIT
|
||||
size_t *n = static_cast<size_t *>(data);
|
||||
*n += compartment->sizeOfMjitCode();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
ChunkCallback(JSContext *cx, void *vdata, gc::Chunk *chunk)
|
||||
{
|
||||
// Nb: This function is only called for dirty chunks, which is why we
|
||||
// increment gcHeapChunkDirtyDecommitted.
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
for (size_t i = 0; i < gc::ArenasPerChunk; i++)
|
||||
if (chunk->decommittedArenas.get(i))
|
||||
data->gcHeapChunkDirtyDecommitted += gc::ArenaSize;
|
||||
}
|
||||
|
||||
static void
|
||||
ArenaCallback(JSContext *cx, void *vdata, gc::Arena *arena,
|
||||
JSGCTraceKind traceKind, size_t thingSize)
|
||||
{
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
|
||||
data->currCompartmentStats->gcHeapArenaHeaders +=
|
||||
sizeof(gc::ArenaHeader);
|
||||
size_t allocationSpace = arena->thingsSpan(thingSize);
|
||||
data->currCompartmentStats->gcHeapArenaPadding +=
|
||||
gc::ArenaSize - allocationSpace - sizeof(gc::ArenaHeader);
|
||||
// We don't call the callback on unused things. So we compute the
|
||||
// unused space like this: arenaUnused = maxArenaUnused - arenaUsed.
|
||||
// We do this by setting arenaUnused to maxArenaUnused here, and then
|
||||
// subtracting thingSize for every used cell, in CellCallback().
|
||||
data->currCompartmentStats->gcHeapArenaUnused += allocationSpace;
|
||||
}
|
||||
|
||||
static void
|
||||
CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind,
|
||||
size_t thingSize)
|
||||
{
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
CompartmentStats *curr = data->currCompartmentStats;
|
||||
switch (traceKind) {
|
||||
case JSTRACE_OBJECT:
|
||||
{
|
||||
JSObject *obj = static_cast<JSObject *>(thing);
|
||||
if (obj->isFunction()) {
|
||||
curr->gcHeapObjectsFunction += thingSize;
|
||||
} else {
|
||||
curr->gcHeapObjectsNonFunction += thingSize;
|
||||
}
|
||||
curr->objectSlots += obj->dynamicSlotSize(data->mallocSizeOf);
|
||||
break;
|
||||
}
|
||||
case JSTRACE_STRING:
|
||||
{
|
||||
JSString *str = static_cast<JSString *>(thing);
|
||||
curr->gcHeapStrings += thingSize;
|
||||
curr->stringChars += str->charsHeapSize(data->mallocSizeOf);
|
||||
break;
|
||||
}
|
||||
case JSTRACE_SHAPE:
|
||||
{
|
||||
Shape *shape = static_cast<Shape*>(thing);
|
||||
if (shape->inDictionary()) {
|
||||
curr->gcHeapShapesDict += thingSize;
|
||||
curr->shapesExtraDictTables +=
|
||||
shape->sizeOfPropertyTable(data->mallocSizeOf);
|
||||
} else {
|
||||
curr->gcHeapShapesTree += thingSize;
|
||||
curr->shapesExtraTreeTables +=
|
||||
shape->sizeOfPropertyTable(data->mallocSizeOf);
|
||||
curr->shapesExtraTreeShapeKids +=
|
||||
shape->sizeOfKids(data->mallocSizeOf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSTRACE_BASE_SHAPE:
|
||||
{
|
||||
curr->gcHeapShapesBase += thingSize;
|
||||
break;
|
||||
}
|
||||
case JSTRACE_SCRIPT:
|
||||
{
|
||||
JSScript *script = static_cast<JSScript *>(thing);
|
||||
curr->gcHeapScripts += thingSize;
|
||||
curr->scriptData += script->dataSize(data->mallocSizeOf);
|
||||
#ifdef JS_METHODJIT
|
||||
curr->mjitData += script->jitDataSize(data->mallocSizeOf);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case JSTRACE_TYPE_OBJECT:
|
||||
{
|
||||
types::TypeObject *obj = static_cast<types::TypeObject *>(thing);
|
||||
curr->gcHeapTypeObjects += thingSize;
|
||||
SizeOfObjectTypeInferenceData(obj, &curr->typeInferenceMemory,
|
||||
data->mallocSizeOf);
|
||||
break;
|
||||
}
|
||||
case JSTRACE_XML:
|
||||
{
|
||||
curr->gcHeapXML += thingSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Yes, this is a subtraction: see ArenaCallback() for details.
|
||||
curr->gcHeapArenaUnused -= thingSize;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
|
||||
{
|
||||
JSContext *cx = JS_NewContext(rt, 0);
|
||||
if (!cx)
|
||||
return false;
|
||||
|
||||
{
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
if (!data->compartmentStatsVector.reserve(rt->compartments.length()))
|
||||
return false;
|
||||
|
||||
data->gcHeapChunkCleanDecommitted =
|
||||
rt->gcChunkPool.countCleanDecommittedArenas(rt) *
|
||||
gc::ArenaSize;
|
||||
data->gcHeapChunkCleanUnused =
|
||||
int64_t(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) *
|
||||
gc::ChunkSize -
|
||||
data->gcHeapChunkCleanDecommitted;
|
||||
data->gcHeapChunkTotal =
|
||||
int64_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
|
||||
gc::ChunkSize;
|
||||
|
||||
IterateCompartmentsArenasCells(cx, data, CompartmentMemoryCallback,
|
||||
ArenaCallback, CellCallback);
|
||||
IterateChunks(cx, data, ChunkCallback);
|
||||
|
||||
data->runtimeObject = data->mallocSizeOf(rt, sizeof(JSRuntime));
|
||||
|
||||
// Nb: we use sizeOfExcludingThis() because atomState.atoms is within
|
||||
// JSRuntime, and so counted when JSRuntime is counted.
|
||||
data->runtimeAtomsTable =
|
||||
rt->atomState.atoms.sizeOfExcludingThis(data->mallocSizeOf);
|
||||
|
||||
{
|
||||
#ifndef JS_THREADSAFE
|
||||
#error "This code assumes JS_THREADSAFE is defined"
|
||||
#endif
|
||||
|
||||
// Need the GC lock to call JS_ContextIteratorUnlocked() and to
|
||||
// access rt->threads.
|
||||
AutoLockGC lock(rt);
|
||||
|
||||
JSContext *acx, *iter = NULL;
|
||||
while ((acx = JS_ContextIteratorUnlocked(rt, &iter)) != NULL) {
|
||||
data->runtimeContexts +=
|
||||
acx->sizeOfIncludingThis(data->mallocSizeOf);
|
||||
}
|
||||
|
||||
for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
|
||||
JSThread *thread = r.front().value;
|
||||
size_t normal, temporary, regexpCode, stackCommitted;
|
||||
thread->sizeOfIncludingThis(data->mallocSizeOf,
|
||||
&normal,
|
||||
&temporary,
|
||||
®expCode,
|
||||
&stackCommitted);
|
||||
|
||||
data->runtimeThreadsNormal += normal;
|
||||
data->runtimeThreadsTemporary += temporary;
|
||||
data->runtimeThreadsRegexpCode += regexpCode;
|
||||
data->runtimeThreadsStackCommitted += stackCommitted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS_DestroyContextNoGC(cx);
|
||||
|
||||
// This is initialized to all bytes stored in used chunks, and then we
|
||||
// subtract used space from it each time around the loop.
|
||||
data->gcHeapChunkDirtyUnused = data->gcHeapChunkTotal -
|
||||
data->gcHeapChunkCleanUnused -
|
||||
data->gcHeapChunkCleanDecommitted -
|
||||
data->gcHeapChunkDirtyDecommitted;
|
||||
|
||||
for (size_t index = 0;
|
||||
index < data->compartmentStatsVector.length();
|
||||
index++) {
|
||||
CompartmentStats &stats = data->compartmentStatsVector[index];
|
||||
|
||||
int64_t used = stats.gcHeapArenaHeaders +
|
||||
stats.gcHeapArenaPadding +
|
||||
stats.gcHeapArenaUnused +
|
||||
stats.gcHeapObjectsNonFunction +
|
||||
stats.gcHeapObjectsFunction +
|
||||
stats.gcHeapStrings +
|
||||
stats.gcHeapShapesTree +
|
||||
stats.gcHeapShapesDict +
|
||||
stats.gcHeapShapesBase +
|
||||
stats.gcHeapScripts +
|
||||
stats.gcHeapTypeObjects +
|
||||
stats.gcHeapXML;
|
||||
|
||||
data->gcHeapChunkDirtyUnused -= used;
|
||||
data->gcHeapArenaUnused += stats.gcHeapArenaUnused;
|
||||
data->totalObjects += stats.gcHeapObjectsNonFunction +
|
||||
stats.gcHeapObjectsFunction +
|
||||
stats.objectSlots;
|
||||
data->totalShapes += stats.gcHeapShapesTree +
|
||||
stats.gcHeapShapesDict +
|
||||
stats.gcHeapShapesBase +
|
||||
stats.shapesExtraTreeTables +
|
||||
stats.shapesExtraDictTables +
|
||||
stats.shapesCompartmentTables;
|
||||
data->totalScripts += stats.gcHeapScripts +
|
||||
stats.scriptData;
|
||||
data->totalStrings += stats.gcHeapStrings +
|
||||
stats.stringChars;
|
||||
#ifdef JS_METHODJIT
|
||||
data->totalMjit += stats.mjitCode +
|
||||
stats.mjitData;
|
||||
#endif
|
||||
data->totalTypeInference += stats.gcHeapTypeObjects +
|
||||
stats.typeInferenceMemory.objects +
|
||||
stats.typeInferenceMemory.scripts +
|
||||
stats.typeInferenceMemory.tables;
|
||||
data->totalAnalysisTemp += stats.typeInferenceMemory.temporary;
|
||||
}
|
||||
|
||||
size_t numDirtyChunks = (data->gcHeapChunkTotal -
|
||||
data->gcHeapChunkCleanUnused) /
|
||||
gc::ChunkSize;
|
||||
int64_t perChunkAdmin =
|
||||
sizeof(gc::Chunk) - (sizeof(gc::Arena) * gc::ArenasPerChunk);
|
||||
data->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin;
|
||||
data->gcHeapChunkDirtyUnused -= data->gcHeapChunkAdmin;
|
||||
|
||||
// Why 10000x? 100x because it's a percentage, and another 100x
|
||||
// because nsIMemoryReporter requires that for percentage amounts so
|
||||
// they can be fractional.
|
||||
data->gcHeapUnusedPercentage = (data->gcHeapChunkCleanUnused +
|
||||
data->gcHeapChunkDirtyUnused +
|
||||
data->gcHeapChunkCleanDecommitted +
|
||||
data->gcHeapChunkDirtyDecommitted +
|
||||
data->gcHeapArenaUnused) * 10000 /
|
||||
data->gcHeapChunkTotal;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
GetExplicitNonHeapForRuntime(JSRuntime *rt, int64_t *amount,
|
||||
JSMallocSizeOfFun mallocSizeOf)
|
||||
{
|
||||
JSContext *cx = JS_NewContext(rt, 0);
|
||||
if (!cx)
|
||||
return false;
|
||||
|
||||
// explicit/<compartment>/gc-heap/*
|
||||
*amount = int64_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
|
||||
gc::ChunkSize;
|
||||
|
||||
{
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
// explicit/<compartment>/mjit-code
|
||||
size_t n = 0;
|
||||
IterateCompartments(cx, &n, ExplicitNonHeapCompartmentCallback);
|
||||
*amount += n;
|
||||
|
||||
{
|
||||
#ifndef JS_THREADSAFE
|
||||
#error "This code assumes JS_THREADSAFE is defined"
|
||||
#endif
|
||||
|
||||
// Need the GC lock to call JS_ContextIteratorUnlocked() and to
|
||||
// access rt->threads.
|
||||
AutoLockGC lock(rt);
|
||||
|
||||
// explicit/runtime/threads/regexp-code
|
||||
// explicit/runtime/threads/stack-committed
|
||||
for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
|
||||
JSThread *thread = r.front().value;
|
||||
size_t regexpCode, stackCommitted;
|
||||
thread->sizeOfIncludingThis(mallocSizeOf,
|
||||
NULL,
|
||||
NULL,
|
||||
®expCode,
|
||||
&stackCommitted);
|
||||
|
||||
*amount += regexpCode;
|
||||
*amount += stackCommitted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS_DestroyContextNoGC(cx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace JS
|
|
@ -156,12 +156,6 @@ JSCompartment::sizeOfMjitCode() const
|
|||
return method + unused;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(size_t)
|
||||
JS::SizeOfCompartmentMjitCode(const JSCompartment *c)
|
||||
{
|
||||
return c->sizeOfMjitCode();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool
|
||||
|
|
|
@ -6599,12 +6599,6 @@ js::HandleNonGenericMethodClassMismatch(JSContext *cx, CallArgs args, Native nat
|
|||
return false;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(size_t)
|
||||
JS::SizeOfObjectDynamicSlots(JSObject *obj, JSMallocSizeOfFun mallocSizeOf)
|
||||
{
|
||||
return obj->dynamicSlotSize(mallocSizeOf);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
/*
|
||||
|
|
|
@ -1522,21 +1522,3 @@ JSCompartment::sweepInitialShapeTable(JSContext *cx)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::IsShapeInDictionary(const void *shape)
|
||||
{
|
||||
return static_cast<const Shape*>(shape)->inDictionary();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(size_t)
|
||||
JS::SizeOfShapePropertyTable(const void *shape, JSMallocSizeOfFun mallocSizeOf)
|
||||
{
|
||||
return static_cast<const Shape*>(shape)->sizeOfPropertyTable(mallocSizeOf);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(size_t)
|
||||
JS::SizeOfShapeKids(const void *shape, JSMallocSizeOfFun mallocSizeOf)
|
||||
{
|
||||
return static_cast<const Shape*>(shape)->sizeOfKids(mallocSizeOf);
|
||||
}
|
||||
|
|
|
@ -1314,12 +1314,6 @@ JSScript::dataSize(JSMallocSizeOfFun mallocSizeOf)
|
|||
return mallocSizeOf(data, dataSize());
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(size_t)
|
||||
JS::SizeOfScriptData(JSScript *script, JSMallocSizeOfFun mallocSizeOf)
|
||||
{
|
||||
return script->dataSize(mallocSizeOf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Nb: srcnotes are variable-length. This function computes the number of
|
||||
* srcnote *slots*, which may be greater than the number of srcnotes.
|
||||
|
|
|
@ -1297,12 +1297,6 @@ JSScript::jitDataSize(JSMallocSizeOfFun mallocSizeOf)
|
|||
return n;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(size_t)
|
||||
JS::SizeOfScriptJitData(JSScript *script, JSMallocSizeOfFun mallocSizeOf)
|
||||
{
|
||||
return script->jitDataSize(mallocSizeOf);
|
||||
}
|
||||
|
||||
/* Please keep in sync with Compiler::finishThisUp! */
|
||||
size_t
|
||||
mjit::JITScript::scriptDataSize(JSMallocSizeOfFun mallocSizeOf)
|
||||
|
|
|
@ -77,8 +77,6 @@
|
|||
JS_LOCK_GC, JS_UNLOCK_GC
|
||||
|
||||
js_NextActiveContext, js::TriggerOperationCallback
|
||||
JSString::charsHeapSize
|
||||
CollectCompartmentStatsForRuntime
|
||||
mWatchdogWakeup = JS_NEW_CONDVAR(mJSRuntime->gcLock);
|
||||
mJSRuntime->setActivityCallback(ActivityCallback, this);
|
||||
#endif
|
||||
|
@ -1254,7 +1252,9 @@ XPCJSRuntime::~XPCJSRuntime()
|
|||
XPCPerThreadData::ShutDown();
|
||||
}
|
||||
|
||||
static void*
|
||||
namespace xpc {
|
||||
|
||||
void*
|
||||
GetCompartmentName(JSContext *cx, JSCompartment *c)
|
||||
{
|
||||
nsCString* name = new nsCString();
|
||||
|
@ -1295,147 +1295,17 @@ GetCompartmentName(JSContext *cx, JSCompartment *c)
|
|||
return name;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
DestroyCompartmentName(void *string)
|
||||
{
|
||||
delete static_cast<nsCString*>(string);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsMallocSizeOf, "js")
|
||||
|
||||
void
|
||||
CompartmentMemoryCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
|
||||
{
|
||||
// Append a new CompartmentStats to the vector.
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
JS::CompartmentStats *curr =
|
||||
data->compartmentStatsVector.AppendElement();
|
||||
curr->init(GetCompartmentName(cx, compartment), DestroyCompartmentName);
|
||||
data->currCompartmentStats = curr;
|
||||
} // namespace xpc
|
||||
|
||||
// Get the compartment-level numbers.
|
||||
#ifdef JS_METHODJIT
|
||||
curr->mjitCode = JS::SizeOfCompartmentMjitCode(compartment);
|
||||
#endif
|
||||
JS::SizeOfCompartmentTypeInferenceData(cx, compartment,
|
||||
&curr->typeInferenceMemory,
|
||||
JsMallocSizeOf);
|
||||
curr->shapesCompartmentTables =
|
||||
JS::SizeOfCompartmentShapeTable(compartment, JsMallocSizeOf);
|
||||
}
|
||||
|
||||
void
|
||||
ExplicitNonHeapCompartmentCallback(JSContext *cx, void *data, JSCompartment *compartment)
|
||||
{
|
||||
size_t *n = static_cast<size_t *>(data);
|
||||
#ifdef JS_METHODJIT
|
||||
*n += JS::SizeOfCompartmentMjitCode(compartment);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ChunkCallback(JSContext *cx, void *vdata, js::gc::Chunk *chunk)
|
||||
{
|
||||
// Nb: This function is only called for dirty chunks, which is why we
|
||||
// increment gcHeapChunkDirtyDecommitted.
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
for (uint32_t i = 0; i < js::gc::ArenasPerChunk; i++)
|
||||
if (chunk->decommittedArenas.get(i))
|
||||
data->gcHeapChunkDirtyDecommitted += js::gc::ArenaSize;
|
||||
}
|
||||
|
||||
void
|
||||
ArenaCallback(JSContext *cx, void *vdata, js::gc::Arena *arena,
|
||||
JSGCTraceKind traceKind, size_t thingSize)
|
||||
{
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
|
||||
data->currCompartmentStats->gcHeapArenaHeaders +=
|
||||
sizeof(js::gc::ArenaHeader);
|
||||
size_t allocationSpace = arena->thingsSpan(thingSize);
|
||||
data->currCompartmentStats->gcHeapArenaPadding +=
|
||||
js::gc::ArenaSize - allocationSpace - sizeof(js::gc::ArenaHeader);
|
||||
// We don't call the callback on unused things. So we compute the
|
||||
// unused space like this: arenaUnused = maxArenaUnused - arenaUsed.
|
||||
// We do this by setting arenaUnused to maxArenaUnused here, and then
|
||||
// subtracting thingSize for every used cell, in CellCallback().
|
||||
data->currCompartmentStats->gcHeapArenaUnused += allocationSpace;
|
||||
}
|
||||
|
||||
void
|
||||
CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind,
|
||||
size_t thingSize)
|
||||
{
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
JS::CompartmentStats *curr = data->currCompartmentStats;
|
||||
switch (traceKind) {
|
||||
case JSTRACE_OBJECT:
|
||||
{
|
||||
JSObject *obj = static_cast<JSObject *>(thing);
|
||||
if (JS_ObjectIsFunction(cx, obj)) {
|
||||
curr->gcHeapObjectsFunction += thingSize;
|
||||
} else {
|
||||
curr->gcHeapObjectsNonFunction += thingSize;
|
||||
}
|
||||
curr->objectSlots += JS::SizeOfObjectDynamicSlots(obj, JsMallocSizeOf);
|
||||
break;
|
||||
}
|
||||
case JSTRACE_STRING:
|
||||
{
|
||||
JSString *str = static_cast<JSString *>(thing);
|
||||
curr->gcHeapStrings += thingSize;
|
||||
curr->stringChars += str->charsHeapSize(JsMallocSizeOf);
|
||||
break;
|
||||
}
|
||||
case JSTRACE_SHAPE:
|
||||
{
|
||||
if (JS::IsShapeInDictionary(thing)) {
|
||||
curr->gcHeapShapesDict += thingSize;
|
||||
curr->shapesExtraDictTables +=
|
||||
JS::SizeOfShapePropertyTable(thing, JsMallocSizeOf);
|
||||
} else {
|
||||
curr->gcHeapShapesTree += thingSize;
|
||||
curr->shapesExtraTreeTables +=
|
||||
JS::SizeOfShapePropertyTable(thing, JsMallocSizeOf);
|
||||
curr->shapesExtraTreeShapeKids +=
|
||||
JS::SizeOfShapeKids(thing, JsMallocSizeOf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSTRACE_BASE_SHAPE:
|
||||
{
|
||||
curr->gcHeapShapesBase += thingSize;
|
||||
break;
|
||||
}
|
||||
case JSTRACE_SCRIPT:
|
||||
{
|
||||
JSScript *script = static_cast<JSScript *>(thing);
|
||||
curr->gcHeapScripts += thingSize;
|
||||
curr->scriptData += JS::SizeOfScriptData(script, JsMallocSizeOf);
|
||||
#ifdef JS_METHODJIT
|
||||
curr->mjitData += JS::SizeOfScriptJitData(script, JsMallocSizeOf);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case JSTRACE_TYPE_OBJECT:
|
||||
{
|
||||
js::types::TypeObject *obj = static_cast<js::types::TypeObject *>(thing);
|
||||
curr->gcHeapTypeObjects += thingSize;
|
||||
JS::SizeOfObjectTypeInferenceData(obj, &curr->typeInferenceMemory,
|
||||
JsMallocSizeOf);
|
||||
break;
|
||||
}
|
||||
case JSTRACE_XML:
|
||||
{
|
||||
curr->gcHeapXML += thingSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Yes, this is a subtraction: see ArenaCallback() for details.
|
||||
curr->gcHeapArenaUnused -= thingSize;
|
||||
}
|
||||
namespace {
|
||||
|
||||
template <int N>
|
||||
inline void
|
||||
|
@ -1577,209 +1447,6 @@ namespace mozilla {
|
|||
namespace xpconnect {
|
||||
namespace memory {
|
||||
|
||||
JSBool
|
||||
CollectCompartmentStatsForRuntime(JSRuntime *rt, void *vdata)
|
||||
{
|
||||
IterateData *data = (IterateData *)vdata;
|
||||
JSContext *cx = JS_NewContext(rt, 0);
|
||||
if (!cx) {
|
||||
NS_ERROR("couldn't create context for memory tracing");
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
data->compartmentStatsVector.SetCapacity(rt->compartments.length());
|
||||
|
||||
data->gcHeapChunkCleanDecommitted =
|
||||
rt->gcChunkPool.countCleanDecommittedArenas(rt) *
|
||||
js::gc::ArenaSize;
|
||||
data->gcHeapChunkCleanUnused =
|
||||
PRInt64(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) *
|
||||
js::gc::ChunkSize -
|
||||
data->gcHeapChunkCleanDecommitted;
|
||||
data->gcHeapChunkTotal =
|
||||
PRInt64(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
|
||||
js::gc::ChunkSize;
|
||||
|
||||
js::IterateCompartmentsArenasCells(cx, data, CompartmentMemoryCallback,
|
||||
ArenaCallback, CellCallback);
|
||||
js::IterateChunks(cx, data, ChunkCallback);
|
||||
|
||||
data->runtimeObject = JsMallocSizeOf(rt, sizeof(JSRuntime));
|
||||
|
||||
// Nb: we use sizeOfExcludingThis() because atomState.atoms is within
|
||||
// JSRuntime, and so counted when JSRuntime is counted.
|
||||
data->runtimeAtomsTable =
|
||||
rt->atomState.atoms.sizeOfExcludingThis(JsMallocSizeOf);
|
||||
|
||||
{
|
||||
#ifndef JS_THREADSAFE
|
||||
#error "This code assumes JS_THREADSAFE is defined"
|
||||
#endif
|
||||
|
||||
// Need the GC lock to call JS_ContextIteratorUnlocked() and to
|
||||
// access rt->threads.
|
||||
js::AutoLockGC lock(rt);
|
||||
|
||||
JSContext *acx, *iter = NULL;
|
||||
while ((acx = JS_ContextIteratorUnlocked(rt, &iter)) != NULL) {
|
||||
data->runtimeContexts +=
|
||||
acx->sizeOfIncludingThis(JsMallocSizeOf);
|
||||
}
|
||||
|
||||
for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
|
||||
JSThread *thread = r.front().value;
|
||||
size_t normal, temporary, regexpCode, stackCommitted;
|
||||
thread->sizeOfIncludingThis(JsMallocSizeOf,
|
||||
&normal,
|
||||
&temporary,
|
||||
®expCode,
|
||||
&stackCommitted);
|
||||
|
||||
data->runtimeThreadsNormal += normal;
|
||||
data->runtimeThreadsTemporary += temporary;
|
||||
data->runtimeThreadsRegexpCode += regexpCode;
|
||||
data->runtimeThreadsStackCommitted += stackCommitted;
|
||||
}
|
||||
}
|
||||
|
||||
XPCJSRuntime *xpcrt = nsXPConnect::GetRuntimeInstance();
|
||||
data->xpconnect +=
|
||||
xpcrt->SizeOfIncludingThis(JsMallocSizeOf);
|
||||
data->xpconnect +=
|
||||
XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(JsMallocSizeOf);
|
||||
}
|
||||
|
||||
JS_DestroyContextNoGC(cx);
|
||||
|
||||
// This is initialized to all bytes stored in used chunks, and then we
|
||||
// subtract used space from it each time around the loop.
|
||||
data->gcHeapChunkDirtyUnused = data->gcHeapChunkTotal -
|
||||
data->gcHeapChunkCleanUnused -
|
||||
data->gcHeapChunkCleanDecommitted -
|
||||
data->gcHeapChunkDirtyDecommitted;
|
||||
|
||||
for (PRUint32 index = 0;
|
||||
index < data->compartmentStatsVector.Length();
|
||||
index++) {
|
||||
JS::CompartmentStats &stats = data->compartmentStatsVector[index];
|
||||
|
||||
PRInt64 used = stats.gcHeapArenaHeaders +
|
||||
stats.gcHeapArenaPadding +
|
||||
stats.gcHeapArenaUnused +
|
||||
stats.gcHeapObjectsNonFunction +
|
||||
stats.gcHeapObjectsFunction +
|
||||
stats.gcHeapStrings +
|
||||
stats.gcHeapShapesTree +
|
||||
stats.gcHeapShapesDict +
|
||||
stats.gcHeapShapesBase +
|
||||
stats.gcHeapScripts +
|
||||
stats.gcHeapTypeObjects +
|
||||
stats.gcHeapXML;
|
||||
|
||||
data->gcHeapChunkDirtyUnused -= used;
|
||||
data->gcHeapArenaUnused += stats.gcHeapArenaUnused;
|
||||
data->totalObjects += stats.gcHeapObjectsNonFunction +
|
||||
stats.gcHeapObjectsFunction +
|
||||
stats.objectSlots;
|
||||
data->totalShapes += stats.gcHeapShapesTree +
|
||||
stats.gcHeapShapesDict +
|
||||
stats.gcHeapShapesBase +
|
||||
stats.shapesExtraTreeTables +
|
||||
stats.shapesExtraDictTables +
|
||||
stats.shapesCompartmentTables;
|
||||
data->totalScripts += stats.gcHeapScripts +
|
||||
stats.scriptData;
|
||||
data->totalStrings += stats.gcHeapStrings +
|
||||
stats.stringChars;
|
||||
#ifdef JS_METHODJIT
|
||||
data->totalMjit += stats.mjitCode +
|
||||
stats.mjitData;
|
||||
#endif
|
||||
data->totalTypeInference += stats.gcHeapTypeObjects +
|
||||
stats.typeInferenceMemory.objects +
|
||||
stats.typeInferenceMemory.scripts +
|
||||
stats.typeInferenceMemory.tables;
|
||||
data->totalAnalysisTemp += stats.typeInferenceMemory.temporary;
|
||||
}
|
||||
|
||||
size_t numDirtyChunks = (data->gcHeapChunkTotal -
|
||||
data->gcHeapChunkCleanUnused) /
|
||||
js::gc::ChunkSize;
|
||||
PRInt64 perChunkAdmin =
|
||||
sizeof(js::gc::Chunk) - (sizeof(js::gc::Arena) * js::gc::ArenasPerChunk);
|
||||
data->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin;
|
||||
data->gcHeapChunkDirtyUnused -= data->gcHeapChunkAdmin;
|
||||
|
||||
// Why 10000x? 100x because it's a percentage, and another 100x
|
||||
// because nsIMemoryReporter requires that for percentage amounts so
|
||||
// they can be fractional.
|
||||
data->gcHeapUnusedPercentage = (data->gcHeapChunkCleanUnused +
|
||||
data->gcHeapChunkDirtyUnused +
|
||||
data->gcHeapChunkCleanDecommitted +
|
||||
data->gcHeapChunkDirtyDecommitted +
|
||||
data->gcHeapArenaUnused) * 10000 /
|
||||
data->gcHeapChunkTotal;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
GetExplicitNonHeapForRuntime(JSRuntime *rt, void *data)
|
||||
{
|
||||
PRInt64 *amount = (PRInt64 *)data;
|
||||
|
||||
JSContext *cx = JS_NewContext(rt, 0);
|
||||
if (!cx) {
|
||||
NS_ERROR("couldn't create context for memory tracing");
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
// explicit/<compartment>/gc-heap/*
|
||||
*amount = PRInt64(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
|
||||
js::gc::ChunkSize;
|
||||
|
||||
{
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
// explicit/<compartment>/mjit-code
|
||||
size_t n = 0;
|
||||
js::IterateCompartments(cx, &n, ExplicitNonHeapCompartmentCallback);
|
||||
*amount += n;
|
||||
|
||||
{
|
||||
#ifndef JS_THREADSAFE
|
||||
#error "This code assumes JS_THREADSAFE is defined"
|
||||
#endif
|
||||
|
||||
// Need the GC lock to call JS_ContextIteratorUnlocked() and to
|
||||
// access rt->threads.
|
||||
js::AutoLockGC lock(rt);
|
||||
|
||||
// explicit/runtime/threads/regexp-code
|
||||
// explicit/runtime/threads/stack-committed
|
||||
for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
|
||||
JSThread *thread = r.front().value;
|
||||
size_t regexpCode, stackCommitted;
|
||||
thread->sizeOfIncludingThis(JsMallocSizeOf,
|
||||
NULL,
|
||||
NULL,
|
||||
®expCode,
|
||||
&stackCommitted);
|
||||
|
||||
*amount += regexpCode;
|
||||
*amount += stackCommitted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS_DestroyContextNoGC(cx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define SLOP_BYTES_STRING \
|
||||
" The measurement includes slop bytes caused by the heap allocator rounding up request sizes."
|
||||
|
||||
|
@ -1985,13 +1652,13 @@ ReportCompartmentStats(const JS::CompartmentStats &stats,
|
|||
}
|
||||
|
||||
void
|
||||
ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix,
|
||||
ReportJSRuntimeStats(const JS::IterateData &data, const nsACString &pathPrefix,
|
||||
nsIMemoryMultiReporterCallback *callback,
|
||||
nsISupports *closure)
|
||||
{
|
||||
PRInt64 gcTotal = 0;
|
||||
for (PRUint32 index = 0;
|
||||
index < data.compartmentStatsVector.Length();
|
||||
for (size_t index = 0;
|
||||
index < data.compartmentStatsVector.length();
|
||||
index++) {
|
||||
gcTotal += ReportCompartmentStats(data.compartmentStatsVector[index], pathPrefix,
|
||||
callback, closure);
|
||||
|
@ -2039,11 +1706,6 @@ ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix,
|
|||
"hardly cost anything.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("xpconnect"),
|
||||
nsIMemoryReporter::KIND_HEAP, data.xpconnect,
|
||||
"Memory used by XPConnect." SLOP_BYTES_STRING,
|
||||
callback, closure);
|
||||
|
||||
ReportGCHeapBytes(pathPrefix +
|
||||
NS_LITERAL_CSTRING("gc-heap-chunk-dirty-unused"),
|
||||
&gcTotal, data.gcHeapChunkDirtyUnused,
|
||||
|
@ -2094,22 +1756,35 @@ public:
|
|||
NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *callback,
|
||||
nsISupports *closure)
|
||||
{
|
||||
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
|
||||
XPCJSRuntime *xpcrt = nsXPConnect::GetRuntimeInstance();
|
||||
|
||||
// In the first step we get all the stats and stash them in a local
|
||||
// data structure. In the second step we pass all the stashed stats to
|
||||
// the callback. Separating these steps is important because the
|
||||
// callback may be a JS function, and executing JS while getting these
|
||||
// stats seems like a bad idea.
|
||||
IterateData data;
|
||||
if (!CollectCompartmentStatsForRuntime(rt, &data))
|
||||
JS::IterateData data(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
|
||||
xpc::DestroyCompartmentName);
|
||||
if (!JS::CollectCompartmentStatsForRuntime(xpcrt->GetJSRuntime(), &data))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
uint64_t xpconnect;
|
||||
{
|
||||
xpconnect =
|
||||
xpcrt->SizeOfIncludingThis(xpc::JsMallocSizeOf) +
|
||||
XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(xpc::JsMallocSizeOf);
|
||||
}
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(pathPrefix, "explicit/js/");
|
||||
|
||||
// This is the second step (see above).
|
||||
ReportJSRuntimeStats(data, pathPrefix, callback, closure);
|
||||
|
||||
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("xpconnect"),
|
||||
nsIMemoryReporter::KIND_HEAP, xpconnect,
|
||||
"Memory used by XPConnect." SLOP_BYTES_STRING,
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-chunk-dirty-unused"),
|
||||
nsIMemoryReporter::KIND_OTHER,
|
||||
data.gcHeapChunkDirtyUnused,
|
||||
|
@ -2203,7 +1878,7 @@ public:
|
|||
{
|
||||
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
|
||||
|
||||
if (!GetExplicitNonHeapForRuntime(rt, n))
|
||||
if (!JS::GetExplicitNonHeapForRuntime(rt, n, xpc::JsMallocSizeOf))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -207,6 +207,10 @@ bool Base64Decode(JSContext *cx, JS::Value val, JS::Value *out);
|
|||
*/
|
||||
bool StringToJsval(JSContext *cx, nsString &str, JS::Value *rval);
|
||||
|
||||
void *GetCompartmentName(JSContext *cx, JSCompartment *c);
|
||||
void DestroyCompartmentName(void *string);
|
||||
size_t JsMallocSizeOf(const void *ptr, size_t computedSize);
|
||||
|
||||
} // namespace xpc
|
||||
|
||||
class nsIMemoryMultiReporterCallback;
|
||||
|
@ -215,74 +219,8 @@ namespace mozilla {
|
|||
namespace xpconnect {
|
||||
namespace memory {
|
||||
|
||||
struct IterateData
|
||||
{
|
||||
IterateData()
|
||||
: runtimeObject(0),
|
||||
runtimeAtomsTable(0),
|
||||
runtimeContexts(0),
|
||||
runtimeThreadsNormal(0),
|
||||
runtimeThreadsTemporary(0),
|
||||
runtimeThreadsRegexpCode(0),
|
||||
runtimeThreadsStackCommitted(0),
|
||||
xpconnect(0),
|
||||
gcHeapChunkTotal(0),
|
||||
gcHeapChunkCleanUnused(0),
|
||||
gcHeapChunkDirtyUnused(0),
|
||||
gcHeapChunkCleanDecommitted(0),
|
||||
gcHeapChunkDirtyDecommitted(0),
|
||||
gcHeapArenaUnused(0),
|
||||
gcHeapChunkAdmin(0),
|
||||
gcHeapUnusedPercentage(0),
|
||||
totalObjects(0),
|
||||
totalShapes(0),
|
||||
totalScripts(0),
|
||||
totalStrings(0),
|
||||
#ifdef JS_METHODJIT
|
||||
totalMjit(0),
|
||||
#endif
|
||||
totalTypeInference(0),
|
||||
totalAnalysisTemp(0),
|
||||
compartmentStatsVector(),
|
||||
currCompartmentStats(NULL) { }
|
||||
|
||||
PRInt64 runtimeObject;
|
||||
PRInt64 runtimeAtomsTable;
|
||||
PRInt64 runtimeContexts;
|
||||
PRInt64 runtimeThreadsNormal;
|
||||
PRInt64 runtimeThreadsTemporary;
|
||||
PRInt64 runtimeThreadsRegexpCode;
|
||||
PRInt64 runtimeThreadsStackCommitted;
|
||||
PRInt64 xpconnect;
|
||||
PRInt64 gcHeapChunkTotal;
|
||||
PRInt64 gcHeapChunkCleanUnused;
|
||||
PRInt64 gcHeapChunkDirtyUnused;
|
||||
PRInt64 gcHeapChunkCleanDecommitted;
|
||||
PRInt64 gcHeapChunkDirtyDecommitted;
|
||||
PRInt64 gcHeapArenaUnused;
|
||||
PRInt64 gcHeapChunkAdmin;
|
||||
PRInt64 gcHeapUnusedPercentage;
|
||||
PRInt64 totalObjects;
|
||||
PRInt64 totalShapes;
|
||||
PRInt64 totalScripts;
|
||||
PRInt64 totalStrings;
|
||||
#ifdef JS_METHODJIT
|
||||
PRInt64 totalMjit;
|
||||
#endif
|
||||
PRInt64 totalTypeInference;
|
||||
PRInt64 totalAnalysisTemp;
|
||||
|
||||
nsTArray<JS::CompartmentStats> compartmentStatsVector;
|
||||
JS::CompartmentStats *currCompartmentStats;
|
||||
};
|
||||
|
||||
JSBool
|
||||
CollectCompartmentStatsForRuntime(JSRuntime *rt, void *data);
|
||||
JSBool
|
||||
GetExplicitNonHeapForRuntime(JSRuntime *rt, void *data);
|
||||
|
||||
void
|
||||
ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix,
|
||||
ReportJSRuntimeStats(const JS::IterateData &data, const nsACString &pathPrefix,
|
||||
nsIMemoryMultiReporterCallback *callback,
|
||||
nsISupports *closure);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче