/* * Copyright (C) 2018 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 #include #include #include #include #include #include #include #include using ProcMemInfo = ::android::meminfo::ProcMemInfo; using MemUsage = ::android::meminfo::MemUsage; 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); } static void show_footer(uint32_t nelem, const std::string& padding) { std::string elem(7, '-'); for (uint32_t i = 0; i < nelem; ++i) { std::cout << std::setw(7) << elem << padding; } std::cout << std::endl; } static void show_header(const std::vector& header, const std::string& padding) { if (header.empty()) return; for (size_t i = 0; i < header.size() - 1; ++i) { std::cout << std::setw(7) << header[i] << padding; } std::cout << header.back() << std::endl; show_footer(header.size() - 1, padding); } static void scan_usage(std::stringstream& ss, const MemUsage& usage, const std::string& padding, bool show_wss) { // clear string stream first. ss.str(""); // TODO: use ::android::base::StringPrintf instead of here. if (!show_wss) ss << std::setw(6) << usage.vss/1024 << padding; ss << std::setw(6) << usage.rss/1024 << padding << std::setw(6) << usage.pss/1024 << padding << std::setw(6) << usage.uss/1024 << padding << std::setw(6) << usage.shared_clean/1024 << padding << std::setw(6) << usage.shared_dirty/1024 << padding << std::setw(6) << usage.private_clean/1024 << padding << std::setw(6) << usage.private_dirty/1024 << padding; } static int show(ProcMemInfo& proc, bool hide_zeroes, bool show_wss) { const std::vector main_header = {"Vss", "Rss", "Pss", "Uss", "ShCl", "ShDi", "PrCl", "PrDi", "Name"}; const std::vector wss_header = {"WRss", "WPss", "WUss", "WShCl", "WShDi", "WPrCl", "WPrDi", "Name"}; const std::vector& header = show_wss ? wss_header : main_header; // Read process memory stats const MemUsage& stats = show_wss ? proc.Wss() : proc.Usage(); const std::vector<::android::meminfo::Vma>& maps = proc.Maps(); // following retains 'procmem' output so as to not break any scripts // that rely on it. std::string spaces = " "; show_header(header, spaces); const std::string padding = "K "; std::stringstream ss; for (auto& vma : maps) { const MemUsage& vma_stats = show_wss ? vma.wss : vma.usage; if (hide_zeroes && vma_stats.rss == 0) { continue; } scan_usage(ss, vma_stats, padding, show_wss); ss << vma.name << std::endl; std::cout << ss.str(); } show_footer(header.size() - 1, spaces); scan_usage(ss, stats, padding, show_wss); ss << "TOTAL" << std::endl; std::cout << ss.str(); return 0; } int main(int argc, char* argv[]) { bool use_pageidle = false; bool hide_zeroes = false; bool wss_reset = false; bool show_wss = false; int opt; while ((opt = getopt(argc, argv, "himpuWw")) != -1) { switch (opt) { case 'h': hide_zeroes = true; break; case 'i': use_pageidle = true; break; case 'm': break; case 'p': break; case 'u': break; case 'W': wss_reset = true; break; case 'w': show_wss = true; break; case '?': usage(argv[0]); return 0; default: abort(); } } if (optind != (argc - 1)) { fprintf(stderr, "Need exactly one pid at the end\n"); usage(argv[0]); exit(EXIT_FAILURE); } pid_t pid = atoi(argv[optind]); if (pid == 0) { std::cerr << "Invalid process id" << std::endl; exit(EXIT_FAILURE); } bool need_wss = wss_reset || show_wss; ProcMemInfo proc(pid, need_wss); if (wss_reset) { if (!proc.WssReset()) { std::cerr << "Failed to reset working set of pid : " << pid << std::endl; exit(EXIT_FAILURE); } return 0; } return show(proc, hide_zeroes, show_wss); }