• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //! Tool to help the parsing and filtering of /proc/allocinfo
18 
19 use alloctop::{run, SortBy};
20 use std::env;
21 use std::process;
22 
print_help()23 fn print_help() {
24     println!("alloctop - A tool for analyzing memory allocations from /proc/allocinfo\n");
25     println!("Usage: alloctop [OPTIONS]\n");
26     println!("Options:");
27     println!("  -m, --min <size>    Only display allocations with size greater than <size>");
28     println!("  -n, --lines <num>   Only output the first <num> lines");
29     println!("  -o, --once          Display the output once and then exit.");
30     println!("  -s, --sort <s|c|t>  Sort the output by size (s), number of calls (c), or tag (t)");
31     println!("  -t, --tree          Aggregate output data by tag components. Only the \"min\"");
32     println!("                      option is implemented for this visualization\n");
33     println!("  -h, --help          Display this help message and exit");
34 }
35 
36 #[cfg(unix)]
reset_sigpipe()37 fn reset_sigpipe() {
38     // SAFETY:
39     // This is safe because we are simply resetting the SIGPIPE signal handler to its default behavior.
40     // The `signal` function itself is marked as unsafe because it can globally modify process state.
41     // However, in this specific case, we are restoring the default behavior of ignoring the signal
42     // which is a well-defined and safe operation.
43     unsafe {
44         libc::signal(libc::SIGPIPE, libc::SIG_DFL);
45     }
46 }
47 
48 #[cfg(not(unix))]
reset_sigpipe()49 fn reset_sigpipe() {
50     // no-op
51 }
52 
main()53 fn main() {
54     reset_sigpipe();
55 
56     let args: Vec<String> = env::args().collect();
57     let mut max_lines: usize = usize::MAX;
58     let mut sort_by = None;
59     let mut min_size = 0;
60     let mut use_tree = false;
61     let mut display_once = false;
62 
63     let mut i = 1;
64     while i < args.len() {
65         match args[i].as_str() {
66             "-h" | "--help" => {
67                 print_help();
68                 process::exit(0);
69             }
70             "-s" | "--sort" => {
71                 i += 1;
72                 if i < args.len() {
73                     sort_by = match args[i].as_str() {
74                         "s" => Some(SortBy::Size),
75                         "c" => Some(SortBy::Calls),
76                         "t" => Some(SortBy::Tag),
77                         _ => {
78                             eprintln!("Invalid sort option. Use 's', 'c', or 't'.");
79                             process::exit(1);
80                         }
81                     };
82                 } else {
83                     eprintln!("Missing argument for --sort.");
84                     process::exit(1);
85                 }
86             }
87             "-m" | "--min" => {
88                 i += 1;
89                 if i < args.len() {
90                     min_size = match args[i].parse::<u64>() {
91                         Ok(val) => val,
92                         Err(_) => {
93                             eprintln!("Invalid minimum size. Please provide a valid number.");
94                             process::exit(1);
95                         }
96                     };
97                 } else {
98                     eprintln!("Missing argument for --min.");
99                     process::exit(1);
100                 }
101             }
102             "-n" | "--lines" => {
103                 i += 1;
104                 if i < args.len() {
105                     max_lines = match args[i].parse::<usize>() {
106                         Ok(val) => val,
107                         Err(_) => {
108                             eprintln!("Invalid lines. Please provide a valid number.");
109                             process::exit(1);
110                         }
111                     };
112                 } else {
113                     eprintln!("Missing argument for --lines.");
114                     process::exit(1);
115                 }
116             }
117             "-o" | "--once" => {
118                 display_once = true;
119             }
120             "-t" | "--tree" => {
121                 use_tree = true;
122             }
123             _ => {
124                 eprintln!("Invalid argument: {}", args[i]);
125                 print_help();
126                 process::exit(1);
127             }
128         }
129         i += 1;
130     }
131 
132     if !display_once {
133         eprintln!("Only \"display once\" mode currently available, run with \"-o\".");
134         process::exit(1);
135     }
136 
137     if let Err(e) = run(max_lines, sort_by, min_size, use_tree, alloctop::PROC_ALLOCINFO) {
138         eprintln!("{}", e);
139         process::exit(1);
140     }
141 }
142