1 /* 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 #pragma once 18 19 #include <sys/types.h> 20 21 #include <functional> 22 #include <string> 23 #include <string_view> 24 #include <vector> 25 26 #include "meminfo.h" 27 28 namespace android { 29 namespace meminfo { 30 31 using VmaCallback = std::function<bool(Vma&)>; 32 33 class ProcMemInfo final { 34 // Per-process memory accounting 35 public: 36 // Reset the working set accounting of the process via /proc/<pid>/clear_refs 37 static bool ResetWorkingSet(pid_t pid); 38 39 ProcMemInfo(pid_t pid, bool get_wss = false, uint64_t pgflags = 0, uint64_t pgflags_mask = 0); 40 41 const std::vector<Vma>& Maps(); 42 const MemUsage& Usage(); 43 const MemUsage& Wss(); 44 45 // Same as Maps() except, only valid for reading working set using CONFIG_IDLE_PAGE_TRACKING 46 // support in kernel. If the kernel support doesn't exist, the function will return an empty 47 // vector. 48 const std::vector<Vma>& MapsWithPageIdle(); 49 50 // Same as Maps() except, do not read the usage stats for each map. 51 const std::vector<Vma>& MapsWithoutUsageStats(); 52 53 // If MapsWithoutUsageStats was called, this function will fill in 54 // usage stats for this single vma. If 'use_kb' is true, the vma's 55 // usage will be populated in kilobytes instead of bytes. 56 bool FillInVmaStats(Vma& vma, bool use_kb = false); 57 58 // If ReadMaps (with get_usage_stats == false) or MapsWithoutUsageStats was 59 // called, this function will fill in usage stats for all vmas in 'maps_'. 60 bool GetUsageStats(bool get_wss, bool use_pageidle = false, bool update_mem_usage = true); 61 62 // Collect all 'vma' or 'maps' from /proc/<pid>/smaps and store them in 'maps_'. 63 // If 'collect_usage' is 'true', this method will populate 'usage_' as vmas are being 64 // collected. If 'collect_swap_offsets' is 'true', pagemap will be read in order to 65 // populate 'swap_offsets_'. 66 // 67 // Returns a constant reference to the vma vector after the collection is 68 // done. 69 // 70 // Each 'struct Vma' is *fully* populated by this method (unlike SmapsOrRollup). 71 const std::vector<Vma>& Smaps(const std::string& path = "", bool collect_usage = false, 72 bool collect_swap_offsets = false); 73 74 // If 'use_smaps' is 'true' this method reads /proc/<pid>/smaps and calls the callback() 75 // for each vma or map that it finds, else if 'use_smaps' is false /proc/<pid>/maps is 76 // used instead. Each vma or map found, is converted to 'struct Vma' object which is then 77 // passed to the callback. 78 // Returns 'false' if the file is malformed. 79 bool ForEachVma(const VmaCallback& callback, bool use_smaps = true); 80 81 // Reads all VMAs from /proc/<pid>/maps and calls the callback() for each one of them. 82 // Returns false in case of failure during parsing. 83 bool ForEachVmaFromMaps(const VmaCallback& callback); 84 85 // Similar to other VMA reading methods, except this one allows passing a reusable buffer 86 // to store the /proc/<pid>/maps content 87 bool ForEachVmaFromMaps(const VmaCallback& callback, std::string& mapsBuffer); 88 89 // Takes the existing VMAs in 'maps_' and calls the callback() for each one 90 // of them. This is intended to avoid parsing /proc/<pid>/maps or 91 // /proc/<pid>/smaps twice. 92 // Returns false if 'maps_' is empty. 93 bool ForEachExistingVma(const VmaCallback& callback); 94 95 // Used to parse either of /proc/<pid>/{smaps, smaps_rollup} and record the process's 96 // Pss and Private memory usage in 'stats'. In particular, the method only populates the fields 97 // of the MemUsage structure that are intended to be used by Android's periodic Pss collection. 98 // 99 // The method populates the following statistics in order to be fast an efficient. 100 // Pss 101 // Rss 102 // Uss 103 // private_clean 104 // private_dirty 105 // SwapPss 106 // All other fields of MemUsage are zeroed. 107 bool SmapsOrRollup(MemUsage* stats) const; 108 109 // Used to parse either of /proc/<pid>/{smaps, smaps_rollup} and record the process's 110 // Pss. 111 // Returns 'true' on success and the value of Pss in the out parameter. 112 bool SmapsOrRollupPss(uint64_t* pss) const; 113 114 // Used to parse /proc/<pid>/status and record the process's RSS memory as 115 // reported by VmRSS. This is cheaper than using smaps or maps. VmRSS as 116 // reported by the kernel is not accurate; one of the maps or smaps methods 117 // should be used if an estimate is not sufficient. 118 // 119 // Returns 'true' on success and the value of VmRSS in the out parameter. 120 bool StatusVmRSS(uint64_t* rss) const; 121 122 const std::vector<uint64_t>& SwapOffsets(); 123 124 // Reads /proc/<pid>/pagemap for this process for each page within 125 // the 'vma' and stores that in 'pagemap'. It is assumed that the 'vma' 126 // is obtained by calling Maps() or 'ForEachVma' for the same object. No special checks 127 // are made to see if 'vma' is *valid*. 128 // Returns false if anything goes wrong, 'true' otherwise. 129 bool PageMap(const Vma& vma, std::vector<uint64_t>* pagemap); 130 131 ~ProcMemInfo() = default; 132 133 private: 134 bool ReadMaps(bool get_wss, bool use_pageidle = false, bool get_usage_stats = true, 135 bool update_mem_usage = true); 136 bool ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_pageidle, 137 bool update_mem_usage, bool update_swap_usage); 138 139 pid_t pid_; 140 bool get_wss_; 141 uint64_t pgflags_; 142 uint64_t pgflags_mask_; 143 144 std::vector<Vma> maps_; 145 146 MemUsage usage_; 147 std::vector<uint64_t> swap_offsets_; 148 }; 149 150 // Makes callback for each 'vma' or 'map' found in file provided. 151 // If 'read_smaps_fields' is 'true', the file is expected to be in the 152 // same format as /proc/<pid>/smaps, else the file is expected to be 153 // formatted as /proc/<pid>/maps. 154 // Returns 'false' if the file is malformed. 155 bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback, 156 bool read_smaps_fields = true); 157 158 // Returns if the kernel supports /proc/<pid>/smaps_rollup. Assumes that the 159 // calling process has access to the /proc/<pid>/smaps_rollup. 160 // Returns 'false' if the file doesn't exist. 161 bool IsSmapsRollupSupported(); 162 163 // Same as ProcMemInfo::SmapsOrRollup but reads the statistics directly 164 // from a file. The file MUST be in the same format as /proc/<pid>/smaps 165 // or /proc/<pid>/smaps_rollup 166 bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats); 167 168 // Same as ProcMemInfo::SmapsOrRollupPss but reads the statistics directly 169 // from a file and returns total Pss in kB. The file MUST be in the same format 170 // as /proc/<pid>/smaps or /proc/<pid>/smaps_rollup 171 bool SmapsOrRollupPssFromFile(const std::string& path, uint64_t* pss); 172 173 // Same as ProcMemInfo::StatusVmRSS but reads the statistics directly from a file. 174 // The file MUST be in the same format as /proc/<pid>/status. 175 bool StatusVmRSSFromFile(const std::string& path, uint64_t* rss); 176 177 // The output format that can be specified by user. 178 enum class Format { INVALID = 0, RAW, JSON, CSV }; 179 180 Format GetFormat(std::string_view arg); 181 182 std::string EscapeCsvString(const std::string& raw); 183 184 std::string EscapeJsonString(const std::string& raw); 185 186 } // namespace meminfo 187 } // namespace android 188