From 838f4b76537a4afc704595a8c7319f3a01b5317f Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 27 Jul 2020 08:23:06 -0700 Subject: [PATCH 1/7] Make `Dir::copy` take a second `Dir` for the destination. --- cap-async-std/src/fs/dir.rs | 4 ++-- cap-async-std/src/fs_utf8/dir.rs | 4 ++-- src/fs/dir.rs | 4 ++-- src/fs_utf8/dir.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cap-async-std/src/fs/dir.rs b/cap-async-std/src/fs/dir.rs index b4b0ecda..73e7ad8c 100644 --- a/cap-async-std/src/fs/dir.rs +++ b/cap-async-std/src/fs/dir.rs @@ -206,7 +206,7 @@ impl Dir { /// /// [`async_std::fs::copy`]: https://docs.rs/async-std/latest/async_std/fs/fn.copy.html #[inline] - pub async fn copy, Q: AsRef>(&self, from: P, to: Q) -> io::Result { + pub async fn copy, Q: AsRef>(&self, from: P, to_dir: &Self, to: Q) -> io::Result { // Implementation derived from `copy` in Rust's // src/libstd/sys_common/fs.rs at revision // 7e11379f3b4c376fbb9a6c4d44f3286ccc28d149. @@ -221,7 +221,7 @@ impl Dir { } let mut reader = self.open(from)?; - let mut writer = self.create(to.as_ref())?; + let mut writer = to_dir.create(to.as_ref())?; let perm = reader.metadata().await?.permissions(); let ret = io::copy(&mut reader, &mut writer).await?; diff --git a/cap-async-std/src/fs_utf8/dir.rs b/cap-async-std/src/fs_utf8/dir.rs index df3413ad..789eb170 100644 --- a/cap-async-std/src/fs_utf8/dir.rs +++ b/cap-async-std/src/fs_utf8/dir.rs @@ -149,10 +149,10 @@ impl Dir { /// /// [`async_std::fs::copy`]: https://docs.rs/async-std/latest/async_std/fs/fn.copy.html #[inline] - pub async fn copy, Q: AsRef>(&self, from: P, to: Q) -> io::Result { + pub async fn copy, Q: AsRef>(&self, from: P, to_dir: &Self, to: Q) -> io::Result { let from = from_utf8(from)?; let to = from_utf8(to)?; - self.cap_std.copy(from, to).await + self.cap_std.copy(from, &to_dir.cap_std, to).await } /// Creates a new hard link on a filesystem. diff --git a/src/fs/dir.rs b/src/fs/dir.rs index 08bdcae6..9d76a38e 100644 --- a/src/fs/dir.rs +++ b/src/fs/dir.rs @@ -199,7 +199,7 @@ impl Dir { /// /// [`std::fs::copy`]: https://doc.rust-lang.org/std/fs/fn.copy.html #[inline] - pub fn copy, Q: AsRef>(&self, from: P, to: Q) -> io::Result { + pub fn copy, Q: AsRef>(&self, from: P, to_dir: &Self, to: Q) -> io::Result { // Implementation derived from `copy` in Rust's // src/libstd/sys_common/fs.rs at revision // 7e11379f3b4c376fbb9a6c4d44f3286ccc28d149. @@ -214,7 +214,7 @@ impl Dir { } let mut reader = self.open(from)?; - let mut writer = self.create(to.as_ref())?; + let mut writer = to_dir.create(to.as_ref())?; let perm = reader.metadata()?.permissions(); let ret = io::copy(&mut reader, &mut writer)?; diff --git a/src/fs_utf8/dir.rs b/src/fs_utf8/dir.rs index c5215ece..a8e7d430 100644 --- a/src/fs_utf8/dir.rs +++ b/src/fs_utf8/dir.rs @@ -148,10 +148,10 @@ impl Dir { /// /// [`std::fs::copy`]: https://doc.rust-lang.org/std/fs/fn.copy.html #[inline] - pub fn copy, Q: AsRef>(&self, from: P, to: Q) -> io::Result { + pub fn copy, Q: AsRef>(&self, from: P, to_dir: &Self, to: Q) -> io::Result { let from = from_utf8(from)?; let to = from_utf8(to)?; - self.cap_std.copy(from, to) + self.cap_std.copy(from, &to_dir.cap_std, to) } /// Creates a new hard link on a filesystem. From c862d2460327720c0b85945e2d6ebd79e4cfd19d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 27 Jul 2020 08:57:20 -0700 Subject: [PATCH 2/7] Add some basic `cargo bench` benchmarks. --- Cargo.toml | 1 + benches/mod.rs | 404 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 405 insertions(+) create mode 100644 benches/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 8bd01e42..2f16d5da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ yanix = "0.19.0" rand = "0.7.3" cap-tempfile = { path = "cap-tempfile", version = "0.0.0" } cap-directories = { path = "cap-directories", version = "0.0.0" } +tempfile = "3.1.0" [target.'cfg(not(windows))'.dev-dependencies] libc = "0.2.72" diff --git a/benches/mod.rs b/benches/mod.rs new file mode 100644 index 00000000..74e5e594 --- /dev/null +++ b/benches/mod.rs @@ -0,0 +1,404 @@ +//! Microbenchmarks for `cap_std`. These have pathological behavior and are +//! not representative of typical real-world use cases. + +#![feature(test)] + +extern crate cap_tempfile; +extern crate tempfile; +extern crate test; + +use std::{fs, path::PathBuf}; + +#[bench] +fn nested_directories_open(b: &mut test::Bencher) { + let dir = cap_tempfile::tempdir().unwrap(); + + let mut path = PathBuf::new(); + for _ in 0..256 { + path.push("abc"); + } + dir.create_dir_all(&path).unwrap(); + + b.iter(|| { + let _file = dir.open(&path).unwrap(); + }); +} + +#[bench] +fn nested_directories_open_baseline(b: &mut test::Bencher) { + let dir = tempfile::tempdir().unwrap(); + + let mut path = PathBuf::new(); + for _ in 0..256 { + path.push("abc"); + } + fs::create_dir_all(dir.path().join(&path)).unwrap(); + + b.iter(|| { + let _file = fs::File::open(dir.path().join(&path)).unwrap(); + }); +} + +#[bench] +fn nested_directories_metadata(b: &mut test::Bencher) { + let dir = cap_tempfile::tempdir().unwrap(); + + let mut path = PathBuf::new(); + for _ in 0..256 { + path.push("abc"); + } + dir.create_dir_all(&path).unwrap(); + + b.iter(|| { + let _metadata = dir.metadata(&path).unwrap(); + }); +} + +#[bench] +fn nested_directories_metadata_baseline(b: &mut test::Bencher) { + let dir = tempfile::tempdir().unwrap(); + + let mut path = PathBuf::new(); + path.push(dir); + for _ in 0..256 { + path.push("abc"); + } + fs::create_dir_all(&path).unwrap(); + + b.iter(|| { + let _metadata = fs::metadata(&path).unwrap(); + }); +} + +#[cfg(unix)] +#[bench] +fn nested_directories_readlink(b: &mut test::Bencher) { + let dir = cap_tempfile::tempdir().unwrap(); + + let mut path = PathBuf::new(); + for _ in 0..256 { + path.push("abc"); + } + dir.create_dir_all(&path).unwrap(); + + path.push("symlink"); + dir.symlink("source", &path).unwrap(); + + b.iter(|| { + let _destination = dir.read_link(&path).unwrap(); + }); +} + +#[cfg(unix)] +#[bench] +fn nested_directories_readlink_baseline(b: &mut test::Bencher) { + use std::os::unix::fs::symlink; + + let dir = tempfile::tempdir().unwrap(); + + let mut path = PathBuf::new(); + path.push(dir); + for _ in 0..256 { + path.push("abc"); + } + fs::create_dir_all(&path).unwrap(); + + path.push("symlink"); + symlink("source", &path).unwrap(); + + b.iter(|| { + let _destination = fs::read_link(&path).unwrap(); + }); +} + +#[bench] +fn curdir(b: &mut test::Bencher) { + let dir = cap_tempfile::tempdir().unwrap(); + + let mut path = PathBuf::new(); + for _ in 0..256 { + path.push("."); + } + path.push("def"); + dir.create("def").unwrap(); + + b.iter(|| { + let _file = dir.open(&path).unwrap(); + }); +} + +#[bench] +fn curdir_baseline(b: &mut test::Bencher) { + let dir = tempfile::tempdir().unwrap(); + + let mut path = PathBuf::new(); + path.push(&dir); + for _ in 0..256 { + path.push("."); + } + path.push("def"); + fs::File::create(dir.path().join("def")).unwrap(); + + b.iter(|| { + let _file = fs::File::open(&path).unwrap(); + }); +} + +#[bench] +fn parentdir(b: &mut test::Bencher) { + let dir = cap_tempfile::tempdir().unwrap(); + + let mut path = PathBuf::new(); + for _ in 0..256 { + path.push("abc"); + } + dir.create_dir_all(&path).unwrap(); + + for _ in 0..256 { + path.push(".."); + } + path.push("def"); + dir.create("def").unwrap(); + + b.iter(|| { + let _file = dir.open(&path).unwrap(); + }); +} + +#[bench] +fn parentdir_baseline(b: &mut test::Bencher) { + let dir = tempfile::tempdir().unwrap(); + + let mut path = PathBuf::new(); + path.push(&dir); + for _ in 0..256 { + path.push("abc"); + } + fs::create_dir_all(&path).unwrap(); + + for _ in 0..256 { + path.push(".."); + } + path.push("def"); + fs::File::create(dir.path().join("def")).unwrap(); + + b.iter(|| { + let _file = fs::File::open(&path).unwrap(); + }); +} + +#[bench] +fn directory_iteration(b: &mut test::Bencher) { + let dir = cap_tempfile::tempdir().unwrap(); + + for i in 0..256 { + dir.create(i.to_string()).unwrap(); + } + + b.iter(|| { + for entry in dir.entries().unwrap() { + let _file = dir.open(entry.unwrap().file_name()).unwrap(); + } + }); +} + +#[bench] +fn directory_iteration_fast(b: &mut test::Bencher) { + let dir = cap_tempfile::tempdir().unwrap(); + + for i in 0..256 { + dir.create(i.to_string()).unwrap(); + } + + b.iter(|| { + for entry in dir.entries().unwrap() { + let _file = entry.unwrap().open().unwrap(); + } + }); +} + +#[bench] +fn directory_iteration_baseline(b: &mut test::Bencher) { + let dir = tempfile::tempdir().unwrap(); + + for i in 0..256 { + fs::File::create(dir.path().join(i.to_string())).unwrap(); + } + + b.iter(|| { + for entry in fs::read_dir(&dir).unwrap() { + let _file = fs::File::open(dir.path().join(entry.unwrap().file_name())).unwrap(); + } + }); +} + +#[cfg(unix)] +#[bench] +fn symlink_chasing_open(b: &mut test::Bencher) { + let dir = cap_tempfile::tempdir().unwrap(); + + dir.create("0").unwrap(); + for i in 0..32 { + dir.symlink(i.to_string(), (i + 1).to_string()).unwrap(); + } + + let name = "32"; + b.iter(|| { + let _file = dir.open(name).unwrap(); + }); +} + +#[cfg(unix)] +#[bench] +fn symlink_chasing_open_baseline(b: &mut test::Bencher) { + use std::os::unix::fs::symlink; + + let dir = tempfile::tempdir().unwrap(); + + fs::File::create(dir.path().join("0")).unwrap(); + for i in 0..32 { + symlink(dir.path().join(i.to_string()), dir.path().join((i + 1).to_string())).unwrap(); + } + + let name = dir.path().join("32"); + b.iter(|| { + let _file = fs::File::open(&name).unwrap(); + }); +} + +#[cfg(unix)] +#[bench] +fn symlink_chasing_metadata(b: &mut test::Bencher) { + let dir = cap_tempfile::tempdir().unwrap(); + + dir.create("0").unwrap(); + for i in 0..32 { + dir.symlink(i.to_string(), (i + 1).to_string()).unwrap(); + } + + let name = "32"; + b.iter(|| { + let _metadata = dir.metadata(name).unwrap(); + }); +} + +#[cfg(unix)] +#[bench] +fn symlink_chasing_metadata_baseline(b: &mut test::Bencher) { + use std::os::unix::fs::symlink; + + let dir = tempfile::tempdir().unwrap(); + + fs::File::create(dir.path().join("0")).unwrap(); + for i in 0..32 { + symlink(dir.path().join(i.to_string()), dir.path().join((i + 1).to_string())).unwrap(); + } + + let name = dir.path().join("32"); + b.iter(|| { + let _metadata = fs::metadata(&name).unwrap(); + }); +} + +#[bench] +fn recursive_create_delete(b: &mut test::Bencher) { + let dir = cap_tempfile::tempdir().unwrap(); + + let mut path = PathBuf::new(); + for _ in 0..256 { + path.push("abc"); + } + + b.iter(|| { + dir.create_dir_all(&path).unwrap(); + dir.remove_dir_all(&path).unwrap(); + }); +} + +#[bench] +fn recursive_create_delete_baseline(b: &mut test::Bencher) { + let dir = tempfile::tempdir().unwrap(); + + let mut path = PathBuf::new(); + path.push(dir); + for _ in 0..256 { + path.push("abc"); + } + + b.iter(|| { + fs::create_dir_all(&path).unwrap(); + fs::remove_dir_all(&path).unwrap(); + }); +} + +#[bench] +fn copy_4b(b: &mut test::Bencher) { + let dir = cap_tempfile::tempdir().unwrap(); + + dir.write("file", &vec![1u8; 0x4]).unwrap(); + + b.iter(|| { + dir.copy("file", &dir, "copy").unwrap(); + }); +} + +#[bench] +fn copy_4b_baseline(b: &mut test::Bencher) { + let dir = tempfile::tempdir().unwrap(); + + let file = dir.path().join("file"); + let copy = dir.path().join("copy"); + fs::write(&file, &vec![1u8; 0x4]).unwrap(); + + b.iter(|| { + fs::copy(&file, ©).unwrap(); + }); +} + +#[bench] +fn copy_4k(b: &mut test::Bencher) { + let dir = cap_tempfile::tempdir().unwrap(); + + dir.write("file", &vec![1u8; 0x1000]).unwrap(); + + b.iter(|| { + dir.copy("file", &dir, "copy").unwrap(); + }); +} + +#[bench] +fn copy_4k_baseline(b: &mut test::Bencher) { + let dir = tempfile::tempdir().unwrap(); + + let file = dir.path().join("file"); + let copy = dir.path().join("copy"); + fs::write(&file, &vec![1u8; 0x1000]).unwrap(); + + b.iter(|| { + fs::copy(&file, ©).unwrap(); + }); +} + +#[bench] +fn copy_4m(b: &mut test::Bencher) { + let dir = cap_tempfile::tempdir().unwrap(); + + dir.write("file", &vec![1u8; 0x400000]).unwrap(); + + b.iter(|| { + dir.copy("file", &dir, "copy").unwrap(); + }); +} + +#[bench] +fn copy_4m_baseline(b: &mut test::Bencher) { + let dir = tempfile::tempdir().unwrap(); + + let file = dir.path().join("file"); + let copy = dir.path().join("copy"); + fs::write(&file, &vec![1u8; 0x400000]).unwrap(); + + b.iter(|| { + fs::copy(&file, ©).unwrap(); + }); +} From 4e614188b8b4c8a26d614897b701063faaa1548e Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 27 Jul 2020 12:04:51 -0700 Subject: [PATCH 3/7] Add a note about the benchmarks in CONTRIBUTING.md. --- CONTRIBUTING.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2942639a..1494cc9a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,3 +34,15 @@ To run the `cap-primitives` fuzzer, run: cargo +nightly fuzz run cap-primitives ``` +## Benchmarking + +There are several micro-benchmarks for the `cap-std` crate which stress-test +specific API features. As micro-benchmarks, they aren't representative of +real-world use, but they are useful for development of `cap-std`. + +To run the `cap-std` benchmarks, run: + +``` +cargo +nightly bench +``` + From dbdefc7037258149b1424e19c8c36f59ca293efc Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 27 Jul 2020 12:07:25 -0700 Subject: [PATCH 4/7] Disable the fast-dir-iteration benchmark for now. --- benches/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/benches/mod.rs b/benches/mod.rs index 74e5e594..e3ea7dde 100644 --- a/benches/mod.rs +++ b/benches/mod.rs @@ -202,6 +202,7 @@ fn directory_iteration(b: &mut test::Bencher) { }); } +/* TODO: This depends on https://github.com/sunfishcode/cap-std/pull/72 #[bench] fn directory_iteration_fast(b: &mut test::Bencher) { let dir = cap_tempfile::tempdir().unwrap(); @@ -216,6 +217,7 @@ fn directory_iteration_fast(b: &mut test::Bencher) { } }); } +*/ #[bench] fn directory_iteration_baseline(b: &mut test::Bencher) { From cd6709f2347b0946e829d2cf90d607a8fb475a48 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 27 Jul 2020 12:21:47 -0700 Subject: [PATCH 5/7] rustfmt --- benches/mod.rs | 20 ++++++++++++++------ cap-async-std/src/fs/dir.rs | 7 ++++++- cap-async-std/src/fs_utf8/dir.rs | 7 ++++++- src/fs/dir.rs | 7 ++++++- src/fs_utf8/dir.rs | 7 ++++++- 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/benches/mod.rs b/benches/mod.rs index e3ea7dde..f75d2d3f 100644 --- a/benches/mod.rs +++ b/benches/mod.rs @@ -246,7 +246,7 @@ fn symlink_chasing_open(b: &mut test::Bencher) { let name = "32"; b.iter(|| { - let _file = dir.open(name).unwrap(); + let _file = dir.open(name).unwrap(); }); } @@ -259,12 +259,16 @@ fn symlink_chasing_open_baseline(b: &mut test::Bencher) { fs::File::create(dir.path().join("0")).unwrap(); for i in 0..32 { - symlink(dir.path().join(i.to_string()), dir.path().join((i + 1).to_string())).unwrap(); + symlink( + dir.path().join(i.to_string()), + dir.path().join((i + 1).to_string()), + ) + .unwrap(); } let name = dir.path().join("32"); b.iter(|| { - let _file = fs::File::open(&name).unwrap(); + let _file = fs::File::open(&name).unwrap(); }); } @@ -280,7 +284,7 @@ fn symlink_chasing_metadata(b: &mut test::Bencher) { let name = "32"; b.iter(|| { - let _metadata = dir.metadata(name).unwrap(); + let _metadata = dir.metadata(name).unwrap(); }); } @@ -293,12 +297,16 @@ fn symlink_chasing_metadata_baseline(b: &mut test::Bencher) { fs::File::create(dir.path().join("0")).unwrap(); for i in 0..32 { - symlink(dir.path().join(i.to_string()), dir.path().join((i + 1).to_string())).unwrap(); + symlink( + dir.path().join(i.to_string()), + dir.path().join((i + 1).to_string()), + ) + .unwrap(); } let name = dir.path().join("32"); b.iter(|| { - let _metadata = fs::metadata(&name).unwrap(); + let _metadata = fs::metadata(&name).unwrap(); }); } diff --git a/cap-async-std/src/fs/dir.rs b/cap-async-std/src/fs/dir.rs index 73e7ad8c..f2901186 100644 --- a/cap-async-std/src/fs/dir.rs +++ b/cap-async-std/src/fs/dir.rs @@ -206,7 +206,12 @@ impl Dir { /// /// [`async_std::fs::copy`]: https://docs.rs/async-std/latest/async_std/fs/fn.copy.html #[inline] - pub async fn copy, Q: AsRef>(&self, from: P, to_dir: &Self, to: Q) -> io::Result { + pub async fn copy, Q: AsRef>( + &self, + from: P, + to_dir: &Self, + to: Q, + ) -> io::Result { // Implementation derived from `copy` in Rust's // src/libstd/sys_common/fs.rs at revision // 7e11379f3b4c376fbb9a6c4d44f3286ccc28d149. diff --git a/cap-async-std/src/fs_utf8/dir.rs b/cap-async-std/src/fs_utf8/dir.rs index 789eb170..6cbb044c 100644 --- a/cap-async-std/src/fs_utf8/dir.rs +++ b/cap-async-std/src/fs_utf8/dir.rs @@ -149,7 +149,12 @@ impl Dir { /// /// [`async_std::fs::copy`]: https://docs.rs/async-std/latest/async_std/fs/fn.copy.html #[inline] - pub async fn copy, Q: AsRef>(&self, from: P, to_dir: &Self, to: Q) -> io::Result { + pub async fn copy, Q: AsRef>( + &self, + from: P, + to_dir: &Self, + to: Q, + ) -> io::Result { let from = from_utf8(from)?; let to = from_utf8(to)?; self.cap_std.copy(from, &to_dir.cap_std, to).await diff --git a/src/fs/dir.rs b/src/fs/dir.rs index 9d76a38e..0ca8cb7a 100644 --- a/src/fs/dir.rs +++ b/src/fs/dir.rs @@ -199,7 +199,12 @@ impl Dir { /// /// [`std::fs::copy`]: https://doc.rust-lang.org/std/fs/fn.copy.html #[inline] - pub fn copy, Q: AsRef>(&self, from: P, to_dir: &Self, to: Q) -> io::Result { + pub fn copy, Q: AsRef>( + &self, + from: P, + to_dir: &Self, + to: Q, + ) -> io::Result { // Implementation derived from `copy` in Rust's // src/libstd/sys_common/fs.rs at revision // 7e11379f3b4c376fbb9a6c4d44f3286ccc28d149. diff --git a/src/fs_utf8/dir.rs b/src/fs_utf8/dir.rs index a8e7d430..66fa206e 100644 --- a/src/fs_utf8/dir.rs +++ b/src/fs_utf8/dir.rs @@ -148,7 +148,12 @@ impl Dir { /// /// [`std::fs::copy`]: https://doc.rust-lang.org/std/fs/fn.copy.html #[inline] - pub fn copy, Q: AsRef>(&self, from: P, to_dir: &Self, to: Q) -> io::Result { + pub fn copy, Q: AsRef>( + &self, + from: P, + to_dir: &Self, + to: Q, + ) -> io::Result { let from = from_utf8(from)?; let to = from_utf8(to)?; self.cap_std.copy(from, &to_dir.cap_std, to) From 2b98cad0c67639c8b8b89d658eddb64c5c855d37 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 27 Jul 2020 12:25:03 -0700 Subject: [PATCH 6/7] Update test to account for `copy`'s signature change. --- tests/fs.rs | 20 ++++++++++---------- tests/paths-containing-nul.rs | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/fs.rs b/tests/fs.rs index a4bc1027..33926623 100644 --- a/tests/fs.rs +++ b/tests/fs.rs @@ -725,7 +725,7 @@ fn copy_file_does_not_exist() { let from = Path::new("test/nonexistent-bogus-path"); let to = Path::new("test/other-bogus-path"); - match tmpdir.copy(&from, &to) { + match tmpdir.copy(&from, &tmpdir, &to) { Ok(..) => panic!(), Err(..) => { assert!(!tmpdir.exists(from)); @@ -740,7 +740,7 @@ fn copy_src_does_not_exist() { let from = Path::new("test/nonexistent-bogus-path"); let to = "out.txt"; check!(check!(tmpdir.create(&to)).write(b"hello")); - assert!(tmpdir.copy(&from, &to).is_err()); + assert!(tmpdir.copy(&from, &tmpdir, &to).is_err()); assert!(!tmpdir.exists(from)); let mut v = Vec::new(); check!(check!(tmpdir.open(&to)).read_to_end(&mut v)); @@ -756,7 +756,7 @@ fn copy_file_ok() { let out = "out.txt"; check!(check!(tmpdir.create(&input)).write(b"hello")); - check!(tmpdir.copy(&input, &out)); + check!(tmpdir.copy(&input, &tmpdir, &out)); let mut v = Vec::new(); check!(check!(tmpdir.open(&out)).read_to_end(&mut v)); assert_eq!(v, b"hello"); @@ -775,7 +775,7 @@ fn copy_file_dst_dir() { let out = "out"; check!(tmpdir.create(&out)); - match tmpdir.copy(&*out, ".") { + match tmpdir.copy(&*out, &tmpdir, ".") { Ok(..) => panic!(), Err(..) => {} } @@ -791,7 +791,7 @@ fn copy_file_dst_exists() { check!(check!(tmpdir.create(&input)).write("foo".as_bytes())); check!(check!(tmpdir.create(&output)).write("bar".as_bytes())); - check!(tmpdir.copy(&input, &output)); + check!(tmpdir.copy(&input, &tmpdir, &output)); let mut v = Vec::new(); check!(check!(tmpdir.open(&output)).read_to_end(&mut v)); @@ -805,7 +805,7 @@ fn copy_file_src_dir() { let tmpdir = tmpdir(); let out = "out"; - match tmpdir.copy(".", &out) { + match tmpdir.copy(".", &tmpdir, &out) { Ok(..) => panic!(), Err(..) => {} } @@ -824,7 +824,7 @@ fn copy_file_preserves_perm_bits() { let mut p = attr.permissions(); p.set_readonly(true); check!(tmpdir.open(&input).and_then(|file| file.set_permissions(p))); - check!(tmpdir.copy(&input, &out)); + check!(tmpdir.copy(&input, &tmpdir, &out)); assert!(check!(tmpdir.metadata(out)).permissions().readonly()); check!(tmpdir .open(&input) @@ -840,7 +840,7 @@ fn copy_file_preserves_perm_bits() { fn copy_file_preserves_streams() { let tmp = tmpdir(); check!(check!(tmp.create("in.txt:bunny")).write("carrot".as_bytes())); - assert_eq!(check!(tmp.copy("in.txt", "out.txt")), 0); + assert_eq!(check!(tmp.copy("in.txt", &tmp, "out.txt")), 0); assert_eq!(check!(tmp.metadata("out.txt")).len(), 0); let mut v = Vec::new(); check!(check!(tmp.open("out.txt:bunny")).read_to_end(&mut v)); @@ -857,7 +857,7 @@ fn copy_file_returns_metadata_len() { check!(check!(tmp.create(&in_path)).write(b"lettuce")); #[cfg(windows)] check!(check!(tmp.create("in.txt:bunny")).write(b"carrot")); - let copied_len = check!(tmp.copy(&in_path, &out_path)); + let copied_len = check!(tmp.copy(&in_path, &tmp, &out_path)); assert_eq!(check!(tmp.metadata(out_path)).len(), copied_len); } @@ -878,7 +878,7 @@ fn copy_file_follows_dst_symlink() { check!(tmp.write(&out_path, "bar")); check!(symlink_file(&out_path, &tmp, &out_path_symlink)); - check!(tmp.copy(&in_path, &out_path_symlink)); + check!(tmp.copy(&in_path, &tmp, &out_path_symlink)); assert!(check!(tmp.symlink_metadata(out_path_symlink)) .file_type() diff --git a/tests/paths-containing-nul.rs b/tests/paths-containing-nul.rs index 977673f0..0d02ed65 100644 --- a/tests/paths-containing-nul.rs +++ b/tests/paths-containing-nul.rs @@ -47,8 +47,8 @@ fn paths_containing_nul() { assert_invalid_input("rename1", tmpdir.rename("\0", &tmpdir, "a")); assert_invalid_input("rename2", tmpdir.rename(&dummy_file, &tmpdir, "\0")); - assert_invalid_input("copy1", tmpdir.copy("\0", "a")); - assert_invalid_input("copy2", tmpdir.copy(&dummy_file, "\0")); + assert_invalid_input("copy1", tmpdir.copy("\0", &tmpdir, "a")); + assert_invalid_input("copy2", tmpdir.copy(&dummy_file, &tmpdir, "\0")); assert_invalid_input("hard_link1", tmpdir.hard_link("\0", &tmpdir, "a")); assert_invalid_input("hard_link2", tmpdir.hard_link(&dummy_file, &tmpdir, "\0")); //fixmeassert_invalid_input("soft_link1", tmpdir.soft_link("\0", &tmpdir, "a")); From 0eee47473cc3eb8deca472e57d806acc8d4ebd3b Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 29 Jul 2020 14:45:09 -0700 Subject: [PATCH 7/7] Add benchmarks for `canonicalize`. --- benches/mod.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/benches/mod.rs b/benches/mod.rs index f75d2d3f..a7b1e5c5 100644 --- a/benches/mod.rs +++ b/benches/mod.rs @@ -70,6 +70,36 @@ fn nested_directories_metadata_baseline(b: &mut test::Bencher) { }); } +#[bench] +fn nested_directories_canonicalize(b: &mut test::Bencher) { + let dir = cap_tempfile::tempdir().unwrap(); + + let mut path = PathBuf::new(); + for _ in 0..256 { + path.push("abc"); + } + dir.create_dir_all(&path).unwrap(); + + b.iter(|| { + let _canonical = dir.canonicalize(&path).unwrap(); + }); +} + +#[bench] +fn nested_directories_canonicalize_baseline(b: &mut test::Bencher) { + let dir = tempfile::tempdir().unwrap(); + + let mut path = PathBuf::new(); + for _ in 0..256 { + path.push("abc"); + } + fs::create_dir_all(dir.path().join(&path)).unwrap(); + + b.iter(|| { + let _canonical = fs::canonicalize(dir.path().join(&path)).unwrap(); + }); +} + #[cfg(unix)] #[bench] fn nested_directories_readlink(b: &mut test::Bencher) { @@ -310,6 +340,44 @@ fn symlink_chasing_metadata_baseline(b: &mut test::Bencher) { }); } +#[cfg(unix)] +#[bench] +fn symlink_chasing_canonicalize(b: &mut test::Bencher) { + let dir = cap_tempfile::tempdir().unwrap(); + + dir.create("0").unwrap(); + for i in 0..32 { + dir.symlink(i.to_string(), (i + 1).to_string()).unwrap(); + } + + let name = "32"; + b.iter(|| { + let _canonical = dir.canonicalize(name).unwrap(); + }); +} + +#[cfg(unix)] +#[bench] +fn symlink_chasing_canonicalize_baseline(b: &mut test::Bencher) { + use std::os::unix::fs::symlink; + + let dir = tempfile::tempdir().unwrap(); + + fs::File::create(dir.path().join("0")).unwrap(); + for i in 0..32 { + symlink( + dir.path().join(i.to_string()), + dir.path().join((i + 1).to_string()), + ) + .unwrap(); + } + + let name = dir.path().join("32"); + b.iter(|| { + let _canonical = fs::canonicalize(&name).unwrap(); + }); +} + #[bench] fn recursive_create_delete(b: &mut test::Bencher) { let dir = cap_tempfile::tempdir().unwrap();