Skip to content

Commit

Permalink
fixup! Preallocate the changes returned by getPlannedRateChanges
Browse files Browse the repository at this point in the history
  • Loading branch information
mstoykov committed Oct 11, 2019
1 parent 29e2024 commit c42e218
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 25 deletions.
9 changes: 6 additions & 3 deletions lib/executor/variable_arrival_rate.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,12 @@ func (varc VariableArrivalRateConfig) getPlannedRateChanges(segment *lib.Executi

var size int
for i, stage := range varc.Stages {
if i == 0 {
size = int(time.Duration(stage.Duration.Duration) / minIntervalBetweenRateAdjustments)
} else if varc.Stages[i-1].Target.Int64 != stage.Target.Int64 {
if stage.Duration.Duration == 0 &&
(i == 0 ||
(i >= 2 && varc.Stages[i-1].Target.Int64 != stage.Target.Int64 &&
varc.Stages[i-1].Target.Int64 == varc.Stages[i-2].Target.Int64)) {
size++
} else if i == 0 || varc.Stages[i-1].Target.Int64 != stage.Target.Int64 {
size += int(time.Duration(stage.Duration.Duration) / minIntervalBetweenRateAdjustments)
}
}
Expand Down
110 changes: 88 additions & 22 deletions lib/executor/variable_arrival_rate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,94 @@ func TestGetPlannedRateChanges0DurationStage(t *testing.T) {
Duration: types.NullDurationFrom(time.Minute),
Target: null.IntFrom(50),
},
{
Duration: types.NullDurationFrom(0),
Target: null.IntFrom(100),
},
{
Duration: types.NullDurationFrom(time.Minute),
Target: null.IntFrom(100),
},
},
}
var v *lib.ExecutionSegment
changes := config.getPlannedRateChanges(v)
var es *lib.ExecutionSegment
changes := config.getPlannedRateChanges(es)
require.Equal(t, len(changes), cap(changes))
require.Equal(t, 1, len(changes))
require.Equal(t, 2, len(changes))
require.Equal(t, time.Duration(0), changes[0].timeOffset)
require.Equal(t, types.NullDurationFrom(time.Millisecond*20), changes[0].tickerPeriod)

require.Equal(t, time.Duration(time.Minute), changes[1].timeOffset)
require.Equal(t, types.NullDurationFrom(time.Millisecond*10), changes[1].tickerPeriod)
}

func TestGetPlannedRateChanges(t *testing.T) {
// helper function to calculate the expected rate change at a given time
func calculateTickerPeriod(current, start, duration time.Duration, from, to int64) types.Duration {
var coef = big.NewRat(
(current - start).Nanoseconds(),
duration.Nanoseconds(),
)

var oneRat = new(big.Rat).Mul(big.NewRat(from-to, 1), coef)
oneRat = new(big.Rat).Sub(big.NewRat(from, 1), oneRat)
oneRat = new(big.Rat).Mul(big.NewRat(int64(time.Second), 1), new(big.Rat).Inv(oneRat))
return types.Duration(new(big.Int).Div(oneRat.Num(), oneRat.Denom()).Int64())
}

func TestGetPlannedRateChangesZeroDurationStart(t *testing.T) {
// TODO: Make multiple of those tests
t.Parallel()
var config = VariableArrivalRateConfig{
TimeUnit: types.NullDurationFrom(time.Second),
StartRate: null.IntFrom(0),
Stages: []Stage{
{
Duration: types.NullDurationFrom(0),
Target: null.IntFrom(50),
},
{
Duration: types.NullDurationFrom(time.Minute),
Target: null.IntFrom(50),
},
{
Duration: types.NullDurationFrom(0),
Target: null.IntFrom(100),
},
{
Duration: types.NullDurationFrom(time.Minute),
Target: null.IntFrom(100),
},
{
Duration: types.NullDurationFrom(time.Minute),
Target: null.IntFrom(0),
},
},
}

var es *lib.ExecutionSegment
changes := config.getPlannedRateChanges(es)
require.Equal(t, len(changes), cap(changes))
var expectedTickerPeriod types.Duration
for i, change := range changes {
switch {
case change.timeOffset == 0:
expectedTickerPeriod = types.Duration(20 * time.Millisecond)
case change.timeOffset == time.Minute*1:
expectedTickerPeriod = types.Duration(10 * time.Millisecond)
case change.timeOffset < time.Minute*3:
expectedTickerPeriod = calculateTickerPeriod(change.timeOffset, 2*time.Minute, time.Minute, 100, 0)
case change.timeOffset == time.Minute*3:
expectedTickerPeriod = 0
default:
t.Fatalf("this shouldn't happen %d index %+v", i, change)
}
require.Equal(t, time.Duration(0),
change.timeOffset%minIntervalBetweenRateAdjustments, "%d index %+v", i, change)
require.Equal(t, change.tickerPeriod.Duration, expectedTickerPeriod, "%d index %+v", i, change)
}
}

func TestGetPlannedRateChanges2(t *testing.T) {
// TODO: Make multiple of those tests
t.Parallel()
var config = VariableArrivalRateConfig{
Expand Down Expand Up @@ -73,31 +150,20 @@ func TestGetPlannedRateChanges(t *testing.T) {
},
}

var v *lib.ExecutionSegment
changes := config.getPlannedRateChanges(v)
c := func(change rateChange, start, duration time.Duration, from, to int64) types.Duration {
var coef = big.NewRat(
(change.timeOffset - start).Nanoseconds(),
duration.Nanoseconds(),
)

var oneRat = new(big.Rat).Mul(big.NewRat(from-to, 1), coef)
oneRat = new(big.Rat).Sub(big.NewRat(from, 1), oneRat)
oneRat = new(big.Rat).Mul(big.NewRat(int64(time.Second), 1), new(big.Rat).Inv(oneRat))
return types.Duration(new(big.Int).Div(oneRat.Num(), oneRat.Denom()).Int64())
}
var es *lib.ExecutionSegment
changes := config.getPlannedRateChanges(es)
require.Equal(t, len(changes), cap(changes))
var expectedTickerPeriod types.Duration
for i, change := range changes {
switch {
case change.timeOffset <= time.Minute*2:
expectedTickerPeriod = c(change, 0, time.Minute*2, 0, 50)
expectedTickerPeriod = calculateTickerPeriod(change.timeOffset, 0, time.Minute*2, 0, 50)
case change.timeOffset < time.Minute*4:
expectedTickerPeriod = c(change, time.Minute*3, time.Minute, 50, 100)
expectedTickerPeriod = calculateTickerPeriod(change.timeOffset, time.Minute*3, time.Minute, 50, 100)
case change.timeOffset == time.Minute*4:
expectedTickerPeriod = types.Duration(5 * time.Millisecond)
default:
expectedTickerPeriod = c(change, 4*time.Minute, 23*time.Second, 200, 50)
expectedTickerPeriod = calculateTickerPeriod(change.timeOffset, 4*time.Minute, 23*time.Second, 200, 50)
}
require.Equal(t, time.Duration(0),
change.timeOffset%minIntervalBetweenRateAdjustments, "%d index %+v", i, change)
Expand Down Expand Up @@ -125,10 +191,10 @@ func BenchmarkGetPlannedRateChanges(b *testing.B) {
},
}

var v *lib.ExecutionSegment
var es *lib.ExecutionSegment
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
changes := config.getPlannedRateChanges(v)
changes := config.getPlannedRateChanges(es)

require.Equal(b, time.Duration(0),
changes[0].timeOffset%minIntervalBetweenRateAdjustments, "%+v", changes[0])
Expand Down

0 comments on commit c42e218

Please sign in to comment.