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 <dirent.h> |
| 18 | #include <errno.h> |
Colin Cross | 4d2488a | 2014-06-17 14:38:34 -0700 | [diff] [blame] | 19 | #include <fcntl.h> |
| 20 | #include <inttypes.h> |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -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> |
Colin Cross | 4d2488a | 2014-06-17 14:38:34 -0700 | [diff] [blame] | 23 | #include <string.h> |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 24 | #include <sys/types.h> |
| 25 | #include <unistd.h> |
| 26 | |
| 27 | #include <pagemap/pagemap.h> |
| 28 | |
| 29 | struct proc_info { |
| 30 | pid_t pid; |
| 31 | pm_memusage_t usage; |
Colin Cross | 4d2488a | 2014-06-17 14:38:34 -0700 | [diff] [blame] | 32 | uint64_t wss; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 33 | }; |
| 34 | |
| 35 | static void usage(char *myname); |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 36 | static int getprocname(pid_t pid, char *buf, int len); |
Colin Cross | 4d2488a | 2014-06-17 14:38:34 -0700 | [diff] [blame] | 37 | static int numcmp(uint64_t a, uint64_t b); |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 38 | |
| 39 | #define declare_sort(field) \ |
| 40 | static int sort_by_ ## field (const void *a, const void *b) |
| 41 | |
| 42 | declare_sort(vss); |
| 43 | declare_sort(rss); |
| 44 | declare_sort(pss); |
| 45 | declare_sort(uss); |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 46 | declare_sort(swap); |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 47 | |
| 48 | int (*compfn)(const void *a, const void *b); |
| 49 | static int order; |
| 50 | |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 51 | void print_mem_info() { |
Dianne Hackborn | 83b0b0a | 2011-11-04 20:08:19 -0700 | [diff] [blame] | 52 | char buffer[1024]; |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 53 | int numFound = 0; |
| 54 | |
| 55 | int fd = open("/proc/meminfo", O_RDONLY); |
| 56 | |
| 57 | if (fd < 0) { |
| 58 | printf("Unable to open /proc/meminfo: %s\n", strerror(errno)); |
| 59 | return; |
| 60 | } |
| 61 | |
| 62 | const int len = read(fd, buffer, sizeof(buffer)-1); |
| 63 | close(fd); |
| 64 | |
| 65 | if (len < 0) { |
| 66 | printf("Empty /proc/meminfo"); |
| 67 | return; |
| 68 | } |
| 69 | buffer[len] = 0; |
| 70 | |
| 71 | static const char* const tags[] = { |
| 72 | "MemTotal:", |
| 73 | "MemFree:", |
| 74 | "Buffers:", |
| 75 | "Cached:", |
Dianne Hackborn | 83b0b0a | 2011-11-04 20:08:19 -0700 | [diff] [blame] | 76 | "Shmem:", |
| 77 | "Slab:", |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 78 | NULL |
| 79 | }; |
| 80 | static const int tagsLen[] = { |
| 81 | 9, |
| 82 | 8, |
| 83 | 8, |
| 84 | 7, |
Dianne Hackborn | 83b0b0a | 2011-11-04 20:08:19 -0700 | [diff] [blame] | 85 | 6, |
| 86 | 5, |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 87 | 0 |
| 88 | }; |
Colin Cross | 4d2488a | 2014-06-17 14:38:34 -0700 | [diff] [blame] | 89 | uint64_t mem[] = { 0, 0, 0, 0, 0, 0 }; |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 90 | |
| 91 | char* p = buffer; |
Dianne Hackborn | 83b0b0a | 2011-11-04 20:08:19 -0700 | [diff] [blame] | 92 | while (*p && numFound < 6) { |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 93 | int i = 0; |
| 94 | while (tags[i]) { |
| 95 | if (strncmp(p, tags[i], tagsLen[i]) == 0) { |
| 96 | p += tagsLen[i]; |
| 97 | while (*p == ' ') p++; |
| 98 | char* num = p; |
| 99 | while (*p >= '0' && *p <= '9') p++; |
| 100 | if (*p != 0) { |
| 101 | *p = 0; |
| 102 | p++; |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 103 | } |
| 104 | mem[i] = atoll(num); |
| 105 | numFound++; |
| 106 | break; |
| 107 | } |
| 108 | i++; |
| 109 | } |
Dianne Hackborn | 83b0b0a | 2011-11-04 20:08:19 -0700 | [diff] [blame] | 110 | while (*p && *p != '\n') { |
| 111 | p++; |
| 112 | } |
| 113 | if (*p) p++; |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 114 | } |
| 115 | |
Colin Cross | 4d2488a | 2014-06-17 14:38:34 -0700 | [diff] [blame] | 116 | printf("RAM: %" PRIu64 "K total, %" PRIu64 "K free, %" PRIu64 "K buffers, " |
| 117 | "%" PRIu64 "K cached, %" PRIu64 "K shmem, %" PRIu64 "K slab\n", |
Dianne Hackborn | 83b0b0a | 2011-11-04 20:08:19 -0700 | [diff] [blame] | 118 | mem[0], mem[1], mem[2], mem[3], mem[4], mem[5]); |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 119 | } |
| 120 | |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 121 | int main(int argc, char *argv[]) { |
| 122 | pm_kernel_t *ker; |
| 123 | pm_process_t *proc; |
| 124 | pid_t *pids; |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 125 | struct proc_info **procs; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 126 | size_t num_procs; |
Colin Cross | 4d2488a | 2014-06-17 14:38:34 -0700 | [diff] [blame] | 127 | uint64_t total_pss; |
| 128 | uint64_t total_uss; |
| 129 | uint64_t total_swap; |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 130 | char cmdline[256]; // this must be within the range of int |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 131 | int error; |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 132 | bool has_swap = false; |
Colin Cross | 8a807c3 | 2013-06-21 17:02:05 -0700 | [diff] [blame] | 133 | uint64_t required_flags = 0; |
| 134 | uint64_t flags_mask = 0; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 135 | |
| 136 | #define WS_OFF 0 |
| 137 | #define WS_ONLY 1 |
| 138 | #define WS_RESET 2 |
| 139 | int ws; |
| 140 | |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 141 | int arg; |
| 142 | size_t i, j; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 143 | |
JP Abgrall | 80cb155 | 2012-05-11 14:09:59 -0700 | [diff] [blame] | 144 | signal(SIGPIPE, SIG_IGN); |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 145 | compfn = &sort_by_pss; |
| 146 | order = -1; |
| 147 | ws = WS_OFF; |
| 148 | |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 149 | for (arg = 1; arg < argc; arg++) { |
| 150 | if (!strcmp(argv[arg], "-v")) { compfn = &sort_by_vss; continue; } |
| 151 | if (!strcmp(argv[arg], "-r")) { compfn = &sort_by_rss; continue; } |
| 152 | if (!strcmp(argv[arg], "-p")) { compfn = &sort_by_pss; continue; } |
| 153 | if (!strcmp(argv[arg], "-u")) { compfn = &sort_by_uss; continue; } |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 154 | if (!strcmp(argv[arg], "-s")) { compfn = &sort_by_swap; continue; } |
Colin Cross | 8a807c3 | 2013-06-21 17:02:05 -0700 | [diff] [blame] | 155 | if (!strcmp(argv[arg], "-c")) { required_flags = 0; flags_mask = PM_PAGE_SWAPBACKED; continue; } |
| 156 | if (!strcmp(argv[arg], "-C")) { required_flags = flags_mask = PM_PAGE_SWAPBACKED; continue; } |
| 157 | if (!strcmp(argv[arg], "-k")) { required_flags = flags_mask = PM_PAGE_KSM; continue; } |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 158 | if (!strcmp(argv[arg], "-w")) { ws = WS_ONLY; continue; } |
| 159 | if (!strcmp(argv[arg], "-W")) { ws = WS_RESET; continue; } |
| 160 | if (!strcmp(argv[arg], "-R")) { order *= -1; continue; } |
| 161 | if (!strcmp(argv[arg], "-h")) { usage(argv[0]); exit(0); } |
| 162 | fprintf(stderr, "Invalid argument \"%s\".\n", argv[arg]); |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 163 | usage(argv[0]); |
| 164 | exit(EXIT_FAILURE); |
| 165 | } |
| 166 | |
| 167 | error = pm_kernel_create(&ker); |
| 168 | if (error) { |
| 169 | fprintf(stderr, "Error creating kernel interface -- " |
| 170 | "does this kernel have pagemap?\n"); |
| 171 | exit(EXIT_FAILURE); |
| 172 | } |
| 173 | |
| 174 | error = pm_kernel_pids(ker, &pids, &num_procs); |
| 175 | if (error) { |
| 176 | fprintf(stderr, "Error listing processes.\n"); |
| 177 | exit(EXIT_FAILURE); |
| 178 | } |
| 179 | |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 180 | procs = calloc(num_procs, sizeof(struct proc_info*)); |
| 181 | if (procs == NULL) { |
| 182 | fprintf(stderr, "calloc: %s", strerror(errno)); |
| 183 | exit(EXIT_FAILURE); |
| 184 | } |
| 185 | |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 186 | for (i = 0; i < num_procs; i++) { |
| 187 | procs[i] = malloc(sizeof(struct proc_info)); |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 188 | if (procs[i] == NULL) { |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 189 | fprintf(stderr, "malloc: %s\n", strerror(errno)); |
| 190 | exit(EXIT_FAILURE); |
| 191 | } |
| 192 | procs[i]->pid = pids[i]; |
Colin Cross | eff7888 | 2011-07-12 22:30:14 -0700 | [diff] [blame] | 193 | pm_memusage_zero(&procs[i]->usage); |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 194 | error = pm_process_create(ker, pids[i], &proc); |
Colin Cross | eff7888 | 2011-07-12 22:30:14 -0700 | [diff] [blame] | 195 | if (error) { |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 196 | fprintf(stderr, "warning: could not create process interface for %d\n", pids[i]); |
Colin Cross | eff7888 | 2011-07-12 22:30:14 -0700 | [diff] [blame] | 197 | continue; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 198 | } |
Colin Cross | eff7888 | 2011-07-12 22:30:14 -0700 | [diff] [blame] | 199 | |
| 200 | switch (ws) { |
| 201 | case WS_OFF: |
Colin Cross | 8a807c3 | 2013-06-21 17:02:05 -0700 | [diff] [blame] | 202 | error = pm_process_usage_flags(proc, &procs[i]->usage, flags_mask, |
| 203 | required_flags); |
Colin Cross | eff7888 | 2011-07-12 22:30:14 -0700 | [diff] [blame] | 204 | break; |
| 205 | case WS_ONLY: |
| 206 | error = pm_process_workingset(proc, &procs[i]->usage, 0); |
| 207 | break; |
| 208 | case WS_RESET: |
| 209 | error = pm_process_workingset(proc, NULL, 1); |
| 210 | break; |
| 211 | } |
| 212 | |
| 213 | if (error) { |
| 214 | fprintf(stderr, "warning: could not read usage for %d\n", pids[i]); |
| 215 | } |
| 216 | |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 217 | if (ws != WS_RESET && procs[i]->usage.swap) { |
| 218 | has_swap = true; |
| 219 | } |
| 220 | |
Colin Cross | eff7888 | 2011-07-12 22:30:14 -0700 | [diff] [blame] | 221 | pm_process_destroy(proc); |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 222 | } |
| 223 | |
| 224 | free(pids); |
| 225 | |
| 226 | if (ws == WS_RESET) exit(0); |
| 227 | |
| 228 | j = 0; |
| 229 | for (i = 0; i < num_procs; i++) { |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 230 | if (procs[i]->usage.vss) { |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 231 | procs[j++] = procs[i]; |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 232 | } else { |
| 233 | free(procs[i]); |
| 234 | } |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 235 | } |
| 236 | num_procs = j; |
| 237 | |
| 238 | qsort(procs, num_procs, sizeof(procs[0]), compfn); |
| 239 | |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 240 | printf("%5s ", "PID"); |
| 241 | if (ws) { |
| 242 | printf("%s %7s %7s ", "WRss", "WPss", "WUss"); |
| 243 | if (has_swap) { |
| 244 | printf("%7s ", "WSwap"); |
| 245 | } |
| 246 | } else { |
| 247 | printf("%8s %7s %7s %7s ", "Vss", "Rss", "Pss", "Uss"); |
| 248 | if (has_swap) { |
| 249 | printf("%7s ", "Swap"); |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | printf("%s\n", "cmdline"); |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 254 | |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 255 | total_pss = 0; |
| 256 | total_uss = 0; |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 257 | total_swap = 0; |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 258 | |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 259 | for (i = 0; i < num_procs; i++) { |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 260 | if (getprocname(procs[i]->pid, cmdline, (int)sizeof(cmdline)) < 0) { |
| 261 | /* |
| 262 | * Something is probably seriously wrong if writing to the stack |
| 263 | * failed. |
| 264 | */ |
| 265 | free(procs[i]); |
| 266 | continue; |
| 267 | } |
| 268 | |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 269 | total_pss += procs[i]->usage.pss; |
| 270 | total_uss += procs[i]->usage.uss; |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 271 | total_swap += procs[i]->usage.swap; |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 272 | |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 273 | printf("%5d ", procs[i]->pid); |
| 274 | |
| 275 | if (ws) { |
Ashok Bhat | af3263f | 2013-01-10 15:52:55 +0000 | [diff] [blame] | 276 | printf("%6zuK %6zuK %6zuK ", |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 277 | procs[i]->usage.rss / 1024, |
| 278 | procs[i]->usage.pss / 1024, |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 279 | procs[i]->usage.uss / 1024 |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 280 | ); |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 281 | } else { |
Ashok Bhat | af3263f | 2013-01-10 15:52:55 +0000 | [diff] [blame] | 282 | printf("%7zuK %6zuK %6zuK %6zuK ", |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 283 | procs[i]->usage.vss / 1024, |
| 284 | procs[i]->usage.rss / 1024, |
| 285 | procs[i]->usage.pss / 1024, |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 286 | procs[i]->usage.uss / 1024 |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 287 | ); |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 288 | } |
| 289 | |
| 290 | if (has_swap) { |
Ashok Bhat | af3263f | 2013-01-10 15:52:55 +0000 | [diff] [blame] | 291 | printf("%6zuK ", procs[i]->usage.swap / 1024); |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 292 | } |
| 293 | |
| 294 | printf("%s\n", cmdline); |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 295 | |
| 296 | free(procs[i]); |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 297 | } |
| 298 | |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 299 | free(procs); |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 300 | |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 301 | /* Print the separator line */ |
| 302 | printf("%5s ", ""); |
| 303 | |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 304 | if (ws) { |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 305 | printf("%7s %7s %7s ", "", "------", "------"); |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 306 | } else { |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 307 | printf("%8s %7s %7s %7s ", "", "", "------", "------"); |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 308 | } |
| 309 | |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 310 | if (has_swap) { |
| 311 | printf("%7s ", "------"); |
| 312 | } |
| 313 | |
| 314 | printf("%s\n", "------"); |
| 315 | |
| 316 | /* Print the total line */ |
| 317 | printf("%5s ", ""); |
| 318 | if (ws) { |
Colin Cross | 4d2488a | 2014-06-17 14:38:34 -0700 | [diff] [blame] | 319 | printf("%7s %6" PRIu64 "K %" PRIu64 "K ", |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 320 | "", total_pss / 1024, total_uss / 1024); |
| 321 | } else { |
Colin Cross | 4d2488a | 2014-06-17 14:38:34 -0700 | [diff] [blame] | 322 | printf("%8s %7s %6" PRIu64 "K %6" PRIu64 "K ", |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 323 | "", "", total_pss / 1024, total_uss / 1024); |
| 324 | } |
| 325 | |
| 326 | if (has_swap) { |
Colin Cross | 4d2488a | 2014-06-17 14:38:34 -0700 | [diff] [blame] | 327 | printf("%6" PRIu64 "K ", total_swap); |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 328 | } |
| 329 | |
| 330 | printf("TOTAL\n"); |
| 331 | |
Dianne Hackborn | e9eeec8 | 2011-07-18 12:41:50 -0700 | [diff] [blame] | 332 | printf("\n"); |
| 333 | print_mem_info(); |
| 334 | |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 335 | return 0; |
| 336 | } |
| 337 | |
| 338 | static void usage(char *myname) { |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 339 | fprintf(stderr, "Usage: %s [ -W ] [ -v | -r | -p | -u | -s | -h ]\n" |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 340 | " -v Sort by VSS.\n" |
| 341 | " -r Sort by RSS.\n" |
| 342 | " -p Sort by PSS.\n" |
| 343 | " -u Sort by USS.\n" |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 344 | " -s Sort by swap.\n" |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 345 | " (Default sort order is PSS.)\n" |
| 346 | " -R Reverse sort order (default is descending).\n" |
Colin Cross | 8a807c3 | 2013-06-21 17:02:05 -0700 | [diff] [blame] | 347 | " -c Only show cached (storage backed) pages\n" |
| 348 | " -C Only show non-cached (ram/swap backed) pages\n" |
| 349 | " -k Only show pages collapsed by KSM\n" |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 350 | " -w Display statistics for working set only.\n" |
| 351 | " -W Reset working set of all processes.\n" |
| 352 | " -h Display this help screen.\n", |
| 353 | myname); |
| 354 | } |
| 355 | |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 356 | /* |
| 357 | * Get the process name for a given PID. Inserts the process name into buffer |
| 358 | * buf of length len. The size of the buffer must be greater than zero to get |
| 359 | * any useful output. |
| 360 | * |
| 361 | * Note that fgets(3) only declares length as an int, so our buffer size is |
| 362 | * also declared as an int. |
| 363 | * |
| 364 | * Returns 0 on success, a positive value on partial success, and -1 on |
| 365 | * failure. Other interesting values: |
| 366 | * 1 on failure to create string to examine proc cmdline entry |
| 367 | * 2 on failure to open proc cmdline entry |
| 368 | * 3 on failure to read proc cmdline entry |
| 369 | */ |
| 370 | static int getprocname(pid_t pid, char *buf, int len) { |
| 371 | char *filename; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 372 | FILE *f; |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 373 | int rc = 0; |
| 374 | static const char* unknown_cmdline = "<unknown>"; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 375 | |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 376 | if (len <= 0) { |
| 377 | return -1; |
| 378 | } |
| 379 | |
Ashok Bhat | af3263f | 2013-01-10 15:52:55 +0000 | [diff] [blame] | 380 | if (asprintf(&filename, "/proc/%d/cmdline", pid) < 0) { |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 381 | rc = 1; |
| 382 | goto exit; |
| 383 | } |
| 384 | |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 385 | f = fopen(filename, "r"); |
Kenny Root | 16abe7a | 2010-09-21 10:46:57 -0700 | [diff] [blame] | 386 | if (f == NULL) { |
| 387 | rc = 2; |
| 388 | goto releasefilename; |
| 389 | } |
| 390 | |
| 391 | if (fgets(buf, len, f) == NULL) { |
| 392 | rc = 3; |
| 393 | goto closefile; |
| 394 | } |
| 395 | |
| 396 | closefile: |
| 397 | (void) fclose(f); |
| 398 | releasefilename: |
| 399 | free(filename); |
| 400 | exit: |
| 401 | if (rc != 0) { |
| 402 | /* |
| 403 | * The process went away before we could read its process name. Try |
| 404 | * to give the user "<unknown>" here, but otherwise they get to look |
| 405 | * at a blank. |
| 406 | */ |
| 407 | if (strlcpy(buf, unknown_cmdline, (size_t)len) >= (size_t)len) { |
| 408 | rc = 4; |
| 409 | } |
| 410 | } |
| 411 | |
| 412 | return rc; |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 413 | } |
| 414 | |
Colin Cross | 4d2488a | 2014-06-17 14:38:34 -0700 | [diff] [blame] | 415 | static int numcmp(uint64_t a, uint64_t b) { |
The Android Open Source Project | e16cb84 | 2009-03-03 19:32:58 -0800 | [diff] [blame] | 416 | if (a < b) return -1; |
| 417 | if (a > b) return 1; |
| 418 | return 0; |
| 419 | } |
| 420 | |
| 421 | #define create_sort(field, compfn) \ |
| 422 | static int sort_by_ ## field (const void *a, const void *b) { \ |
| 423 | return order * compfn( \ |
| 424 | (*((struct proc_info**)a))->usage.field, \ |
| 425 | (*((struct proc_info**)b))->usage.field \ |
| 426 | ); \ |
| 427 | } |
| 428 | |
| 429 | create_sort(vss, numcmp) |
| 430 | create_sort(rss, numcmp) |
| 431 | create_sort(pss, numcmp) |
| 432 | create_sort(uss, numcmp) |
Colin Cross | 6f5b13c | 2013-06-21 12:54:13 -0700 | [diff] [blame] | 433 | create_sort(swap, numcmp) |