1 /* 2 * Copyright (C) 2013 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 <errno.h> 18 #include <fcntl.h> 19 #include <getopt.h> 20 #include <inttypes.h> 21 #include <stdbool.h> 22 #include <stdint.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <sys/types.h> 26 #include <unistd.h> 27 28 #include <pagemap/pagemap.h> 29 30 #define MAX_FILENAME 64 31 32 #define GROWTH_FACTOR 10 33 34 #define NO_PATTERN 0x100 35 36 #define PR_SORTED 1 37 #define PR_VERBOSE 2 38 #define PR_ALL 4 39 40 struct vaddr { 41 unsigned long addr; 42 size_t num_pages; 43 pid_t pid; 44 }; 45 46 struct ksm_page { 47 uint64_t count; 48 uint32_t hash; 49 struct vaddr *vaddr; 50 size_t vaddr_len, vaddr_size; 51 size_t vaddr_count; 52 uint16_t pattern; 53 }; 54 55 struct ksm_pages { 56 struct ksm_page *pages; 57 size_t len, size; 58 }; 59 60 static void usage(char *myname); 61 static int getprocname(pid_t pid, char *buf, int len); 62 static int read_pages(struct ksm_pages *kp, pm_map_t **maps, size_t num_maps, uint8_t pr_flags); 63 static void print_pages(struct ksm_pages *kp, uint8_t pr_flags); 64 static void free_pages(struct ksm_pages *kp, uint8_t pr_flags); 65 static bool is_pattern(uint8_t *data, size_t len); 66 static int cmp_pages(const void *a, const void *b); 67 extern uint32_t hashword(const uint32_t *, size_t, int32_t); 68 69 int main(int argc, char *argv[]) { 70 pm_kernel_t *ker; 71 pm_process_t *proc; 72 pid_t *pids; 73 size_t num_procs; 74 size_t i; 75 pm_map_t **maps; 76 size_t num_maps; 77 char cmdline[256]; // this must be within the range of int 78 int error; 79 int rc = EXIT_SUCCESS; 80 uint8_t pr_flags = 0; 81 struct ksm_pages kp; 82 83 memset(&kp, 0, sizeof(kp)); 84 85 opterr = 0; 86 do { 87 int c = getopt(argc, argv, "hvsa"); 88 if (c == -1) 89 break; 90 91 switch (c) { 92 case 'a': 93 pr_flags |= PR_ALL; 94 break; 95 case 's': 96 pr_flags |= PR_SORTED; 97 break; 98 case 'v': 99 pr_flags |= PR_VERBOSE; 100 break; 101 case 'h': 102 usage(argv[0]); 103 exit(EXIT_SUCCESS); 104 case '?': 105 fprintf(stderr, "unknown option: %c\n", optopt); 106 usage(argv[0]); 107 exit(EXIT_FAILURE); 108 } 109 } while (1); 110 111 error = pm_kernel_create(&ker); 112 if (error) { 113 fprintf(stderr, "Error creating kernel interface -- " 114 "does this kernel have pagemap?\n"); 115 exit(EXIT_FAILURE); 116 } 117 118 if (pr_flags & PR_ALL) { 119 error = pm_kernel_pids(ker, &pids, &num_procs); 120 if (error) { 121 fprintf(stderr, "Error listing processes.\n"); 122 exit(EXIT_FAILURE); 123 } 124 } else { 125 if (optind != argc - 1) { 126 usage(argv[0]); 127 exit(EXIT_FAILURE); 128 } 129 130 pids = malloc(sizeof(*pids)); 131 if (pids == NULL) { 132 fprintf(stderr, "Error allocating pid memory\n"); 133 exit(EXIT_FAILURE); 134 } 135 136 *pids = strtoul(argv[optind], NULL, 10); 137 if (*pids == 0) { 138 fprintf(stderr, "Invalid PID\n"); 139 rc = EXIT_FAILURE; 140 goto exit; 141 } 142 num_procs = 1; 143 if (getprocname(*pids, cmdline, sizeof(cmdline)) < 0) { 144 cmdline[0] = '\0'; 145 } 146 printf("%s (%u):\n", cmdline, *pids); 147 } 148 149 printf("Warning: this tool only compares the KSM CRCs of pages, there is a chance of " 150 "collisions\n"); 151 152 for (i = 0; i < num_procs; i++) { 153 error = pm_process_create(ker, pids[i], &proc); 154 if (error) { 155 fprintf(stderr, "warning: could not create process interface for %d\n", pids[i]); 156 rc = EXIT_FAILURE; 157 goto exit; 158 } 159 160 error = pm_process_maps(proc, &maps, &num_maps); 161 if (error) { 162 pm_process_destroy(proc); 163 fprintf(stderr, "warning: could not read process map for %d\n", pids[i]); 164 rc = EXIT_FAILURE; 165 goto exit; 166 } 167 168 if (read_pages(&kp, maps, num_maps, pr_flags) < 0) { 169 free(maps); 170 pm_process_destroy(proc); 171 rc = EXIT_FAILURE; 172 goto exit; 173 } 174 175 free(maps); 176 pm_process_destroy(proc); 177 } 178 179 if (pr_flags & PR_SORTED) { 180 qsort(kp.pages, kp.len, sizeof(*kp.pages), cmp_pages); 181 } 182 print_pages(&kp, pr_flags); 183 184 exit: 185 free_pages(&kp, pr_flags); 186 free(pids); 187 return rc; 188 } 189 190 static int read_pages(struct ksm_pages *kp, pm_map_t **maps, size_t num_maps, uint8_t pr_flags) { 191 size_t i, j, k; 192 uint64_t *pagemap; 193 size_t map_len; 194 uint64_t flags; 195 pm_kernel_t *ker; 196 int error; 197 unsigned long vaddr; 198 int fd; 199 off_t off; 200 char filename[MAX_FILENAME]; 201 uint32_t *data; 202 uint32_t hash; 203 int rc = 0; 204 struct ksm_page *cur_page; 205 pid_t pid; 206 207 if (num_maps == 0) 208 return 0; 209 210 pid = pm_process_pid(maps[0]->proc); 211 ker = maps[0]->proc->ker; 212 error = snprintf(filename, MAX_FILENAME, "/proc/%d/mem", pid); 213 if (error < 0 || error >= MAX_FILENAME) { 214 return -1; 215 } 216 217 data = malloc(pm_kernel_pagesize(ker)); 218 if (data == NULL) { 219 fprintf(stderr, "warning: not enough memory to malloc data buffer\n"); 220 return -1; 221 } 222 223 fd = open(filename, O_RDONLY); 224 if (fd < 0) { 225 fprintf(stderr, "warning: could not open %s\n", filename); 226 rc = -1; 227 goto err_open; 228 } 229 230 for (i = 0; i < num_maps; i++) { 231 error = pm_map_pagemap(maps[i], &pagemap, &map_len); 232 if (error) { 233 fprintf(stderr, "warning: could not read the pagemap of %d\n", 234 pm_process_pid(maps[i]->proc)); 235 continue; 236 } 237 for (j = 0; j < map_len; j++) { 238 error = pm_kernel_flags(ker, PM_PAGEMAP_PFN(pagemap[j]), &flags); 239 if (error) { 240 fprintf(stderr, "warning: could not read flags for pfn at address 0x%016" PRIx64 "\n", 241 pagemap[i]); 242 continue; 243 } 244 if (!(flags & PM_PAGE_KSM)) { 245 continue; 246 } 247 vaddr = pm_map_start(maps[i]) + j * pm_kernel_pagesize(ker); 248 off = lseek(fd, vaddr, SEEK_SET); 249 if (off == (off_t)-1) { 250 fprintf(stderr, "warning: could not lseek to 0x%08lx\n", vaddr); 251 continue; 252 } 253 ssize_t len = read(fd, data, pm_kernel_pagesize(ker)); 254 if (len != pm_kernel_pagesize(ker)) { 255 fprintf(stderr, "warning: could not read page at 0x%08lx\n", vaddr); 256 continue; 257 } 258 259 hash = hashword(data, pm_kernel_pagesize(ker) / sizeof(*data), 17); 260 261 for (k = 0; k < kp->len; k++) { 262 if (kp->pages[k].hash == hash) break; 263 } 264 265 if (k == kp->len) { 266 if (kp->len == kp->size) { 267 struct ksm_page *tmp = realloc(kp->pages, 268 (kp->size + GROWTH_FACTOR) * sizeof(*kp->pages)); 269 if (tmp == NULL) { 270 fprintf(stderr, "warning: not enough memory to realloc pages struct\n"); 271 free(pagemap); 272 rc = -1; 273 goto err_realloc; 274 } 275 memset(&tmp[k], 0, sizeof(tmp[k]) * GROWTH_FACTOR); 276 kp->pages = tmp; 277 kp->size += GROWTH_FACTOR; 278 } 279 rc = pm_kernel_count(ker, PM_PAGEMAP_PFN(pagemap[j]), &kp->pages[kp->len].count); 280 if (rc) { 281 fprintf(stderr, "error reading page count\n"); 282 free(pagemap); 283 goto err_count; 284 } 285 kp->pages[kp->len].hash = hash; 286 kp->pages[kp->len].pattern = 287 is_pattern((uint8_t *)data, pm_kernel_pagesize(ker)) ? 288 (data[0] & 0xFF) : NO_PATTERN; 289 kp->len++; 290 } 291 292 cur_page = &kp->pages[k]; 293 294 if (pr_flags & PR_VERBOSE) { 295 if (cur_page->vaddr_len > 0 && 296 cur_page->vaddr[cur_page->vaddr_len - 1].pid == pid && 297 cur_page->vaddr[cur_page->vaddr_len - 1].addr == 298 vaddr - (cur_page->vaddr[cur_page->vaddr_len - 1].num_pages * 299 pm_kernel_pagesize(ker))) { 300 cur_page->vaddr[cur_page->vaddr_len - 1].num_pages++; 301 } else { 302 if (cur_page->vaddr_len == cur_page->vaddr_size) { 303 struct vaddr *tmp = realloc(cur_page->vaddr, 304 (cur_page->vaddr_size + GROWTH_FACTOR) * sizeof(*(cur_page->vaddr))); 305 if (tmp == NULL) { 306 fprintf(stderr, "warning: not enough memory to realloc vaddr array\n"); 307 free(pagemap); 308 rc = -1; 309 goto err_realloc; 310 } 311 memset(&tmp[cur_page->vaddr_len], 0, sizeof(tmp[cur_page->vaddr_len]) * GROWTH_FACTOR); 312 cur_page->vaddr = tmp; 313 cur_page->vaddr_size += GROWTH_FACTOR; 314 } 315 cur_page->vaddr[cur_page->vaddr_len].addr = vaddr; 316 cur_page->vaddr[cur_page->vaddr_len].num_pages = 1; 317 cur_page->vaddr[cur_page->vaddr_len].pid = pid; 318 cur_page->vaddr_len++; 319 } 320 } 321 cur_page->vaddr_count++; 322 } 323 free(pagemap); 324 } 325 goto no_err; 326 327 err_realloc: 328 err_count: 329 if (pr_flags & PR_VERBOSE) { 330 for (i = 0; i < kp->len; i++) { 331 free(kp->pages[i].vaddr); 332 } 333 } 334 free(kp->pages); 335 336 no_err: 337 close(fd); 338 err_open: 339 free(data); 340 return rc; 341 } 342 343 static void print_pages(struct ksm_pages *kp, uint8_t pr_flags) { 344 size_t i, j, k; 345 char suffix[13]; 346 int index; 347 348 for (i = 0; i < kp->len; i++) { 349 if (kp->pages[i].pattern != NO_PATTERN) { 350 printf("0x%02x byte pattern: ", kp->pages[i].pattern); 351 } else { 352 printf("KSM CRC 0x%08x:", kp->pages[i].hash); 353 } 354 printf(" %4zu page", kp->pages[i].vaddr_count); 355 if (kp->pages[i].vaddr_count > 1) { 356 printf("s"); 357 } 358 if (!(pr_flags & PR_ALL)) { 359 printf(" (%" PRIu64 " reference", kp->pages[i].count); 360 if (kp->pages[i].count > 1) { 361 printf("s"); 362 } 363 printf(")"); 364 } 365 printf("\n"); 366 367 if (pr_flags & PR_VERBOSE) { 368 j = 0; 369 while (j < kp->pages[i].vaddr_len) { 370 printf(" "); 371 for (k = 0; k < 8 && j < kp->pages[i].vaddr_len; k++, j++) { 372 printf(" 0x%08lx", kp->pages[i].vaddr[j].addr); 373 374 index = snprintf(suffix, sizeof(suffix), ":%zu", 375 kp->pages[i].vaddr[j].num_pages); 376 if (pr_flags & PR_ALL) { 377 index += snprintf(suffix + index, sizeof(suffix) - index, "[%d]", 378 kp->pages[i].vaddr[j].pid); 379 } 380 printf("%-12s", suffix); 381 } 382 printf("\n"); 383 } 384 } 385 } 386 } 387 388 static void free_pages(struct ksm_pages *kp, uint8_t pr_flags) { 389 size_t i; 390 391 if (pr_flags & PR_VERBOSE) { 392 for (i = 0; i < kp->len; i++) { 393 free(kp->pages[i].vaddr); 394 } 395 } 396 free(kp->pages); 397 } 398 399 static void usage(char *myname) { 400 fprintf(stderr, "Usage: %s [-s | -v | -a | -h ] <pid>\n" 401 " -s Sort pages by usage count.\n" 402 " -v Verbose: print virtual addresses.\n" 403 " -a Display all the KSM pages in the system. Ignore the pid argument.\n" 404 " -h Display this help screen.\n", 405 myname); 406 } 407 408 static int cmp_pages(const void *a, const void *b) { 409 const struct ksm_page *pg_a = a; 410 const struct ksm_page *pg_b = b; 411 int cmp = pg_b->vaddr_count - pg_a->vaddr_count; 412 413 return cmp ? cmp : pg_b->count - pg_a->count; 414 } 415 416 static bool is_pattern(uint8_t *data, size_t len) { 417 size_t i; 418 uint8_t first_byte = data[0]; 419 420 for (i = 1; i < len; i++) { 421 if (first_byte != data[i]) return false; 422 } 423 424 return true; 425 } 426 427 /* 428 * Get the process name for a given PID. Inserts the process name into buffer 429 * buf of length len. The size of the buffer must be greater than zero to get 430 * any useful output. 431 * 432 * Note that fgets(3) only declares length as an int, so our buffer size is 433 * also declared as an int. 434 * 435 * Returns 0 on success, a positive value on partial success, and -1 on 436 * failure. Other interesting values: 437 * 1 on failure to create string to examine proc cmdline entry 438 * 2 on failure to open proc cmdline entry 439 * 3 on failure to read proc cmdline entry 440 */ 441 static int getprocname(pid_t pid, char *buf, int len) { 442 char *filename; 443 FILE *f; 444 int rc = 0; 445 static const char* unknown_cmdline = "<unknown>"; 446 447 if (len <= 0) { 448 return -1; 449 } 450 451 if (asprintf(&filename, "/proc/%d/cmdline", (int)pid) < 0) { 452 rc = 1; 453 goto exit; 454 } 455 456 f = fopen(filename, "r"); 457 if (f == NULL) { 458 rc = 2; 459 goto releasefilename; 460 } 461 462 if (fgets(buf, len, f) == NULL) { 463 rc = 3; 464 goto closefile; 465 } 466 467 closefile: 468 (void) fclose(f); 469 releasefilename: 470 free(filename); 471 exit: 472 if (rc != 0) { 473 /* 474 * The process went away before we could read its process name. Try 475 * to give the user "<unknown>" here, but otherwise they get to look 476 * at a blank. 477 */ 478 if (strlcpy(buf, unknown_cmdline, (size_t)len) >= (size_t)len) { 479 rc = 4; 480 } 481 } 482 483 return rc; 484 } 485 486