aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHolden Rohrer <hr@hrhr.dev>2020-01-17 00:32:53 -0500
committerHolden Rohrer <hr@hrhr.dev>2020-01-17 00:32:53 -0500
commitf71719631dd793f39e6c629314fd81a4c06c19d2 (patch)
treed0652df31ee65dbceeab02e3996521ee8131698a
parent8d4ea0bb9cdda4021c54ed564382b89ddec8c800 (diff)
finally made schedule.js
-rw-r--r--architecture21
-rw-r--r--tools/schedule.js102
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;
+ }
+}