cli_rs: Loop fetching access counts

Summary: Loop fetching access counts and update rendering.

Reviewed By: fanzeyi

Differential Revision: D32109917

fbshipit-source-id: 83eae25bc7938497f2f99cb966e0fd7ce907f017
This commit is contained in:
Grace Ku 2021-11-05 16:21:19 -07:00 committed by Facebook GitHub Bot
parent 62315132a1
commit a324477274
2 changed files with 97 additions and 75 deletions

View File

@ -10,6 +10,7 @@ license = "GPLv2+"
[dependencies]
anyhow = "1.0"
async-trait = "0.1.51"
crossterm = { version = "0.20.0", features = ["event-stream"] }
dirs = "2.0"
edenfs-client = { version = "0.1.0", path = "../edenfs-client" }
edenfs-error = { version = "0.1.0", path = "../edenfs-error" }

View File

@ -8,7 +8,9 @@
//! edenfsctl minitop
use async_trait::async_trait;
use crossterm::{cursor, QueueableCommand};
use std::collections::BTreeMap;
use std::io::{stdout, Write};
use std::path::Path;
use std::time::Duration;
use std::time::SystemTime;
@ -47,6 +49,20 @@ fn parse_refresh_rate(arg: &str) -> Duration {
}
const UNKNOWN_COMMAND: &str = "<unknown>";
const COLUMN_TITLES: &[&str] = &[
"TOP PID",
"MOUNT",
"FUSE R",
"FUSE W",
"FUSE COUNT",
"FUSE FETCH",
"MEMORY",
"DISK",
"IMPORTS",
"FUSE TIME",
"FUSE LAST",
"CMD",
];
trait GetAccessCountsResultExt {
fn get_cmd_for_pid(&self, pid: &i32) -> Result<String>;
@ -199,14 +215,16 @@ impl TrackedProcesses {
impl crate::Subcommand for MinitopCmd {
async fn run(&self, instance: EdenFsInstance) -> Result<ExitCode> {
let client = instance.connect(None).await?;
let mut tracked_processes = TrackedProcesses::new();
let mut stdout = stdout();
loop {
// Update currently tracked processes (and add new ones if they haven't been tracked yet)
let counts = client
.getAccessCounts(self.refresh_rate.as_secs().try_into().from_err()?)
.await
.from_err()?;
// Update currently tracked processes (and add new ones if they haven't been tracked yet)
let mut tracked_processes = TrackedProcesses::new();
for (mount, accesses) in &counts.accessesByMount {
for (pid, access_counts) in &accesses.accessCountsByPid {
tracked_processes.update_process(
@ -229,24 +247,16 @@ impl crate::Subcommand for MinitopCmd {
}
}
const COLUMN_TITLES: &[&str] = &[
"TOP PID",
"MOUNT",
"FUSE R",
"FUSE W",
"FUSE COUNT",
"FUSE FETCH",
"MEMORY",
"DISK",
"IMPORTS",
"FUSE TIME",
"FUSE LAST",
"CMD",
];
// Render aggregated processes
stdout.queue(cursor::SavePosition).from_err()?;
println!("{}", COLUMN_TITLES.join("\t"));
stdout
.write(format!("{}\n", COLUMN_TITLES.join("\t")).as_bytes())
.from_err()?;
for aggregated_process in tracked_processes.aggregated_processes() {
println!(
stdout
.write(
format!(
"{top_pid}\t \
{mount}\t \
{fuse_reads}\t \
@ -258,7 +268,7 @@ impl crate::Subcommand for MinitopCmd {
{fuse_backing_store_imports}\t \
{fuse_duration}\t \
{fuse_last_access}\t \
{command}",
{command}\n",
top_pid = aggregated_process.pid,
mount = aggregated_process.mount,
fuse_reads = aggregated_process.access_counts.fsChannelReads,
@ -280,7 +290,18 @@ impl crate::Subcommand for MinitopCmd {
.as_nanos(),
command = aggregated_process.cmd,
)
.as_bytes(),
)
.from_err()?;
}
stdout.queue(cursor::RestorePosition).from_err()?;
stdout.flush().from_err()?;
tokio::time::sleep(self.refresh_rate).await;
}
unreachable!("minitop is unable to start");
Ok(0)
}
}