Created
November 14, 2017 04:18
-
-
Save apsicle/f99154e7d64295e11b9e0d6b8589674f to your computer and use it in GitHub Desktop.
codefights problem I may come back to.
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
// if you have backup time k for each of n jobs, and each job in parallel goes n times slow (k * n), the completion time for the whole batch is always k * n with or without parallelization. | |
function backupTimeEstimator(startTimes, backupDuration, maxThreads) { | |
// Null case | |
if (startTimes.length === 0) { | |
return []; | |
} | |
// Set up jobs queue, ending time array, jobs running array, and current time. | |
let jobsQueue = startTimes.map((time, index) => { | |
return [time, index]; | |
}); | |
let backupDurationOriginal = backupDuration.slice(); | |
let endTimes = startTimes.slice(); | |
let jobsRunning = []; | |
let jobsWaiting = []; | |
let currentTime = startTimes[0]; | |
// Utility function to find the amount of time for the fastest job to finish in jobsRunning | |
let findTimeToNextFinish = (jobsArr) => { | |
return Math.min.apply(null, jobsArr.map((job) => backupDuration[job[1]])) * jobsRunning.length; | |
} | |
// Utility function to find the job with the smallest initial backup time | |
// The trick is we always jump ahead to the next event. Events can be: | |
// a) Job comes in from jobs array; | |
// b) Job comes in the the waiting array; | |
// c) Job finishes. | |
while (jobsWaiting.length > 0 || jobsQueue.length > 0 || jobsRunning.length > 0) { | |
console.log('------------------------') | |
console.log('Waiting: ', jobsWaiting); | |
// Grab the next job to be handled. | |
let nextJob = null; | |
let from = null; | |
if (jobsWaiting.length > 0) { | |
nextJob = jobsWaiting.shift(); | |
from = 'waiting'; | |
} else if (jobsQueue.length > 0) { | |
nextJob = jobsQueue.shift(); | |
from = 'queue'; | |
} | |
// Figure out whether the next job comes first, or a job in jobsRunning finishes first. | |
let timeToNextJob = nextJob !== null ? nextJob[0] - currentTime : Infinity; | |
let timeToJobCompletion = jobsRunning.length > 0 ? findTimeToNextFinish(jobsRunning) : Infinity; | |
let timestep; | |
console.log('Next Job & Job Completion: ', timeToNextJob, timeToJobCompletion) | |
// If the next job comes first... | |
if (timeToNextJob < timeToJobCompletion) { | |
// If jobsRunning is full, we cannot add the job to the jobsRunning, so we put it in | |
// jobsWaiting. Then update the jobsQueue and | |
// jobsWaiting by increasing the startTimes by the amount of delay | |
// between when they would have started and when they will actually start. | |
if (jobsRunning.length === maxThreads) { | |
timestep = timeToJobCompletion; | |
jobsWaiting.unshift(nextJob); | |
nextJob = null; | |
jobsWaiting.forEach((job) => { | |
console.log('doing'); | |
job[0] += timestep - timeToNextJob; | |
}); | |
jobsQueue.forEach((job) => { | |
job[0] += timestep - timeToNextJob; | |
}); | |
} else { | |
timestep = timeToNextJob; | |
} | |
} else { | |
// If the next job completion comes first... | |
timestep = timeToJobCompletion; | |
if (nextJob !== null) { | |
if (from === 'waiting') jobsWaiting.unshift(nextJob); | |
if (from === 'queue') jobsQueue.unshift(nextJob); | |
nextJob = null; | |
} | |
} | |
// console.log('next job: ', nextJob); | |
console.log('timestep: ', timestep); | |
console.log('Current time: ', currentTime); | |
// Let the current jobs run for the timestep and subtract the parallelized time from their backupDurations | |
for (let i = 0; i < jobsRunning.length ; i++) { | |
backupDuration[jobsRunning[i][1]] -= timestep / jobsRunning.length; | |
} | |
console.log('jobs running: ', jobsRunning); | |
const durations = jobsRunning.map((job) => { | |
return backupDuration[job[1]]; | |
}) | |
console.log('backupDurations: ', durations); | |
// Check which jobs have finished. According to our model we will NEVER overshoot a job finishing. | |
jobsRunning = jobsRunning.filter((job, i) => { | |
if (backupDuration[job[1]] < .00001) { | |
endTimes[job[1]] = currentTime + timestep; | |
return false; | |
} else { | |
return true; | |
} | |
}); | |
console.log('jobs running after filter: ', jobsRunning); | |
// Add the nextjob if there is one. | |
if (nextJob !== null) { | |
if (jobsRunning.length < maxThreads) { | |
jobsRunning.push(nextJob); | |
} | |
} | |
currentTime += timestep; | |
} | |
return endTimes; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment