Skip to content

Commit 0885b30

Browse files
committed
benchmarking jwalk and serial
1 parent daacced commit 0885b30

File tree

4 files changed

+162
-12
lines changed

4 files changed

+162
-12
lines changed

Cargo.lock

Lines changed: 44 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ enum_dispatch = "0.3.13"
1717
fast-glob = "0.4.0"
1818
ignore = "0.4.23"
1919
itertools = "0.13.0"
20+
jwalk = "0.8.1"
2021
lazy_static = "1.5.0"
2122
path-clean = "1.0.1"
2223
rayon = "1.10.0"

dev/run_benchmarks.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@ echo "To run these benchmarks on your application, you can place this repo next
99

1010
hyperfine --warmup=2 --runs=3 --export-markdown tmp/codeowners_benchmarks.md \
1111
'../rubyatscale/codeowners-rs/target/release/codeowners gv' \
12-
'bin/codeowners-rs gv'
12+
'jwalk=1 ../rubyatscale/codeowners-rs/target/release/codeowners gv' \
13+
'jwalk=1 entryrayon=1 ../rubyatscale/codeowners-rs/target/release/codeowners gv' \
14+
'entryrayon=1 ../rubyatscale/codeowners-rs/target/release/codeowners gv' \
15+
'bin/codeowners-rs gv'

src/project_builder.rs

Lines changed: 113 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use std::{
2-
fs::File,
3-
path::{Path, PathBuf},
2+
env, fs::File, path::{Path, PathBuf}
43
};
54

65
use error_stack::{Result, ResultExt};
76
use fast_glob::glob_match;
87
use ignore::WalkBuilder;
8+
use jwalk::WalkDir;
99
use rayon::iter::{IntoParallelIterator, ParallelIterator};
1010
use tracing::instrument;
1111

@@ -50,22 +50,46 @@ impl<'a> ProjectBuilder<'a> {
5050

5151
#[instrument(level = "debug", skip_all)]
5252
pub fn build(&mut self) -> Result<Project, Error> {
53+
match env::var("jwalk") {
54+
Ok(_) => self.build_with_jwalk(),
55+
Err(_) => self.build_with_walkdir(),
56+
}
57+
}
58+
59+
fn build_with_jwalk(&mut self) -> Result<Project, Error> {
60+
dbg!("building with jwalk");
61+
let mut entry_types = Vec::with_capacity(INITIAL_VECTOR_CAPACITY);
62+
63+
for entry in WalkDir::new(&self.base_path).follow_links(true).skip_hidden(false).into_iter() {
64+
let entry = match entry.change_context(Error::Io) {
65+
Ok(entry) => entry,
66+
Err(_) => continue,
67+
};
68+
let absolute_path = entry.path();
69+
let is_dir = entry.file_type().is_dir();
70+
entry_types.push(self.build_entry_type(&absolute_path, is_dir)?);
71+
}
72+
self.build_project_from_entry_types(entry_types)
73+
}
74+
75+
fn build_with_walkdir(&mut self) -> Result<Project, Error> {
76+
dbg!("building with walkdir");
5377
let mut entry_types = Vec::with_capacity(INITIAL_VECTOR_CAPACITY);
5478
let mut builder = WalkBuilder::new(&self.base_path);
5579
builder.hidden(false);
5680
let walkdir = builder.build();
5781

5882
for entry in walkdir {
5983
let entry = entry.change_context(Error::Io)?;
60-
entry_types.push(self.build_entry_type(entry)?);
84+
let absolute_path = entry.path();
85+
let is_dir = entry.file_type().ok_or(Error::Io).change_context(Error::Io)?.is_dir();
86+
87+
entry_types.push(self.build_entry_type(absolute_path, is_dir)?);
6188
}
6289
self.build_project_from_entry_types(entry_types)
6390
}
6491

65-
fn build_entry_type(&mut self, entry: ignore::DirEntry) -> Result<EntryType, Error> {
66-
let absolute_path = entry.path();
67-
68-
let is_dir = entry.file_type().ok_or(Error::Io).change_context(Error::Io)?.is_dir();
92+
fn build_entry_type(&mut self, absolute_path: &Path, is_dir: bool) -> Result<EntryType, Error> {
6993
let relative_path = absolute_path.strip_prefix(&self.base_path).change_context(Error::Io)?.to_owned();
7094

7195
if is_dir {
@@ -97,6 +121,88 @@ impl<'a> ProjectBuilder<'a> {
97121
}
98122

99123
fn build_project_from_entry_types(&mut self, entry_types: Vec<EntryType>) -> Result<Project, Error> {
124+
match env::var("entryrayon") {
125+
Ok(_) => self.build_project_from_entry_types_rayon(entry_types),
126+
Err(_) => self.build_project_from_entry_types_serial(entry_types),
127+
}
128+
}
129+
130+
fn build_project_from_entry_types_serial(&mut self, entry_types: Vec<EntryType>) -> Result<Project, Error> {
131+
dbg!("building with serial");
132+
let mut project_files = Vec::<ProjectFile>::with_capacity(INITIAL_VECTOR_CAPACITY);
133+
let mut vendored_gems = Vec::<VendoredGem>::new();
134+
let mut packages = Vec::<Package>::new();
135+
let mut directory_codeowner_files = Vec::<DirectoryCodeownersFile>::new();
136+
let mut teams = Vec::<Team>::new();
137+
138+
for entry_type in entry_types {
139+
match entry_type {
140+
EntryType::OwnedFile(project_file) => {
141+
project_files.push(project_file);
142+
}
143+
EntryType::Directory(absolute_path, relative_path) => {
144+
if relative_path.parent() == Some(Path::new(&self.config.vendored_gems_path)) {
145+
let file_name = relative_path.file_name().expect("expected a file_name");
146+
vendored_gems.push(VendoredGem {
147+
path: absolute_path,
148+
name: file_name.to_string_lossy().to_string(),
149+
});
150+
}
151+
}
152+
EntryType::RubyPackage(absolute_path, relative_path) => {
153+
if let Some(owner) = ruby_package_owner(&absolute_path).unwrap() {
154+
packages.push(Package {
155+
path: relative_path.clone(),
156+
owner,
157+
package_type: PackageType::Ruby,
158+
});
159+
}
160+
}
161+
EntryType::JavascriptPackage(absolute_path, relative_path) => {
162+
if let Some(owner) = javascript_package_owner(&absolute_path).unwrap() {
163+
packages.push(Package {
164+
path: relative_path.clone(),
165+
owner,
166+
package_type: PackageType::Javascript,
167+
});
168+
}
169+
}
170+
EntryType::CodeownerFile(absolute_path, relative_path) => {
171+
let owner = std::fs::read_to_string(absolute_path).unwrap();
172+
let owner = owner.trim().to_owned();
173+
directory_codeowner_files.push(DirectoryCodeownersFile {
174+
path: relative_path.clone(),
175+
owner,
176+
});
177+
}
178+
EntryType::TeamFile(absolute_path, _relative_path) => {
179+
let file = File::open(&absolute_path).unwrap();
180+
let deserializer: deserializers::Team = serde_yaml::from_reader(file).unwrap();
181+
teams.push(Team {
182+
path: absolute_path.to_owned(),
183+
name: deserializer.name,
184+
github_team: deserializer.github.team,
185+
owned_globs: deserializer.owned_globs,
186+
owned_gems: deserializer.ruby.map(|ruby| ruby.owned_gems).unwrap_or_default(),
187+
avoid_ownership: deserializer.github.do_not_add_to_codeowners_file,
188+
});
189+
}
190+
EntryType::NullEntry() => {}
191+
}
192+
}
193+
Ok(Project {
194+
base_path: self.base_path.to_owned(),
195+
files: project_files,
196+
vendored_gems,
197+
teams,
198+
packages,
199+
codeowners_file_path: self.codeowners_file_path.to_path_buf(),
200+
directory_codeowner_files,
201+
})
202+
}
203+
204+
fn build_project_from_entry_types_rayon(&mut self, entry_types: Vec<EntryType>) -> Result<Project, Error> {
205+
dbg!("building entry types with rayon");
100206
let (project_files, packages, vendored_gems, directory_codeowners, teams): (Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>) = entry_types
101207
.into_par_iter()
102208
.fold(

0 commit comments

Comments
 (0)