44// file that was distributed with this source code.
55
66use crate :: picker:: sysinfo;
7+ use crate :: platform:: * ;
8+ use crate :: tui:: stat:: { CpuValueMode , TuiStat } ;
79use bytesize:: ByteSize ;
10+ use uu_vmstat:: CpuLoad ;
811use uu_w:: get_formatted_uptime_procps;
912use uucore:: uptime:: { get_formatted_loadavg, get_formatted_nusers, get_formatted_time} ;
1013
11- pub ( crate ) fn header ( scale_summary_mem : Option < & String > ) -> String {
12- format ! (
13- "top - {time} {uptime}, {user}, {load_average}\n \
14- {task}\n \
15- {cpu}\n \
16- {memory}",
17- time = get_formatted_time( ) ,
18- uptime = uptime( ) ,
19- user = user( ) ,
20- load_average = load_average( ) ,
21- task = task( ) ,
22- cpu = cpu( ) ,
23- memory = memory( scale_summary_mem) ,
24- )
14+ pub ( crate ) struct Header {
15+ pub uptime : Uptime ,
16+ pub task : Task ,
17+ pub cpu : Vec < ( String , CpuLoad ) > ,
18+ pub memory : Memory ,
2519}
2620
27- #[ cfg( target_os = "linux" ) ]
28- extern "C" {
29- pub fn sd_booted ( ) -> libc:: c_int ;
30- pub fn sd_get_sessions ( sessions : * mut * mut * mut libc:: c_char ) -> libc:: c_int ;
31- pub fn sd_session_get_class (
32- session : * const libc:: c_char ,
33- class : * mut * mut libc:: c_char ,
34- ) -> libc:: c_int ;
21+ impl Header {
22+ pub fn new ( stat : & TuiStat ) -> Header {
23+ Header {
24+ uptime : Uptime :: new ( ) ,
25+ task : Task :: new ( ) ,
26+ cpu : cpu ( stat) ,
27+ memory : Memory :: new ( ) ,
28+ }
29+ }
30+
31+ pub fn update_cpu ( & mut self , stat : & TuiStat ) {
32+ self . cpu = cpu ( stat) ;
33+ }
3534}
3635
37- fn format_memory ( memory_b : u64 , unit : u64 ) -> f64 {
38- ByteSize :: b ( memory_b) . 0 as f64 / unit as f64
36+ pub ( crate ) struct Uptime {
37+ pub time : String ,
38+ pub uptime : String ,
39+ pub user : String ,
40+ pub load_average : String ,
41+ }
42+
43+ impl Uptime {
44+ pub fn new ( ) -> Uptime {
45+ Uptime {
46+ time : get_formatted_time ( ) ,
47+ uptime : get_formatted_uptime_procps ( ) . unwrap_or_default ( ) ,
48+ user : user ( ) ,
49+ load_average : get_formatted_loadavg ( ) . unwrap_or_default ( ) ,
50+ }
51+ }
3952}
4053
41- #[ inline]
42- fn uptime ( ) -> String {
43- get_formatted_uptime_procps ( ) . unwrap_or_default ( )
54+ pub ( crate ) struct Task {
55+ pub total : usize ,
56+ pub running : usize ,
57+ pub sleeping : usize ,
58+ pub stopped : usize ,
59+ pub zombie : usize ,
4460}
61+ impl Task {
62+ pub fn new ( ) -> Task {
63+ let binding = sysinfo ( ) . read ( ) . unwrap ( ) ;
64+
65+ let process = binding. processes ( ) ;
66+ let mut running_process = 0 ;
67+ let mut sleeping_process = 0 ;
68+ let mut stopped_process = 0 ;
69+ let mut zombie_process = 0 ;
70+
71+ for ( _, process) in process. iter ( ) {
72+ match process. status ( ) {
73+ sysinfo:: ProcessStatus :: Run => running_process += 1 ,
74+ sysinfo:: ProcessStatus :: Sleep => sleeping_process += 1 ,
75+ sysinfo:: ProcessStatus :: Stop => stopped_process += 1 ,
76+ sysinfo:: ProcessStatus :: Zombie => zombie_process += 1 ,
77+ _ => { }
78+ } ;
79+ }
4580
46- #[ cfg( target_os = "linux" ) ]
47- pub fn get_nusers_systemd ( ) -> uucore:: error:: UResult < usize > {
48- use std:: ffi:: CStr ;
49- use std:: ptr;
50- use uucore:: error:: USimpleError ;
51- use uucore:: libc:: * ;
52-
53- // SAFETY: sd_booted to check if system is booted with systemd.
54- unsafe {
55- // systemd
56- if sd_booted ( ) > 0 {
57- let mut sessions_list: * mut * mut c_char = ptr:: null_mut ( ) ;
58- let mut num_user = 0 ;
59- let sessions = sd_get_sessions ( & mut sessions_list) ;
60-
61- if sessions > 0 {
62- for i in 0 ..sessions {
63- let mut class: * mut c_char = ptr:: null_mut ( ) ;
64-
65- if sd_session_get_class (
66- * sessions_list. add ( i as usize ) as * const c_char ,
67- & mut class,
68- ) < 0
69- {
70- continue ;
71- }
72- if CStr :: from_ptr ( class) . to_str ( ) . unwrap ( ) . starts_with ( "user" ) {
73- num_user += 1 ;
74- }
75- free ( class as * mut c_void ) ;
76- }
77- }
78-
79- for i in 0 ..sessions {
80- free ( * sessions_list. add ( i as usize ) as * mut c_void ) ;
81- }
82- free ( sessions_list as * mut c_void ) ;
83-
84- return Ok ( num_user) ;
81+ Task {
82+ total : process. len ( ) ,
83+ running : running_process,
84+ sleeping : sleeping_process,
85+ stopped : stopped_process,
86+ zombie : zombie_process,
8587 }
8688 }
87- Err ( USimpleError :: new (
88- 1 ,
89- "could not retrieve number of logged users" ,
90- ) )
89+ }
90+
91+ pub ( crate ) struct Memory {
92+ pub total : u64 ,
93+ pub free : u64 ,
94+ pub used : u64 ,
95+ pub buff_cache : u64 ,
96+ pub available : u64 ,
97+ pub total_swap : u64 ,
98+ pub free_swap : u64 ,
99+ pub used_swap : u64 ,
100+ }
101+
102+ impl Memory {
103+ pub fn new ( ) -> Memory {
104+ get_memory ( )
105+ }
106+ }
107+
108+ pub ( crate ) fn format_memory ( memory_b : u64 , unit : u64 ) -> f64 {
109+ ByteSize :: b ( memory_b) . 0 as f64 / unit as f64
91110}
92111
93112// see: https://gitlab.com/procps-ng/procps/-/blob/4740a0efa79cade867cfc7b32955fe0f75bf5173/library/uptime.c#L63-L115
@@ -100,152 +119,52 @@ fn user() -> String {
100119 get_formatted_nusers ( )
101120}
102121
103- fn load_average ( ) -> String {
104- get_formatted_loadavg ( ) . unwrap_or_default ( )
105- }
122+ fn sum_cpu_loads ( cpu_loads : & [ uu_vmstat:: CpuLoadRaw ] ) -> uu_vmstat:: CpuLoadRaw {
123+ let mut total = uu_vmstat:: CpuLoadRaw {
124+ user : 0 ,
125+ nice : 0 ,
126+ system : 0 ,
127+ idle : 0 ,
128+ io_wait : 0 ,
129+ hardware_interrupt : 0 ,
130+ software_interrupt : 0 ,
131+ steal_time : 0 ,
132+ guest : 0 ,
133+ guest_nice : 0 ,
134+ } ;
106135
107- fn task ( ) -> String {
108- let binding = sysinfo ( ) . read ( ) . unwrap ( ) ;
109-
110- let process = binding. processes ( ) ;
111- let mut running_process = 0 ;
112- let mut sleeping_process = 0 ;
113- let mut stopped_process = 0 ;
114- let mut zombie_process = 0 ;
115-
116- for ( _, process) in process. iter ( ) {
117- match process. status ( ) {
118- sysinfo:: ProcessStatus :: Run => running_process += 1 ,
119- sysinfo:: ProcessStatus :: Sleep => sleeping_process += 1 ,
120- sysinfo:: ProcessStatus :: Stop => stopped_process += 1 ,
121- sysinfo:: ProcessStatus :: Zombie => zombie_process += 1 ,
122- _ => { }
123- } ;
136+ for load in cpu_loads {
137+ total. user += load. user ;
138+ total. nice += load. nice ;
139+ total. system += load. system ;
140+ total. idle += load. idle ;
141+ total. io_wait += load. io_wait ;
142+ total. hardware_interrupt += load. hardware_interrupt ;
143+ total. software_interrupt += load. software_interrupt ;
144+ total. steal_time += load. steal_time ;
145+ total. guest += load. guest ;
146+ total. guest_nice += load. guest_nice ;
124147 }
125148
126- format ! (
127- "Tasks: {} total, {} running, {} sleeping, {} stopped, {} zombie" ,
128- process. len( ) ,
129- running_process,
130- sleeping_process,
131- stopped_process,
132- zombie_process,
133- )
149+ total
134150}
135151
136- #[ cfg( target_os = "linux" ) ]
137- fn cpu ( ) -> String {
138- let cpu_load = uu_vmstat:: CpuLoad :: current ( ) ;
139-
140- format ! (
141- "%Cpu(s): {:.1} us, {:.1} sy, {:.1} ni, {:.1} id, {:.1} wa, {:.1} hi, {:.1} si, {:.1} st" ,
142- cpu_load. user,
143- cpu_load. system,
144- cpu_load. nice,
145- cpu_load. idle,
146- cpu_load. io_wait,
147- cpu_load. hardware_interrupt,
148- cpu_load. software_interrupt,
149- cpu_load. steal_time,
150- )
151- }
152-
153- #[ cfg( target_os = "windows" ) ]
154- fn cpu ( ) -> String {
155- use libc:: malloc;
156- use windows_sys:: Wdk :: System :: SystemInformation :: NtQuerySystemInformation ;
157-
158- #[ repr( C ) ]
159- #[ derive( Debug ) ]
160- struct SystemProcessorPerformanceInformation {
161- idle_time : i64 , // LARGE_INTEGER
162- kernel_time : i64 , // LARGE_INTEGER
163- user_time : i64 , // LARGE_INTEGER
164- dpc_time : i64 , // LARGE_INTEGER
165- interrupt_time : i64 , // LARGE_INTEGER
166- interrupt_count : u32 , // ULONG
167- }
168-
169- let n_cpu = sysinfo ( ) . read ( ) . unwrap ( ) . cpus ( ) . len ( ) ;
170- let mut cpu_load = SystemProcessorPerformanceInformation {
171- idle_time : 0 ,
172- kernel_time : 0 ,
173- user_time : 0 ,
174- dpc_time : 0 ,
175- interrupt_time : 0 ,
176- interrupt_count : 0 ,
177- } ;
178- // SAFETY: malloc is safe to use here. We free the memory after we are done with it. If action fails, all "time" will be 0.
179- unsafe {
180- let len = n_cpu * size_of :: < SystemProcessorPerformanceInformation > ( ) ;
181- let data = malloc ( len) ;
182- let status = NtQuerySystemInformation (
183- windows_sys:: Wdk :: System :: SystemInformation :: SystemProcessorPerformanceInformation ,
184- data,
185- ( n_cpu * size_of :: < SystemProcessorPerformanceInformation > ( ) ) as u32 ,
186- std:: ptr:: null_mut ( ) ,
187- ) ;
188- if status == 0 {
189- for i in 0 ..n_cpu {
190- let cpu = data. add ( i * size_of :: < SystemProcessorPerformanceInformation > ( ) )
191- as * const SystemProcessorPerformanceInformation ;
192- let cpu = cpu. as_ref ( ) . unwrap ( ) ;
193- cpu_load. idle_time += cpu. idle_time ;
194- cpu_load. kernel_time += cpu. kernel_time ;
195- cpu_load. user_time += cpu. user_time ;
196- cpu_load. dpc_time += cpu. dpc_time ;
197- cpu_load. interrupt_time += cpu. interrupt_time ;
198- cpu_load. interrupt_count += cpu. interrupt_count ;
199- }
152+ fn cpu ( stat : & TuiStat ) -> Vec < ( String , CpuLoad ) > {
153+ let cpu_loads = get_cpu_loads ( ) ;
154+
155+ match stat. cpu_value_mode {
156+ CpuValueMode :: PerCore => cpu_loads
157+ . iter ( )
158+ . enumerate ( )
159+ . map ( |( nth, cpu_load_raw) | {
160+ let cpu_load = CpuLoad :: from_raw ( cpu_load_raw) ;
161+ ( format ! ( "Cpu{nth}" ) , cpu_load)
162+ } )
163+ . collect :: < Vec < ( String , CpuLoad ) > > ( ) ,
164+ CpuValueMode :: Sum => {
165+ let total = sum_cpu_loads ( & cpu_loads) ;
166+ let cpu_load = CpuLoad :: from_raw ( & total) ;
167+ vec ! [ ( String :: from( "Cpu(s)" ) , cpu_load) ]
200168 }
201169 }
202- let total = cpu_load. idle_time
203- + cpu_load. kernel_time
204- + cpu_load. user_time
205- + cpu_load. dpc_time
206- + cpu_load. interrupt_time ;
207- format ! (
208- "%Cpu(s): {:.1} us, {:.1} sy, {:.1} id, {:.1} hi, {:.1} si" ,
209- cpu_load. user_time as f64 / total as f64 * 100.0 ,
210- cpu_load. kernel_time as f64 / total as f64 * 100.0 ,
211- cpu_load. idle_time as f64 / total as f64 * 100.0 ,
212- cpu_load. interrupt_time as f64 / total as f64 * 100.0 ,
213- cpu_load. dpc_time as f64 / total as f64 * 100.0 ,
214- )
215- }
216-
217- //TODO: Implement for macos
218- #[ cfg( target_os = "macos" ) ]
219- fn cpu ( ) -> String {
220- "TODO" . into ( )
221- }
222-
223- fn memory ( scale_summary_mem : Option < & String > ) -> String {
224- let binding = sysinfo ( ) . read ( ) . unwrap ( ) ;
225- let ( unit, unit_name) = match scale_summary_mem {
226- Some ( scale) => match scale. as_str ( ) {
227- "k" => ( bytesize:: KIB , "KiB" ) ,
228- "m" => ( bytesize:: MIB , "MiB" ) ,
229- "g" => ( bytesize:: GIB , "GiB" ) ,
230- "t" => ( bytesize:: TIB , "TiB" ) ,
231- "p" => ( bytesize:: PIB , "PiB" ) ,
232- "e" => ( 1_152_921_504_606_846_976 , "EiB" ) ,
233- _ => ( bytesize:: MIB , "MiB" ) ,
234- } ,
235- None => ( bytesize:: MIB , "MiB" ) ,
236- } ;
237-
238- format ! (
239- "{unit_name} Mem : {:8.1} total, {:8.1} free, {:8.1} used, {:8.1} buff/cache\n \
240- {unit_name} Swap: {:8.1} total, {:8.1} free, {:8.1} used, {:8.1} avail Mem",
241- format_memory( binding. total_memory( ) , unit) ,
242- format_memory( binding. free_memory( ) , unit) ,
243- format_memory( binding. used_memory( ) , unit) ,
244- format_memory( binding. available_memory( ) - binding. free_memory( ) , unit) ,
245- format_memory( binding. total_swap( ) , unit) ,
246- format_memory( binding. free_swap( ) , unit) ,
247- format_memory( binding. used_swap( ) , unit) ,
248- format_memory( binding. available_memory( ) , unit) ,
249- unit_name = unit_name
250- )
251170}
0 commit comments