procrank.c revision 7341494707810f709855ea85ce03a8ec3ac8dbaf
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> 19#include <stdlib.h> 20#include <sys/types.h> 21#include <unistd.h> 22 23#include <pagemap/pagemap.h> 24 25struct proc_info { 26 pid_t pid; 27 pm_memusage_t usage; 28 unsigned long wss; 29}; 30 31static void usage(char *myname); 32static int getprocname(pid_t pid, char *buf, size_t len); 33static int numcmp(long long a, long long b); 34 35#define declare_sort(field) \ 36 static int sort_by_ ## field (const void *a, const void *b) 37 38declare_sort(vss); 39declare_sort(rss); 40declare_sort(pss); 41declare_sort(uss); 42 43int (*compfn)(const void *a, const void *b); 44static int order; 45 46#define MAX_PROCS 256 47 48int main(int argc, char *argv[]) { 49 pm_kernel_t *ker; 50 pm_process_t *proc; 51 pid_t *pids; 52 struct proc_info *procs[MAX_PROCS]; 53 size_t num_procs; 54 char cmdline[256]; 55 int error; 56 57 #define WS_OFF 0 58 #define WS_ONLY 1 59 #define WS_RESET 2 60 int ws; 61 62 int i, j; 63 64 compfn = &sort_by_pss; 65 order = -1; 66 ws = WS_OFF; 67 68 for (i = 1; i < argc; i++) { 69 if (!strcmp(argv[i], "-v")) { compfn = &sort_by_vss; continue; } 70 if (!strcmp(argv[i], "-r")) { compfn = &sort_by_rss; continue; } 71 if (!strcmp(argv[i], "-p")) { compfn = &sort_by_pss; continue; } 72 if (!strcmp(argv[i], "-u")) { compfn = &sort_by_uss; continue; } 73 if (!strcmp(argv[i], "-w")) { ws = WS_ONLY; continue; } 74 if (!strcmp(argv[i], "-W")) { ws = WS_RESET; continue; } 75 if (!strcmp(argv[i], "-R")) { order *= -1; continue; } 76 if (!strcmp(argv[i], "-h")) { usage(argv[0]); exit(0); } 77 fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]); 78 usage(argv[0]); 79 exit(EXIT_FAILURE); 80 } 81 82 error = pm_kernel_create(&ker); 83 if (error) { 84 fprintf(stderr, "Error creating kernel interface -- " 85 "does this kernel have pagemap?\n"); 86 exit(EXIT_FAILURE); 87 } 88 89 error = pm_kernel_pids(ker, &pids, &num_procs); 90 if (error) { 91 fprintf(stderr, "Error listing processes.\n"); 92 exit(EXIT_FAILURE); 93 } 94 95 for (i = 0; i < num_procs; i++) { 96 procs[i] = malloc(sizeof(struct proc_info)); 97 if (!procs[i]) { 98 fprintf(stderr, "malloc: %s\n", strerror(errno)); 99 exit(EXIT_FAILURE); 100 } 101 procs[i]->pid = pids[i]; 102 error = pm_process_create(ker, pids[i], &proc); 103 if (!error) { 104 switch (ws) { 105 case WS_OFF: 106 pm_process_usage(proc, &procs[i]->usage); 107 break; 108 case WS_ONLY: 109 pm_process_workingset(proc, &procs[i]->usage, 0); 110 break; 111 case WS_RESET: 112 pm_process_workingset(proc, NULL, 1); 113 break; 114 } 115 pm_process_destroy(proc); 116 } else { 117 fprintf(stderr, "warning: could not create process interface for %d\n", pids[i]); 118 pm_memusage_zero(&procs[i]->usage); 119 } 120 } 121 122 free(pids); 123 124 if (ws == WS_RESET) exit(0); 125 126 j = 0; 127 for (i = 0; i < num_procs; i++) { 128 if (procs[i]->usage.vss) 129 procs[j++] = procs[i]; 130 } 131 num_procs = j; 132 133 qsort(procs, num_procs, sizeof(procs[0]), compfn); 134 135 if (ws) 136 printf("%5s %7s %7s %7s %s\n", "PID", "WRss", "WPss", "WUss", "cmdline"); 137 else 138 printf("%5s %7s %7s %7s %7s %s\n", "PID", "Vss", "Rss", "Pss", "Uss", "cmdline"); 139 for (i = 0; i < num_procs; i++) { 140 getprocname(procs[i]->pid, cmdline, sizeof(cmdline)); 141 if (ws) 142 printf("%5d %6dK %6dK %6dK %s\n", 143 procs[i]->pid, 144 procs[i]->usage.rss / 1024, 145 procs[i]->usage.pss / 1024, 146 procs[i]->usage.uss / 1024, 147 cmdline 148 ); 149 else 150 printf("%5d %6dK %6dK %6dK %6dK %s\n", 151 procs[i]->pid, 152 procs[i]->usage.vss / 1024, 153 procs[i]->usage.rss / 1024, 154 procs[i]->usage.pss / 1024, 155 procs[i]->usage.uss / 1024, 156 cmdline 157 ); 158 } 159 160 return 0; 161} 162 163static void usage(char *myname) { 164 fprintf(stderr, "Usage: %s [ -W ] [ -v | -r | -p | -u | -h ]\n" 165 " -v Sort by VSS.\n" 166 " -r Sort by RSS.\n" 167 " -p Sort by PSS.\n" 168 " -u Sort by USS.\n" 169 " (Default sort order is PSS.)\n" 170 " -R Reverse sort order (default is descending).\n" 171 " -w Display statistics for working set only.\n" 172 " -W Reset working set of all processes.\n" 173 " -h Display this help screen.\n", 174 myname); 175} 176 177static int getprocname(pid_t pid, char *buf, size_t len) { 178 char filename[20]; 179 FILE *f; 180 181 sprintf(filename, "/proc/%d/cmdline", pid); 182 f = fopen(filename, "r"); 183 if (!f) { *buf = '\0'; return 1; } 184 if (!fgets(buf, len, f)) { *buf = '\0'; return 2; } 185 fclose(f); 186 return 0; 187} 188 189static int numcmp(long long a, long long b) { 190 if (a < b) return -1; 191 if (a > b) return 1; 192 return 0; 193} 194 195#define create_sort(field, compfn) \ 196 static int sort_by_ ## field (const void *a, const void *b) { \ 197 return order * compfn( \ 198 (*((struct proc_info**)a))->usage.field, \ 199 (*((struct proc_info**)b))->usage.field \ 200 ); \ 201 } 202 203create_sort(vss, numcmp) 204create_sort(rss, numcmp) 205create_sort(pss, numcmp) 206create_sort(uss, numcmp) 207