Skip to content

Commit 6e0bc96

Browse files
authored
feature: Add zfs feature flag for arc memory (#784)
* freebsd clippy * add arc support * Code Review: moved runtime cfg checks to compile time and formatting * remove compile platform checks * add zfs feature flag to get_arc_data
1 parent 11657aa commit 6e0bc96

16 files changed

+375
-8
lines changed

Cargo.lock

+34
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,12 @@ opt-level = 3
4141
codegen-units = 1
4242

4343
[features]
44-
default = ["fern", "log", "battery", "gpu"]
44+
default = ["fern", "log", "battery", "gpu", "zfs"]
4545
battery = ["starship-battery"]
4646
deploy = ["battery", "gpu"]
4747
gpu = ["nvidia"]
4848
nvidia = ["nvml-wrapper"]
49+
zfs = ["sysctl"]
4950

5051
[dependencies]
5152
anyhow = "1.0.57"
@@ -96,6 +97,7 @@ winapi = "0.3.9"
9697

9798
[target.'cfg(target_os = "freebsd")'.dependencies]
9899
serde_json = { version = "1.0.82" }
100+
sysctl = { version = "0.4.6", optional = true }
99101

100102
[dev-dependencies]
101103
assert_cmd = "2.0.4"

src/app/data_farmer.rs

+23
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ pub struct TimedData {
4141
pub load_avg_data: [f32; 3],
4242
pub mem_data: Option<Value>,
4343
pub swap_data: Option<Value>,
44+
#[cfg(feature = "zfs")]
45+
pub arc_data: Option<Value>,
4446
}
4547

4648
pub type StringPidMap = FxHashMap<String, Vec<Pid>>;
@@ -161,6 +163,8 @@ pub struct DataCollection {
161163
pub temp_harvest: Vec<temperature::TempHarvest>,
162164
#[cfg(feature = "battery")]
163165
pub battery_harvest: Vec<batteries::BatteryHarvest>,
166+
#[cfg(feature = "zfs")]
167+
pub arc_harvest: memory::MemHarvest,
164168
}
165169

166170
impl Default for DataCollection {
@@ -182,6 +186,8 @@ impl Default for DataCollection {
182186
temp_harvest: Vec::default(),
183187
#[cfg(feature = "battery")]
184188
battery_harvest: Vec::default(),
189+
#[cfg(feature = "zfs")]
190+
arc_harvest: memory::MemHarvest::default(),
185191
}
186192
}
187193
}
@@ -202,6 +208,10 @@ impl DataCollection {
202208
{
203209
self.battery_harvest = Vec::default();
204210
}
211+
#[cfg(feature = "zfs")]
212+
{
213+
self.arc_harvest = memory::MemHarvest::default();
214+
}
205215
}
206216

207217
pub fn freeze(&mut self) {
@@ -247,6 +257,12 @@ impl DataCollection {
247257
self.eat_memory_and_swap(memory, swap, &mut new_entry);
248258
}
249259

260+
#[cfg(feature = "zfs")]
261+
{
262+
if let Some(arc) = harvested_data.arc {
263+
self.eat_arc(arc, &mut new_entry);
264+
}
265+
}
250266
// CPU
251267
if let Some(cpu) = harvested_data.cpu {
252268
self.eat_cpu(cpu, &mut new_entry);
@@ -427,4 +443,11 @@ impl DataCollection {
427443
fn eat_battery(&mut self, list_of_batteries: Vec<batteries::BatteryHarvest>) {
428444
self.battery_harvest = list_of_batteries;
429445
}
446+
447+
#[cfg(feature = "zfs")]
448+
fn eat_arc(&mut self, arc: memory::MemHarvest, new_entry: &mut TimedData) {
449+
// Arc
450+
new_entry.arc_data = arc.use_percent;
451+
self.arc_harvest = arc;
452+
}
430453
}

src/app/data_harvester.rs

+13
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ pub struct Data {
4040
pub io: Option<disks::IoHarvest>,
4141
#[cfg(feature = "battery")]
4242
pub list_of_batteries: Option<Vec<batteries::BatteryHarvest>>,
43+
#[cfg(feature = "zfs")]
44+
pub arc: Option<memory::MemHarvest>,
4345
}
4446

4547
impl Default for Data {
@@ -57,6 +59,8 @@ impl Default for Data {
5759
network: None,
5860
#[cfg(feature = "battery")]
5961
list_of_batteries: None,
62+
#[cfg(feature = "zfs")]
63+
arc: None,
6064
}
6165
}
6266
}
@@ -75,6 +79,10 @@ impl Data {
7579
if let Some(network) = &mut self.network {
7680
network.first_run_cleanup();
7781
}
82+
#[cfg(feature = "zfs")]
83+
{
84+
self.arc = None;
85+
}
7886
}
7987
}
8088

