Skip to content

Commit b89bf28

Browse files
authored
Record smaps less often (#1236)
* Record smaps data every tenth sample * clippies
1 parent 39688fe commit b89bf28

File tree

3 files changed

+85
-71
lines changed

3 files changed

+85
-71
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## Fixed
99
- `smaps` parsing logic correctly collects memory region pathnames that contain whitespace
1010
- Fixes issue when parsing `NaN` values from a prometheus endpoint
11+
## Changed
12+
- smaps data is scraped every tenth sample to reduce capture size.
1113

1214
## [0.25.5]
1315
## Added

lading/src/observer/linux.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ pub enum Error {
1616

1717
#[derive(Debug)]
1818
pub(crate) struct Sampler {
19-
procfs_sampler: procfs::Sampler,
20-
cgroup_sampler: cgroup::Sampler,
19+
procfs: procfs::Sampler,
20+
cgroup: cgroup::Sampler,
21+
smaps_interval: u8,
2122
}
2223

2324
impl Sampler {
@@ -26,14 +27,23 @@ impl Sampler {
2627
let cgroup_sampler = cgroup::Sampler::new(parent_pid, labels)?;
2728

2829
Ok(Self {
29-
procfs_sampler,
30-
cgroup_sampler,
30+
procfs: procfs_sampler,
31+
cgroup: cgroup_sampler,
32+
smaps_interval: 10,
3133
})
3234
}
3335

3436
pub(crate) async fn sample(&mut self) -> Result<(), Error> {
35-
self.procfs_sampler.poll().await?;
36-
self.cgroup_sampler.poll().await?;
37+
self.smaps_interval -= 1;
38+
let sample_smaps = if self.smaps_interval == 0 {
39+
self.smaps_interval = 10;
40+
true
41+
} else {
42+
false
43+
};
44+
45+
self.procfs.poll(sample_smaps).await?;
46+
self.cgroup.poll().await?;
3747

3848
Ok(())
3949
}

lading/src/observer/linux/procfs.rs

Lines changed: 67 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl Sampler {
7979
clippy::cast_possible_truncation,
8080
clippy::cast_possible_wrap
8181
)]
82-
pub(crate) async fn poll(&mut self) -> Result<(), Error> {
82+
pub(crate) async fn poll(&mut self, include_smaps: bool) -> Result<(), Error> {
8383
// A tally of the total RSS and PSS consumed by the parent process and
8484
// its children.
8585
let mut aggr = memory::smaps_rollup::Aggregator::default();
@@ -121,7 +121,7 @@ impl Sampler {
121121
self.process_info.retain(|pid, _| pids.contains(pid));
122122

123123
let pid = process.pid();
124-
if let Err(e) = self.handle_process(process, &mut aggr).await {
124+
if let Err(e) = self.handle_process(process, &mut aggr, include_smaps).await {
125125
warn!("Encountered uncaught error when handling `/proc/{pid}/`: {e}");
126126
}
127127
}
@@ -143,6 +143,7 @@ impl Sampler {
143143
&mut self,
144144
process: Process,
145145
aggr: &mut memory::smaps_rollup::Aggregator,
146+
include_smaps: bool,
146147
) -> Result<(), Error> {
147148
let pid = process.pid();
148149

@@ -238,72 +239,73 @@ impl Sampler {
238239
return Ok(());
239240
}
240241

241-
// `/proc/{pid}/smaps`
242-
match memory::smaps::Regions::from_pid(pid) {
243-
Ok(memory_regions) => {
244-
for (pathname, measures) in memory_regions.aggregate_by_pathname() {
245-
let labels: [(&'static str, String); 5] = [
246-
("pid", pinfo.pid_s.clone()),
247-
("exe", pinfo.exe.clone()),
248-
("cmdline", pinfo.cmdline.clone()),
249-
("comm", pinfo.comm.clone()),
250-
("pathname", pathname),
251-
];
252-
gauge!("smaps.rss.by_pathname", &labels).set(measures.rss as f64);
253-
gauge!("smaps.pss.by_pathname", &labels).set(measures.pss as f64);
254-
gauge!("smaps.swap.by_pathname", &labels).set(measures.swap as f64);
255-
gauge!("smaps.size.by_pathname", &labels).set(measures.size as f64);
242+
if include_smaps {
243+
// `/proc/{pid}/smaps`
244+
match memory::smaps::Regions::from_pid(pid) {
245+
Ok(memory_regions) => {
246+
for (pathname, measures) in memory_regions.aggregate_by_pathname() {
247+
let labels: [(&'static str, String); 5] = [
248+
("pid", pinfo.pid_s.clone()),
249+
("exe", pinfo.exe.clone()),
250+
("cmdline", pinfo.cmdline.clone()),
251+
("comm", pinfo.comm.clone()),
252+
("pathname", pathname),
253+
];
254+
gauge!("smaps.rss.by_pathname", &labels).set(measures.rss as f64);
255+
gauge!("smaps.pss.by_pathname", &labels).set(measures.pss as f64);
256+
gauge!("smaps.swap.by_pathname", &labels).set(measures.swap as f64);
257+
gauge!("smaps.size.by_pathname", &labels).set(measures.size as f64);
256258

257-
if let Some(m) = measures.private_clean {
258-
gauge!("smaps.private_clean.by_pathname", &labels).set(m as f64);
259-
}
260-
if let Some(m) = measures.private_dirty {
261-
gauge!("smaps.private_dirty.by_pathname", &labels).set(m as f64);
262-
}
263-
if let Some(m) = measures.shared_clean {
264-
gauge!("smaps.shared_clean.by_pathname", &labels).set(m as f64);
265-
}
266-
if let Some(m) = measures.shared_dirty {
267-
gauge!("smaps.shared_dirty.by_pathname", &labels).set(m as f64);
268-
}
269-
if let Some(m) = measures.referenced {
270-
gauge!("smaps.referenced.by_pathname", &labels).set(m as f64);
271-
}
272-
if let Some(m) = measures.anonymous {
273-
gauge!("smaps.anonymous.by_pathname", &labels).set(m as f64);
274-
}
275-
if let Some(m) = measures.lazy_free {
276-
gauge!("smaps.lazy_free.by_pathname", &labels).set(m as f64);
277-
}
278-
if let Some(m) = measures.anon_huge_pages {
279-
gauge!("smaps.anon_huge_pages.by_pathname", &labels).set(m as f64);
280-
}
281-
if let Some(m) = measures.shmem_pmd_mapped {
282-
gauge!("smaps.shmem_pmd_mapped.by_pathname", &labels).set(m as f64);
283-
}
284-
if let Some(m) = measures.shared_hugetlb {
285-
gauge!("smaps.shared_hugetlb.by_pathname", &labels).set(m as f64);
286-
}
287-
if let Some(m) = measures.private_hugetlb {
288-
gauge!("smaps.private_hugetlb.by_pathname", &labels).set(m as f64);
289-
}
290-
if let Some(m) = measures.file_pmd_mapped {
291-
gauge!("smaps.file_pmd_mapped.by_pathname", &labels).set(m as f64);
292-
}
293-
if let Some(m) = measures.locked {
294-
gauge!("smaps.locked.by_pathname", &labels).set(m as f64);
295-
}
296-
if let Some(m) = measures.swap_pss {
297-
gauge!("smaps.swap_pss.by_pathname", &labels).set(m as f64);
259+
if let Some(m) = measures.private_clean {
260+
gauge!("smaps.private_clean.by_pathname", &labels).set(m as f64);
261+
}
262+
if let Some(m) = measures.private_dirty {
263+
gauge!("smaps.private_dirty.by_pathname", &labels).set(m as f64);
264+
}
265+
if let Some(m) = measures.shared_clean {
266+
gauge!("smaps.shared_clean.by_pathname", &labels).set(m as f64);
267+
}
268+
if let Some(m) = measures.shared_dirty {
269+
gauge!("smaps.shared_dirty.by_pathname", &labels).set(m as f64);
270+
}
271+
if let Some(m) = measures.referenced {
272+
gauge!("smaps.referenced.by_pathname", &labels).set(m as f64);
273+
}
274+
if let Some(m) = measures.anonymous {
275+
gauge!("smaps.anonymous.by_pathname", &labels).set(m as f64);
276+
}
277+
if let Some(m) = measures.lazy_free {
278+
gauge!("smaps.lazy_free.by_pathname", &labels).set(m as f64);
279+
}
280+
if let Some(m) = measures.anon_huge_pages {
281+
gauge!("smaps.anon_huge_pages.by_pathname", &labels).set(m as f64);
282+
}
283+
if let Some(m) = measures.shmem_pmd_mapped {
284+
gauge!("smaps.shmem_pmd_mapped.by_pathname", &labels).set(m as f64);
285+
}
286+
if let Some(m) = measures.shared_hugetlb {
287+
gauge!("smaps.shared_hugetlb.by_pathname", &labels).set(m as f64);
288+
}
289+
if let Some(m) = measures.private_hugetlb {
290+
gauge!("smaps.private_hugetlb.by_pathname", &labels).set(m as f64);
291+
}
292+
if let Some(m) = measures.file_pmd_mapped {
293+
gauge!("smaps.file_pmd_mapped.by_pathname", &labels).set(m as f64);
294+
}
295+
if let Some(m) = measures.locked {
296+
gauge!("smaps.locked.by_pathname", &labels).set(m as f64);
297+
}
298+
if let Some(m) = measures.swap_pss {
299+
gauge!("smaps.swap_pss.by_pathname", &labels).set(m as f64);
300+
}
298301
}
299302
}
300-
}
301-
Err(err) => {
302-
// We don't want to bail out entirely if we can't read stats
303-
// which will happen if we don't have permissions or, more
304-
// likely, the process has exited.
305-
warn!("Couldn't process `/proc/{pid}/smaps`: {err}");
306-
return Ok(());
303+
Err(err) => {
304+
// We don't want to bail out entirely if we can't read stats
305+
// which will happen if we don't have permissions or, more
306+
// likely, the process has exited.
307+
warn!("Couldn't process `/proc/{pid}/smaps`: {err}");
308+
}
307309
}
308310
}
309311

0 commit comments

Comments
 (0)