Skip to content

Commit 1a0db60

Browse files
committed
top: tui 2 3 (numa view)
1 parent 3b01201 commit 1a0db60

File tree

8 files changed

+312
-85
lines changed

8 files changed

+312
-85
lines changed

src/uu/top/src/header.rs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::picker::sysinfo;
77
use crate::platform::*;
88
use crate::tui::stat::{CpuValueMode, TuiStat};
99
use bytesize::ByteSize;
10-
use uu_vmstat::CpuLoad;
10+
use uu_vmstat::{CpuLoad, CpuLoadRaw};
1111
use uu_w::get_formatted_uptime_procps;
1212
use uucore::uptime::{get_formatted_loadavg, get_formatted_nusers, get_formatted_time};
1313

@@ -119,8 +119,8 @@ fn user() -> String {
119119
get_formatted_nusers()
120120
}
121121

122-
fn sum_cpu_loads(cpu_loads: &[uu_vmstat::CpuLoadRaw]) -> uu_vmstat::CpuLoadRaw {
123-
let mut total = uu_vmstat::CpuLoadRaw {
122+
fn sum_cpu_loads(cpu_loads: Vec<&CpuLoadRaw>) -> CpuLoadRaw {
123+
let mut total = CpuLoadRaw {
124124
user: 0,
125125
nice: 0,
126126
system: 0,
@@ -162,9 +162,38 @@ fn cpu(stat: &TuiStat) -> Vec<(String, CpuLoad)> {
162162
})
163163
.collect::<Vec<(String, CpuLoad)>>(),
164164
CpuValueMode::Sum => {
165-
let total = sum_cpu_loads(&cpu_loads);
165+
let total = sum_cpu_loads(cpu_loads.iter().collect());
166166
let cpu_load = CpuLoad::from_raw(&total);
167167
vec![(String::from("Cpu(s)"), cpu_load)]
168168
}
169+
CpuValueMode::Numa => {
170+
let numa_nodes = get_numa_nodes();
171+
let total = sum_cpu_loads(cpu_loads.iter().collect());
172+
let cpu_load = CpuLoad::from_raw(&total);
173+
let mut data = vec![(String::from("Cpu(s)"), cpu_load)];
174+
for (id, cores) in numa_nodes {
175+
let loads = cores.iter().map(|id| &cpu_loads[*id]).collect();
176+
let total = sum_cpu_loads(loads);
177+
let cpu_load = CpuLoad::from_raw(&total);
178+
data.push((format!("Node{id}"), cpu_load));
179+
}
180+
data
181+
}
182+
CpuValueMode::NumaNode(id) => {
183+
let numa_nodes = get_numa_nodes();
184+
if let Some(cores) = numa_nodes.get(&id) {
185+
let loads = cores.iter().map(|id| &cpu_loads[*id]).collect();
186+
let total = sum_cpu_loads(loads);
187+
let cpu_load = CpuLoad::from_raw(&total);
188+
let mut data = vec![(format!("Node{id}"), cpu_load)];
189+
data.extend(cores.iter().map(|core_id| {
190+
let cpu_load = CpuLoad::from_raw(&cpu_loads[*core_id]);
191+
(format!("Cpu{core_id}"), cpu_load)
192+
}));
193+
data
194+
} else {
195+
vec![]
196+
}
197+
}
169198
}
170199
}

src/uu/top/src/platform/fallback.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
use crate::header::Memory;
99
use crate::picker::sysinfo;
10+
use std::collections::HashMap;
1011

1112
pub fn get_cpu_loads() -> Vec<uu_vmstat::CpuLoadRaw> {
1213
vec![]
@@ -26,3 +27,6 @@ pub fn get_memory() -> Memory {
2627
used_swap: binding.used_swap(),
2728
}
2829
}
30+
pub fn get_numa_nodes() -> HashMap<usize, Vec<usize>> {
31+
HashMap::new()
32+
}

src/uu/top/src/platform/linux.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// file that was distributed with this source code.
55

66
use crate::header::Memory;
7+
use std::collections::HashMap;
78
use std::str::FromStr;
89

910
extern "C" {
@@ -92,3 +93,38 @@ pub fn get_memory() -> Memory {
9293
used_swap: mem_info.swap_total.0 - mem_info.swap_free.0,
9394
}
9495
}
96+
97+
pub fn get_numa_nodes() -> HashMap<usize, Vec<usize>> {
98+
let mut map = HashMap::new();
99+
if let Ok(entries) = std::fs::read_dir("/sys/devices/system/node/") {
100+
for entry in entries.flatten() {
101+
let file_name = entry.file_name();
102+
let file_name = file_name.to_string_lossy();
103+
if file_name.starts_with("node") {
104+
let node_id = file_name.trim_start_matches("node").parse::<usize>();
105+
let node_id = match node_id {
106+
Ok(id) => id,
107+
Err(_) => continue,
108+
};
109+
110+
let mut nodes = Vec::new();
111+
112+
if let Ok(node_entries) = std::fs::read_dir(entry.path()) {
113+
for node_entry in node_entries.flatten() {
114+
let cpu_file_name = node_entry.file_name();
115+
let cpu_file_name = cpu_file_name.to_string_lossy();
116+
if cpu_file_name.starts_with("cpu") {
117+
let cpu_id = cpu_file_name.trim_start_matches("cpu").parse::<usize>();
118+
if let Ok(cpu_id) = cpu_id {
119+
nodes.push(cpu_id);
120+
}
121+
}
122+
}
123+
nodes.sort();
124+
map.insert(node_id, nodes);
125+
}
126+
}
127+
}
128+
}
129+
map
130+
}

src/uu/top/src/platform/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub mod windows;
1111
pub mod fallback;
1212

1313
#[cfg(target_os = "linux")]
14-
pub use linux::{get_cpu_loads, get_memory, get_nusers_systemd};
14+
pub use linux::{get_cpu_loads, get_memory, get_numa_nodes, get_nusers_systemd};
1515
#[cfg(target_os = "windows")]
1616
pub use windows::get_cpu_loads;
1717

src/uu/top/src/top.rs

Lines changed: 4 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55

66
use crate::header::Header;
77
use crate::tui::stat::TuiStat;
8-
use crate::tui::Tui;
8+
use crate::tui::{handle_input, Tui};
99
use clap::{arg, crate_version, value_parser, ArgAction, ArgGroup, ArgMatches, Command};
1010
use picker::pickers;
1111
use picker::sysinfo;
1212
use ratatui::crossterm::event;
13-
use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
1413
use ratatui::prelude::Widget;
1514
use std::sync::atomic::{AtomicBool, Ordering};
1615
use std::sync::{Arc, RwLock};
@@ -125,6 +124,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
125124
{
126125
let header = Header::new(&tui_stat.read().unwrap());
127126
let proc_list = ProcList::new(&settings);
127+
tui_stat.write().unwrap().input_error = None;
128128
*data.write().unwrap() = (header, proc_list);
129129
should_update.store(true, Ordering::Relaxed);
130130
}
@@ -142,82 +142,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
142142
})?;
143143
loop {
144144
if let Ok(true) = event::poll(Duration::from_millis(20)) {
145-
// If event available, break this loop
146145
if let Ok(e) = event::read() {
147-
match e {
148-
event::Event::Key(KeyEvent {
149-
code: KeyCode::Char('c'),
150-
modifiers: KeyModifiers::CONTROL,
151-
..
152-
})
153-
| event::Event::Key(KeyEvent {
154-
code: KeyCode::Char('q'),
155-
..
156-
}) => {
157-
uucore::error::set_exit_code(0);
158-
break;
159-
}
160-
event::Event::Key(KeyEvent {
161-
code: KeyCode::Char('l'),
162-
..
163-
}) => {
164-
let mut stat = tui_stat.write().unwrap();
165-
stat.show_load_avg = !stat.show_load_avg;
166-
should_update.store(true, Ordering::Relaxed);
167-
}
168-
event::Event::Key(KeyEvent {
169-
code: KeyCode::Char('t'),
170-
..
171-
}) => {
172-
let mut stat = tui_stat.write().unwrap();
173-
stat.cpu_graph_mode = stat.cpu_graph_mode.next();
174-
should_update.store(true, Ordering::Relaxed);
175-
}
176-
event::Event::Key(KeyEvent {
177-
code: KeyCode::Char('1'),
178-
..
179-
}) => {
180-
let mut stat = tui_stat.write().unwrap();
181-
stat.cpu_value_mode = stat.cpu_value_mode.next();
182-
183-
should_update.store(true, Ordering::Relaxed);
184-
data.write().unwrap().0.update_cpu(&stat);
185-
}
186-
event::Event::Key(KeyEvent {
187-
code: KeyCode::Char('4'),
188-
..
189-
}) => {
190-
let mut stat = tui_stat.write().unwrap();
191-
stat.cpu_column = stat.cpu_column % 8 + 1;
192-
should_update.store(true, Ordering::Relaxed);
193-
}
194-
event::Event::Key(KeyEvent {
195-
code: KeyCode::Char('m'),
196-
..
197-
}) => {
198-
let mut stat = tui_stat.write().unwrap();
199-
stat.memory_graph_mode = stat.memory_graph_mode.next();
200-
should_update.store(true, Ordering::Relaxed);
201-
}
202-
event::Event::Key(KeyEvent {
203-
code: KeyCode::Up, ..
204-
}) => {
205-
let mut stat = tui_stat.write().unwrap();
206-
if stat.list_offset > 0 {
207-
stat.list_offset -= 1;
208-
should_update.store(true, Ordering::Relaxed);
209-
}
210-
}
211-
event::Event::Key(KeyEvent {
212-
code: KeyCode::Down,
213-
..
214-
}) => {
215-
let mut stat = tui_stat.write().unwrap();
216-
stat.list_offset += 1;
217-
should_update.store(true, Ordering::Relaxed);
218-
}
219-
event::Event::Resize(_, _) => should_update.store(true, Ordering::Relaxed),
220-
_ => {}
146+
if handle_input(e, &tui_stat, &data, &should_update)? {
147+
break;
221148
}
222149
}
223150
}
@@ -233,8 +160,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
233160
})?;
234161
}
235162
should_update.store(false, Ordering::Relaxed);
236-
237-
sleep(Duration::from_millis(20));
238163
}
239164

240165
ratatui::restore();

0 commit comments

Comments
 (0)