transfer commit

This commit is contained in:
2023-02-03 14:40:34 +00:00
parent a500f8b87a
commit 3c63cae242
63 changed files with 3227 additions and 2850 deletions

View File

@@ -0,0 +1,51 @@
use std::{ops::{Generator, GeneratorState}, pin::Pin};
use super::{Task, Nice, TaskState};
pub struct GeneratorTask<G: Generator<(), Yield = ()>> {
nice: Nice,
generator: Pin<Box<G>>
}
impl<G> GeneratorTask<G> where G: Generator<(), Yield = ()> {
fn new(nice: Nice, generator: G) -> Self { Self {
nice,
generator: Box::pin(generator)
} }
}
impl<G> Task for GeneratorTask<G>
where G: Generator<(), Yield = ()> {
type Result = G::Return;
fn run_once(&mut self) -> super::TaskState<Self::Result> {
match self.generator.as_mut().resume(()) {
GeneratorState::Yielded(()) => super::TaskState::Yield,
GeneratorState::Complete(r) => super::TaskState::Complete(r)
}
}
}
impl<T> Task for Pin<Box<T>> where T: Generator<(), Yield = ()> {
type Result = T::Return;
fn run_once(&mut self) -> super::TaskState<Self::Result> {
match self.as_mut().resume(()) {
GeneratorState::Yielded(()) => TaskState::Yield,
GeneratorState::Complete(r) => TaskState::Complete(r)
}
}
}
#[macro_export]
macro_rules! subtask {
($g:tt) => { {
let task = $g;
loop {
match task.run_once() {
TaskState::Yield => yield;
TaskState::Complete(r) => break r;
}
}
} };
}

47
src/scheduler/mod.rs Normal file
View File

@@ -0,0 +1,47 @@
mod generator_task;
mod task_pair;
mod task_vec;
pub type Nice = u16;
pub type Priority = i32;
pub enum TaskState<R> {
Yield,
Complete(R)
}
pub trait Task {
type Result;
fn run_once(&mut self) -> TaskState<Self::Result>;
fn run_n_times(&mut self, count: u64) -> TaskState<Self::Result> {
for _ in 0..count {
if let r@TaskState::Complete(_) = self.run_once() {
return r
}
}
return TaskState::Yield
}
fn run_to_completion(&mut self) -> Self::Result {
loop { if let TaskState::Complete(r) = self.run_once() {return r} }
}
fn boxed<'a>(self) -> TaskBox<'a, Self::Result> where Self: 'a + Sized { Box::new(self) }
}
pub type TaskBox<'a, T> = Box<dyn Task<Result = T> + 'a>;
impl<'a, R> Task for TaskBox<'a, R> {
type Result = R;
fn run_once(&mut self) -> TaskState<Self::Result> { self.as_mut().run_once() }
fn run_n_times(&mut self, count: u64) -> TaskState<Self::Result> {
self.as_mut().run_n_times(count)
}
fn run_to_completion(&mut self) -> Self::Result {
self.as_mut().run_to_completion()
}
}

3
src/scheduler/notes.md Normal file
View File

@@ -0,0 +1,3 @@
# Purpose
Type expressions are trees. Any single branch could terminate the solver and any branch may be nonterminating, therefore all of them must be run concurrently. Thread-based concurrency isn't an option because a compiler must be perfectly deterministic. It is also beneficial to have fine-grained control over the relative priority of different tasks.

View File

@@ -0,0 +1,67 @@
use crate::utils::translate::process;
use super::{Task, Nice, Priority, TaskState};
enum TaskPairState<T: Task, U: Task> {
Empty,
Left(T, U::Result),
Right(T::Result, U),
Both(T, U)
}
pub struct TaskPair<T: Task, U: Task> {
l_nice: Nice,
r_nice: Nice,
state: TaskPairState<T, U>,
tally: Priority,
}
impl<T: Task, U: Task> TaskPair<T, U> {
pub fn new(l_nice: Nice, left: T, r_nice: Nice, right: U) -> Self {
Self {
l_nice, r_nice,
tally: 0,
state: TaskPairState::Both(left, right)
}
}
}
impl<T: Task, U: Task> Task for TaskPair<T, U> {
type Result = (T::Result, U::Result);
fn run_once(&mut self) -> TaskState<Self::Result> {
let TaskPair{ state, tally, l_nice, r_nice } = self;
let ret = process(state, |s| match s {
TaskPairState::Empty => panic!("Generator completed and empty"),
TaskPairState::Left(mut l_task, r_res) => {
match l_task.run_once() {
TaskState::Complete(r) => (TaskPairState::Empty, TaskState::Complete((r, r_res))),
TaskState::Yield => (TaskPairState::Left(l_task, r_res), TaskState::Yield),
}
}
TaskPairState::Right(l_res, mut r_task) => {
match r_task.run_once() {
TaskState::Complete(r) => (TaskPairState::Empty, TaskState::Complete((l_res, r))),
TaskState::Yield => (TaskPairState::Right(l_res, r_task), TaskState::Yield),
}
}
TaskPairState::Both(mut l_task, mut r_task) => {
let state = if 0 <= *tally {
*tally -= *l_nice as Priority;
match l_task.run_once() {
TaskState::Complete(r) => TaskPairState::Right(r, r_task),
TaskState::Yield => TaskPairState::Both(l_task, r_task),
}
} else {
*tally += *r_nice as Priority;
match r_task.run_once() {
TaskState::Complete(r) => TaskPairState::Left(l_task, r),
TaskState::Yield => TaskPairState::Both(l_task, r_task),
}
};
(state, TaskState::Yield)
}
});
ret
}
}

107
src/scheduler/task_vec.rs Normal file
View File

@@ -0,0 +1,107 @@
use std::iter;
use itertools::Itertools;
use super::{Task, Nice, TaskState};
const NORMALIZATION_THRESHOLD:Nice = Nice::MAX / 4;
struct TaskEntry<T: Task> {
nice: Nice,
position: usize,
tally: Nice,
task: T
}
struct TaskVec<T: Task> {
results: Vec<Option<T::Result>>,
task_heap: Vec<Option<TaskEntry<T>>>,
}
impl<T: Task> TaskVec<T> {
pub fn new(tasks: Vec<(Nice, T)>) -> Self {
let mut results = Vec::with_capacity(tasks.len());
results.resize_with(tasks.len(), || None);
let task_heap = tasks.into_iter().enumerate()
.map(|(position, (nice, task))| Some(TaskEntry{ nice, task, position, tally: 1 }))
.collect_vec();
Self { results, task_heap }
}
fn entry(&self, i: usize) -> Option<&TaskEntry<T>> {
if self.task_heap.len() <= i {None}
else {self.task_heap[i].as_ref()}
}
fn entry_mut(&mut self, i: usize) -> Option<&mut TaskEntry<T>> {
if self.task_heap.len() <= i {None}
else {self.task_heap[i].as_mut()}
}
fn tally(&self, i: usize) -> Nice {
self.task_heap[i].as_ref().map(|e| e.tally).unwrap_or(0)
}
fn swap(&mut self, a: usize, b: usize) {
self.task_heap.swap(a, b);
}
fn iter_mut(&mut self) -> impl Iterator<Item = &mut TaskEntry<T>> {
self.task_heap.iter_mut().filter_map(|e| e.as_mut())
}
fn normalize(&mut self) {
let shrink_count = self.task_heap.iter().rev().take_while(|e| e.is_none()).count();
let new_len = self.task_heap.len() - shrink_count;
self.task_heap.splice(0..new_len, iter::empty());
let head = self.entry_mut(0);
let offset = if let Some(e) = head {
let offset = e.tally - 1;
if offset < NORMALIZATION_THRESHOLD {return}
e.tally = 1;
offset
} else {return};
for entry in self.iter_mut() { entry.tally -= offset }
}
fn sink(&mut self, i: usize) {
let lchi = 2*i + 1;
let rchi = 2*i + 2;
let t = self.tally(i);
let lcht = if let Some(e) = self.entry(lchi) {e.tally} else {
if self.tally(rchi) < t {
self.swap(rchi, i);
self.sink(rchi);
}
return
};
let rcht = if let Some(e) = self.entry(rchi) {e.tally} else {
if self.tally(lchi) < t {
self.swap(lchi, i);
self.sink(lchi);
}
return
};
let mchi = {
if rcht < t && rcht < lcht {rchi}
else if lcht < t && lcht < rcht {lchi}
else {return}
};
self.swap(i, mchi);
self.sink(mchi);
}
}
impl<T: Task> Task for TaskVec<T> {
fn run_once(&mut self) -> super::TaskState<Self::Result> {
let head = &mut self.task_heap[0];
let head_entry = head.as_mut().expect("All completed, cannot run further");
head_entry.tally += head_entry.nice;
match head_entry.task.run_once() {
TaskState::Complete(r) => {
self.results[head_entry.position] = Some(r);
*head = None;
self.sink(0);
if self.entry(0).is_some() {
}
}
}
}
}