Reduce lock contention (round 1)
- Use an async (i.e. unlimited buffer) MPSC channel instead of an Arc<Mutex<Vec>> for storing the scored matches in Sorter - Use Arc<Matcher> instead of Arc<Mutex<Matcher>> for the matcher, as it's not mutated and appears to be threadsafe. This cuts average iteration time (on the benchmarked machine) from 25.98ms to 16.08ms for the ivy_files benchmark.
This commit is contained in:
parent
ce28b248fa
commit
7fb8be541a
3 changed files with 26 additions and 17 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -5,3 +5,4 @@ compile_commands.json
|
||||||
.luacheckcache
|
.luacheckcache
|
||||||
benchmarks
|
benchmarks
|
||||||
flamegraph*
|
flamegraph*
|
||||||
|
perf.data*
|
||||||
|
|
|
||||||
|
|
@ -66,18 +66,19 @@ pub extern "C" fn ivy_files(c_pattern: *const c_char, c_base_dir: *const c_char)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner_files(pattern: String, base_dir: String) -> String {
|
pub fn inner_files(pattern: String, base_dir: String) -> String {
|
||||||
// Bail out early if the pattern is empty its never going to find anything
|
let mut output = String::new();
|
||||||
|
|
||||||
|
// Bail out early if the pattern is empty; it's never going to find anything
|
||||||
if pattern.is_empty() {
|
if pattern.is_empty() {
|
||||||
return String::new();
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
let files = get_files(&base_dir);
|
let files = get_files(&base_dir);
|
||||||
|
|
||||||
let mut output = String::new();
|
|
||||||
let sorter_options = sorter::Options::new(pattern);
|
let sorter_options = sorter::Options::new(pattern);
|
||||||
|
|
||||||
let files = sorter::sort_strings(sorter_options, files);
|
let files = sorter::sort_strings(sorter_options, files);
|
||||||
for file in files.lock().unwrap().iter() {
|
for file in files.iter() {
|
||||||
output.push_str(&file.content);
|
output.push_str(&file.content);
|
||||||
output.push('\n');
|
output.push('\n');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use super::matcher;
|
use super::matcher;
|
||||||
use super::thread_pool;
|
use super::thread_pool;
|
||||||
|
|
||||||
|
use std::sync::mpsc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
pub struct Match {
|
pub struct Match {
|
||||||
pub score: i64,
|
pub score: i64,
|
||||||
|
|
@ -23,30 +23,37 @@ impl Options {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sort_strings(options: Options, strings: Vec<String>) -> Arc<Mutex<Vec<Match>>> {
|
pub fn sort_strings(options: Options, strings: Vec<String>) -> Vec<Match> {
|
||||||
let matches: Arc<Mutex<Vec<Match>>> = Arc::new(Mutex::new(Vec::new()));
|
let mut matches = Vec::new();
|
||||||
let matcher = Arc::new(Mutex::new(matcher::Matcher::new(options.pattern)));
|
let matcher = Arc::new(matcher::Matcher::new(options.pattern));
|
||||||
|
|
||||||
let pool = thread_pool::ThreadPool::new(std::thread::available_parallelism().unwrap().get());
|
let pool = thread_pool::ThreadPool::new(std::thread::available_parallelism().unwrap().get());
|
||||||
|
|
||||||
|
let (tx, rx) = mpsc::channel::<Match>();
|
||||||
|
|
||||||
for string in strings {
|
for string in strings {
|
||||||
let thread_matcher = Arc::clone(&matcher);
|
let thread_matcher = Arc::clone(&matcher);
|
||||||
let thread_matches = Arc::clone(&matches);
|
let thread_transmitter = tx.clone();
|
||||||
pool.execute(move || {
|
pool.execute(move || {
|
||||||
let score = thread_matcher.lock().unwrap().score(string.to_string());
|
let score = thread_matcher.score(string.to_string());
|
||||||
if score > 25 {
|
if score > 25 {
|
||||||
let mut tmp = thread_matches.lock().unwrap();
|
thread_transmitter
|
||||||
let content = string.clone();
|
.send(Match {
|
||||||
tmp.push(Match { score, content });
|
score,
|
||||||
|
content: string,
|
||||||
|
})
|
||||||
|
.expect("Failed to push data to channel");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(pool);
|
drop(pool);
|
||||||
|
drop(tx);
|
||||||
|
|
||||||
matches
|
while let Ok(result) = rx.recv() {
|
||||||
.lock()
|
matches.push(result)
|
||||||
.unwrap()
|
}
|
||||||
.sort_by(|a, b| a.score.cmp(&b.score));
|
|
||||||
|
matches.sort_by(|a, b| a.score.cmp(&b.score));
|
||||||
matches
|
matches
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue