//! Based on [heim's implementation](https://github.com/heim-rs/heim/blob/master/heim-disk/src/sys/macos/counters.rs). use super::io_kit::{self, get_dict, get_disks, get_i64, get_string}; use crate::app::data_harvester::disks::IoCounters; fn get_device_io(device: io_kit::IoObject) -> anyhow::Result { let parent = device.service_parent()?; // XXX: Re: Conform check being disabled. // // Okay, so this is weird. // // The problem is that if I have this check - this is what sources like psutil use, for // example (see https://github.com/giampaolo/psutil/blob/7eadee31db2f038763a3a6f978db1ea76bbc4674/psutil/_psutil_osx.c#LL1422C20-L1422C20) // then this will only return stuff like disk0. // // The problem with this is that there is *never* a disk0 *disk* entry to correspond to this, // so there will be entries like disk1 or whatnot. Someone's done some digging on the gopsutil // repo (https://github.com/shirou/gopsutil/issues/855#issuecomment-610016435), and it seems // like this is a consequence of how Apple does logical volumes. // // So with all that said, what I've found is that I *can* still get a mapping - but I have // to disable the conform check, which... is weird. I'm not sure if this is valid at all. But // it *does* seem to match Activity Monitor with regards to disk activity, so... I guess we // can leave this for now...? // if !parent.conforms_to_block_storage_driver() { // anyhow::bail!("{parent:?}, the parent of {device:?} does not conform to IOBlockStorageDriver") // } let disk_props = device.properties()?; let parent_props = parent.properties()?; let name = get_string(&disk_props, "BSD Name")?; let stats = get_dict(&parent_props, "Statistics")?; let read_bytes = get_i64(&stats, "Bytes (Read)")? as u64; let write_bytes = get_i64(&stats, "Bytes (Write)")? as u64; // let read_count = stats.get_i64("Operations (Read)")? as u64; // let write_count = stats.get_i64("Operations (Write)")? as u64; Ok(IoCounters::new(name, read_bytes, write_bytes)) } /// Returns an iterator of disk I/O stats. Pulls data through IOKit. pub fn io_stats() -> anyhow::Result>> { Ok(get_disks()?.map(get_device_io).collect()) }