5
5
* GNU General Public License version 2.
6
6
*/
7
7
8
+ use std:: cmp:: Reverse ;
9
+ use std:: collections:: HashMap ;
8
10
use std:: fmt:: Debug ;
9
11
use std:: fs:: File as FsFile ;
10
12
use std:: io:: BufRead ;
@@ -195,6 +197,24 @@ fn parse_events<R: BufRead>(reader: R) -> Result<Vec<Event>> {
195
197
Ok ( objects)
196
198
}
197
199
200
+ fn sort_pids ( events : & [ Event ] ) -> Vec < ( u64 , u64 , u64 ) > {
201
+ // Count the number of events with the same PID
202
+ let mut pid_counts: HashMap < u64 , ( u64 , u64 ) > = HashMap :: new ( ) ; // pid -> (counter, ppid)
203
+ for event in events {
204
+ let process = & event. process ;
205
+ let count = pid_counts. entry ( process. pid ) . or_insert ( ( 0 , process. ppid ) ) ;
206
+ count. 0 += 1 ;
207
+ }
208
+
209
+ // Sort the results so we can find the top k
210
+ let mut sorted_pids: Vec < ( u64 , u64 , u64 ) > = pid_counts
211
+ . into_iter ( )
212
+ . map ( |( pid, ( count, ppid) ) | ( pid, count, ppid) )
213
+ . collect ( ) ;
214
+ sorted_pids. sort_by_key ( |( _, count, _) | Reverse ( * count) ) ;
215
+ sorted_pids
216
+ }
217
+
198
218
#[ async_trait]
199
219
impl crate :: Subcommand for ReadCmd {
200
220
async fn run ( & self ) -> Result < ExitCode > {
@@ -203,13 +223,26 @@ impl crate::Subcommand for ReadCmd {
203
223
let file = FsFile :: open ( path) ?;
204
224
let reader = BufReader :: new ( file) ;
205
225
206
- let objects = parse_events ( reader) ?;
226
+ let events = parse_events ( reader) ?;
207
227
208
228
if self . verbose {
209
- println ! ( "Parsed {} objects" , objects . len( ) ) ;
210
- println ! ( "{:#?}" , objects ) ;
229
+ println ! ( "Parsed {} objects" , events . len( ) ) ;
230
+ println ! ( "{:#?}" , events ) ;
211
231
}
212
232
233
+ let sorted_pids = sort_pids ( & events) ;
234
+
235
+ let slice = if self . count == 0 {
236
+ & sorted_pids
237
+ } else {
238
+ & sorted_pids[ ..self . count . min ( sorted_pids. len ( ) ) ]
239
+ } ;
240
+
241
+ // Print the top results
242
+ println ! ( "{:<6} | {:<7} | {}" , "PID" , "PPID" , "Counts" ) ;
243
+ for ( pid, count, ppid) in slice {
244
+ println ! ( "{:<6} | {:<7} | {}" , pid, ppid, count) ;
245
+ }
213
246
Ok ( 0 )
214
247
}
215
248
}
@@ -337,4 +370,45 @@ mod tests {
337
370
assert ! ( parsed. is_ok( ) ) ;
338
371
assert_eq ! ( parsed. unwrap( ) . len( ) , 1 ) ;
339
372
}
373
+
374
+ #[ test]
375
+ fn test_sort_pids ( ) {
376
+ fn make_event ( pid : u64 , ppid : u64 ) -> Event {
377
+ Event {
378
+ event_type : "NOTIFY_OPEN" . to_string ( ) ,
379
+ file : File {
380
+ path : "what" . to_string ( ) ,
381
+ } ,
382
+ process : Process {
383
+ ancestors : vec ! [ ] ,
384
+ args : vec ! [ ] ,
385
+ command : "what" . to_string ( ) ,
386
+ pid,
387
+ ppid,
388
+ uid : 67890 ,
389
+ } ,
390
+ event_timestamp : 1740024705 ,
391
+ }
392
+ }
393
+
394
+ let events = vec ! [
395
+ make_event( 66778 , 22309 ) ,
396
+ make_event( 980066 , 11759 ) ,
397
+ make_event( 1 , 2 ) ,
398
+ make_event( 1 , 2 ) ,
399
+ make_event( 980066 , 11759 ) ,
400
+ make_event( 980066 , 11759 ) ,
401
+ make_event( 66778 , 22309 ) ,
402
+ make_event( 980066 , 11759 ) ,
403
+ make_event( 1 , 2 ) ,
404
+ make_event( 980066 , 11759 ) ,
405
+ make_event( 1 , 2 ) ,
406
+ ] ;
407
+
408
+ let sorted_pids = sort_pids ( & events) ;
409
+ assert_eq ! ( sorted_pids. len( ) , 3 ) ;
410
+ assert_eq ! ( sorted_pids[ 0 ] . 0 , 980066 ) ;
411
+ assert_eq ! ( sorted_pids[ 1 ] . 0 , 1 ) ;
412
+ assert_eq ! ( sorted_pids[ 2 ] . 0 , 66778 ) ;
413
+ }
340
414
}
0 commit comments