From: Giovanni Bajo Date: Sun, 24 Sep 2017 16:13:26 +0000 (+0200) Subject: runtime: improve comments for nextSample X-Git-Tag: go1.10beta1~975 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=8e11cb3f3b5e383023736172bcbfd847ea529176;p=gostls13.git runtime: improve comments for nextSample The previous comment of nextSample didn't mention Poisson processes, which is the reason why it needed to create an exponential distribution, so it was hard to follow the reasoning for people not highly familiar with statistics. Since we're at it, we also make it clear that we are just creating a random number with exponential distribution by moving the bulk of the function into a new fastexprand(). No functional changes. Change-Id: I9c275e87edb3418ee0974257af64c73465028ad7 Reviewed-on: https://go-review.googlesource.com/65657 Reviewed-by: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot --- diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index d68ebcc5d2..9965ea19a2 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -865,11 +865,13 @@ func profilealloc(mp *m, x unsafe.Pointer, size uintptr) { mProf_Malloc(x, size) } -// nextSample returns the next sampling point for heap profiling. -// It produces a random variable with a geometric distribution and -// mean MemProfileRate. This is done by generating a uniformly -// distributed random number and applying the cumulative distribution -// function for an exponential. +// nextSample returns the next sampling point for heap profiling. The goal is +// to sample allocations on average every MemProfileRate bytes, but with a +// completely random distribution over the allocation timeline; this +// corresponds to a Poisson process with parameter MemProfileRate. In Poisson +// processes, the distance between two samples follows the exponential +// distribution (exp(MemProfileRate)), so the best return value is a random +// number taken from an exponential distribution whose mean is MemProfileRate. func nextSample() int32 { if GOOS == "plan9" { // Plan 9 doesn't support floating point in note handler. @@ -878,25 +880,29 @@ func nextSample() int32 { } } - period := MemProfileRate + return fastexprand(MemProfileRate) +} - // make nextSample not overflow. Maximum possible step is - // -ln(1/(1< 0x7000000: - period = 0x7000000 - case period == 0: + case mean > 0x7000000: + mean = 0x7000000 + case mean == 0: return 0 } - // Let m be the sample rate, - // the probability distribution function is m*exp(-mx), so the CDF is - // p = 1 - exp(-mx), so - // q = 1 - p == exp(-mx) - // log_e(q) = -mx - // -log_e(q)/m = x - // x = -log_e(q) * period - // x = log_2(q) * (-log_e(2)) * period ; Using log_2 for efficiency + // Take a random sample of the exponential distribution exp(-mean*x). + // The probability distribution function is mean*exp(-mean*x), so the CDF is + // p = 1 - exp(-mean*x), so + // q = 1 - p == exp(-mean*x) + // log_e(q) = -mean*x + // -log_e(q)/mean = x + // x = -log_e(q) * mean + // x = log_2(q) * (-log_e(2)) * mean ; Using log_2 for efficiency const randomBitCount = 26 q := fastrand()%(1<