56c414e872
The Vma and ProcMemInfo objects do not need separate stats objects for storing working set. The Vma either has working set or memory usage information and never both. Bug: 111694435 Test: libmeminfo_test 1 Change-Id: I2df05f7e750bbba4325474633e705d6d68dd2ccb Merged-In: I2df05f7e750bbba4325474633e705d6d68dd2ccb Signed-off-by: Sandeep Patil <sspatil@google.com>
192 lines
6.4 KiB
C++
192 lines
6.4 KiB
C++
/*
|
|
* 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 <errno.h>
|
|
#include <inttypes.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <android-base/stringprintf.h>
|
|
#include <meminfo/procmeminfo.h>
|
|
|
|
using Vma = ::android::meminfo::Vma;
|
|
using ProcMemInfo = ::android::meminfo::ProcMemInfo;
|
|
using MemUsage = ::android::meminfo::MemUsage;
|
|
|
|
// Global flags to control procmem output
|
|
|
|
// Set to use page idle bits for working set detection
|
|
bool use_pageidle = false;
|
|
// hides map entries with zero rss
|
|
bool hide_zeroes = false;
|
|
// Reset working set and exit
|
|
bool reset_wss = false;
|
|
// Show working set, mutually exclusive with reset_wss;
|
|
bool show_wss = false;
|
|
|
|
[[noreturn]] static void usage(int exit_status) {
|
|
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",
|
|
getprogname());
|
|
|
|
exit(exit_status);
|
|
}
|
|
|
|
static void print_separator(std::stringstream& ss) {
|
|
if (show_wss) {
|
|
ss << ::android::base::StringPrintf("%7s %7s %7s %7s %7s %7s %7s %s\n", "-------",
|
|
"-------", "-------", "-------", "-------", "-------",
|
|
"-------", "");
|
|
return;
|
|
}
|
|
ss << ::android::base::StringPrintf("%7s %7s %7s %7s %7s %7s %7s %7s %s\n", "-------",
|
|
"-------", "-------", "-------", "-------", "-------",
|
|
"-------", "-------", "");
|
|
}
|
|
|
|
static void print_header(std::stringstream& ss) {
|
|
if (show_wss) {
|
|
ss << ::android::base::StringPrintf("%7s %7s %7s %7s %7s %7s %7s %s\n", "WRss",
|
|
"WPss", "WUss", "WShCl", "WShDi", "WPrCl", "WPrDi",
|
|
"Name");
|
|
} else {
|
|
ss << ::android::base::StringPrintf("%7s %7s %7s %7s %7s %7s %7s %7s %s\n", "Vss",
|
|
"Rss", "Pss", "Uss", "ShCl", "ShDi", "PrCl", "PrDi",
|
|
"Name");
|
|
}
|
|
print_separator(ss);
|
|
}
|
|
|
|
static void print_stats(std::stringstream& ss, const MemUsage& stats) {
|
|
if (!show_wss) {
|
|
ss << ::android::base::StringPrintf("%6" PRIu64 "K ", stats.vss / 1024);
|
|
}
|
|
|
|
ss << ::android::base::StringPrintf("%6" PRIu64 "K %6" PRIu64 "K %6" PRIu64 "K %6" PRIu64
|
|
"K %6" PRIu64 "K %6" PRIu64 "K %6" PRIu64 "K ",
|
|
stats.rss / 1024, stats.pss / 1024, stats.uss / 1024,
|
|
stats.shared_clean / 1024, stats.shared_dirty / 1024,
|
|
stats.private_clean / 1024, stats.private_dirty / 1024);
|
|
}
|
|
|
|
static int show(const MemUsage& proc_stats, const std::vector<Vma>& maps) {
|
|
std::stringstream ss;
|
|
print_header(ss);
|
|
for (auto& vma : maps) {
|
|
const MemUsage& vma_stats = vma.usage;
|
|
if (hide_zeroes && vma_stats.rss == 0) {
|
|
continue;
|
|
}
|
|
print_stats(ss, vma_stats);
|
|
ss << vma.name << std::endl;
|
|
}
|
|
print_separator(ss);
|
|
print_stats(ss, proc_stats);
|
|
ss << "TOTAL" << std::endl;
|
|
std::cout << ss.str();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char* argv[]) {
|
|
int opt;
|
|
auto pss_sort = [](const Vma& a, const Vma& b) {
|
|
uint64_t pss_a = a.usage.pss;
|
|
uint64_t pss_b = b.usage.pss;
|
|
return pss_a > pss_b;
|
|
};
|
|
|
|
auto uss_sort = [](const Vma& a, const Vma& b) {
|
|
uint64_t uss_a = a.usage.uss;
|
|
uint64_t uss_b = b.usage.uss;
|
|
return uss_a > uss_b;
|
|
};
|
|
|
|
std::function<bool(const Vma& a, const Vma& b)> sort_func = nullptr;
|
|
while ((opt = getopt(argc, argv, "himpuWw")) != -1) {
|
|
switch (opt) {
|
|
case 'h':
|
|
hide_zeroes = true;
|
|
break;
|
|
case 'i':
|
|
// TODO: libmeminfo doesn't support the flag to chose
|
|
// between idle page tracking vs clear_refs. So for now,
|
|
// this flag is unused and the library defaults to using
|
|
// /proc/<pid>/clear_refs for finding the working set.
|
|
use_pageidle = true;
|
|
break;
|
|
case 'm':
|
|
// this is the default
|
|
break;
|
|
case 'p':
|
|
sort_func = pss_sort;
|
|
break;
|
|
case 'u':
|
|
sort_func = uss_sort;
|
|
break;
|
|
case 'W':
|
|
reset_wss = true;
|
|
break;
|
|
case 'w':
|
|
show_wss = true;
|
|
break;
|
|
case '?':
|
|
usage(EXIT_SUCCESS);
|
|
default:
|
|
usage(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
if (optind != (argc - 1)) {
|
|
fprintf(stderr, "Need exactly one pid at the end\n");
|
|
usage(EXIT_FAILURE);
|
|
}
|
|
|
|
pid_t pid = atoi(argv[optind]);
|
|
if (pid == 0) {
|
|
std::cerr << "Invalid process id" << std::endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (reset_wss) {
|
|
if (!ProcMemInfo::ResetWorkingSet(pid)) {
|
|
std::cerr << "Failed to reset working set of pid : " << pid << std::endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ProcMemInfo proc(pid, show_wss);
|
|
const MemUsage& proc_stats = proc.Usage();
|
|
std::vector<Vma> maps(proc.Maps());
|
|
if (sort_func != nullptr) {
|
|
std::sort(maps.begin(), maps.end(), sort_func);
|
|
}
|
|
|
|
return show(proc_stats, maps);
|
|
}
|