use std::fmt::{self, Write};
use crate::Opt;
use libamdgpu_top::stat::{FdInfoStat, FdInfoSortType};
const PROC_NAME_LEN: usize = 16;
const PID_MAX_LEN: usize = 7;
const VRAM_LABEL: &str = "VRAM";
const GTT_LABEL: &str = "GTT";
const CPU_LABEL: &str = "CPU";
const GFX_LABEL: &str = "GFX";
const COMPUTE_LABEL: &str = "COMP";
const DMA_LABEL: &str = "DMA";
const DEC_LABEL: &str = "DEC";
const ENC_LABEL: &str = "ENC";
const VCN_UNIFIED_LABEL: &str = "VCNU";
const VPE_LABEL: &str = "VPE";
const KFD_LABEL: &str = "KFD";
use crate::AppTextView;
impl AppTextView {
pub const FDINFO_TITLE: &str = "fdinfo";
pub fn print_fdinfo(
&mut self,
stat: &mut FdInfoStat,
sort: FdInfoSortType,
reverse: bool,
) -> Result<(), fmt::Error> {
self.text.clear();
write!(
self.text.buf,
" {proc_name:<PROC_NAME_LEN$}|{pid:^PID_MAX_LEN$}|{KFD_LABEL}|{VRAM_LABEL:^6}|{GTT_LABEL:^6}|{CPU_LABEL:^4}|{GFX_LABEL:^4}|{COMPUTE_LABEL:^4}|{DMA_LABEL:^4}|",
proc_name = "Name",
pid = "PID",
)?;
if stat.has_vcn_unified {
write!(self.text.buf, "{VCN_UNIFIED_LABEL:^4}|")?;
} else {
write!(self.text.buf, "{DEC_LABEL:^4}|{ENC_LABEL:^4}|")?;
}
if stat.has_vpe {
write!(self.text.buf, "{VPE_LABEL:^4}|")?;
}
writeln!(self.text.buf)?;
stat.sort_proc_usage(sort, reverse);
self.print_fdinfo_usage(stat)?;
Ok(())
}
pub fn print_fdinfo_usage(&mut self, stat: &FdInfoStat) -> Result<(), fmt::Error> {
for pu in &stat.proc_usage {
let utf16_count = pu.name.encode_utf16().filter(|&u| u >= 0x3000).count();
let name_len = if pu.name.len() != utf16_count {
PROC_NAME_LEN - utf16_count
} else {
PROC_NAME_LEN
};
write!(
self.text.buf,
" {name:name_len$}|{pid:>PID_MAX_LEN$}|{kfd:^3}|{vram:>5}M|{gtt:>5}M|",
name = pu.name,
pid = pu.pid,
kfd = if pu.is_kfd_process { "Y" } else { "" },
vram = pu.usage.vram_usage >> 10,
gtt = pu.usage.gtt_usage >> 10,
)?;
write!(self.text.buf, "{:>3}%|", pu.usage.cpu)?;
for (usage, label_len) in [
(pu.usage.gfx, GFX_LABEL.len()),
(pu.usage.compute, COMPUTE_LABEL.len()-1),
(pu.usage.dma, DMA_LABEL.len()),
] {
write!(self.text.buf, "{usage:>label_len$}%|")?;
}
if stat.has_vcn_unified {
write!(self.text.buf, "{:>3}%|", pu.usage.vcn_unified)?;
} else {
write!(self.text.buf, "{:>3}%|", pu.usage.total_dec)?;
write!(self.text.buf, "{:>3}%|", pu.usage.total_enc)?;
}
if stat.has_vpe {
write!(self.text.buf, "{:>3}%|", pu.usage.vpe)?;
}
writeln!(self.text.buf)?;
}
Ok(())
}
pub fn fdinfo_name(index: usize) -> String {
format!("{} {index}", Self::FDINFO_TITLE)
}
pub fn cb_fdinfo(siv: &mut cursive::Cursive) {
use crate::{set_min_height, set_visible_height, Opt};
use cursive::views::TextView;
let visible;
let indexes = {
let mut opt = siv.user_data::<Opt>().unwrap().lock().unwrap();
opt.fdinfo ^= true;
visible = opt.fdinfo;
opt.indexes.clone()
};
for i in &indexes {
let name = Self::fdinfo_name(*i);
if visible {
siv.call_on_name(&name, set_visible_height::<TextView>);
} else {
siv.call_on_name(&name, set_min_height::<TextView>);
}
}
}
pub fn cb_reverse_sort(siv: &mut cursive::Cursive) {
{
let mut opt = siv.user_data::<Opt>().unwrap().lock().unwrap();
opt.reverse_sort ^= true;
}
}
pub fn cb_sort_by_pid(siv: &mut cursive::Cursive) {
{
let mut opt = siv.user_data::<Opt>().unwrap().lock().unwrap();
opt.fdinfo_sort = FdInfoSortType::PID;
}
}
pub fn cb_sort_by_vram(siv: &mut cursive::Cursive) {
{
let mut opt = siv.user_data::<Opt>().unwrap().lock().unwrap();
opt.fdinfo_sort = FdInfoSortType::VRAM;
}
}
pub fn cb_sort_by_cpu(siv: &mut cursive::Cursive) {
{
let mut opt = siv.user_data::<Opt>().unwrap().lock().unwrap();
opt.fdinfo_sort = FdInfoSortType::CPU;
}
}
pub fn cb_sort_by_gfx(siv: &mut cursive::Cursive) {
{
let mut opt = siv.user_data::<Opt>().unwrap().lock().unwrap();
opt.fdinfo_sort = FdInfoSortType::GFX;
}
}
pub fn cb_sort_by_media(siv: &mut cursive::Cursive) {
{
let mut opt = siv.user_data::<Opt>().unwrap().lock().unwrap();
opt.fdinfo_sort = FdInfoSortType::VCNU;
}
}
}