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