Bug 1206596: Change js::SavedStacks to use mozilla::FastBernoulliTrial. r=fitzgen

This commit is contained in:
Jim Blandy 2015-09-17 16:29:39 -07:00
parent d174296950
commit 5fd3a28376
4 changed files with 20 additions and 44 deletions

View File

@ -868,7 +868,7 @@ SetSavedStacksRNGState(JSContext* cx, unsigned argc, Value* vp)
if (!ToInt32(cx, args[0], &seed))
return false;
cx->compartment()->savedStacks().setRNGState((seed ^ RNG_MULTIPLIER) & RNG_MASK);
cx->compartment()->savedStacks().setRNGState(seed, seed * 33);
return true;
}

View File

@ -32,5 +32,5 @@ dbg.memory.trackingAllocationSites = true;
// probability is fine.
measure(0.0, 0);
measure(1.0, 100);
measure(0.1, 9);
measure(0.5, 51);
measure(0.1, 7);
measure(0.5, 44);

View File

@ -6,6 +6,7 @@
#include "vm/SavedStacks.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Move.h"
@ -904,6 +905,10 @@ SavedFrame::toStringMethod(JSContext* cx, unsigned argc, Value* vp)
bool
SavedStacks::init()
{
uint64_t seed[2];
random_generateSeed(seed, mozilla::ArrayLength(seed));
bernoulli.setRandomState(seed[0], seed[1]);
if (!pcLocationMap.init())
return false;
@ -1339,7 +1344,7 @@ SavedStacks::chooseSamplingProbability(JSCompartment* compartment)
mozilla::DebugOnly<Debugger**> begin = dbgs->begin();
mozilla::DebugOnly<bool> foundAnyDebuggers = false;
allocationSamplingProbability = 0;
double probability = 0;
for (Debugger** dbgp = dbgs->begin(); dbgp < dbgs->end(); dbgp++) {
// The set of debuggers had better not change while we're iterating,
// such that the vector gets reallocated.
@ -1347,11 +1352,13 @@ SavedStacks::chooseSamplingProbability(JSCompartment* compartment)
if ((*dbgp)->trackingAllocationSites && (*dbgp)->enabled) {
foundAnyDebuggers = true;
allocationSamplingProbability = std::max((*dbgp)->allocationSamplingProbability,
allocationSamplingProbability);
probability = std::max((*dbgp)->allocationSamplingProbability,
probability);
}
}
MOZ_ASSERT(foundAnyDebuggers);
bernoulli.setProbability(probability);
}
JSObject*
@ -1360,38 +1367,8 @@ SavedStacksMetadataCallback(JSContext* cx, JSObject* target)
RootedObject obj(cx, target);
SavedStacks& stacks = cx->compartment()->savedStacks();
if (stacks.allocationSkipCount > 0) {
stacks.allocationSkipCount--;
if (!stacks.bernoulli.trial())
return nullptr;
}
if (stacks.allocationSamplingProbability == 0.0)
return nullptr;
// If the sampling probability is set to 1.0, we are always taking a sample
// and can therefore leave allocationSkipCount at 0.
if (stacks.allocationSamplingProbability != 1.0) {
// Rather than generating a random number on every allocation to decide
// if we want to sample that particular allocation (which would be
// expensive), we calculate the number of allocations to skip before
// taking the next sample.
//
// P = the probability we sample any given event.
//
// ~P = 1-P, the probability we don't sample a given event.
//
// (~P)^n = the probability that we skip at least the next n events.
//
// let X = random between 0 and 1.
//
// floor(log base ~P of X) = n, aka the number of events we should skip
// until we take the next sample. Any value for X less than (~P)^n
// yields a skip count greater than n, so the likelihood of a skip count
// greater than n is (~P)^n, as required.
double notSamplingProb = 1.0 - stacks.allocationSamplingProbability;
stacks.allocationSkipCount = std::floor(std::log(random_nextDouble(&stacks.rngState)) /
std::log(notSamplingProb));
}
AutoEnterOOMUnsafeRegion oomUnsafe;
RootedSavedFrame frame(cx);

View File

@ -7,6 +7,8 @@
#ifndef vm_SavedStacks_h
#define vm_SavedStacks_h
#include "mozilla/FastBernoulliTrial.h"
#include "jscntxt.h"
#include "jsmath.h"
#include "jswrapper.h"
@ -151,12 +153,11 @@ class SavedStacks {
JS::ubi::StackFrame& ubiFrame,
MutableHandleObject outSavedFrameStack);
public:
SavedStacks()
: frames(),
allocationSamplingProbability(1.0),
allocationSkipCount(0),
rngState(0),
bernoulli(1.0, 0x59fdad7f6b4cc573, 0x91adf38db96a9354),
creatingSavedFrame(false)
{ }
@ -167,16 +168,14 @@ class SavedStacks {
void trace(JSTracer* trc);
uint32_t count();
void clear();
void setRNGState(uint64_t state) { rngState = state; }
void setRNGState(uint64_t state0, uint64_t state1) { bernoulli.setRandomState(state0, state1); }
void chooseSamplingProbability(JSCompartment*);
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
private:
SavedFrame::Set frames;
double allocationSamplingProbability;
uint32_t allocationSkipCount;
uint64_t rngState;
mozilla::FastBernoulliTrial bernoulli;
bool creatingSavedFrame;
// Similar to mozilla::ReentrancyGuard, but instead of asserting against