Created
August 26, 2020 14:24
-
-
Save growler/a05ecabc79f9414c506b556686a08360 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type randomSize interface { | |
clone() randomSize | |
size() int | |
} | |
type sampledTableSize struct { | |
sizes []int | |
ptr int | |
} | |
func (s *sampledTableSize) clone() randomSize { | |
r := &sampledTableSize{ | |
sizes: s.sizes, | |
ptr: s.ptr, | |
} | |
s.ptr = (s.ptr + 1) % len(s.sizes) | |
return r | |
} | |
func (s *sampledTableSize) size() int { | |
r := s.sizes[s.ptr] | |
s.ptr = (s.ptr + 1) % len(s.sizes) | |
return r | |
} | |
type constantSize int | |
func newConstantSize(s int) *constantSize { | |
return (*constantSize)(&s) | |
} | |
func (s *constantSize) clone() randomSize { | |
return s | |
} | |
func (s *constantSize) size() int { | |
return *((*int)(s)) | |
} | |
type logNormalSize struct { | |
logNormalTruncated | |
} | |
func newLogNormalSize(σ float64, mean, min, max int) *logNormalSize { | |
return &logNormalSize{ | |
logNormalTruncated: newLogNormalTruncated(σ, float64(mean), float64(min), float64(max)), | |
} | |
} | |
func (d *logNormalSize) clone() randomSize { | |
return &logNormalSize{ | |
logNormalTruncated: logNormalTruncated{ | |
σ: d.σ, | |
μ: d.μ, | |
min: d.min, | |
max: d.max, | |
rng: rand.New(rand.NewSource(0)), | |
}, | |
} | |
} | |
func (d *logNormalSize) size() int { | |
return int(math.Round(d.rand())) | |
} | |
type eventDelay interface { | |
clone() eventDelay | |
delay() time.Duration | |
wait() time.Duration | |
} | |
type sampledTableDelay struct { | |
delays []float64 | |
ptr int | |
ts time.Time | |
} | |
func (s *sampledTableDelay) newWithTargetScale(scale float64) *sampledTableDelay { | |
newTable := make([]float64, len(s.delays)) | |
for i := range s.delays { | |
newTable[i] = s.delays[i] * scale | |
} | |
return &sampledTableDelay{ | |
delays: newTable, | |
ptr: 0, | |
ts: time.Now(), | |
} | |
} | |
func (s *sampledTableDelay) newWithTargetRate(rate float64) *sampledTableDelay { | |
newTable := make([]float64, len(s.delays)) | |
sum := 0.0 | |
for i := range s.delays { | |
sum = sum + s.delays[i] | |
} | |
mean := sum / float64(len(s.delays)) | |
scale := 1000.0 / (mean * rate) | |
for i := range s.delays { | |
newTable[i] = s.delays[i] * scale | |
} | |
return &sampledTableDelay{ | |
delays: newTable, | |
ptr: 0, | |
ts: time.Now(), | |
} | |
} | |
func (s *sampledTableDelay) newWithTargetMeanDelayMs(delay float64) *sampledTableDelay { | |
newTable := make([]float64, len(s.delays)) | |
sum := 1.0 | |
for i := range s.delays { | |
sum = sum + s.delays[i] | |
} | |
mean := sum / float64(len(s.delays)) | |
scale := delay / mean | |
for i := range s.delays { | |
newTable[i] = s.delays[i] * scale | |
} | |
return &sampledTableDelay{ | |
delays: newTable, | |
ptr: 0, | |
ts: time.Now(), | |
} | |
} | |
func (s *sampledTableDelay) clone() eventDelay { | |
r := &sampledTableDelay{ | |
delays: s.delays, | |
ptr: s.ptr, | |
ts: time.Now(), | |
} | |
s.ptr = (s.ptr + 1) % len(s.delays) | |
return r | |
} | |
func (s *sampledTableDelay) delay() time.Duration { | |
d := time.Duration(s.delays[s.ptr] * float64(time.Millisecond)) | |
s.ptr = (s.ptr + 1) % len(s.delays) | |
return d | |
} | |
func (s *sampledTableDelay) wait() time.Duration { | |
n := time.Now() | |
d := s.delay() | |
e := s.ts.Add(d) | |
if n.Before(e) { | |
time.Sleep(e.Sub(n)) | |
s.ts = e | |
} else { | |
s.ts = n | |
} | |
return d | |
} | |
var zeroDelay = _zeroDelay{} | |
type _zeroDelay struct{} | |
func (z *_zeroDelay) clone() eventDelay { | |
return z | |
} | |
func (*_zeroDelay) wait() time.Duration { | |
return 0 | |
} | |
func (*_zeroDelay) delay() time.Duration { | |
return 0 | |
} | |
type constantDelay struct { | |
t time.Time | |
d time.Duration | |
} | |
func newConstantDelay(d time.Duration) *constantDelay { | |
return &constantDelay{ | |
d: d, | |
t: time.Now(), | |
} | |
} | |
func (d *constantDelay) clone() eventDelay { | |
return &constantDelay{ | |
d: d.d, | |
t: time.Now(), | |
} | |
} | |
func (d *constantDelay) delay() time.Duration { | |
return d.d | |
} | |
func (d *constantDelay) wait() time.Duration { | |
n := time.Now() | |
e := d.t.Add(d.d) | |
if n.Before(e) { | |
time.Sleep(e.Sub(n)) | |
d.t = e | |
} else { | |
d.t = n | |
} | |
return d.d | |
} | |
type logNormalDelay struct { | |
logNormalTruncated | |
t time.Time | |
} | |
func newLogNormalDelay(σ float64, mean, min, max time.Duration) *logNormalDelay { | |
return &logNormalDelay{ | |
logNormalTruncated: newLogNormalTruncated(σ, float64(mean), float64(min), float64(max)), | |
t: time.Now(), | |
} | |
} | |
func (ln *logNormalDelay) clone() eventDelay { | |
return &logNormalDelay{ | |
logNormalTruncated: logNormalTruncated{ | |
σ: ln.σ, | |
μ: ln.μ, | |
min: ln.min, | |
max: ln.max, | |
rng: rand.New(rand.NewSource(0)), | |
}, | |
t: time.Now(), | |
} | |
} | |
func (ln *logNormalDelay) delay() time.Duration { | |
return time.Duration(ln.rand()) | |
} | |
func (ln *logNormalDelay) wait() time.Duration { | |
n := time.Now() | |
d := time.Duration(ln.rand()) | |
e := ln.t.Add(d) | |
if n.Before(e) { | |
time.Sleep(e.Sub(n)) | |
ln.t = e | |
} else { | |
ln.t = n | |
d = 0 | |
} | |
return d | |
} | |
// Truncated LogNormal distribution | |
type logNormalTruncated struct { | |
σ float64 | |
μ float64 | |
min float64 | |
max float64 | |
rng *rand.Rand | |
} | |
// Returns a new LogNormal distrubution with | |
// defined sigma and mean value. Both sigma and mean must be > 0. | |
// `min` and `max` define allowed range for the distribution. | |
// `max` > `min` >= 0 (except the case when maximum is not | |
// defined and therefor `max` is set to zero). | |
func newLogNormalTruncated(σ, mean, min, max float64) logNormalTruncated { | |
μ := math.Log(mean) - (math.Pow(σ, 2.0) / 2.0) | |
return logNormalTruncated{ | |
σ: σ, | |
μ: μ, | |
min: min, | |
max: max, | |
rng: rand.New(rand.NewSource(0)), | |
} | |
} | |
// Returns a randomly generated duration. | |
func (ln *logNormalTruncated) rand() float64 { | |
n := math.Round(math.Exp(ln.rng.NormFloat64()*ln.σ + ln.μ)) | |
if n < ln.min { | |
n = ln.min | |
} else if ln.max != 0.0 && n > ln.max { | |
n = ln.max | |
} | |
return n | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment