Use worker_arenas in load::file

This commit is contained in:
Richard Feldman 2020-08-02 12:09:55 -04:00
parent 54b5e28206
commit 8434af4e63

View file

@ -37,7 +37,7 @@ const ROC_FILE_EXTENSION: &str = "roc";
const MODULE_SEPARATOR: char = '.';
#[derive(Debug)]
pub struct LoadedModule<'a> {
pub struct LoadedModule {
pub module_id: ModuleId,
pub interns: Interns,
pub solved: Solved<Subs>,
@ -45,7 +45,7 @@ pub struct LoadedModule<'a> {
pub type_problems: Vec<solve::TypeError>,
pub declarations_by_id: MutMap<ModuleId, Vec<Declaration>>,
pub exposed_vars_by_symbol: Vec<(Symbol, Variable)>,
pub src: &'a str,
pub src: Box<str>,
}
#[derive(Debug)]
@ -197,6 +197,23 @@ type IdentIdsByModule = MutMap<ModuleId, IdentIds>;
type MsgSender<'a> = Sender<Msg<'a>>;
type MsgReceiver<'a> = Receiver<Msg<'a>>;
/// Add a task to the queue, and notify all the listeners.
fn enqueue_task<'a, 'b>(
injector: &Injector<BuildTask<'a, 'b>>,
listeners: &[Sender<WorkerMsg>],
task: BuildTask<'a, 'b>,
) -> Result<(), LoadingProblem> {
injector.push(task);
for listener in listeners {
listener
.send(WorkerMsg::TaskAdded)
.map_err(|_| LoadingProblem::MsgChannelDied)?;
}
Ok(())
}
/// The loading process works like this, starting from the given filename (e.g. "main.roc"):
///
/// 1. Open the file.
@ -240,16 +257,29 @@ type MsgReceiver<'a> = Receiver<Msg<'a>>;
/// and then linking them together, and possibly caching them by the hash of their
/// specializations, so if none of their specializations changed, we don't even need
/// to rebuild the module and can link in the cached one directly.)
#[allow(clippy::cognitive_complexity)]
pub fn load<'a>(
arena: &'a Bump,
// #[allow(clippy::cognitive_complexity)]
fn load(
filename: PathBuf,
stdlib: &StdLib,
src_dir: &Path,
filename: PathBuf,
arc_modules: Arc<Mutex<ModuleIds>>,
ident_ids_by_module: Arc<Mutex<IdentIdsByModule>>,
exposed_types: SubsByModule,
) -> Result<LoadedModule<'a>, LoadingProblem> {
) -> Result<LoadedModule, LoadingProblem> {
use self::MaybeShared::*;
let arena = Bump::new();
// Reserve one CPU for the main thread, and let all the others be eligible
// to spawn workers.
let num_workers = num_cpus::get() - 1;
let mut worker_arenas = bumpalo::collections::Vec::with_capacity_in(num_workers, &arena);
for _ in 0..num_workers {
worker_arenas.push(Bump::new());
}
let (msg_tx, msg_rx) = bounded(1024);
let arc_modules = Arc::new(Mutex::new(ModuleIds::default()));
let root_exposed_ident_ids = IdentIds::exposed_builtins(0);
@ -265,73 +295,28 @@ pub fn load<'a>(
// Unique(&mut module_ids, &mut root_exposed_ident_ids),
)?;
load_deps(
&arena,
root_id,
msg_tx,
msg_rx,
stdlib,
src_dir,
arc_modules,
ident_ids_by_module,
exposed_types,
)
}
/// Add a task to the queue, and notify all the listeners.
fn enqueue_task<'a, 'b>(
injector: &Injector<BuildTask<'a, 'b>>,
listeners: &[Sender<WorkerMsg>],
task: BuildTask<'a, 'b>,
) -> Result<(), LoadingProblem> {
injector.push(task);
for listener in listeners {
listener
.send(WorkerMsg::TaskAdded)
.map_err(|_| LoadingProblem::MsgChannelDied)?;
}
Ok(())
}
fn load_deps<'a>(
arena: &'a Bump,
root_id: ModuleId,
msg_tx: MsgSender<'a>,
msg_rx: MsgReceiver<'a>,
stdlib: &StdLib,
src_dir: &Path,
arc_modules: Arc<Mutex<ModuleIds>>,
ident_ids_by_module: Arc<Mutex<IdentIdsByModule>>,
exposed_types: SubsByModule,
) -> Result<LoadedModule<'a>, LoadingProblem> {
// Reserve one CPU for the main thread, and let all the others be eligible
// to spawn workers.
let num_workers = num_cpus::get() - 1;
// We'll add tasks to this, and then worker threads will take tasks from it.
let injector = Injector::new();
// We need to allocate worker *queues* on the main thread and then move them
// into the worker threads, because those workers' stealers need to be
// shared between all threads, and this coordination work is much easier
// shared bet,een all threads, and this coordination work is much easier
// on the main thread.
let mut worker_queues = bumpalo::collections::Vec::with_capacity_in(num_workers, arena);
let mut stealers = bumpalo::collections::Vec::with_capacity_in(num_workers, arena);
for _ in 0..num_workers {
let worker = Worker::new_lifo();
stealers.push(worker.stealer());
worker_queues.push(worker);
}
// Get a reference to the completed stealers, so we can send that
// reference to each worker. (Slices are Sync, but bumpalo Vecs are not.)
let stealers = stealers.into_bump_slice();
let mut worker_queues = bumpalo::collections::Vec::with_capacity_in(num_workers, &arena);
let mut stealers = bumpalo::collections::Vec::with_capacity_in(num_workers, &arena);
thread::scope(|thread_scope| {
for _ in 0..num_workers {
let worker = Worker::new_lifo();
stealers.push(worker.stealer());
worker_queues.push(worker);
}
// Get a reference to the completed stealers, so we can send that
// reference to each worker. (Slices are Sync, but bumpalo Vecs are not.)
let stealers = stealers.into_bump_slice();
let mut headers_parsed = MutSet::default();
// We've already parsed the root's header. (But only its header, so far.)
@ -365,10 +350,10 @@ fn load_deps<'a>(
unsolved_modules: MutMap::default(),
};
let mut worker_listeners = bumpalo::collections::Vec::with_capacity_in(num_workers, arena);
let mut worker_listeners = bumpalo::collections::Vec::with_capacity_in(num_workers, &arena);
for _ in 0..num_workers {
let arena = Bump::new();
for worker_arena in worker_arenas.iter_mut() {
let msg_tx = msg_tx.clone();
let worker = worker_queues.pop().unwrap();
let (worker_msg_tx, worker_msg_rx) = bounded(1024);
@ -381,8 +366,6 @@ fn load_deps<'a>(
// Record this thread's handle so the main thread can join it later.
thread_scope.spawn(move |_| {
let msg_tx = msg_tx.clone();
// Keep listening until we receive a Shutdown msg
for msg in worker_msg_rx.iter() {
match msg {
@ -399,7 +382,7 @@ fn load_deps<'a>(
// queue - and run it.
match find_task(&worker, injector, stealers) {
Some(task) => {
run_task(task, &arena, src_dir, msg_tx.clone(), stdlib);
run_task(task, worker_arena, src_dir, msg_tx.clone(), stdlib);
}
None => {
// No tasks to work on! This might be because
@ -779,7 +762,7 @@ fn finish<'a>(
problems: Vec<solve::TypeError>,
exposed_vars_by_symbol: Vec<(Symbol, Variable)>,
src: &'a str,
) -> LoadedModule<'a> {
) -> LoadedModule {
state.type_problems.extend(problems);
let module_ids = Arc::try_unwrap(state.arc_modules)