From 74728f40c650b57acc6821b59d42a81cc6543cc6 Mon Sep 17 00:00:00 2001 From: Chris Down Date: Tue, 4 Jun 2024 12:01:56 -0700 Subject: [PATCH] below: procfs: Reinterpret internal buffer as &str without realloc Summary: Almost all files go through this path, so a little gain here goes a long way. In terms of safety, none of the files we read using read_file_to_string from should have invalid UTF-8. The two that can (cmdline/exe) already have special handling outside of this. This saves about 1-2% of CPU per iteration. Reviewed By: dschatzberg Differential Revision: D58083974 fbshipit-source-id: 9a4fc1a7c0bd7b7bdfb442ef33cfefd21ed4c49d --- below/procfs/src/lib.rs | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/below/procfs/src/lib.rs b/below/procfs/src/lib.rs index 04ece54c..e216f0e5 100644 --- a/below/procfs/src/lib.rs +++ b/below/procfs/src/lib.rs @@ -169,7 +169,7 @@ impl ProcReader { reader } - fn read_file_to_string(&mut self, path: &Path) -> Result { + fn read_file_to_str(&mut self, path: &Path) -> Result<&str> { let mut file = File::open(path).map_err(|e| Error::IoError(path.to_path_buf(), e))?; let mut total_read = 0; @@ -196,12 +196,13 @@ impl ProcReader { } } - Ok(String::from_utf8_lossy(&self.buffer[..total_read]).to_string()) + std::str::from_utf8(&self.buffer[..total_read]) + .map_err(|_| Error::InvalidFileFormat(path.to_path_buf())) } fn read_uptime_secs(&mut self) -> Result { let path = self.path.join("uptime"); - let content = self.read_file_to_string(&path)?; + let content = self.read_file_to_str(&path)?; let mut items = content.split_whitespace(); match parse_item!(path, items.next(), f64, content) { @@ -235,13 +236,13 @@ impl ProcReader { pub fn read_kernel_version(&mut self) -> Result { let path = self.path.join("sys/kernel/osrelease"); - let content = self.read_file_to_string(&path)?; + let content = self.read_file_to_str(&path)?; Ok(content.trim_matches('\n').trim().into()) } pub fn read_stat(&mut self) -> Result { let path = self.path.join("stat"); - let content = self.read_file_to_string(&path)?; + let content = self.read_file_to_str(&path)?; let mut stat: Stat = Default::default(); let mut cpus_map = BTreeMap::new(); @@ -295,7 +296,7 @@ impl ProcReader { pub fn read_meminfo(&mut self) -> Result { let path = self.path.join("meminfo"); - let content = self.read_file_to_string(&path)?; + let content = self.read_file_to_str(&path)?; let mut meminfo: MemInfo = Default::default(); for line in content.lines() { @@ -377,7 +378,7 @@ impl ProcReader { pub fn read_vmstat(&mut self) -> Result { let path = self.path.join("vmstat"); - let content = self.read_file_to_string(&path)?; + let content = self.read_file_to_str(&path)?; let mut vmstat: VmStat = Default::default(); for line in content.lines() { @@ -415,7 +416,7 @@ impl ProcReader { pub fn read_slabinfo(&mut self) -> Result { let path = self.path.join("slabinfo"); - let content = self.read_file_to_string(&path)?; + let content = self.read_file_to_str(&path)?; let mut slab_info_map: SlabInfoMap = Default::default(); // The first line is version, second line is headers: @@ -457,7 +458,7 @@ impl ProcReader { // mount of each mount source. The first mount is what shows in // the 'df' command and reflects the usage of the device. let path = self.path.join("self/mountinfo"); - let content = self.read_file_to_string(&path)?; + let content = self.read_file_to_str(&path)?.to_string(); let mut mount_info_map: HashMap = HashMap::new(); for line in content.lines() { @@ -500,7 +501,7 @@ impl ProcReader { pub fn read_disk_stats_and_fsinfo(&mut self) -> Result { let path = self.path.join("diskstats"); - let content = self.read_file_to_string(&path)?; + let content = self.read_file_to_str(&path)?.to_string(); let mut disk_map: DiskMap = Default::default(); let mount_info_map = self.read_mount_info_map().unwrap_or_default(); @@ -555,10 +556,10 @@ impl ProcReader { fn read_pid_stat_from_path>(&mut self, path: P) -> Result { let path = path.as_ref().join("stat"); - let content = self.read_file_to_string(&path)?; + let content = self.read_file_to_str(&path)?; let mut pidstat: PidStat = Default::default(); - let mut line = content.clone(); + let mut line = content.to_string(); { let b_opt = line.find('('); let e_opt = line.rfind(')'); @@ -614,7 +615,7 @@ impl ProcReader { fn read_pid_status_from_path>(&mut self, path: P) -> Result { let path = path.as_ref().join("status"); - let content = self.read_file_to_string(&path)?; + let content = self.read_file_to_str(&path)?; let mut pidstatus: PidStatus = Default::default(); for line in content.lines() { @@ -648,7 +649,7 @@ impl ProcReader { fn read_pid_io_from_path>(&mut self, path: P) -> Result { let path = path.as_ref().join("io"); - let content = self.read_file_to_string(&path)?; + let content = self.read_file_to_str(&path)?; let mut pidio: PidIo = Default::default(); for line in content.lines() { @@ -675,7 +676,7 @@ impl ProcReader { fn read_pid_cgroup_from_path>(&mut self, path: P) -> Result { let path = path.as_ref().join("cgroup"); - let content = self.read_file_to_string(&path)?; + let content = self.read_file_to_str(&path)?; let mut cgroup_path = None; for line in content.lines() {