1 /*
2 * Copyright (C) 2018 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 #include <error.h>
18 #include <inttypes.h>
19 #include <linux/kernel-page-flags.h>
20 #include <stdlib.h>
21 #include <sys/mman.h>
22 #include <sys/types.h>
23
24 #include <iostream>
25 #include <map>
26 #include <memory>
27 #include <set>
28
29 #include <android-base/parseint.h>
30 #include <android-base/strings.h>
31 #include <meminfo/procmeminfo.h>
32
33 #include <processrecord.h>
34 #include <smapinfo.h>
35
36 using ::android::meminfo::Format;
37 using ::android::meminfo::GetFormat;
38 using ::android::smapinfo::SortOrder;
39
usage(int exit_status)40 [[noreturn]] static void usage(int exit_status) {
41 std::cerr << "Usage: " << getprogname() << " [ -P | -L ] [ -v | -r | -p | -u | -s | -h ]\n"
42 << "\n"
43 << "Sort options:\n"
44 << " -v Sort processes by VSS.\n"
45 << " -r Sort processes by RSS.\n"
46 << " -p Sort processes by PSS.\n"
47 << " -u Sort processes by USS.\n"
48 << " -o Sort (and show) processes by oom score.\n"
49 << " -s Sort processes by swap.\n"
50 << " (Default sort order is PSS.)\n"
51 << " -a Show all mappings, including stack, heap and anon.\n"
52 << " -P /path Limit libraries displayed to those in path.\n"
53 << " -R Reverse sort order (default is descending).\n"
54 << " -m [r][w][x] Only list pages that exactly match permissions\n"
55 << " -c Only show cached (storage backed) pages\n"
56 << " -C Only show non-cached (ram/swap backed) pages\n"
57 << " -k Only show pages collapsed by KSM\n"
58 << " -f [raw][json][csv] Print output in the specified format.\n"
59 << " (Default format is raw text.)\n"
60 << " -h Display this help screen.\n";
61 exit(exit_status);
62 }
63
parse_mapflags(const char * mapflags)64 static uint16_t parse_mapflags(const char* mapflags) {
65 uint16_t ret = 0;
66 for (const char* p = mapflags; *p; p++) {
67 switch (*p) {
68 case 'r':
69 ret |= PROT_READ;
70 break;
71 case 'w':
72 ret |= PROT_WRITE;
73 break;
74 case 'x':
75 ret |= PROT_EXEC;
76 break;
77 default:
78 error(EXIT_FAILURE, 0, "Invalid permissions string: %s, %s", mapflags, p);
79 }
80 }
81 return ret;
82 }
83
main(int argc,char * argv[])84 int main(int argc, char* argv[]) {
85 uint64_t pgflags = 0;
86 uint64_t pgflags_mask = 0;
87
88 // Library filtering options.
89 std::string lib_prefix = "";
90 bool all_libs = false;
91 std::vector<std::string> excluded_libs = {"[heap]", "[stack]"};
92 uint16_t mapflags_mask = 0;
93
94 // Output format (raw text, JSON, CSV).
95 Format format = Format::RAW;
96
97 // Process sorting options.
98 SortOrder sort_order = SortOrder::BY_PSS;
99 bool reverse_sort = false;
100
101 int opt;
102 while ((opt = getopt(argc, argv, "acCf:hkm:opP:uvrsR")) != -1) {
103 switch (opt) {
104 case 'a':
105 all_libs = true;
106 break;
107 case 'c':
108 pgflags = 0;
109 pgflags_mask = (1 << KPF_SWAPBACKED);
110 break;
111 case 'C':
112 pgflags = (1 << KPF_SWAPBACKED);
113 pgflags_mask = (1 << KPF_SWAPBACKED);
114 break;
115 case 'f':
116 format = GetFormat(optarg);
117 if (format == Format::INVALID) {
118 std::cerr << "Invalid format." << std::endl;
119 usage(EXIT_FAILURE);
120 }
121 break;
122 case 'h':
123 usage(EXIT_SUCCESS);
124 case 'k':
125 pgflags = (1 << KPF_KSM);
126 pgflags_mask = (1 << KPF_KSM);
127 break;
128 case 'm':
129 mapflags_mask = parse_mapflags(optarg);
130 break;
131 case 'o':
132 sort_order = SortOrder::BY_OOMADJ;
133 break;
134 case 'p':
135 sort_order = SortOrder::BY_PSS;
136 break;
137 case 'P':
138 lib_prefix = optarg;
139 break;
140 case 'r':
141 sort_order = SortOrder::BY_RSS;
142 break;
143 case 'R':
144 reverse_sort = true;
145 break;
146 case 's':
147 sort_order = SortOrder::BY_SWAP;
148 break;
149 case 'u':
150 sort_order = SortOrder::BY_USS;
151 break;
152 case 'v':
153 sort_order = SortOrder::BY_VSS;
154 break;
155 default:
156 usage(EXIT_FAILURE);
157 }
158 }
159
160 std::set<pid_t> pids;
161 if (!::android::smapinfo::get_all_pids(&pids)) {
162 std::cerr << "Failed to get all pids." << std::endl;
163 exit(EXIT_FAILURE);
164 }
165
166 bool success = ::android::smapinfo::run_librank(
167 pgflags, pgflags_mask, pids, lib_prefix, all_libs, excluded_libs, mapflags_mask, format,
168 sort_order, reverse_sort, nullptr, std::cout, std::cerr);
169 if (!success) {
170 exit(EXIT_FAILURE);
171 }
172 return 0;
173 }
174