@@ -421,6 +429,11 @@ impl DataCollector {
421429
self.data.swap = swap;
422430
}
423431

432+
#[cfg(feature = "zfs")]
433+
if let Ok(arc) = mem_res.2 {
434+
self.data.arc = arc;
435+
}
436+
424437
if let Ok(disks) = disk_res {
425438
self.data.disks = disks;
426439
}

src/app/data_harvester/cpu/sysinfo.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::app::data_harvester::cpu::LoadAvgHarvest;
1010

1111
pub async fn get_cpu_data_list(
1212
sys: &sysinfo::System, show_average_cpu: bool,
13-
_previous_cpu_times: &mut Vec<(PastCpuWork, PastCpuTotal)>,
13+
_previous_cpu_times: &mut [(PastCpuWork, PastCpuTotal)],
1414
_previous_average_cpu_time: &mut Option<(PastCpuWork, PastCpuTotal)>,
1515
) -> crate::error::Result<CpuHarvest> {
1616
let mut cpu_deque: VecDeque<_> = sys

src/app/data_harvester/memory/general/heim.rs

+81-2
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ pub async fn get_mem_data(
77
) -> (
88
crate::utils::error::Result<Option<MemHarvest>>,
99
crate::utils::error::Result<Option<MemHarvest>>,
10+
crate::utils::error::Result<Option<MemHarvest>>,
1011
) {
1112
use futures::join;
1213

1314
if !actually_get {
14-
(Ok(None), Ok(None))
15+
(Ok(None), Ok(None), Ok(None))
1516
} else {
16-
join!(get_ram_data(), get_swap_data())
17+
join!(get_ram_data(), get_swap_data(), get_arc_data())
1718
}
1819
}
1920

@@ -168,3 +169,81 @@ pub async fn get_swap_data() -> crate::utils::error::Result<Option<MemHarvest>>
168169
},
169170
}))
170171
}
172+
173+
pub async fn get_arc_data() -> crate::utils::error::Result<Option<MemHarvest>> {
174+
#[cfg(not(feature = "zfs"))]
175+
let (mem_total_in_kib, mem_used_in_kib) = (0, 0);
176+
177+
#[cfg(feature = "zfs")]
178+
let (mem_total_in_kib, mem_used_in_kib) = {
179+
#[cfg(target_os = "linux")]
180+
{
181+
let mut mem_arc = 0;
182+
let mut mem_total = 0;
183+
use smol::fs::read_to_string;
184+
let arcinfo = read_to_string("/proc/spl/kstat/zfs/arcstats").await?;
185+
for line in arcinfo.lines() {
186+
if let Some((label, value)) = line.split_once(' ') {
187+
let to_write = match label {
188+
"size" => &mut mem_arc,
189+
"memory_all_bytes" => &mut mem_total,
190+
_ => {
191+
continue;
192+
}
193+
};
194+
let mut zfs_keys_read: u8 = 0;
195+
const ZFS_KEYS_NEEDED: u8 = 2;
196+
if let Some((_type, number)) = value.trim_start().rsplit_once(' ') {
197+
// Parse the value, remember it's in bytes!
198+
if let Ok(number) = number.parse::<u64>() {
199+
*to_write = number;
200+
// We only need a few keys, so we can bail early.
201+
zfs_keys_read += 1;
202+
if zfs_keys_read == ZFS_KEYS_NEEDED {
203+
break;
204+
}
205+
}
206+
}
207+
}
208+
}
209+
(mem_total / 1024, mem_arc / 1024)
210+
}
211+
212+
#[cfg(target_os = "freebsd")]
213+
{
214+
use sysctl::Sysctl;
215+
if let (Ok(mem_arc_value), Ok(mem_sys_value)) = (
216+
sysctl::Ctl::new("kstat.zfs.misc.arcstats.size"),
217+
sysctl::Ctl::new("hw.physmem"),
218+
) {
219+
if let (Ok(sysctl::CtlValue::U64(arc)), Ok(sysctl::CtlValue::Ulong(mem))) =
220+
(mem_arc_value.value(), mem_sys_value.value())
221+
{
222+
(mem / 1024, arc / 1024)
223+
} else {
224+
(0, 0)
225+
}
226+
} else {
227+
(0, 0)
228+
}
229+
}
230+
#[cfg(target_os = "macos")]
231+
{
232+
(0, 0)
233+
}
234+
#[cfg(target_os = "windows")]
235+
{
236+
(0, 0)
237+
}
238+
};
239+
240+
Ok(Some(MemHarvest {
241+
mem_total_in_kib,
242+
mem_used_in_kib,
243+
use_percent: if mem_total_in_kib == 0 {
244+
None
245+
} else {
246+
Some(mem_used_in_kib as f64 / mem_total_in_kib as f64 * 100.0)
247+
},
248+
}))
249+
}

src/app/data_harvester/memory/general/sysinfo.rs

+39-2
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ pub async fn get_mem_data(
88
) -> (
99
crate::utils::error::Result<Option<MemHarvest>>,
1010
crate::utils::error::Result<Option<MemHarvest>>,
11+
crate::utils::error::Result<Option<MemHarvest>>,
1112
) {
1213
use futures::join;
1314

1415
if !actually_get {
15-
(Ok(None), Ok(None))
16+
(Ok(None), Ok(None), Ok(None))
1617
} else {
17-
join!(get_ram_data(sys), get_swap_data(sys))
18+
join!(get_ram_data(sys), get_swap_data(sys), get_arc_data())
1819
}
1920
}
2021

@@ -45,3 +46,39 @@ pub async fn get_swap_data(sys: &System) -> crate::utils::error::Result<Option<M
4546
},
4647
}))
4748
}
49+
50+
pub async fn get_arc_data() -> crate::utils::error::Result<Option<MemHarvest>> {
51+
#[cfg(not(feature = "zfs"))]
52+
let (mem_total_in_kib, mem_used_in_kib) = (0, 0);
53+
54+
#[cfg(feature = "zfs")]
55+
let (mem_total_in_kib, mem_used_in_kib) = {
56+
#[cfg(target_os = "freebsd")]
57+
{
58+
use sysctl::Sysctl;
59+
if let (Ok(mem_arc_value), Ok(mem_sys_value)) = (
60+
sysctl::Ctl::new("kstat.zfs.misc.arcstats.size"),
61+
sysctl::Ctl::new("hw.physmem"),
62+
) {
63+
if let (Ok(sysctl::CtlValue::U64(arc)), Ok(sysctl::CtlValue::Ulong(mem))) =
64+
(mem_arc_value.value(), mem_sys_value.value())
65+
{
66+
(mem / 1024, arc / 1024)
67+
} else {
68+
(0, 0)
69+
}
70+
} else {
71+
(0, 0)
72+
}
73+
}
74+
};
75+
Ok(Some(MemHarvest {
76+
mem_total_in_kib,
77+
mem_used_in_kib,
78+
use_percent: if mem_total_in_kib == 0 {
79+
None
80+
} else {
81+
Some(mem_used_in_kib as f64 / mem_total_in_kib as f64 * 100.0)
82+
},
83+
}))
84+
}

src/bin/main.rs

+10
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,21 @@ fn main() -> Result<()> {
191191
convert_mem_data_points(&app.data_collection);
192192
app.converted_data.swap_data =
193193
convert_swap_data_points(&app.data_collection);
194+
#[cfg(feature = "zfs")]
195+
{
196+
app.converted_data.arc_data =
197+
convert_arc_data_points(&app.data_collection);
198+
}
194199
let (memory_labels, swap_labels) =
195200
convert_mem_labels(&app.data_collection);
196201

197202
app.converted_data.mem_labels = memory_labels;
198203
app.converted_data.swap_labels = swap_labels;
204+
#[cfg(feature = "zfs")]
205+
{
206+
let arc_labels = convert_arc_labels(&app.data_collection);
207+
app.converted_data.arc_labels = arc_labels;
208+
}
199209
}
200210

201211
if app.used_widgets.use_cpu {

0 commit comments

Comments
 (0)