Skip to content

Instantly share code, notes, and snippets.

@apsicle
Created November 14, 2017 04:18
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 apsicle/f99154e7d64295e11b9e0d6b8589674f to your computer and use it in GitHub Desktop.
Save apsicle/f99154e7d64295e11b9e0d6b8589674f to your computer and use it in GitHub Desktop.
codefights problem I may come back to.
// 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