Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f6670aa
Multithreading WIP
Colecf Jan 19, 2024
c690522
Multithreaded loading
Colecf Jan 28, 2024
dd80981
Remove FileIds and Use Arc<File> instead
Colecf Feb 10, 2024
248d161
Switch to parallel iterators
Colecf Feb 14, 2024
a0600fd
Use Arc<String> for filenames
Colecf Feb 16, 2024
0748d21
Don't flatten build vector
Colecf Feb 18, 2024
3ebeec7
Parse by chunks
Colecf Feb 20, 2024
740f593
Remove parse::Build, using graph::Build instead
Colecf Feb 21, 2024
127cb25
Standardize on clumps
Colecf Feb 21, 2024
fbfe7ee
Reserve some vector sizes and add traces
Colecf Feb 22, 2024
1e994ee
Fix bug with evaluating variables from parent scope
Colecf Feb 22, 2024
4889576
Box Builds
Colecf Feb 22, 2024
b1213e6
Switch to FxHashMap and deallocate scopes in parallel
Colecf Feb 22, 2024
ec38455
Defer build binding evaluation
Colecf Feb 22, 2024
d10ab6d
Don't own the unevaluated build ins/outs
Colecf Feb 22, 2024
4389ee7
Remove executor argument
Colecf Feb 23, 2024
49e371a
Put unevaluated build ins/outs in 1 vec
Colecf Feb 23, 2024
983f498
Make the files map use FxHasher
Colecf Feb 24, 2024
9212a9b
Use unwrap_err_unchecked in Scope::evaluate
Colecf Feb 26, 2024
5fdd13c
Unmap files in parallel
Colecf Feb 26, 2024
86dacb3
Call format_parse_error again
Colecf Feb 26, 2024
d9d54f9
Fix bug in evaluation order
Colecf Feb 27, 2024
01c246d
Add a test for subninjas
Colecf Feb 27, 2024
a99843a
Double parse evalstrings
Colecf Feb 17, 2024
1718839
owned evalstring parsing
Colecf Feb 27, 2024
04ec995
Fix bug where build paths were evaluated an extra time
Colecf Feb 28, 2024
0d9bf01
Cleanup and prepare for submitting
Colecf Feb 28, 2024
98867a2
Fall back to reading instead of mmap on windows
Colecf Feb 28, 2024
9cc13a8
Update rust to 1.73.0
Colecf Feb 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:

steps:
- uses: actions/checkout@v2
- uses: dtolnay/rust-toolchain@1.70.0
- uses: dtolnay/rust-toolchain@1.73.0
with:
components: rustfmt
- name: Check formatting
Expand Down
64 changes: 60 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ readme = "README.md"
repository = "https://github.com/evmar/n2"
# https://github.com/evmar/n2/issues/74
# Note: if we bump this, may need to bump .github/workflows/ci.yml version too.
rust-version = "1.70.0"
rust-version = "1.73.0"
description = "a ninja compatible build system"

[dependencies]
anyhow = "1.0"
argh = "0.1.10"
dashmap = "5.5.3"
libc = "0.2"
rayon = "1.8.1"
rustc-hash = "1.1.0"

[target.'cfg(windows)'.dependencies.windows-sys]
Expand Down
133 changes: 133 additions & 0 deletions src/concurrent_linked_list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
use std::{
borrow::Borrow,
fmt::Debug,
marker::PhantomData,
ptr::null_mut,
sync::atomic::{AtomicPtr, Ordering},
};

/// ConcurrentLinkedList is a linked list that can only be prepended to or
/// iterated over. prepend() accepts an &self instead of an &mut self, and can
/// be called from multiple threads at the same time.
pub struct ConcurrentLinkedList<T> {
head: AtomicPtr<ConcurrentLinkedListNode<T>>,
}

struct ConcurrentLinkedListNode<T> {
val: T,
next: *mut ConcurrentLinkedListNode<T>,
}

impl<T> ConcurrentLinkedList<T> {
pub fn new() -> Self {
ConcurrentLinkedList {
head: AtomicPtr::new(null_mut()),
}
}

pub fn prepend(&self, val: T) {
let new_head = Box::into_raw(Box::new(ConcurrentLinkedListNode {
val,
next: null_mut(),
}));
loop {
let old_head = self.head.load(Ordering::SeqCst);
unsafe {
(*new_head).next = old_head;
if self
.head
.compare_exchange_weak(old_head, new_head, Ordering::SeqCst, Ordering::SeqCst)
.is_ok()
{
break;
}
}
}
}

pub fn iter(&self) -> impl Iterator<Item = &T> {
ConcurrentLinkedListIterator {
cur: self.head.load(Ordering::Relaxed),
lifetime: PhantomData,
}
}
}

impl<T> Default for ConcurrentLinkedList<T> {
fn default() -> Self {
Self {
head: Default::default(),
}
}
}

impl<T: Clone> Clone for ConcurrentLinkedList<T> {
fn clone(&self) -> Self {
let mut iter = self.iter();
match iter.next() {
None => Self {
head: AtomicPtr::new(null_mut()),
},
Some(x) => {
let new_head = Box::into_raw(Box::new(ConcurrentLinkedListNode {
val: x.clone(),
next: null_mut(),
}));
let mut new_tail = new_head;
for x in iter {
unsafe {
(*new_tail).next = Box::into_raw(Box::new(ConcurrentLinkedListNode {
val: x.clone(),
next: null_mut(),
}));
new_tail = (*new_tail).next;
}
}
Self {
head: AtomicPtr::new(new_head),
}
}
}
}
}

impl<T: Debug> Debug for ConcurrentLinkedList<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Slow, but hopefully Debug is only used for actual debugging
f.write_fmt(format_args!("{:?}", self.iter().collect::<Vec<_>>()))
}
}

impl<T> Drop for ConcurrentLinkedList<T> {
fn drop(&mut self) {
let mut cur = self.head.swap(null_mut(), Ordering::Relaxed);
while !cur.is_null() {
unsafe {
// Re-box it so that box will call Drop and deallocate the memory
let boxed = Box::from_raw(cur);
cur = boxed.next;
}
}
}
}

struct ConcurrentLinkedListIterator<'a, T> {
cur: *const ConcurrentLinkedListNode<T>,
lifetime: PhantomData<&'a ()>,
}

impl<'a, T: 'a> Iterator for ConcurrentLinkedListIterator<'a, T> {
type Item = &'a T;

fn next(&mut self) -> Option<Self::Item> {
if self.cur.is_null() {
None
} else {
unsafe {
let result = Some((*self.cur).val.borrow());
self.cur = (*self.cur).next;
result
}
}
}
}
Loading