// Copyright 2017 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package traceimport ()// mud is an updatable mutator utilization distribution.//// This is a continuous distribution of duration over mutator// utilization. For example, the integral from mutator utilization a// to b is the total duration during which the mutator utilization was// in the range [a, b].//// This distribution is *not* normalized (it is not a probability// distribution). This makes it easier to work with as it's being// updated.//// It is represented as the sum of scaled uniform distribution// functions and Dirac delta functions (which are treated as// degenerate uniform distributions).type mud struct { sorted, unsorted []edge// trackMass is the inverse cumulative sum to track as the // distribution is updated. trackMass float64// trackBucket is the bucket in which trackMass falls. If the // total mass of the distribution is < trackMass, this is // len(hist). trackBucket int// trackSum is the cumulative sum of hist[:trackBucket]. Once // trackSum >= trackMass, trackBucket must be recomputed. trackSum float64// hist is a hierarchical histogram of distribution mass. hist [mudDegree]float64}const (// mudDegree is the number of buckets in the MUD summary // histogram. mudDegree = 1024)type edge struct {// At x, the function increases by y. x, delta float64// Additionally at x is a Dirac delta function with area dirac. dirac float64}// add adds a uniform function over [l, r] scaled so the total weight// of the uniform is area. If l==r, this adds a Dirac delta function.func ( *mud) (, , float64) {if == 0 {return }if < { , = , }// Add the edges.if == { .unsorted = append(.unsorted, edge{, 0, }) } else { := / ( - ) .unsorted = append(.unsorted, edge{, , 0}, edge{, -, 0}) }// Update the histogram. := &.hist , := math.Modf( * mudDegree) := int()if >= mudDegree { , = mudDegree-1, 1 }if == { [] += } else { , := math.Modf( * mudDegree) := int()if >= mudDegree { , = mudDegree-1, 1 }if == { [] += } else { := / ( - ) / mudDegree [] += * (1 - ) [] += * for := + 1; < ; ++ { [] += } } }// Update mass tracking.if := float64(.trackBucket) / mudDegree; < {if < { .trackSum += } else { .trackSum += * ( - ) / ( - ) }if .trackSum >= .trackMass {// The tracked mass now falls in a different // bucket. Recompute the inverse cumulative sum. .setTrackMass(.trackMass) } }}// setTrackMass sets the mass to track the inverse cumulative sum for.//// Specifically, mass is a cumulative duration, and the mutator// utilization bounds for this duration can be queried using// approxInvCumulativeSum.func ( *mud) ( float64) { .trackMass = // Find the bucket currently containing trackMass by computing // the cumulative sum. := 0.0for , := range .hist[:] { := + if > {// mass falls in bucket i. .trackBucket = .trackSum = return } = } .trackBucket = len(.hist) .trackSum = }// approxInvCumulativeSum is like invCumulativeSum, but specifically// operates on the tracked mass and returns an upper and lower bound// approximation of the inverse cumulative sum.//// The true inverse cumulative sum will be in the range [lower, upper).func ( *mud) () (float64, float64, bool) {if .trackBucket == len(.hist) {returnmath.NaN(), math.NaN(), false }returnfloat64(.trackBucket) / mudDegree, float64(.trackBucket+1) / mudDegree, true}// invCumulativeSum returns x such that the integral of d from -∞ to x// is y. If the total weight of d is less than y, it returns the// maximum of the distribution and false.//// Specifically, y is a cumulative duration, and invCumulativeSum// returns the mutator utilization x such that at least y time has// been spent with mutator utilization <= x.func ( *mud) ( float64) (float64, bool) {iflen(.sorted) == 0 && len(.unsorted) == 0 {returnmath.NaN(), false }// Sort edges. := .unsortedslices.SortFunc(, func(, edge) int {returncmp.Compare(.x, .x) })// Merge with sorted edges. .unsorted = nilif .sorted == nil { .sorted = } else { := .sorted := make([]edge, len()+len()) , := 0, 0for := range {if >= len() {copy([:], [:])break } elseif >= len() {copy([:], [:])break } elseif [].x < [].x { [] = [] ++ } else { [] = [] ++ } } .sorted = }// Traverse edges in order computing a cumulative sum. , , := 0.0, 0.0, 0.0for , := range .sorted { := + (.x-)*if >= {// y was exceeded between the previous edge // and this one.if == 0 {// Anywhere between prevX and // e.x will do. We return e.x // because that takes care of // the y==0 case naturally.return .x, true }return (-)/ + , true } += .diracif >= {// y was exceeded by the Dirac delta at e.x.return .x, true } , = , .x += .delta }return , false}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.