Skip to content

Instantly share code, notes, and snippets.

@growler
Created August 26, 2020 14:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save growler/a05ecabc79f9414c506b556686a08360 to your computer and use it in GitHub Desktop.
Save growler/a05ecabc79f9414c506b556686a08360 to your computer and use it in GitHub Desktop.
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