diff options
author | Holden Rohrer <hr@hrhr.dev> | 2020-01-17 00:32:53 -0500 |
---|---|---|
committer | Holden Rohrer <hr@hrhr.dev> | 2020-01-17 00:32:53 -0500 |
commit | f71719631dd793f39e6c629314fd81a4c06c19d2 (patch) | |
tree | d0652df31ee65dbceeab02e3996521ee8131698a | |
parent | 8d4ea0bb9cdda4021c54ed564382b89ddec8c800 (diff) |
finally made schedule.js
-rw-r--r-- | architecture | 21 | ||||
-rw-r--r-- | tools/schedule.js | 102 |
2 files changed, 102 insertions, 21 deletions
diff --git a/architecture b/architecture deleted file mode 100644 index c161699..0000000 --- a/architecture +++ /dev/null @@ -1,21 +0,0 @@ -Say you have several queues A, B, ... -Each queue has a length K_n. -Each queue has a weight K_w. K_w adjusted such that \sumK_w=1 -If k items are requested, a set of items from the tops of each relevant queue will be returned. -K_c <= K_n items were chosen from queue K. -Minimize \sum|kK_w-K_c|. << Jesus Christ that's it. How could I be so stupid. - -main(queueList, num) -> while (not have num) getNumOrAll(queueList[top], remaining) - -getNumOrAll(queue, num): - Step 1: Make array of num*job.weight - Step 2: "Remove" all num%1 from array, and count - Step 3: "Sort" array by num. - Step 4: Continue counting. Subtract one from each array member until at num. -^^ Not perfect - Step 1: (Pre-)sort by job.data.length/job.weight. - Step 2: Start at lowest, and pop all until job.data.length>job.normweight*num (decreasing num as popping and recalc job.normweight). - Step 2.5: If empty, remove prio && jobs[prio]; return. - Step 3: Then, pop job.normweight*num//1 elems from remaining, without num decrease or normweight recalc. But keep job.wacc = job.normweight*num%1 - Step 4: Shallow copy job array, and sort by job.wacc. - Step 5: Iterate through array (high->low), and subtract 1 until the length of output is num. diff --git a/tools/schedule.js b/tools/schedule.js new file mode 100644 index 0000000..02dc883 --- /dev/null +++ b/tools/schedule.js @@ -0,0 +1,102 @@ +// A mixed paradigm scheduler + +// The core managed data type: a queue will be pushed a number of these and asked to manage it. +function Job(data, prio=0, wt=1){ + // Data is an array; + // Ideally, Both prio and wt are functions which take one argument: how many write cycles they've been waiting. This helps manage time-sensitive jobs. + // But this is too computationally difficult, so they are integer constants. + + // Immutable Properties + this.data = data; //A set of work to be done (like character writes) + this.prio = prio; // If a.prio > b.prio, all of `a.data` will be sent before any of `b.data` + this.wt = wt; // After numerous calls, (amount called of a/amount called of b) = a.wt/b.wt if a.prio = b.prio + this.maxr = data.length/wt; // A utility calculation: If a job has a lower maxr, it will run out of data earlier. + + // Mutable Properties + this.wacc = 0; // mutable property: Queue will change this to keep track between dequeues of how much "left over" push real estate this should have. + this.start; // The write # this job was introduced on. Also for Queue use. +} + +function Queue(maxExport, call, delay){ + // Every delay ms, Queue executes `call(maxExport # of objs in queue)` + let jobs = {}; // Links priorities to unordered arrays of jobs + let prios = []; // Array of priorities (keys of jobs), sorted. + let open = false; + let disab = true; + let writes = 0; + + this.enqueue = function(job){ + job.start = writes; + let prio = job.prio; + if (!jobs[prio]) jobs[prio] = []; + jobs[prio].splice(0, Math.abs(bs(jobs[prio], job, (el, ne) => el.maxr - ne.maxr)), job); + push(job); + prios.splice(0, Math.abs(bs(prios, prio, (el, ne) => el-ne)), prio) + if (open) dequeue(); + } + + this.enable = function(){ + disab = false; + if (open) dequeue(); + } + + this.disable = function(){ + disab = true; + } + + function dequeue(){ + if (disab){ + open = true; + return; + } + if (prios.length == 0){ + open = true; + return; + } + open = false; + let data = []; + while (data.length < maxExport){ + data.push(...getNumOrAll(prios[prios.length-1]), maxExport-data.length); + } + + writes++; + call(data); + setTimeout(dequeue, delayms); + } + + function getNumOrAll(prio, num){ + /* + + Step 1: (Pre-)sort by job.data.length/job.weight. + Step 2: Start at lowest, and pop all until job.data.length>job.normweight*num (decreasing num as popping and recalc job.normweight). Delete the job. + Step 3: Then, pop job.normweight*num//1 elems from remaining, without num decrease or normweight recalc. But keep job.wacc = job.normweight*num%1 + Step 4: Shallow copy job array, and sort by job.wacc. + Step 5: Iterate through array (high->low), and subtract 1 until the length of output is num. + Step 6: If empty, remove prio && jobs[prio]; return. + */ + let jobq = jobs[prio]; + let dequeued = []; + let weightsum = Math.sum(jobq.map(job => job.wt)).reduce((acc, cur)=>acc+cur); + while (job[0].data.length<(job[0].wacc+job[0].wt*num/weightsum)){ + weightsum -= job.wt; + dequeued.push(...jobq.shift().data); + } + for (job of jobq){ + job.wacc += job.wt*num/weightsum; + let data = job.data; + let topop = job.wacc-job.wacc%1; + job.wacc -= topop + dequeued.push(...data.splice(-topop)); + } + for (job of jobq.splice().sort((el, ne) => el.wacc-ne.wacc)){ + if (dequeued.length == num) break; + job.wacc--; + dequeue.push(job.pop()); + } + if (jobq.length == 0){ + delete jobs[prio]; + prios.splice(bs(prios, prio, (el, ne)=>el-ne), 1); + } + return dequeued; + } +} |