The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2008 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 <assert.h> |
| 18 | #include <dirent.h> |
| 19 | #include <errno.h> |
Colin Cross | eff57af | 2013-05-22 14:49:19 -0700 | [diff] [blame] | 20 | #include <getopt.h> |
Colin Cross | 122c719 | 2013-05-23 12:38:54 -0700 | [diff] [blame] | 21 | #include <stdbool.h> |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 22 | #include <stdlib.h> |
| 23 | #include <string.h> |
| 24 | #include <sys/types.h> |
| 25 | #include <unistd.h> |
| 26 | |
| 27 | #include <pagemap/pagemap.h> |
| 28 | |
| 29 | #define MAX_CMDLINE 256 |
| 30 | |
| 31 | struct process_info { |
| 32 | pid_t pid; |
| 33 | char cmdline[MAX_CMDLINE]; |
| 34 | }; |
| 35 | |
| 36 | struct mapping_info { |
| 37 | struct process_info *proc; |
| 38 | pm_memusage_t usage; |
Mark Salyzyn | 1154fe3 | 2014-03-17 08:58:40 -0700 | [diff] [blame] | 39 | }; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 40 | |
| 41 | struct library_info { |
| 42 | struct library_info *next; |
| 43 | char *name; |
| 44 | struct mapping_info **mappings; |
Mark Salyzyn | 1154fe3 | 2014-03-17 08:58:40 -0700 | [diff] [blame] | 45 | size_t mappings_count; |
| 46 | size_t mappings_size; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 47 | pm_memusage_t total_usage; |
| 48 | }; |
| 49 | |
| 50 | static void usage(char *myname); |
| 51 | static int getprocname(pid_t pid, char *buf, size_t len); |
| 52 | static int numcmp(long long a, long long b); |
| 53 | static int licmp(const void *a, const void *b); |
| 54 | |
| 55 | char *library_name_blacklist[] = { "[heap]", "[stack]", "", NULL }; |
| 56 | |
| 57 | #define declare_sort(field) \ |
| 58 | static int sort_by_ ## field (const void *a, const void *b) |
| 59 | |
| 60 | declare_sort(vss); |
| 61 | declare_sort(rss); |
| 62 | declare_sort(pss); |
| 63 | declare_sort(uss); |
Colin Cross | d2b8656 | 2013-06-21 12:55:56 -0700 | [diff] [blame] | 64 | declare_sort(swap); |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 65 | |
| 66 | #define INIT_LIBRARIES 16 |
| 67 | #define INIT_MAPPINGS 4 |
| 68 | |
| 69 | static int order; |
| 70 | |
| 71 | struct library_info **libraries; |
Mark Salyzyn | 1154fe3 | 2014-03-17 08:58:40 -0700 | [diff] [blame] | 72 | size_t libraries_count; |
| 73 | size_t libraries_size; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 74 | |
Colin Cross | 122c719 | 2013-05-23 12:38:54 -0700 | [diff] [blame] | 75 | struct library_info *get_library(const char *name, bool all) { |
Mark Salyzyn | 1154fe3 | 2014-03-17 08:58:40 -0700 | [diff] [blame] | 76 | size_t i; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 77 | struct library_info *library; |
| 78 | |
Colin Cross | 122c719 | 2013-05-23 12:38:54 -0700 | [diff] [blame] | 79 | if (!all) { |
| 80 | for (i = 0; library_name_blacklist[i]; i++) |
| 81 | if (!strcmp(name, library_name_blacklist[i])) |
| 82 | return NULL; |
| 83 | } else { |
| 84 | if (name[0] == 0) { |
| 85 | name = "[anon]"; |
| 86 | } |
| 87 | } |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 88 | |
| 89 | for (i = 0; i < libraries_count; i++) { |
| 90 | if (!strcmp(libraries[i]->name, name)) |
| 91 | return libraries[i]; |
| 92 | } |
| 93 | |
| 94 | if (libraries_count >= libraries_size) { |
| 95 | libraries = realloc(libraries, 2 * libraries_size * sizeof(struct library_info *)); |
| 96 | if (!libraries) { |
| 97 | fprintf(stderr, "Couldn't resize libraries array: %s\n", strerror(errno)); |
| 98 | exit(EXIT_FAILURE); |
| 99 | } |
| 100 | libraries_size = 2 * libraries_size; |
| 101 | } |
| 102 | |
| 103 | library = calloc(1, sizeof(*library)); |
| 104 | if (!library) { |
| 105 | fprintf(stderr, "Couldn't allocate space for library struct: %s\n", strerror(errno)); |
| 106 | exit(EXIT_FAILURE); |
| 107 | } |
| 108 | library->name = malloc(strlen(name) + 1); |
| 109 | if (!library->name) { |
| 110 | fprintf(stderr, "Couldn't allocate space for library name: %s\n", strerror(errno)); |
| 111 | exit(EXIT_FAILURE); |
| 112 | } |
| 113 | strcpy(library->name, name); |
| 114 | library->mappings = malloc(INIT_MAPPINGS * sizeof(struct mapping_info *)); |
| 115 | if (!library->mappings) { |
| 116 | fprintf(stderr, "Couldn't allocate space for library mappings array: %s\n", strerror(errno)); |
| 117 | exit(EXIT_FAILURE); |
| 118 | } |
| 119 | library->mappings_count = 0; library->mappings_size = INIT_MAPPINGS; |
| 120 | pm_memusage_zero(&library->total_usage); |
| 121 | |
| 122 | libraries[libraries_count++] = library; |
| 123 | |
| 124 | return library; |
| 125 | } |
| 126 | |
| 127 | struct mapping_info *get_mapping(struct library_info *library, struct process_info *proc) { |
| 128 | struct mapping_info *mapping; |
Mark Salyzyn | 1154fe3 | 2014-03-17 08:58:40 -0700 | [diff] [blame] | 129 | size_t i; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 130 | |
| 131 | for (i = 0; i < library->mappings_count; i++) { |
| 132 | if (library->mappings[i]->proc == proc) |
| 133 | return library->mappings[i]; |
| 134 | } |
| 135 | |
| 136 | if (library->mappings_count >= library->mappings_size) { |
| 137 | library->mappings = realloc(library->mappings, |
| 138 | 2 * library->mappings_size * sizeof(struct mapping*)); |
| 139 | if (!library->mappings) { |
| 140 | fprintf(stderr, "Couldn't resize mappings array: %s\n", strerror(errno)); |
| 141 | exit(EXIT_FAILURE); |
| 142 | } |
| 143 | library->mappings_size = 2 * library->mappings_size; |
| 144 | } |
| 145 | |
| 146 | mapping = calloc(1, sizeof(*mapping)); |
| 147 | if (!mapping) { |
| 148 | fprintf(stderr, "Couldn't allocate space for mapping struct: %s\n", strerror(errno)); |
| 149 | exit(EXIT_FAILURE); |
| 150 | } |
| 151 | mapping->proc = proc; |
| 152 | pm_memusage_zero(&mapping->usage); |
| 153 | |
| 154 | library->mappings[library->mappings_count++] = mapping; |
| 155 | |
| 156 | return mapping; |
| 157 | } |
| 158 | |
| 159 | struct process_info *get_process(pid_t pid) { |
| 160 | struct process_info *process; |
| 161 | |
| 162 | process = calloc(1, sizeof(*process)); |
| 163 | if (!process) { |
| 164 | fprintf(stderr, "Couldn't allocate space for process struct: %s\n", strerror(errno)); |
| 165 | exit(EXIT_FAILURE); |
| 166 | } |
Mark Salyzyn | 1154fe3 | 2014-03-17 08:58:40 -0700 | [diff] [blame] | 167 | |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 168 | process->pid = pid; |
| 169 | getprocname(pid, process->cmdline, sizeof(process->cmdline)); |
| 170 | |
| 171 | return process; |
| 172 | } |
| 173 | |
Colin Cross | 72f75f0 | 2013-05-22 15:03:52 -0700 | [diff] [blame] | 174 | static int parse_perm(const char *perm) |
| 175 | { |
| 176 | int ret = 0; |
| 177 | |
| 178 | while (*perm) { |
| 179 | switch(*perm) { |
| 180 | case 'r': |
| 181 | ret |= PM_MAP_READ; |
| 182 | break; |
| 183 | case 'w': |
| 184 | ret |= PM_MAP_WRITE; |
| 185 | break; |
| 186 | case 'x': |
| 187 | ret |= PM_MAP_EXEC; |
| 188 | break; |
| 189 | default: |
| 190 | fprintf(stderr, "Unknown permission '%c'\n", *perm); |
| 191 | exit(EXIT_FAILURE); |
| 192 | } |
| 193 | perm++; |
| 194 | } |
| 195 | return ret; |
| 196 | } |
| 197 | |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 198 | int main(int argc, char *argv[]) { |
| 199 | char cmdline[256]; |
| 200 | char *prefix; |
| 201 | size_t prefix_len; |
| 202 | int (*compfn)(const void *a, const void *b); |
| 203 | |
| 204 | pm_kernel_t *ker; |
| 205 | pm_process_t *proc; |
| 206 | |
| 207 | pid_t *pids; |
| 208 | size_t num_procs; |
| 209 | |
| 210 | pm_map_t **maps; |
| 211 | size_t num_maps; |
| 212 | pm_memusage_t map_usage; |
| 213 | |
| 214 | struct library_info *li, **lis; |
| 215 | struct mapping_info *mi, **mis; |
| 216 | struct process_info *pi; |
| 217 | |
Mark Salyzyn | 1154fe3 | 2014-03-17 08:58:40 -0700 | [diff] [blame] | 218 | size_t i, j; |
| 219 | int error; |
Colin Cross | 72f75f0 | 2013-05-22 15:03:52 -0700 | [diff] [blame] | 220 | int perm; |
Colin Cross | 122c719 | 2013-05-23 12:38:54 -0700 | [diff] [blame] | 221 | bool all; |
Colin Cross | bd86b3b | 2013-05-23 12:57:36 -0700 | [diff] [blame] | 222 | uint64_t required_flags; |
| 223 | uint64_t flags_mask; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 224 | |
Colin Cross | d2b8656 | 2013-06-21 12:55:56 -0700 | [diff] [blame] | 225 | bool has_swap = false; |
| 226 | |
JP Abgrall | 80cb155 | 2012-05-11 14:09:59 -0700 | [diff] [blame] | 227 | signal(SIGPIPE, SIG_IGN); |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 228 | compfn = &sort_by_pss; |
| 229 | order = -1; |
| 230 | prefix = NULL; |
| 231 | prefix_len = 0; |
Colin Cross | eff57af | 2013-05-22 14:49:19 -0700 | [diff] [blame] | 232 | opterr = 0; |
Colin Cross | 72f75f0 | 2013-05-22 15:03:52 -0700 | [diff] [blame] | 233 | perm = 0; |
Colin Cross | 122c719 | 2013-05-23 12:38:54 -0700 | [diff] [blame] | 234 | all = false; |
Colin Cross | bd86b3b | 2013-05-23 12:57:36 -0700 | [diff] [blame] | 235 | required_flags = 0; |
| 236 | flags_mask = 0; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 237 | |
Colin Cross | eff57af | 2013-05-22 14:49:19 -0700 | [diff] [blame] | 238 | while (1) { |
| 239 | int c; |
| 240 | const struct option longopts[] = { |
Colin Cross | 122c719 | 2013-05-23 12:38:54 -0700 | [diff] [blame] | 241 | {"all", 0, 0, 'a'}, |
Colin Cross | bd86b3b | 2013-05-23 12:57:36 -0700 | [diff] [blame] | 242 | {"cached", 0, 0, 'c'}, |
| 243 | {"nocached", 0, 0, 'C'}, |
Colin Cross | 479747b | 2013-06-21 16:53:03 -0700 | [diff] [blame] | 244 | {"ksm", 0, 0, 'k'}, |
Colin Cross | eff57af | 2013-05-22 14:49:19 -0700 | [diff] [blame] | 245 | {"help", 0, 0, 'h'}, |
| 246 | {"pss", 0, 0, 'p'}, |
| 247 | {"uss", 0, 0, 'u'}, |
| 248 | {"vss", 0, 0, 'v'}, |
| 249 | {"rss", 0, 0, 'r'}, |
Colin Cross | d2b8656 | 2013-06-21 12:55:56 -0700 | [diff] [blame] | 250 | {"swap", 0, 0, 's'}, |
Colin Cross | eff57af | 2013-05-22 14:49:19 -0700 | [diff] [blame] | 251 | {"reverse", 0, 0, 'R'}, |
| 252 | {"path", required_argument, 0, 'P'}, |
Colin Cross | 72f75f0 | 2013-05-22 15:03:52 -0700 | [diff] [blame] | 253 | {"perm", required_argument, 0, 'm'}, |
Colin Cross | eff57af | 2013-05-22 14:49:19 -0700 | [diff] [blame] | 254 | {0, 0, 0, 0} |
| 255 | }; |
Colin Cross | 479747b | 2013-06-21 16:53:03 -0700 | [diff] [blame] | 256 | c = getopt_long(argc, argv, "acChkm:pP:uvrsR", longopts, NULL); |
Colin Cross | eff57af | 2013-05-22 14:49:19 -0700 | [diff] [blame] | 257 | if (c < 0) { |
| 258 | break; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 259 | } |
Colin Cross | eff57af | 2013-05-22 14:49:19 -0700 | [diff] [blame] | 260 | /* Alphabetical cases */ |
| 261 | switch (c) { |
Colin Cross | 122c719 | 2013-05-23 12:38:54 -0700 | [diff] [blame] | 262 | case 'a': |
| 263 | all = true; |
| 264 | break; |
Colin Cross | bd86b3b | 2013-05-23 12:57:36 -0700 | [diff] [blame] | 265 | case 'c': |
| 266 | required_flags = 0; |
| 267 | flags_mask = PM_PAGE_SWAPBACKED; |
| 268 | break; |
| 269 | case 'C': |
| 270 | required_flags = PM_PAGE_SWAPBACKED; |
| 271 | flags_mask = PM_PAGE_SWAPBACKED; |
| 272 | break; |
Colin Cross | 479747b | 2013-06-21 16:53:03 -0700 | [diff] [blame] | 273 | case 'k': |
| 274 | required_flags = PM_PAGE_KSM; |
| 275 | flags_mask = PM_PAGE_KSM; |
| 276 | break; |
Colin Cross | eff57af | 2013-05-22 14:49:19 -0700 | [diff] [blame] | 277 | case 'h': |
| 278 | usage(argv[0]); |
| 279 | exit(EXIT_SUCCESS); |
Colin Cross | 72f75f0 | 2013-05-22 15:03:52 -0700 | [diff] [blame] | 280 | case 'm': |
| 281 | perm = parse_perm(optarg); |
| 282 | break; |
Colin Cross | eff57af | 2013-05-22 14:49:19 -0700 | [diff] [blame] | 283 | case 'p': |
| 284 | compfn = &sort_by_pss; |
| 285 | break; |
| 286 | case 'P': |
| 287 | prefix = optarg; |
| 288 | prefix_len = strlen(prefix); |
| 289 | break; |
| 290 | case 'u': |
| 291 | compfn = &sort_by_uss; |
| 292 | break; |
| 293 | case 'v': |
| 294 | compfn = &sort_by_vss; |
| 295 | break; |
| 296 | case 'r': |
| 297 | compfn = &sort_by_rss; |
| 298 | break; |
Colin Cross | d2b8656 | 2013-06-21 12:55:56 -0700 | [diff] [blame] | 299 | case 's': |
| 300 | compfn = &sort_by_swap; |
| 301 | break; |
Colin Cross | eff57af | 2013-05-22 14:49:19 -0700 | [diff] [blame] | 302 | case 'R': |
| 303 | order *= -1; |
| 304 | break; |
| 305 | case '?': |
| 306 | fprintf(stderr, "Invalid argument \"%s\".\n", argv[optind - 1]); |
| 307 | usage(argv[0]); |
| 308 | exit(EXIT_FAILURE); |
| 309 | default: |
| 310 | abort(); |
| 311 | } |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 312 | } |
| 313 | |
Colin Cross | eff57af | 2013-05-22 14:49:19 -0700 | [diff] [blame] | 314 | argc -= optind; |
| 315 | argv += optind; |
| 316 | |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 317 | libraries = malloc(INIT_LIBRARIES * sizeof(struct library_info *)); |
| 318 | libraries_count = 0; libraries_size = INIT_LIBRARIES; |
| 319 | |
| 320 | error = pm_kernel_create(&ker); |
| 321 | if (error) { |
| 322 | fprintf(stderr, "Error initializing kernel interface -- " |
| 323 | "does this kernel have pagemap?\n"); |
| 324 | exit(EXIT_FAILURE); |
| 325 | } |
| 326 | |
| 327 | error = pm_kernel_pids(ker, &pids, &num_procs); |
| 328 | if (error) { |
| 329 | fprintf(stderr, "Error listing processes.\n"); |
| 330 | exit(EXIT_FAILURE); |
| 331 | } |
| 332 | |
| 333 | for (i = 0; i < num_procs; i++) { |
| 334 | error = pm_process_create(ker, pids[i], &proc); |
| 335 | if (error) { |
| 336 | fprintf(stderr, "warning: could not create process interface for %d\n", pids[i]); |
| 337 | continue; |
| 338 | } |
Mark Salyzyn | 1154fe3 | 2014-03-17 08:58:40 -0700 | [diff] [blame] | 339 | |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 340 | pi = get_process(pids[i]); |
| 341 | |
| 342 | error = pm_process_maps(proc, &maps, &num_maps); |
| 343 | if (error) { |
| 344 | fprintf(stderr, "Error listing maps for process %d.\n", proc->pid); |
| 345 | exit(EXIT_FAILURE); |
| 346 | } |
| 347 | |
| 348 | for (j = 0; j < num_maps; j++) { |
| 349 | if (prefix && (strncmp(pm_map_name(maps[j]), prefix, prefix_len))) |
| 350 | continue; |
| 351 | |
Colin Cross | 72f75f0 | 2013-05-22 15:03:52 -0700 | [diff] [blame] | 352 | if (perm && (pm_map_flags(maps[j]) & PM_MAP_PERMISSIONS) != perm) |
| 353 | continue; |
| 354 | |
Colin Cross | 122c719 | 2013-05-23 12:38:54 -0700 | [diff] [blame] | 355 | li = get_library(pm_map_name(maps[j]), all); |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 356 | if (!li) |
| 357 | continue; |
| 358 | |
| 359 | mi = get_mapping(li, pi); |
Mark Salyzyn | 1154fe3 | 2014-03-17 08:58:40 -0700 | [diff] [blame] | 360 | |
Colin Cross | bd86b3b | 2013-05-23 12:57:36 -0700 | [diff] [blame] | 361 | error = pm_map_usage_flags(maps[j], &map_usage, flags_mask, |
| 362 | required_flags); |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 363 | if (error) { |
| 364 | fprintf(stderr, "Error getting map memory usage of " |
| 365 | "map %s in process %d.\n", |
| 366 | pm_map_name(maps[j]), proc->pid); |
| 367 | exit(EXIT_FAILURE); |
| 368 | } |
Colin Cross | d2b8656 | 2013-06-21 12:55:56 -0700 | [diff] [blame] | 369 | |
| 370 | if (map_usage.swap) { |
| 371 | has_swap = true; |
| 372 | } |
| 373 | |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 374 | pm_memusage_add(&mi->usage, &map_usage); |
| 375 | pm_memusage_add(&li->total_usage, &map_usage); |
| 376 | } |
| 377 | } |
| 378 | |
Colin Cross | d2b8656 | 2013-06-21 12:55:56 -0700 | [diff] [blame] | 379 | printf(" %6s %6s %6s %6s %6s ", "RSStot", "VSS", "RSS", "PSS", "USS"); |
| 380 | |
| 381 | if (has_swap) { |
| 382 | printf(" %6s ", "Swap"); |
| 383 | } |
| 384 | |
| 385 | printf("Name/PID\n"); |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 386 | fflush(stdout); |
| 387 | |
| 388 | qsort(libraries, libraries_count, sizeof(libraries[0]), &licmp); |
| 389 | |
| 390 | for (i = 0; i < libraries_count; i++) { |
| 391 | li = libraries[i]; |
| 392 | |
Mark Salyzyn | 1154fe3 | 2014-03-17 08:58:40 -0700 | [diff] [blame] | 393 | printf("%6zdK %6s %6s %6s %6s ", li->total_usage.pss / 1024, "", "", "", ""); |
Colin Cross | d2b8656 | 2013-06-21 12:55:56 -0700 | [diff] [blame] | 394 | if (has_swap) { |
| 395 | printf(" %6s ", ""); |
| 396 | } |
| 397 | printf("%s\n", li->name); |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 398 | fflush(stdout); |
| 399 | |
| 400 | qsort(li->mappings, li->mappings_count, sizeof(li->mappings[0]), compfn); |
| 401 | |
| 402 | for (j = 0; j < li->mappings_count; j++) { |
| 403 | mi = li->mappings[j]; |
| 404 | pi = mi->proc; |
Mark Salyzyn | 1154fe3 | 2014-03-17 08:58:40 -0700 | [diff] [blame] | 405 | printf( " %6s %6zdK %6zdK %6zdK %6zdK ", "", |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 406 | mi->usage.vss / 1024, |
| 407 | mi->usage.rss / 1024, |
| 408 | mi->usage.pss / 1024, |
Colin Cross | d2b8656 | 2013-06-21 12:55:56 -0700 | [diff] [blame] | 409 | mi->usage.uss / 1024); |
| 410 | if (has_swap) { |
Mark Salyzyn | 1154fe3 | 2014-03-17 08:58:40 -0700 | [diff] [blame] | 411 | printf("%6zdK ", mi->usage.swap / 1024); |
Colin Cross | d2b8656 | 2013-06-21 12:55:56 -0700 | [diff] [blame] | 412 | } |
| 413 | printf(" %s [%d]\n", |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 414 | pi->cmdline, |
| 415 | pi->pid); |
| 416 | } |
| 417 | printf("\n"); |
| 418 | fflush(stdout); |
| 419 | } |
| 420 | |
| 421 | return 0; |
| 422 | } |
| 423 | |
| 424 | static void usage(char *myname) { |
Colin Cross | d2b8656 | 2013-06-21 12:55:56 -0700 | [diff] [blame] | 425 | fprintf(stderr, "Usage: %s [ -P | -L ] [ -v | -r | -p | -u | -s | -h ]\n" |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 426 | "\n" |
| 427 | "Sort options:\n" |
| 428 | " -v Sort processes by VSS.\n" |
| 429 | " -r Sort processes by RSS.\n" |
| 430 | " -p Sort processes by PSS.\n" |
| 431 | " -u Sort processes by USS.\n" |
Colin Cross | d2b8656 | 2013-06-21 12:55:56 -0700 | [diff] [blame] | 432 | " -s Sort processes by swap.\n" |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 433 | " (Default sort order is PSS.)\n" |
Colin Cross | 122c719 | 2013-05-23 12:38:54 -0700 | [diff] [blame] | 434 | " -a Show all mappings, including stack, heap and anon.\n" |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 435 | " -P /path Limit libraries displayed to those in path.\n" |
| 436 | " -R Reverse sort order (default is descending).\n" |
Colin Cross | 72f75f0 | 2013-05-22 15:03:52 -0700 | [diff] [blame] | 437 | " -m [r][w][x] Only list pages that exactly match permissions\n" |
Colin Cross | bd86b3b | 2013-05-23 12:57:36 -0700 | [diff] [blame] | 438 | " -c Only show cached (storage backed) pages\n" |
| 439 | " -C Only show non-cached (ram/swap backed) pages\n" |
Colin Cross | 479747b | 2013-06-21 16:53:03 -0700 | [diff] [blame] | 440 | " -k Only show pages collapsed by KSM\n" |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 441 | " -h Display this help screen.\n", |
| 442 | myname); |
| 443 | } |
| 444 | |
| 445 | static int getprocname(pid_t pid, char *buf, size_t len) { |
daegeun.song | b03afb4 | 2015-04-22 11:31:29 +0900 | [diff] [blame] | 446 | char filename[32]; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 447 | FILE *f; |
| 448 | |
daegeun.song | b03afb4 | 2015-04-22 11:31:29 +0900 | [diff] [blame] | 449 | snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid); |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 450 | f = fopen(filename, "r"); |
daegeun.song | b03afb4 | 2015-04-22 11:31:29 +0900 | [diff] [blame] | 451 | if (!f) { |
| 452 | *buf = '\0'; |
| 453 | return 1; |
| 454 | } |
| 455 | if (!fgets(buf, len, f)) { |
| 456 | *buf = '\0'; |
| 457 | fclose(f); |
| 458 | return 2; |
| 459 | } |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 460 | fclose(f); |
| 461 | return 0; |
| 462 | } |
| 463 | |
| 464 | static int numcmp(long long a, long long b) { |
| 465 | if (a < b) return -1; |
| 466 | if (a > b) return 1; |
| 467 | return 0; |
| 468 | } |
| 469 | |
| 470 | static int licmp(const void *a, const void *b) { |
| 471 | return order * numcmp( |
| 472 | (*((struct library_info**)a))->total_usage.pss, |
| 473 | (*((struct library_info**)b))->total_usage.pss |
| 474 | ); |
| 475 | } |
| 476 | |
| 477 | #define create_sort(field, compfn) \ |
| 478 | static int sort_by_ ## field (const void *a, const void *b) { \ |
| 479 | return order * compfn( \ |
| 480 | (*((struct mapping_info**)a))->usage.field, \ |
| 481 | (*((struct mapping_info**)b))->usage.field \ |
| 482 | ); \ |
| 483 | } |
| 484 | |
| 485 | create_sort(vss, numcmp) |
| 486 | create_sort(rss, numcmp) |
| 487 | create_sort(pss, numcmp) |
| 488 | create_sort(uss, numcmp) |
Colin Cross | d2b8656 | 2013-06-21 12:55:56 -0700 | [diff] [blame] | 489 | create_sort(swap, numcmp) |