blob: d30c2f2ba707e7d09f2763f4d91324b31a6b840c [file] [log] [blame]
Sandeep Patil54d87212018-08-29 17:10:47 -07001/*
2 * Copyright (C) 2018 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 <stdlib.h>
19#include <unistd.h>
20
21#include <iomanip>
22#include <iostream>
23#include <sstream>
24#include <string>
25#include <vector>
26
27#include <meminfo/procmeminfo.h>
28
29using ProcMemInfo = ::android::meminfo::ProcMemInfo;
30using MemUsage = ::android::meminfo::MemUsage;
31
32static void usage(const char* cmd) {
33 fprintf(stderr,
34 "Usage: %s [-i] [ -w | -W ] [ -p | -m ] [ -h ] pid\n"
35 " -i Uses idle page tracking for working set statistics.\n"
36 " -w Displays statistics for the working set only.\n"
37 " -W Resets the working set of the process.\n"
38 " -p Sort by PSS.\n"
39 " -u Sort by USS.\n"
40 " -m Sort by mapping order (as read from /proc).\n"
41 " -h Hide maps with no RSS.\n",
42 cmd);
43}
44
45static void show_footer(uint32_t nelem, const std::string& padding) {
46 std::string elem(7, '-');
47
48 for (uint32_t i = 0; i < nelem; ++i) {
49 std::cout << std::setw(7) << elem << padding;
50 }
51 std::cout << std::endl;
52}
53
54static void show_header(const std::vector<std::string>& header, const std::string& padding) {
55 if (header.empty()) return;
56
57 for (size_t i = 0; i < header.size() - 1; ++i) {
58 std::cout << std::setw(7) << header[i] << padding;
59 }
60 std::cout << header.back() << std::endl;
61 show_footer(header.size() - 1, padding);
62}
63
64static void scan_usage(std::stringstream& ss, const MemUsage& usage, const std::string& padding,
65 bool show_wss) {
66 // clear string stream first.
67 ss.str("");
68 // TODO: use ::android::base::StringPrintf instead of <iomanip> here.
Sandeep Patilf1291992018-11-19 15:25:18 -080069 if (!show_wss) ss << std::setw(6) << usage.vss / 1024 << padding;
70 ss << std::setw(6) << usage.rss / 1024 << padding << std::setw(6) << usage.pss / 1024 << padding
71 << std::setw(6) << usage.uss / 1024 << padding << std::setw(6) << usage.shared_clean / 1024
72 << padding << std::setw(6) << usage.shared_dirty / 1024 << padding << std::setw(6)
73 << usage.private_clean / 1024 << padding << std::setw(6) << usage.private_dirty / 1024
74 << padding;
Sandeep Patil54d87212018-08-29 17:10:47 -070075}
76
77static int show(ProcMemInfo& proc, bool hide_zeroes, bool show_wss) {
78 const std::vector<std::string> main_header = {"Vss", "Rss", "Pss", "Uss", "ShCl",
79 "ShDi", "PrCl", "PrDi", "Name"};
80 const std::vector<std::string> wss_header = {"WRss", "WPss", "WUss", "WShCl",
81 "WShDi", "WPrCl", "WPrDi", "Name"};
82 const std::vector<std::string>& header = show_wss ? wss_header : main_header;
83
84 // Read process memory stats
85 const MemUsage& stats = show_wss ? proc.Wss() : proc.Usage();
86 const std::vector<::android::meminfo::Vma>& maps = proc.Maps();
87
88 // following retains 'procmem' output so as to not break any scripts
89 // that rely on it.
90 std::string spaces = " ";
91 show_header(header, spaces);
92 const std::string padding = "K ";
93 std::stringstream ss;
94 for (auto& vma : maps) {
95 const MemUsage& vma_stats = show_wss ? vma.wss : vma.usage;
96 if (hide_zeroes && vma_stats.rss == 0) {
97 continue;
98 }
99 scan_usage(ss, vma_stats, padding, show_wss);
100 ss << vma.name << std::endl;
101 std::cout << ss.str();
102 }
103 show_footer(header.size() - 1, spaces);
104 scan_usage(ss, stats, padding, show_wss);
105 ss << "TOTAL" << std::endl;
106 std::cout << ss.str();
107
108 return 0;
109}
110
111int main(int argc, char* argv[]) {
112 bool use_pageidle = false;
113 bool hide_zeroes = false;
114 bool wss_reset = false;
115 bool show_wss = false;
116 int opt;
117
118 while ((opt = getopt(argc, argv, "himpuWw")) != -1) {
119 switch (opt) {
120 case 'h':
121 hide_zeroes = true;
122 break;
123 case 'i':
124 use_pageidle = true;
125 break;
126 case 'm':
127 break;
128 case 'p':
129 break;
130 case 'u':
131 break;
132 case 'W':
133 wss_reset = true;
134 break;
135 case 'w':
136 show_wss = true;
137 break;
138 case '?':
139 usage(argv[0]);
140 return 0;
141 default:
142 abort();
143 }
144 }
145
146 if (optind != (argc - 1)) {
147 fprintf(stderr, "Need exactly one pid at the end\n");
148 usage(argv[0]);
149 exit(EXIT_FAILURE);
150 }
151
152 pid_t pid = atoi(argv[optind]);
153 if (pid == 0) {
154 std::cerr << "Invalid process id" << std::endl;
155 exit(EXIT_FAILURE);
156 }
157
158 bool need_wss = wss_reset || show_wss;
Sandeep Patil54d87212018-08-29 17:10:47 -0700159 if (wss_reset) {
Sandeep Patilf1291992018-11-19 15:25:18 -0800160 if (!ProcMemInfo::ResetWorkingSet(pid)) {
Sandeep Patil54d87212018-08-29 17:10:47 -0700161 std::cerr << "Failed to reset working set of pid : " << pid << std::endl;
162 exit(EXIT_FAILURE);
163 }
164 return 0;
165 }
166
Sandeep Patilf1291992018-11-19 15:25:18 -0800167 ProcMemInfo proc(pid, need_wss);
Sandeep Patil54d87212018-08-29 17:10:47 -0700168 return show(proc, hide_zeroes, show_wss);
169}