Skip to content

Instantly share code, notes, and snippets.

@mschoch
Created February 10, 2014 22:05
Show Gist options
  • Save mschoch/8925204 to your computer and use it in GitHub Desktop.
Save mschoch/8925204 to your computer and use it in GitHub Desktop.
package workload
import (
"math/rand"
"time"
)
type Schedule []time.Duration
type ScheduleBuilder struct {
schedules []Schedule
lastOffTime []time.Duration
lastOnTime []time.Duration
numUsers int
maxActive int
rampOffset time.Duration
minOfflineDuration time.Duration
maxOfflineDuration time.Duration
totalDuration time.Duration
}
func NewScheduleBuilder(numUsers, maxActive int, rampOffset time.Duration, minOfflineDuration, maxOfflineDuration, totalDuration time.Duration) *ScheduleBuilder {
return &ScheduleBuilder{
schedules: make([]Schedule, numUsers),
lastOffTime: make([]time.Duration, numUsers),
lastOnTime: make([]time.Duration, numUsers),
numUsers: numUsers,
maxActive: maxActive,
rampOffset: rampOffset,
minOfflineDuration: minOfflineDuration,
maxOfflineDuration: maxOfflineDuration,
totalDuration: totalDuration,
}
}
func (sb *ScheduleBuilder) BuildSchedule() []Schedule {
// initially everyone is offline
sb.init()
// schedule the initial ramp up
sb.rampUp()
// look for offline duration violations
violator := sb.findNextOfflineViolation()
for violator != -1 {
// if we find an offline violation, we need to turn that user on
// compute random off duration
offDuration := time.Duration(rand.Float64()*float64(sb.maxOfflineDuration-sb.minOfflineDuration)) + sb.minOfflineDuration
transitionTime := sb.lastOffTime[violator] + offDuration
sb.turnOnUser(violator, transitionTime)
// now that we have turned on an additional user, we should have to many users on at once
// find user thats been on the longest and turn them off at the same time
longestOn := sb.findUserOnLongest()
sb.turnOffUser(longestOn, transitionTime)
}
return sb.schedules
}
func (sb *ScheduleBuilder) init() {
for i := 0; i < sb.numUsers; i++ {
sb.schedules[i] = make(Schedule, 0)
sb.lastOffTime[i] = 0
sb.lastOnTime[i] = 0
}
}
func (sb *ScheduleBuilder) rampUp() {
var durationIterator time.Duration
for i := 0; i < sb.maxActive; i++ {
sb.turnOnUser(i, durationIterator)
durationIterator += sb.rampOffset
}
}
func (sb *ScheduleBuilder) turnOnUser(index int, at time.Duration) {
sb.schedules[index] = append(sb.schedules[index], at)
sb.lastOnTime[index] = at
}
func (sb *ScheduleBuilder) turnOffUser(index int, at time.Duration) {
sb.schedules[index] = append(sb.schedules[index], at)
sb.lastOffTime[index] = at
}
func (sb *ScheduleBuilder) isUserOn(index int) bool {
if sb.lastOnTime[index] > sb.lastOffTime[index] {
return true
}
return false
}
func (sb *ScheduleBuilder) isUserOff(index int) bool {
if sb.lastOnTime[index] < sb.lastOffTime[index] {
return true
}
return false
}
func (sb *ScheduleBuilder) lastOfflineDuration(index int) time.Duration {
return sb.totalDuration - sb.lastOffTime[index]
}
func (sb *ScheduleBuilder) findNextOfflineViolation() int {
rv := -1
for i := 0; i < sb.numUsers; i++ {
// if the user is offline and their offline duration would exceed
// the max if they never go back online, return this user as violation
if sb.isUserOff(i) && sb.lastOfflineDuration(i) > sb.maxOfflineDuration {
return i
}
}
// otherwise -1 to indicate no violation
return rv
}
func (sb *ScheduleBuilder) findUserOnLongest() int {
var longestTime time.Duration
longestIndex := -1
for i := 0; i < sb.numUsers; i++ {
if sb.isUserOn(i) {
userOnTime := sb.totalDuration - sb.lastOnTime[i]
if userOnTime > longestTime {
// new highest
longestTime = userOnTime
longestIndex = i
}
}
}
return longestIndex
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment