зеркало из https://github.com/mozilla/gecko-dev.git
Bug 850523 (part 1) - Add a "js-main-runtime-temporary-peak" memory reporter. r=wmccloskey,jlebar.
--HG-- extra : rebase_source : d183213c48b9d07fb62fce830998bcb8bb044f47
This commit is contained in:
Родитель
f42ce30aaa
Коммит
b381a3dc72
|
@ -429,6 +429,9 @@ SystemCompartmentCount(JSRuntime *rt);
|
|||
extern JS_PUBLIC_API(size_t)
|
||||
UserCompartmentCount(JSRuntime *rt);
|
||||
|
||||
extern JS_PUBLIC_API(size_t)
|
||||
PeakSizeOfTemporary(const JSRuntime *rt);
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#endif // js_MemoryMetrics_h
|
||||
|
|
|
@ -60,9 +60,16 @@ LifoAlloc::freeAll()
|
|||
while (first) {
|
||||
BumpChunk *victim = first;
|
||||
first = first->next();
|
||||
decrementCurSize(victim->computedSizeOfIncludingThis());
|
||||
BumpChunk::delete_(victim);
|
||||
}
|
||||
first = latest = last = NULL;
|
||||
|
||||
/*
|
||||
* Nb: maintaining curSize_ correctly isn't easy. Fortunately, this is an
|
||||
* excellent sanity check.
|
||||
*/
|
||||
JS_ASSERT(curSize_ == 0);
|
||||
}
|
||||
|
||||
LifoAlloc::BumpChunk *
|
||||
|
@ -105,6 +112,11 @@ LifoAlloc::getOrCreateChunk(size_t n)
|
|||
latest->setNext(newChunk);
|
||||
latest = last = newChunk;
|
||||
}
|
||||
|
||||
size_t computedChunkSize = newChunk->computedSizeOfIncludingThis();
|
||||
JS_ASSERT(computedChunkSize == chunkSize);
|
||||
incrementCurSize(computedChunkSize);
|
||||
|
||||
return newChunk;
|
||||
}
|
||||
|
||||
|
@ -118,8 +130,10 @@ LifoAlloc::transferFrom(LifoAlloc *other)
|
|||
if (!other->first)
|
||||
return;
|
||||
|
||||
incrementCurSize(other->curSize_);
|
||||
append(other->first, other->last);
|
||||
other->first = other->last = other->latest = NULL;
|
||||
other->curSize_ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -131,14 +145,22 @@ LifoAlloc::transferUnusedFrom(LifoAlloc *other)
|
|||
if (other->markCount || !other->first)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Because of how getOrCreateChunk works, there may be unused chunks before
|
||||
* |last|. We do not transfer those chunks. In most cases it is expected
|
||||
* that last == first, so this should be a rare situation that, when it
|
||||
* happens, should not recur.
|
||||
*/
|
||||
// Transfer all chunks *after* |latest|.
|
||||
|
||||
if (other->latest->next()) {
|
||||
if (other->latest == other->first) {
|
||||
// We're transferring everything except the first chunk.
|
||||
size_t delta = other->curSize_ - other->first->computedSizeOfIncludingThis();
|
||||
other->decrementCurSize(delta);
|
||||
incrementCurSize(delta);
|
||||
} else {
|
||||
for (BumpChunk *chunk = other->latest->next(); chunk; chunk = chunk->next()) {
|
||||
size_t size = chunk->computedSizeOfIncludingThis();
|
||||
incrementCurSize(size);
|
||||
other->decrementCurSize(size);
|
||||
}
|
||||
}
|
||||
|
||||
append(other->latest->next(), other->last);
|
||||
other->latest->setNext(NULL);
|
||||
other->last = other->latest;
|
||||
|
|
|
@ -94,10 +94,15 @@ class BumpChunk
|
|||
void setNext(BumpChunk *succ) { next_ = succ; }
|
||||
|
||||
size_t used() const { return bump - bumpBase(); }
|
||||
|
||||
size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) {
|
||||
return mallocSizeOf(this);
|
||||
}
|
||||
|
||||
size_t computedSizeOfIncludingThis() {
|
||||
return limit - headerBase();
|
||||
}
|
||||
|
||||
void resetBump() {
|
||||
setBump(headerBase() + sizeof(BumpChunk));
|
||||
}
|
||||
|
@ -165,11 +170,13 @@ class LifoAlloc
|
|||
BumpChunk *last;
|
||||
size_t markCount;
|
||||
size_t defaultChunkSize_;
|
||||
size_t curSize_;
|
||||
size_t peakSize_;
|
||||
|
||||
void operator=(const LifoAlloc &) MOZ_DELETE;
|
||||
LifoAlloc(const LifoAlloc &) MOZ_DELETE;
|
||||
|
||||
/*
|
||||
/*
|
||||
* Return a BumpChunk that can perform an allocation of at least size |n|
|
||||
* and add it to the chain appropriately.
|
||||
*
|
||||
|
@ -183,6 +190,7 @@ class LifoAlloc
|
|||
first = latest = last = NULL;
|
||||
defaultChunkSize_ = defaultChunkSize;
|
||||
markCount = 0;
|
||||
curSize_ = 0;
|
||||
}
|
||||
|
||||
void append(BumpChunk *start, BumpChunk *end) {
|
||||
|
@ -194,17 +202,39 @@ class LifoAlloc
|
|||
last = end;
|
||||
}
|
||||
|
||||
void incrementCurSize(size_t size) {
|
||||
curSize_ += size;
|
||||
if (curSize_ > peakSize_)
|
||||
peakSize_ = curSize_;
|
||||
}
|
||||
void decrementCurSize(size_t size) {
|
||||
MOZ_ASSERT(curSize_ >= size);
|
||||
curSize_ -= size;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit LifoAlloc(size_t defaultChunkSize) { reset(defaultChunkSize); }
|
||||
explicit LifoAlloc(size_t defaultChunkSize)
|
||||
: peakSize_(0)
|
||||
{
|
||||
reset(defaultChunkSize);
|
||||
}
|
||||
|
||||
/* Steal allocated chunks from |other|. */
|
||||
void steal(LifoAlloc *other) {
|
||||
JS_ASSERT(!other->markCount);
|
||||
|
||||
/*
|
||||
* Copy everything from |other| to |this| except for |peakSize_|, which
|
||||
* requires some care.
|
||||
*/
|
||||
size_t oldPeakSize = peakSize_;
|
||||
PodCopy((char *) this, (char *) other, sizeof(*this));
|
||||
peakSize_ = Max(oldPeakSize, curSize_);
|
||||
|
||||
other->reset(defaultChunkSize_);
|
||||
}
|
||||
|
||||
/* Append allocated chunks from |other|. They are removed from |other|. */
|
||||
/* Append all chunks from |other|. They are removed from |other|. */
|
||||
void transferFrom(LifoAlloc *other);
|
||||
|
||||
/* Append unused chunks from |other|. They are removed from |other|. */
|
||||
|
@ -249,12 +279,10 @@ class LifoAlloc
|
|||
JS_ALWAYS_INLINE
|
||||
bool ensureUnusedApproximate(size_t n) {
|
||||
size_t total = 0;
|
||||
BumpChunk *chunk = latest;
|
||||
while (chunk) {
|
||||
for (BumpChunk *chunk = latest; chunk; chunk = chunk->next()) {
|
||||
total += chunk->unused();
|
||||
if (total >= n)
|
||||
return true;
|
||||
chunk = chunk->next();
|
||||
}
|
||||
BumpChunk *latestBefore = latest;
|
||||
if (!getOrCreateChunk(n))
|
||||
|
@ -298,18 +326,15 @@ class LifoAlloc
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Find the chunk that contains |mark|, and make sure we don't pass
|
||||
* |latest| along the way -- we should be making the chain of active
|
||||
* chunks shorter, not longer!
|
||||
*/
|
||||
BumpChunk *container = first;
|
||||
while (true) {
|
||||
if (container->contains(mark))
|
||||
break;
|
||||
BumpChunk *container;
|
||||
for (container = first; !container->contains(mark); container = container->next())
|
||||
JS_ASSERT(container != latest);
|
||||
container = container->next();
|
||||
}
|
||||
|
||||
latest = container;
|
||||
latest->release(mark);
|
||||
}
|
||||
|
@ -324,25 +349,23 @@ class LifoAlloc
|
|||
/* Get the total "used" (occupied bytes) count for the arena chunks. */
|
||||
size_t used() const {
|
||||
size_t accum = 0;
|
||||
BumpChunk *it = first;
|
||||
while (it) {
|
||||
accum += it->used();
|
||||
if (it == latest)
|
||||
for (BumpChunk *chunk = first; chunk; chunk = chunk->next()) {
|
||||
accum += chunk->used();
|
||||
if (chunk == latest)
|
||||
break;
|
||||
it = it->next();
|
||||
}
|
||||
return accum;
|
||||
}
|
||||
|
||||
/* Get the total size of the arena chunks (including unused space). */
|
||||
size_t sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const {
|
||||
size_t accum = 0;
|
||||
BumpChunk *it = first;
|
||||
while (it) {
|
||||
accum += it->sizeOfIncludingThis(mallocSizeOf);
|
||||
it = it->next();
|
||||
}
|
||||
return accum;
|
||||
size_t n = 0;
|
||||
for (BumpChunk *chunk = first; chunk; chunk = chunk->next())
|
||||
n += chunk->sizeOfIncludingThis(mallocSizeOf);
|
||||
|
||||
/* While we're here, let's sanity check curSize_. */
|
||||
MOZ_ASSERT(curSize_ == n);
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Like sizeOfExcludingThis(), but includes the size of the LifoAlloc itself. */
|
||||
|
@ -350,6 +373,12 @@ class LifoAlloc
|
|||
return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the peak size of the arena chunks (including unused space and
|
||||
* bookkeeping space).
|
||||
*/
|
||||
size_t peakSizeOfExcludingThis() const { return peakSize_; }
|
||||
|
||||
/* Doesn't perform construction; useful for lazily-initialized POD types. */
|
||||
template <typename T>
|
||||
JS_ALWAYS_INLINE
|
||||
|
|
|
@ -392,3 +392,10 @@ JS::UserCompartmentCount(JSRuntime *rt)
|
|||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(size_t)
|
||||
JS::PeakSizeOfTemporary(const JSRuntime *rt)
|
||||
{
|
||||
return rt->tempLifoAlloc.peakSizeOfExcludingThis();
|
||||
}
|
||||
|
||||
|
|
|
@ -1412,6 +1412,7 @@ NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSGCHeap,
|
|||
nsIMemoryReporter::UNITS_BYTES,
|
||||
GetGCChunkTotalBytes,
|
||||
"Memory used by the garbage-collected JavaScript heap.")
|
||||
|
||||
static int64_t
|
||||
GetJSSystemCompartmentCount()
|
||||
{
|
||||
|
@ -1451,6 +1452,22 @@ NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSUserCompartmentCount,
|
|||
"listed under 'js' if a garbage collection occurs at an inopportune time, "
|
||||
"but such cases should be rare.")
|
||||
|
||||
static int64_t
|
||||
GetJSMainRuntimeTemporaryPeakSize()
|
||||
{
|
||||
return JS::PeakSizeOfTemporary(nsXPConnect::GetRuntimeInstance()->GetJSRuntime());
|
||||
}
|
||||
|
||||
// This is also a single reporter so it can be used by telemetry.
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(JSMainRuntimeTemporaryPeak,
|
||||
"js-main-runtime-temporary-peak",
|
||||
KIND_OTHER,
|
||||
nsIMemoryReporter::UNITS_BYTES,
|
||||
GetJSMainRuntimeTemporaryPeakSize,
|
||||
"The peak size of the transient storage in the main JSRuntime (the "
|
||||
"current size of which is reported as "
|
||||
"'explicit/js-non-window/runtime/temporary').");
|
||||
|
||||
// The REPORT* macros do an unconditional report. The ZCREPORT* macros are for
|
||||
// compartments and zones; they aggregate any entries smaller than
|
||||
// SUNDRIES_THRESHOLD into "gc-heap/sundries" and "other-sundries" entries for
|
||||
|
@ -2666,6 +2683,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
|
|||
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSGCHeap));
|
||||
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSSystemCompartmentCount));
|
||||
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSUserCompartmentCount));
|
||||
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(JSMainRuntimeTemporaryPeak));
|
||||
NS_RegisterMemoryMultiReporter(new JSCompartmentsMultiReporter);
|
||||
|
||||
mJSHolders.Init(512);
|
||||
|
|
|
@ -210,6 +210,14 @@
|
|||
"extended_statistics_ok": true,
|
||||
"description": "Total JavaScript compartments used for web pages"
|
||||
},
|
||||
"MEMORY_JS_MAIN_RUNTIME_TEMPORARY_PEAK": {
|
||||
"kind": "exponential",
|
||||
"low": 1024,
|
||||
"high": "16 * 1024 * 1024",
|
||||
"n_buckets": 200,
|
||||
"extended_statistics_ok": true,
|
||||
"description": "Peak memory used by the main JSRuntime to store transient data (KB)"
|
||||
},
|
||||
"MEMORY_JS_GC_HEAP": {
|
||||
"kind": "exponential",
|
||||
"low": 1024,
|
||||
|
|
|
@ -59,6 +59,7 @@ const MEM_HISTOGRAMS = {
|
|||
"js-gc-heap": "MEMORY_JS_GC_HEAP",
|
||||
"js-compartments/system": "MEMORY_JS_COMPARTMENTS_SYSTEM",
|
||||
"js-compartments/user": "MEMORY_JS_COMPARTMENTS_USER",
|
||||
"js-main-runtime-temporary-peak": "MEMORY_JS_MAIN_RUNTIME_TEMPORARY_PEAK",
|
||||
"explicit": "MEMORY_EXPLICIT",
|
||||
"resident-fast": "MEMORY_RESIDENT",
|
||||
"vsize": "MEMORY_VSIZE",
|
||||
|
|
Загрузка…
Ссылка в новой задаче