summaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-02-14 05:06:45 +0000
committerGitHub <noreply@github.com>2022-02-14 05:06:45 +0000
commit3ea9b7b6730ca380ddd1681f8ee594aeeed8fa2f (patch)
treec8e85cee4ebbcd071d74d26adf687bf9c53de2e3 /src/lib.rs
parentb38a88a306b828629159502f26ccc23d4d5de941 (diff)
parentbb54af538d607530f3a67679ad8c0ca8cd5759b3 (diff)
downloadnix-3ea9b7b6730ca380ddd1681f8ee594aeeed8fa2f.zip
Merge #1655
1655: 30x performance improvement in `with_nix_path` r=rtzoeller a=SUPERCILEX I've been digging into CPU instructions counts and found that `nix` accounted for an eye-watering 85% of my program's instruction counts (yes, I do a lot of I/O, I know). The fix is simple: don't initialize the stack memory since we're just going to overwrite it anyway. > Note: I also ran rustfmt in a separate commit, not sure if that's ok. ### Before ``` 650,398,225 (85.05%) 5,451,056 (17.31%) 627,714,969 (97.28%) 60 ( 0.54%) 22 ( 0.07%) 3,997 (20.98%) 10 ( 0.18%) 0 752 ( 5.98%) 627,716,244 (97.30%) 267,333 (34.62%) 914,814 (35.11%) 105 ( 0.73%) => /home/asaveau/Desktop/nix/src/lib.rs:<[u8] as nix::NixPath>::with_nix_path (152,469x) ``` ``` 1,677,159 ( 0.22%) 0 762,345 ( 0.12%) 14 ( 0.13%) 0 0 2 ( 0.04%) . . . . . . fn with_nix_path<T, F>(&self, f: F) -> Result<T> 2,287,035 ( 0.30%) 304,938 ( 0.97%) 152,469 ( 0.02%) 5 ( 0.04%) 0 0 0 0 0 304,938 ( 0.05%) . . . => ???:__rust_probestack (152,469x) . . . . . . . . . . . . . where . . . . . . . . . . . . . F: FnOnce(&CStr) -> T, . . . . . . . . . . . . . { 457,407 ( 0.06%) 152,469 ( 0.48%) 152,469 ( 0.02%) 0 0 93 ( 0.49%) 0 0 16 ( 0.13%) 0 0 152,469 ( 5.85%) 97 ( 0.67%) let mut buf = [0u8; PATH_MAX as usize]; 627,104,997 (82.00%) 304,938 ( 0.97%) 624,513,024 (96.78%) 1 ( 0.01%) 0 3,814 (20.02%) 1 ( 0.02%) 0 720 ( 5.72%) 625,122,900 (96.90%) 152,495 (19.75%) . . => ./string/../sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S:__memset_avx2_unaligned_erms (152,469x) . . . . . . . . . . . . . 304,938 ( 0.04%) 0 0 0 0 0 0 0 0 152,469 ( 0.02%) 2 ( 0.00%) . . if self.len() >= PATH_MAX as usize { . . . . . . . . . . . . . return Err(Errno::ENAMETOOLONG); . . . . . . . . . . . . . } . . . . . . . . . . . . . 1,067,283 ( 0.14%) 152,469 ( 0.48%) 152,469 ( 0.02%) 1 ( 0.01%) 4 ( 0.01%) 0 1 ( 0.02%) 0 0 0 0 152,469 ( 5.85%) 1 ( 0.01%) buf[..self.len()].copy_from_slice(self); 3,202,541 ( 0.42%) 914,814 ( 2.91%) 609,876 ( 0.09%) 1 ( 0.01%) 2 ( 0.01%) 0 0 0 0 458,005 ( 0.07%) 114,562 (14.84%) 152,469 ( 5.85%) . => /rustc/21b4a9cfdcbb1e76f4b36b5c3cfd64d627285093/library/core/src/slice/mod.rs:core::slice::<impl [T]>::copy_from_slice (152,469x) 762,345 ( 0.10%) 304,938 ( 0.97%) 152,469 ( 0.02%) 0 6 ( 0.02%) 0 0 0 0 152,469 ( 0.02%) 6 ( 0.00%) 152,469 ( 5.85%) 1 ( 0.01%) match CStr::from_bytes_with_nul(&buf[..=self.len()]) { 8,350,190 ( 1.09%) 1,181,828 ( 3.75%) 1,067,283 ( 0.17%) 19 ( 0.17%) 2 ( 0.01%) 87 ( 0.46%) 3 ( 0.05%) 0 16 ( 0.13%) 1,220,525 ( 0.19%) 167 ( 0.02%) 152,469 ( 5.85%) 5 ( 0.03%) => /rustc/21b4a9cfdcbb1e76f4b36b5c3cfd64d627285093//library/std/src/ffi/c_str.rs:std::ffi::c_str::CStr::from_bytes_with_nul (152,469x) 609,876 ( 0.08%) 609,876 ( 1.94%) 0 0 1 ( 0.00%) . . . . . . . . Ok(s) => Ok(f(s)), . . . . . . . . . . . . . Err(_) => Err(Errno::EINVAL), . . . . . . . . . . . . . } 914,814 ( 0.12%) 762,345 ( 2.42%) . . . . . . . . . . . } . . . . . . . . . . . . . } ``` ### After ``` 21,462,416 (15.81%) 4,688,455 (15.27%) 2,896,847 (14.17%) 74 ( 0.64%) 11 ( 0.04%) 249 ( 1.58%) 8 ( 0.15%) 0 48 ( 0.38%) 2,593,200 (12.98%) 1,128 ( 0.22%) 762,305 (31.08%) 158 ( 1.32%) => /home/asaveau/Desktop/nix/src/lib.rs:<[u8] as nix::NixPath>::with_nix_path (152,461x) ``` ``` 1,067,227 ( 0.79%) 0 609,844 ( 2.98%) 1 ( 0.01%) 0 0 1 ( 0.02%) . . . . . . fn with_nix_path<T, F>(&self, f: F) -> Result<T> 2,286,915 ( 1.68%) 304,922 ( 0.99%) 152,461 ( 0.75%) 19 ( 0.16%) 0 0 0 0 0 304,922 ( 1.53%) . . . => ???:__rust_probestack (152,461x) . . . . . . . . . . . . . where . . . . . . . . . . . . . F: FnOnce(&CStr) -> T, . . . . . . . . . . . . . { 304,922 ( 0.22%) 0 0 0 0 0 0 0 0 152,461 ( 0.76%) 6 ( 0.00%) . . if self.len() >= PATH_MAX as usize { . . . . . . . . . . . . . return Err(Errno::ENAMETOOLONG); . . . . . . . . . . . . . } . . . . . . . . . . . . . . . . . . . . . . . . . . let mut buf = MaybeUninit::<[u8; PATH_MAX as usize]>::uninit(); . . . . . . . . . . . . . let buf_ptr = buf.as_mut_ptr() as *mut u8; . . . . . . . . . . . . . . . . . . . . . . . . . . unsafe { . . . . . . . . . . . . . ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len()); . . . . . . . . . . . . . buf_ptr.add(self.len()).write(0); . . . . . . . . . . . . . } . . . . . . . . . . . . . 1,067,227 ( 0.79%) 304,922 ( 0.99%) 152,461 ( 0.75%) 1 ( 0.01%) 3 ( 0.01%) 0 1 ( 0.02%) 0 0 304,922 ( 1.53%) 4 ( 0.00%) 152,461 ( 6.22%) 1 ( 0.01%) match CStr::from_bytes_with_nul(unsafe { slice::from_raw_parts(buf_ptr, self.len() + 1) }) { 8,349,726 ( 6.15%) 1,181,764 ( 3.85%) 1,067,227 ( 5.22%) 18 ( 0.15%) 1 ( 0.00%) 83 ( 0.53%) 2 ( 0.04%) 0 16 ( 0.13%) 1,220,453 ( 6.11%) 158 ( 0.03%) 152,461 ( 6.22%) 4 ( 0.03%) => /rustc/21b4a9cfdcbb1e76f4b36b5c3cfd64d627285093//library/std/src/ffi/c_str.rs:std::ffi::c_str::CStr::from_bytes_with_nul (152,461x) 609,844 ( 0.45%) 609,844 ( 1.99%) . . . . . . . . . . . Ok(s) => Ok(f(s)), . . . . . . . . . . . . . Err(_) => Err(Errno::EINVAL), . . . . . . . . . . . . . } 762,305 ( 0.56%) 609,844 ( 1.99%) 0 1 ( 0.01%) 0 0 1 ( 0.02%) . . . . . . } . . . . . . . . . . . . . } ``` Co-authored-by: Alex Saveau <saveau.alexandre@gmail.com>
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs22
1 files changed, 15 insertions, 7 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 86dbaffd..0cfd3fb4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -164,8 +164,9 @@ pub mod unistd;
use libc::PATH_MAX;
-use std::result;
+use std::{ptr, result, slice};
use std::ffi::{CStr, OsStr};
+use std::mem::MaybeUninit;
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};
@@ -261,15 +262,22 @@ impl NixPath for [u8] {
}
fn with_nix_path<T, F>(&self, f: F) -> Result<T>
- where F: FnOnce(&CStr) -> T {
- let mut buf = [0u8; PATH_MAX as usize];
-
+ where
+ F: FnOnce(&CStr) -> T,
+ {
if self.len() >= PATH_MAX as usize {
- return Err(Errno::ENAMETOOLONG)
+ return Err(Errno::ENAMETOOLONG);
+ }
+
+ let mut buf = MaybeUninit::<[u8; PATH_MAX as usize]>::uninit();
+ let buf_ptr = buf.as_mut_ptr() as *mut u8;
+
+ unsafe {
+ ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len());
+ buf_ptr.add(self.len()).write(0);
}
- buf[..self.len()].copy_from_slice(self);
- match CStr::from_bytes_with_nul(&buf[..=self.len()]) {
+ match CStr::from_bytes_with_nul(unsafe { slice::from_raw_parts(buf_ptr, self.len() + 1) }) {
Ok(s) => Ok(f(s)),
Err(_) => Err(Errno::EINVAL),
}