diff options
author | Sandeep Patil <sspatil@google.com> | 2019-01-19 12:22:36 -0800 |
---|---|---|
committer | Sandeep Patil <sspatil@google.com> | 2019-01-19 12:22:36 -0800 |
commit | c1f064caa86300d98aa856cb961d3e09bed66a40 (patch) | |
tree | 26fe3c21e4f0c3ee5c0034e4d08b2e2a10c82a77 /libpagemap | |
parent | 48f6b916e9b81d4fee3e3d387c72a3d5ea40cae1 (diff) | |
download | extras-c1f064caa86300d98aa856cb961d3e09bed66a40.tar.gz |
pagemap/tools: remove all pagemap based tools
Bug: 111694435
Test: builds
Test: showmap and procrank exist on userdebug builds.
Change-Id: I3fb63d3adeedd7dece843cbc38e1667f4309bfd3
Signed-off-by: Sandeep Patil <sspatil@google.com>
Diffstat (limited to 'libpagemap')
-rw-r--r-- | libpagemap/Android.bp | 21 | ||||
-rw-r--r-- | libpagemap/librank.cpp | 480 | ||||
-rw-r--r-- | libpagemap/procmem.cpp | 374 | ||||
-rw-r--r-- | libpagemap/procrank.cpp | 610 |
4 files changed, 0 insertions, 1485 deletions
diff --git a/libpagemap/Android.bp b/libpagemap/Android.bp index 6a7ee26b..e89d1d8a 100644 --- a/libpagemap/Android.bp +++ b/libpagemap/Android.bp @@ -29,27 +29,6 @@ cc_library { export_include_dirs: ["include"], } -cc_binary { - name: "librank", - cflags: ["-Werror"], - srcs: ["librank.cpp"], - shared_libs: ["libpagemap"], -} - -cc_binary { - name: "procmem", - cflags: ["-Werror"], - srcs: ["procmem.cpp"], - shared_libs: ["libpagemap"], -} - -cc_binary { - name: "procrank", - cflags: ["-Werror"], - srcs: ["procrank.cpp"], - shared_libs: ["libpagemap", "libbase"], -} - cc_test { name: "pagemap_test", cflags: ["-Werror"], diff --git a/libpagemap/librank.cpp b/libpagemap/librank.cpp deleted file mode 100644 index fbba399b..00000000 --- a/libpagemap/librank.cpp +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <errno.h> -#include <getopt.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <unistd.h> - -#include <pagemap/pagemap.h> - -#define MAX_CMDLINE 256 - -struct process_info { - pid_t pid; - char cmdline[MAX_CMDLINE]; -}; - -struct mapping_info { - process_info* proc; - pm_memusage_t usage; -}; - -struct library_info { - char* name; - mapping_info** mappings; - size_t mappings_count; - size_t mappings_size; - pm_memusage_t total_usage; -}; - -static void usage(char *myname); -static int getprocname(pid_t pid, char *buf, size_t len); -static int numcmp(long long a, long long b); -static int licmp(const void *a, const void *b); - -static const char* library_name_blacklist[] = { "[heap]", "[stack]", "", NULL }; - -#define declare_sort(field) \ - static int sort_by_ ## field (const void *a, const void *b) - -declare_sort(vss); -declare_sort(rss); -declare_sort(pss); -declare_sort(uss); -declare_sort(swap); - -#define INIT_LIBRARIES 16 -#define INIT_MAPPINGS 4 - -static int order; - -library_info** libraries; -size_t libraries_count; -size_t libraries_size; - -library_info* get_library(const char *name, bool all) { - if (!all) { - for (size_t i = 0; library_name_blacklist[i]; i++) - if (!strcmp(name, library_name_blacklist[i])) - return NULL; - } else { - if (name[0] == 0) { - name = "[anon]"; - } - } - - for (size_t i = 0; i < libraries_count; i++) { - if (!strcmp(libraries[i]->name, name)) - return libraries[i]; - } - - if (libraries_size && libraries_count >= libraries_size) { - libraries = - reinterpret_cast<library_info**>(realloc(libraries, - 2 * libraries_size * sizeof(library_info*))); - if (!libraries) { - fprintf(stderr, "Couldn't resize libraries array: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - libraries_size = 2 * libraries_size; - } - - library_info* library = reinterpret_cast<library_info*>(calloc(1, sizeof(*library))); - if (!library) { - fprintf(stderr, "Couldn't allocate space for library struct: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - library->name = strdup(name); - if (!library->name) { - fprintf(stderr, "Couldn't allocate space for library name: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - library->mappings = reinterpret_cast<mapping_info**>(malloc(INIT_MAPPINGS * sizeof(mapping_info*))); - if (!library->mappings) { - fprintf(stderr, "Couldn't allocate space for library mappings array: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - library->mappings_count = 0; library->mappings_size = INIT_MAPPINGS; - pm_memusage_zero(&library->total_usage); - - libraries[libraries_count++] = library; - - return library; -} - -mapping_info* get_mapping(library_info* library, process_info* proc) { - mapping_info* mapping; - size_t i; - - for (i = 0; i < library->mappings_count; i++) { - if (library->mappings[i]->proc == proc) - return library->mappings[i]; - } - - if (library->mappings_size && library->mappings_count >= library->mappings_size) { - library->mappings = - reinterpret_cast<mapping_info**>(realloc(library->mappings, - 2 * library->mappings_size * sizeof(mapping_info*))); - if (!library->mappings) { - fprintf(stderr, "Couldn't resize mappings array: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - library->mappings_size = 2 * library->mappings_size; - } - - mapping = reinterpret_cast<mapping_info*>(calloc(1, sizeof(*mapping))); - if (!mapping) { - fprintf(stderr, "Couldn't allocate space for mapping struct: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - mapping->proc = proc; - pm_memusage_zero(&mapping->usage); - - library->mappings[library->mappings_count++] = mapping; - - return mapping; -} - -process_info* get_process(pid_t pid) { - process_info* process = reinterpret_cast<process_info*>(calloc(1, sizeof(*process))); - if (!process) { - fprintf(stderr, "Couldn't allocate space for process struct: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - - process->pid = pid; - getprocname(pid, process->cmdline, sizeof(process->cmdline)); - - return process; -} - -static int parse_perm(const char *perm) -{ - int ret = 0; - - while (*perm) { - switch(*perm) { - case 'r': - ret |= PM_MAP_READ; - break; - case 'w': - ret |= PM_MAP_WRITE; - break; - case 'x': - ret |= PM_MAP_EXEC; - break; - default: - fprintf(stderr, "Unknown permission '%c'\n", *perm); - exit(EXIT_FAILURE); - } - perm++; - } - return ret; -} - -int main(int argc, char *argv[]) { - char *prefix; - size_t prefix_len; - int (*compfn)(const void *a, const void *b); - - pm_kernel_t *ker; - pm_process_t *proc; - - pid_t *pids; - size_t num_procs; - - pm_map_t **maps; - size_t num_maps; - pm_memusage_t map_usage; - - library_info* li; - mapping_info* mi; - process_info* pi; - - size_t i, j; - int error; - int perm; - bool all; - uint64_t required_flags; - uint64_t flags_mask; - - bool has_swap = false; - - signal(SIGPIPE, SIG_IGN); - compfn = &sort_by_pss; - order = -1; - prefix = NULL; - prefix_len = 0; - opterr = 0; - perm = 0; - all = false; - required_flags = 0; - flags_mask = 0; - - while (1) { - int c; - const option longopts[] = { - {"all", 0, 0, 'a'}, - {"cached", 0, 0, 'c'}, - {"nocached", 0, 0, 'C'}, - {"ksm", 0, 0, 'k'}, - {"help", 0, 0, 'h'}, - {"pss", 0, 0, 'p'}, - {"uss", 0, 0, 'u'}, - {"vss", 0, 0, 'v'}, - {"rss", 0, 0, 'r'}, - {"swap", 0, 0, 's'}, - {"reverse", 0, 0, 'R'}, - {"path", required_argument, 0, 'P'}, - {"perm", required_argument, 0, 'm'}, - {0, 0, 0, 0} - }; - c = getopt_long(argc, argv, "acChkm:pP:uvrsR", longopts, NULL); - if (c < 0) { - break; - } - /* Alphabetical cases */ - switch (c) { - case 'a': - all = true; - break; - case 'c': - required_flags = 0; - flags_mask = (1 << KPF_SWAPBACKED); - break; - case 'C': - required_flags = flags_mask = (1 << KPF_SWAPBACKED); - break; - case 'k': - required_flags = flags_mask = (1 << KPF_KSM); - break; - case 'h': - usage(argv[0]); - exit(EXIT_SUCCESS); - case 'm': - perm = parse_perm(optarg); - break; - case 'p': - compfn = &sort_by_pss; - break; - case 'P': - prefix = optarg; - prefix_len = strlen(prefix); - break; - case 'u': - compfn = &sort_by_uss; - break; - case 'v': - compfn = &sort_by_vss; - break; - case 'r': - compfn = &sort_by_rss; - break; - case 's': - compfn = &sort_by_swap; - break; - case 'R': - order *= -1; - break; - case '?': - fprintf(stderr, "Invalid argument \"%s\".\n", argv[optind - 1]); - usage(argv[0]); - exit(EXIT_FAILURE); - default: - abort(); - } - } - - argc -= optind; - argv += optind; - - libraries = reinterpret_cast<library_info**>(malloc(INIT_LIBRARIES * sizeof(library_info*))); - libraries_count = 0; libraries_size = INIT_LIBRARIES; - pm_memusage_zero(&map_usage); - - error = pm_kernel_create(&ker); - if (error) { - fprintf(stderr, "Error initializing kernel interface -- " - "does this kernel have pagemap?\n"); - exit(EXIT_FAILURE); - } - - error = pm_kernel_pids(ker, &pids, &num_procs); - if (error) { - fprintf(stderr, "Error listing processes.\n"); - exit(EXIT_FAILURE); - } - - for (i = 0; i < num_procs; i++) { - error = pm_process_create(ker, pids[i], &proc); - if (error) { - fprintf(stderr, "warning: could not create process interface for %d\n", pids[i]); - continue; - } - - pi = get_process(pids[i]); - - error = pm_process_maps(proc, &maps, &num_maps); - if (error) { - fprintf(stderr, "Error listing maps for process %d.\n", proc->pid); - exit(EXIT_FAILURE); - } - - for (j = 0; j < num_maps; j++) { - if (prefix && (strncmp(pm_map_name(maps[j]), prefix, prefix_len))) - continue; - - if (perm && (pm_map_flags(maps[j]) & PM_MAP_PERMISSIONS) != perm) - continue; - - li = get_library(pm_map_name(maps[j]), all); - if (!li) - continue; - - mi = get_mapping(li, pi); - - error = pm_map_usage_flags(maps[j], &map_usage, flags_mask, - required_flags); - if (error) { - fprintf(stderr, "Error getting map memory usage of " - "map %s in process %d.\n", - pm_map_name(maps[j]), proc->pid); - exit(EXIT_FAILURE); - } - - if (map_usage.swap) { - has_swap = true; - } - - pm_memusage_add(&mi->usage, &map_usage); - pm_memusage_add(&li->total_usage, &map_usage); - } - } - - printf(" %6s %7s %6s %6s %6s ", "RSStot", "VSS", "RSS", "PSS", "USS"); - - if (has_swap) { - printf(" %6s ", "Swap"); - } - - printf("Name/PID\n"); - fflush(stdout); - - qsort(libraries, libraries_count, sizeof(libraries[0]), &licmp); - - for (i = 0; i < libraries_count; i++) { - li = libraries[i]; - - printf("%6zdK %7s %6s %6s %6s ", li->total_usage.pss / 1024, "", "", "", ""); - if (has_swap) { - printf(" %6s ", ""); - } - printf("%s\n", li->name); - fflush(stdout); - - qsort(li->mappings, li->mappings_count, sizeof(li->mappings[0]), compfn); - - for (j = 0; j < li->mappings_count; j++) { - mi = li->mappings[j]; - pi = mi->proc; - printf( " %6s %7zdK %6zdK %6zdK %6zdK ", "", - mi->usage.vss / 1024, - mi->usage.rss / 1024, - mi->usage.pss / 1024, - mi->usage.uss / 1024); - if (has_swap) { - printf("%6zdK ", mi->usage.swap / 1024); - } - printf(" %s [%d]\n", - pi->cmdline, - pi->pid); - } - printf("\n"); - fflush(stdout); - } - - exit(0); -} - -static void usage(char *myname) { - fprintf(stderr, "Usage: %s [ -P | -L ] [ -v | -r | -p | -u | -s | -h ]\n" - "\n" - "Sort options:\n" - " -v Sort processes by VSS.\n" - " -r Sort processes by RSS.\n" - " -p Sort processes by PSS.\n" - " -u Sort processes by USS.\n" - " -s Sort processes by swap.\n" - " (Default sort order is PSS.)\n" - " -a Show all mappings, including stack, heap and anon.\n" - " -P /path Limit libraries displayed to those in path.\n" - " -R Reverse sort order (default is descending).\n" - " -m [r][w][x] Only list pages that exactly match permissions\n" - " -c Only show cached (storage backed) pages\n" - " -C Only show non-cached (ram/swap backed) pages\n" - " -k Only show pages collapsed by KSM\n" - " -h Display this help screen.\n", - myname); -} - -static int getprocname(pid_t pid, char *buf, size_t len) { - char filename[32]; - FILE *f; - - snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid); - f = fopen(filename, "r"); - if (!f) { - *buf = '\0'; - return 1; - } - if (!fgets(buf, len, f)) { - *buf = '\0'; - fclose(f); - return 2; - } - fclose(f); - return 0; -} - -static int numcmp(long long a, long long b) { - if (a < b) return -1; - if (a > b) return 1; - return 0; -} - -static int licmp(const void *a, const void *b) { - return order * numcmp( - (*((library_info**)a))->total_usage.pss, - (*((library_info**)b))->total_usage.pss - ); -} - -#define create_sort(field, compfn) \ - static int sort_by_ ## field (const void *a, const void *b) { \ - return order * compfn( \ - (*((mapping_info**)a))->usage.field, \ - (*((mapping_info**)b))->usage.field \ - ); \ - } - -create_sort(vss, numcmp) -create_sort(rss, numcmp) -create_sort(pss, numcmp) -create_sort(uss, numcmp) -create_sort(swap, numcmp) diff --git a/libpagemap/procmem.cpp b/libpagemap/procmem.cpp deleted file mode 100644 index e8eb4eda..00000000 --- a/libpagemap/procmem.cpp +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <errno.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <pagemap/pagemap.h> - -/* Information about a single mapping */ -struct map_info { - pm_map_t *map; - pm_memusage_t usage; - /* page counts */ - unsigned long shared_clean; - unsigned long shared_dirty; - unsigned long private_clean; - unsigned long private_dirty; -}; - -/* display the help screen */ -static void usage(const char *cmd); - -/* qsort compare function to compare maps by PSS */ -int comp_pss(const void *a, const void *b); - -/* qsort compare function to compare maps by USS */ -int comp_uss(const void* a, const void* b); - -int main(int argc, char *argv[]) { - pid_t pid; - - /* libpagemap context */ - pm_kernel_t *ker; - int pagesize; /* cached for speed */ - pm_process_t *proc; - - /* maps and such */ - pm_map_t **maps; size_t num_maps; - - struct map_info **mis = NULL; - struct map_info *mi; - - /* pagemap information */ - uint64_t *pagemap; size_t num_pages; - uint64_t mapentry; - uint64_t count, flags; - - /* totals */ - unsigned long total_shared_clean, total_shared_dirty, total_private_clean, total_private_dirty; - pm_memusage_t total_usage; - - /* command-line options */ - int ws; -#define WS_OFF (0) -#define WS_ONLY (1) -#define WS_RESET (2) - int (*compfn)(const void *a, const void *b); - int hide_zeros; - - /* Use kernel's idle page tracking interface for working set determination */ - int use_pageidle; - - /* temporary variables */ - size_t i, j; - char *endptr; - int error; - - if (argc < 2) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - - ws = WS_OFF; - compfn = NULL; - hide_zeros = 0; - use_pageidle = 0; - for (i = 1; i < (size_t)(argc - 1); i++) { - if (!strcmp(argv[i], "-w")) { ws = WS_ONLY; continue; } - if (!strcmp(argv[i], "-W")) { ws = WS_RESET; continue; } - if (!strcmp(argv[i], "-i")) { - use_pageidle = 1; - continue; - } - if (!strcmp(argv[i], "-m")) { compfn = NULL; continue; } - if (!strcmp(argv[i], "-p")) { compfn = &comp_pss; continue; } - if (!strcmp(argv[i], "-u")) { - compfn = &comp_uss; - continue; - } - if (!strcmp(argv[i], "-h")) { hide_zeros = 1; continue; } - fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]); - usage(argv[0]); - exit(EXIT_FAILURE); - } - - pid = (pid_t)strtol(argv[argc - 1], &endptr, 10); - if (*endptr != '\0') { - fprintf(stderr, "Invalid PID \"%s\".\n", argv[argc - 1]); - exit(EXIT_FAILURE); - } - - error = pm_kernel_create(&ker); - if (error) { - fprintf(stderr, "error creating kernel interface -- " - "does this kernel have pagemap?\n"); - exit(EXIT_FAILURE); - } - - if (ws != WS_OFF && use_pageidle) { - error = pm_kernel_init_page_idle(ker); - if (error) { - fprintf(stderr, - "error initalizing idle page tracking -- " - "enable CONFIG_IDLE_PAGE_TRACKING in kernel.\n"); - exit(EXIT_FAILURE); - } - } - - pagesize = pm_kernel_pagesize(ker); - - error = pm_process_create(ker, pid, &proc); - if (error) { - fprintf(stderr, "error creating process interface -- " - "does process %d really exist?\n", pid); - exit(EXIT_FAILURE); - } - - if (ws != WS_OFF) { - /* - * The idle page tracking interface will update the PageIdle flags - * upon writing. So, even if we are called only to read the *current* - * working set, we need to reset the bitmap to make sure we get - * the updated page idle flags. This is not true with the 'clear_refs' - * implementation. - */ - if (ws == WS_RESET || use_pageidle) { - error = pm_process_workingset(proc, NULL, 1); - if (error) { - fprintf(stderr, "error resetting working set for process.\n"); - exit(EXIT_FAILURE); - } - } - if (ws == WS_RESET) exit(EXIT_SUCCESS); - } - - /* get maps, and allocate our map_info array */ - error = pm_process_maps(proc, &maps, &num_maps); - if (error) { - fprintf(stderr, "error listing maps.\n"); - exit(EXIT_FAILURE); - } - - mis = (struct map_info **)calloc(num_maps, sizeof(struct map_info *)); - if (!mis) { - fprintf(stderr, "error allocating map_info array: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - - /* print header */ - if (ws == WS_ONLY) { - printf("%7s %7s %7s %7s %7s %7s %7s %s\n", - "WRss", "WPss", "WUss", "WShCl", "WShDi", "WPrCl", "WPrDi", "Name"); - printf("%7s %7s %7s %7s %7s %7s %7s %s\n", - "-------", "-------", "-------", "-------", "-------", "-------", "-------", ""); - } else { - printf("%7s %7s %7s %7s %7s %7s %7s %7s %s\n", - "Vss", "Rss", "Pss", "Uss", "ShCl", "ShDi", "PrCl", "PrDi", "Name"); - printf("%7s %7s %7s %7s %7s %7s %7s %7s %s\n", - "-------", "-------", "-------", "-------", "-------", "-------", "-------", "-------", ""); - } - - /* zero things */ - pm_memusage_zero(&total_usage); - total_shared_clean = total_shared_dirty = total_private_clean = total_private_dirty = 0; - - for (i = 0; i < num_maps; i++) { - mi = (struct map_info *)calloc(1, sizeof(struct map_info)); - if (!mi) { - fprintf(stderr, "error allocating map_info: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - - mi->map = maps[i]; - - /* get, and sum, memory usage */ - - if (ws == WS_ONLY) - error = pm_map_workingset(mi->map, &mi->usage); - else - error = pm_map_usage(mi->map, &mi->usage); - if (error) { - fflush(stdout); - fprintf(stderr, "error getting usage for map.\n"); - continue; - } - - pm_memusage_add(&total_usage, &mi->usage); - - /* get, and sum, individual page counts */ - - error = pm_map_pagemap(mi->map, &pagemap, &num_pages); - if (error) { - fflush(stdout); - fprintf(stderr, "error getting pagemap for map.\n"); - continue; - } - - mi->shared_clean = mi->shared_dirty = mi->private_clean = mi->private_dirty = 0; - - for (j = 0; j < num_pages; j++) { - mapentry = pagemap[j]; - - if (PM_PAGEMAP_PRESENT(mapentry) && !PM_PAGEMAP_SWAPPED(mapentry)) { - - error = pm_kernel_count(ker, PM_PAGEMAP_PFN(mapentry), &count); - if (error) { - fflush(stdout); - fprintf(stderr, "error getting count for frame.\n"); - } - - error = pm_kernel_flags(ker, PM_PAGEMAP_PFN(mapentry), &flags); - if (error) { - fflush(stdout); - fprintf(stderr, "error getting flags for frame.\n"); - } - - if ((ws != WS_ONLY) || - pm_kernel_page_is_accessed(ker, PM_PAGEMAP_PFN(mapentry), &flags)) { - if (count > 1) { - if (flags & (1 << KPF_DIRTY)) { - mi->shared_dirty++; - } else { - mi->shared_clean++; - } - } else { - if (flags & (1 << KPF_DIRTY)) { - mi->private_dirty++; - } else { - mi->private_clean++; - } - } - } - } - } - - total_shared_clean += mi->shared_clean; - total_shared_dirty += mi->shared_dirty; - total_private_clean += mi->private_clean; - total_private_dirty += mi->private_dirty; - - /* add to array */ - mis[i] = mi; - } - - /* sort the array, if requested (compfn == NULL for original order) */ - if (compfn) - qsort(mis, num_maps, sizeof(mis[0]), compfn); - - for (i = 0; i < num_maps; i++) { - mi = mis[i]; - - if ((!mi) || (hide_zeros && !mi->usage.rss)) - continue; - - if (ws == WS_ONLY) { - printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n", - (long)mi->usage.rss / 1024, - (long)mi->usage.pss / 1024, - (long)mi->usage.uss / 1024, - mi->shared_clean * pagesize / 1024, - mi->shared_dirty * pagesize / 1024, - mi->private_clean * pagesize / 1024, - mi->private_dirty * pagesize / 1024, - pm_map_name(mi->map) - ); - } else { - printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n", - (long)mi->usage.vss / 1024, - (long)mi->usage.rss / 1024, - (long)mi->usage.pss / 1024, - (long)mi->usage.uss / 1024, - mi->shared_clean * pagesize / 1024, - mi->shared_dirty * pagesize / 1024, - mi->private_clean * pagesize / 1024, - mi->private_dirty * pagesize / 1024, - pm_map_name(mi->map) - ); - } - } - - /* print totals */ - if (ws == WS_ONLY) { - printf("%7s %7s %7s %7s %7s %7s %7s %s\n", - "-------", "-------", "-------", "-------", "-------", "-------", "-------", ""); - printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n", - (long)total_usage.rss / 1024, - (long)total_usage.pss / 1024, - (long)total_usage.uss / 1024, - total_shared_clean * pagesize / 1024, - total_shared_dirty * pagesize / 1024, - total_private_clean * pagesize / 1024, - total_private_dirty * pagesize / 1024, - "TOTAL" - ); - } else { - printf("%7s %7s %7s %7s %7s %7s %7s %7s %s\n", - "-------", "-------", "-------", "-------", "-------", "-------", "-------", "-------", ""); - printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n", - (long)total_usage.vss / 1024, - (long)total_usage.rss / 1024, - (long)total_usage.pss / 1024, - (long)total_usage.uss / 1024, - total_shared_clean * pagesize / 1024, - total_shared_dirty * pagesize / 1024, - total_private_clean * pagesize / 1024, - total_private_dirty * pagesize / 1024, - "TOTAL" - ); - } - - free(mis); - return 0; -} - -static void usage(const char* cmd) { - fprintf(stderr, - "Usage: %s [-i] [ -w | -W ] [ -p | -m ] [ -h ] pid\n" - " -i Uses idle page tracking for working set statistics.\n" - " -w Displays statistics for the working set only.\n" - " -W Resets the working set of the process.\n" - " -p Sort by PSS.\n" - " -u Sort by USS.\n" - " -m Sort by mapping order (as read from /proc).\n" - " -h Hide maps with no RSS.\n", - cmd); -} - -int comp_pss(const void *a, const void *b) { - struct map_info *ma, *mb; - - ma = *((struct map_info **)a); - mb = *((struct map_info **)b); - - if (mb->usage.pss < ma->usage.pss) return -1; - if (mb->usage.pss > ma->usage.pss) return 1; - return 0; -} - -int comp_uss(const void* a, const void* b) { - struct map_info *ma, *mb; - - ma = *((struct map_info**)a); - mb = *((struct map_info**)b); - - if (mb->usage.uss < ma->usage.uss) return -1; - if (mb->usage.uss > ma->usage.uss) return 1; - return 0; -} diff --git a/libpagemap/procrank.cpp b/libpagemap/procrank.cpp deleted file mode 100644 index 7519e3b8..00000000 --- a/libpagemap/procrank.cpp +++ /dev/null @@ -1,610 +0,0 @@ -// -// Copyright (C) 2008 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <unistd.h> - -#include <vector> - -#include <android-base/file.h> -#include <android-base/stringprintf.h> -#include <android-base/strings.h> -#include <pagemap/pagemap.h> - -struct proc_info { - pid_t pid; - pm_memusage_t usage; - uint64_t wss; - int oomadj; -}; - -static void usage(char *myname); -static std::string getprocname(pid_t pid); -static int getoomadj(pid_t pid); -static bool getminfree(std::vector<uint64_t>* minfree, std::vector<int>* adj); -static int numcmp(uint64_t a, uint64_t b); - -#define declare_sort(field) \ - static int sort_by_ ## field (const void *a, const void *b) - -declare_sort(vss); -declare_sort(rss); -declare_sort(pss); -declare_sort(uss); -declare_sort(swap); -declare_sort(oomadj); - -int (*compfn)(const void *a, const void *b); -static int order; - -enum { - MEMINFO_TOTAL, - MEMINFO_FREE, - MEMINFO_BUFFERS, - MEMINFO_CACHED, - MEMINFO_SHMEM, - MEMINFO_SLAB, - MEMINFO_SWAP_TOTAL, - MEMINFO_SWAP_FREE, - MEMINFO_ZRAM_TOTAL, - MEMINFO_MAPPED, - MEMINFO_VMALLOC_USED, - MEMINFO_PAGE_TABLES, - MEMINFO_KERNEL_STACK, - MEMINFO_COUNT -}; - -void get_mem_info(uint64_t mem[]) { - char buffer[1024]; - unsigned int numFound = 0; - - int fd = open("/proc/meminfo", O_RDONLY); - - if (fd < 0) { - printf("Unable to open /proc/meminfo: %s\n", strerror(errno)); - return; - } - - const int len = read(fd, buffer, sizeof(buffer)-1); - close(fd); - - if (len < 0) { - printf("Empty /proc/meminfo"); - return; - } - buffer[len] = 0; - - static const char* const tags[] = { - "MemTotal:", - "MemFree:", - "Buffers:", - "Cached:", - "Shmem:", - "Slab:", - "SwapTotal:", - "SwapFree:", - "ZRam:", // not read from meminfo but from /sys/block/zram0 - "Mapped:", - "VmallocUsed:", - "PageTables:", - "KernelStack:", - NULL - }; - static const int tagsLen[] = { - 9, - 8, - 8, - 7, - 6, - 5, - 10, - 9, - 5, - 7, - 12, - 11, - 12, - 0 - }; - - char* p = buffer; - while (*p && (numFound < (sizeof(tagsLen) / sizeof(tagsLen[0])))) { - int i = 0; - while (tags[i]) { - if (strncmp(p, tags[i], tagsLen[i]) == 0) { - p += tagsLen[i]; - while (*p == ' ') p++; - char* num = p; - while (*p >= '0' && *p <= '9') p++; - if (*p != 0) { - *p = 0; - p++; - } - mem[i] = atoll(num); - numFound++; - break; - } - i++; - } - while (*p && *p != '\n') { - p++; - } - if (*p) p++; - } -} - -static uint64_t get_zram_mem_used() { -#define ZRAM_SYSFS "/sys/block/zram0/" - FILE *f = fopen(ZRAM_SYSFS "mm_stat", "r"); - if (f) { - uint64_t mem_used_total = 0; - - int matched = fscanf(f, "%*d %*d %" SCNu64 " %*d %*d %*d %*d", &mem_used_total); - if (matched != 1) - fprintf(stderr, "warning: failed to parse " ZRAM_SYSFS "mm_stat\n"); - - fclose(f); - return mem_used_total; - } - - f = fopen(ZRAM_SYSFS "mem_used_total", "r"); - if (f) { - uint64_t mem_used_total = 0; - - int matched = fscanf(f, "%" SCNu64, &mem_used_total); - if (matched != 1) - fprintf(stderr, "warning: failed to parse " ZRAM_SYSFS "mem_used_total\n"); - - fclose(f); - return mem_used_total; - } - - return 0; -} - -int main(int argc, char *argv[]) { - pm_kernel_t *ker; - pm_process_t *proc; - pid_t *pids; - size_t num_procs; - uint64_t total_pss; - uint64_t total_uss; - uint64_t total_swap; - uint64_t total_pswap; - uint64_t total_uswap; - uint64_t total_zswap; - int error; - bool has_swap = false, has_zram = false; - uint64_t required_flags = 0; - uint64_t flags_mask = 0; - - int arg; - size_t i; - - enum { - WS_OFF, - WS_ONLY, - WS_RESET, - } ws; - - uint64_t mem[MEMINFO_COUNT] = { }; - pm_proportional_swap_t *p_swap; - float zram_cr = 0.0; - - signal(SIGPIPE, SIG_IGN); - compfn = &sort_by_pss; - order = -1; - ws = WS_OFF; - bool oomadj = false; - - for (arg = 1; arg < argc; arg++) { - if (!strcmp(argv[arg], "-v")) { compfn = &sort_by_vss; continue; } - if (!strcmp(argv[arg], "-r")) { compfn = &sort_by_rss; continue; } - if (!strcmp(argv[arg], "-p")) { compfn = &sort_by_pss; continue; } - if (!strcmp(argv[arg], "-u")) { compfn = &sort_by_uss; continue; } - if (!strcmp(argv[arg], "-s")) { compfn = &sort_by_swap; continue; } - if (!strcmp(argv[arg], "-o")) { compfn = &sort_by_oomadj; oomadj = true; continue; } - if (!strcmp(argv[arg], "-c")) { required_flags = 0; flags_mask = (1 << KPF_SWAPBACKED); continue; } - if (!strcmp(argv[arg], "-C")) { required_flags = flags_mask = (1 << KPF_SWAPBACKED); continue; } - if (!strcmp(argv[arg], "-k")) { required_flags = flags_mask = (1 << KPF_KSM); continue; } - if (!strcmp(argv[arg], "-w")) { ws = WS_ONLY; continue; } - if (!strcmp(argv[arg], "-W")) { ws = WS_RESET; continue; } - if (!strcmp(argv[arg], "-R")) { order *= -1; continue; } - if (!strcmp(argv[arg], "-h")) { usage(argv[0]); exit(0); } - fprintf(stderr, "Invalid argument \"%s\".\n", argv[arg]); - usage(argv[0]); - exit(EXIT_FAILURE); - } - - get_mem_info(mem); - p_swap = pm_memusage_pswap_create(mem[MEMINFO_SWAP_TOTAL] * 1024); - - error = pm_kernel_create(&ker); - if (error) { - fprintf(stderr, "Error creating kernel interface -- " - "does this kernel have pagemap?\n"); - exit(EXIT_FAILURE); - } - - error = pm_kernel_pids(ker, &pids, &num_procs); - if (error) { - fprintf(stderr, "Error listing processes.\n"); - exit(EXIT_FAILURE); - } - - std::vector<proc_info> procs(num_procs); - for (i = 0; i < num_procs; i++) { - procs[i].pid = pids[i]; - procs[i].oomadj = getoomadj(pids[i]); - pm_memusage_zero(&procs[i].usage); - pm_memusage_pswap_init_handle(&procs[i].usage, p_swap); - error = pm_process_create(ker, pids[i], &proc); - if (error) { - fprintf(stderr, "warning: could not create process interface for %d\n", pids[i]); - continue; - } - - switch (ws) { - case WS_OFF: - error = pm_process_usage_flags(proc, &procs[i].usage, flags_mask, - required_flags); - break; - case WS_ONLY: - error = pm_process_workingset(proc, &procs[i].usage, 0); - break; - case WS_RESET: - error = pm_process_workingset(proc, NULL, 1); - break; - } - - if (error) { - fprintf(stderr, "warning: could not read usage for %d\n", pids[i]); - } - - if (ws != WS_RESET && procs[i].usage.swap) { - has_swap = true; - } - - pm_process_destroy(proc); - } - - free(pids); - - if (ws == WS_RESET) exit(0); - - procs.erase(std::remove_if(procs.begin(), - procs.end(), - [](auto proc){ - return proc.usage.vss == 0; - }), - procs.end()); - - qsort(procs.data(), procs.size(), sizeof(procs[0]), compfn); - - if (has_swap) { - uint64_t zram_mem_used = get_zram_mem_used(); - if (zram_mem_used) { - mem[MEMINFO_ZRAM_TOTAL] = zram_mem_used/1024; - zram_cr = (float) mem[MEMINFO_ZRAM_TOTAL] / - (mem[MEMINFO_SWAP_TOTAL] - mem[MEMINFO_SWAP_FREE]); - has_zram = true; - } - } - - printf("%5s ", "PID"); - if (oomadj) { - printf("%5s ", "oom"); - } - if (ws) { - printf("%7s %7s %7s ", "WRss", "WPss", "WUss"); - if (has_swap) { - printf("%7s %7s %7s ", "WSwap", "WPSwap", "WUSwap"); - if (has_zram) { - printf("%7s ", "WZSwap"); - } - } - } else { - printf("%8s %7s %7s %7s ", "Vss", "Rss", "Pss", "Uss"); - if (has_swap) { - printf("%7s %7s %7s ", "Swap", "PSwap", "USwap"); - if (has_zram) { - printf("%7s ", "ZSwap"); - } - } - } - - printf("%s\n", "cmdline"); - - total_pss = 0; - total_uss = 0; - total_swap = 0; - total_pswap = 0; - total_uswap = 0; - total_zswap = 0; - - std::vector<uint64_t> lmk_minfree; - std::vector<int> lmk_adj; - if (oomadj) { - getminfree(&lmk_minfree, &lmk_adj); - } - auto lmk_minfree_it = lmk_minfree.cbegin(); - auto lmk_adj_it = lmk_adj.cbegin(); - - auto print_oomadj_totals = [&](int adj){ - for (; lmk_adj_it != lmk_adj.cend() && lmk_minfree_it != lmk_minfree.cend() && - adj > *lmk_adj_it; lmk_adj_it++, lmk_minfree_it++) { - // Print the cumulative total line - printf("%5s ", ""); // pid - - printf("%5s ", ""); // oomadj - - if (ws) { - printf("%7s %6" PRIu64 "K %6" PRIu64 "K ", - "", total_pss / 1024, total_uss / 1024); - } else { - printf("%8s %7s %6" PRIu64 "K %6" PRIu64 "K ", - "", "", total_pss / 1024, total_uss / 1024); - } - - if (has_swap) { - printf("%6" PRIu64 "K ", total_swap / 1024); - printf("%6" PRIu64 "K ", total_pswap / 1024); - printf("%6" PRIu64 "K ", total_uswap / 1024); - if (has_zram) { - printf("%6" PRIu64 "K ", total_zswap / 1024); - } - } - - printf("TOTAL for oomadj < %d (%6" PRIu64 "K)\n", *lmk_adj_it, *lmk_minfree_it / 1024); - } - }; - - for (auto& proc: procs) { - if (oomadj) { - print_oomadj_totals(proc.oomadj); - } - - std::string cmdline = getprocname(proc.pid); - - total_pss += proc.usage.pss; - total_uss += proc.usage.uss; - total_swap += proc.usage.swap; - - printf("%5d ", proc.pid); - - if (oomadj) { - printf("%5d ", proc.oomadj); - } - - if (ws) { - printf("%6zuK %6zuK %6zuK ", - proc.usage.rss / 1024, - proc.usage.pss / 1024, - proc.usage.uss / 1024 - ); - } else { - printf("%7zuK %6zuK %6zuK %6zuK ", - proc.usage.vss / 1024, - proc.usage.rss / 1024, - proc.usage.pss / 1024, - proc.usage.uss / 1024 - ); - } - - if (has_swap) { - pm_swapusage_t su; - - pm_memusage_pswap_get_usage(&proc.usage, &su); - printf("%6zuK ", proc.usage.swap / 1024); - printf("%6zuK ", su.proportional / 1024); - printf("%6zuK ", su.unique / 1024); - total_pswap += su.proportional; - total_uswap += su.unique; - pm_memusage_pswap_free(&proc.usage); - if (has_zram) { - size_t zpswap = su.proportional * zram_cr; - printf("%6zuK ", zpswap / 1024); - total_zswap += zpswap; - } - } - - printf("%s\n", cmdline.c_str()); - } - - pm_memusage_pswap_destroy(p_swap); - - if (oomadj) { - print_oomadj_totals(INT_MAX); - } - - // Print the separator line - printf("%5s ", ""); - - if (oomadj) { - printf("%5s ", ""); - } - - if (ws) { - printf("%7s %7s %7s ", "", "------", "------"); - } else { - printf("%8s %7s %7s %7s ", "", "", "------", "------"); - } - - if (has_swap) { - printf("%7s %7s %7s ", "------", "------", "------"); - if (has_zram) { - printf("%7s ", "------"); - } - } - - printf("%s\n", "------"); - - // Print the total line - printf("%5s ", ""); - - if (oomadj) { - printf("%5s ", ""); - } - - if (ws) { - printf("%7s %6" PRIu64 "K %6" PRIu64 "K ", - "", total_pss / 1024, total_uss / 1024); - } else { - printf("%8s %7s %6" PRIu64 "K %6" PRIu64 "K ", - "", "", total_pss / 1024, total_uss / 1024); - } - - if (has_swap) { - printf("%6" PRIu64 "K ", total_swap / 1024); - printf("%6" PRIu64 "K ", total_pswap / 1024); - printf("%6" PRIu64 "K ", total_uswap / 1024); - if (has_zram) { - printf("%6" PRIu64 "K ", total_zswap / 1024); - } - } - - printf("TOTAL\n"); - - printf("\n"); - - if (has_swap) { - printf("ZRAM: %" PRIu64 "K physical used for %" PRIu64 "K in swap " - "(%" PRIu64 "K total swap)\n", - mem[MEMINFO_ZRAM_TOTAL], (mem[MEMINFO_SWAP_TOTAL] - mem[MEMINFO_SWAP_FREE]), - mem[MEMINFO_SWAP_TOTAL]); - } - printf(" RAM: %" PRIu64 "K total, %" PRIu64 "K free, %" PRIu64 "K buffers, " - "%" PRIu64 "K cached, %" PRIu64 "K shmem, %" PRIu64 "K slab\n", - mem[MEMINFO_TOTAL], mem[MEMINFO_FREE], mem[MEMINFO_BUFFERS], - mem[MEMINFO_CACHED], mem[MEMINFO_SHMEM], mem[MEMINFO_SLAB]); - - return 0; -} - -static void usage(char *myname) { - fprintf(stderr, "Usage: %s [ -W ] [ -v | -r | -p | -u | -s | -h ]\n" - " -v Sort by VSS.\n" - " -r Sort by RSS.\n" - " -p Sort by PSS.\n" - " -u Sort by USS.\n" - " -s Sort by swap.\n" - " (Default sort order is PSS.)\n" - " -R Reverse sort order (default is descending).\n" - " -c Only show cached (storage backed) pages\n" - " -C Only show non-cached (ram/swap backed) pages\n" - " -k Only show pages collapsed by KSM\n" - " -w Display statistics for working set only.\n" - " -W Reset working set of all processes.\n" - " -o Show and sort by oom score against lowmemorykiller thresholds.\n" - " -h Display this help screen.\n", - myname); -} - -// Get the process name for a given PID. -static std::string getprocname(pid_t pid) { - std::string filename = android::base::StringPrintf("/proc/%d/cmdline", pid); - - std::string procname; - if (!android::base::ReadFileToString(filename, &procname)) { - // The process went away before we could read its process name. - procname = "<unknown>"; - } - - return procname; -} - -static int getoomadj(pid_t pid) { - std::string filename = android::base::StringPrintf("/proc/%d/oom_score_adj", pid); - std::string oomadj; - - if (!android::base::ReadFileToString(filename, &oomadj)) { - return -1001; - } - - return strtol(oomadj.c_str(), NULL, 10); -} - -static bool getminfree(std::vector<uint64_t>* minfree, std::vector<int>* adj) { - std::string minfree_str; - std::string adj_str; - - if (!android::base::ReadFileToString("/sys/module/lowmemorykiller/parameters/minfree", &minfree_str)) { - return false; - } - - if (!android::base::ReadFileToString("/sys/module/lowmemorykiller/parameters/adj", &adj_str)) { - return false; - } - - std::vector<std::string> minfree_vec = android::base::Split(minfree_str, ","); - std::vector<std::string> adj_vec = android::base::Split(adj_str, ","); - - minfree->clear(); - minfree->resize(minfree_vec.size()); - adj->clear(); - adj->resize(adj_vec.size()); - - std::transform(minfree_vec.begin(), minfree_vec.end(), minfree->begin(), - [](const std::string& s) -> uint64_t { - return strtoull(s.c_str(), NULL, 10) * PAGE_SIZE; - }); - - std::transform(adj_vec.begin(), adj_vec.end(), adj->begin(), - [](const std::string& s) -> int { - return strtol(s.c_str(), NULL, 10); - }); - - return true; -} - -static int numcmp(uint64_t a, uint64_t b) { - if (a < b) return -1; - if (a > b) return 1; - return 0; -} - -static int snumcmp(int64_t a, int64_t b) { - if (a < b) return -1; - if (a > b) return 1; - return 0; -} - -#define create_sort(field, compfn) \ - static int sort_by_ ## field (const void *a, const void *b) { \ - return order * compfn( \ - ((struct proc_info*)(a))->usage.field, \ - ((struct proc_info*)(b))->usage.field \ - ); \ - } - -create_sort(vss, numcmp) -create_sort(rss, numcmp) -create_sort(pss, numcmp) -create_sort(uss, numcmp) -create_sort(swap, numcmp) - -static int sort_by_oomadj (const void *a, const void *b) { - // Negative oomadj is higher priority, reverse the sort order - return -1 * order * snumcmp( - ((struct proc_info*)a)->oomadj, - ((struct proc_info*)b)->oomadj - ); -} |