/* * 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. */ #pragma once #include #include #include #include #include #include "meminfo.h" namespace android { namespace meminfo { using VmaCallback = std::function; class ProcMemInfo final { // Per-process memory accounting public: // Reset the working set accounting of the process via /proc//clear_refs static bool ResetWorkingSet(pid_t pid); ProcMemInfo(pid_t pid, bool get_wss = false, uint64_t pgflags = 0, uint64_t pgflags_mask = 0); const std::vector& Maps(); const MemUsage& Usage(); const MemUsage& Wss(); // Same as Maps() except, only valid for reading working set using CONFIG_IDLE_PAGE_TRACKING // support in kernel. If the kernel support doesn't exist, the function will return an empty // vector. const std::vector& MapsWithPageIdle(); // Same as Maps() except, do not read the usage stats for each map. const std::vector& MapsWithoutUsageStats(); // If MapsWithoutUsageStats was called, this function will fill in // usage stats for this single vma. If 'use_kb' is true, the vma's // usage will be populated in kilobytes instead of bytes. bool FillInVmaStats(Vma& vma, bool use_kb = false); // If ReadMaps (with get_usage_stats == false) or MapsWithoutUsageStats was // called, this function will fill in usage stats for all vmas in 'maps_'. bool GetUsageStats(bool get_wss, bool use_pageidle = false, bool update_mem_usage = true); // Collect all 'vma' or 'maps' from /proc//smaps and store them in 'maps_'. // If 'collect_usage' is 'true', this method will populate 'usage_' as vmas are being // collected. If 'collect_swap_offsets' is 'true', pagemap will be read in order to // populate 'swap_offsets_'. // // Returns a constant reference to the vma vector after the collection is // done. // // Each 'struct Vma' is *fully* populated by this method (unlike SmapsOrRollup). const std::vector& Smaps(const std::string& path = "", bool collect_usage = false, bool collect_swap_offsets = false); // If 'use_smaps' is 'true' this method reads /proc//smaps and calls the callback() // for each vma or map that it finds, else if 'use_smaps' is false /proc//maps is // used instead. Each vma or map found, is converted to 'struct Vma' object which is then // passed to the callback. // Returns 'false' if the file is malformed. bool ForEachVma(const VmaCallback& callback, bool use_smaps = true); // Reads all VMAs from /proc//maps and calls the callback() for each one of them. // Returns false in case of failure during parsing. bool ForEachVmaFromMaps(const VmaCallback& callback); // Similar to other VMA reading methods, except this one allows passing a reusable buffer // to store the /proc//maps content bool ForEachVmaFromMaps(const VmaCallback& callback, std::string& mapsBuffer); // Takes the existing VMAs in 'maps_' and calls the callback() for each one // of them. This is intended to avoid parsing /proc//maps or // /proc//smaps twice. // Returns false if 'maps_' is empty. bool ForEachExistingVma(const VmaCallback& callback); // Used to parse either of /proc//{smaps, smaps_rollup} and record the process's // Pss and Private memory usage in 'stats'. In particular, the method only populates the fields // of the MemUsage structure that are intended to be used by Android's periodic Pss collection. // // The method populates the following statistics in order to be fast an efficient. // Pss // Rss // Uss // private_clean // private_dirty // SwapPss // All other fields of MemUsage are zeroed. bool SmapsOrRollup(MemUsage* stats) const; // Used to parse either of /proc//{smaps, smaps_rollup} and record the process's // Pss. // Returns 'true' on success and the value of Pss in the out parameter. bool SmapsOrRollupPss(uint64_t* pss) const; // Used to parse /proc//status and record the process's RSS memory as // reported by VmRSS. This is cheaper than using smaps or maps. VmRSS as // reported by the kernel is not accurate; one of the maps or smaps methods // should be used if an estimate is not sufficient. // // Returns 'true' on success and the value of VmRSS in the out parameter. bool StatusVmRSS(uint64_t* rss) const; const std::vector& SwapOffsets(); // Reads /proc//pagemap for this process for each page within // the 'vma' and stores that in 'pagemap'. It is assumed that the 'vma' // is obtained by calling Maps() or 'ForEachVma' for the same object. No special checks // are made to see if 'vma' is *valid*. // Returns false if anything goes wrong, 'true' otherwise. bool PageMap(const Vma& vma, std::vector* pagemap); ~ProcMemInfo() = default; private: bool ReadMaps(bool get_wss, bool use_pageidle = false, bool get_usage_stats = true, bool update_mem_usage = true); bool ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_pageidle, bool update_mem_usage, bool update_swap_usage); pid_t pid_; bool get_wss_; uint64_t pgflags_; uint64_t pgflags_mask_; std::vector maps_; MemUsage usage_; std::vector swap_offsets_; }; // Makes callback for each 'vma' or 'map' found in file provided. // If 'read_smaps_fields' is 'true', the file is expected to be in the // same format as /proc//smaps, else the file is expected to be // formatted as /proc//maps. // Returns 'false' if the file is malformed. bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback, bool read_smaps_fields = true); // Returns if the kernel supports /proc//smaps_rollup. Assumes that the // calling process has access to the /proc//smaps_rollup. // Returns 'false' if the file doesn't exist. bool IsSmapsRollupSupported(); // Same as ProcMemInfo::SmapsOrRollup but reads the statistics directly // from a file. The file MUST be in the same format as /proc//smaps // or /proc//smaps_rollup bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats); // Same as ProcMemInfo::SmapsOrRollupPss but reads the statistics directly // from a file and returns total Pss in kB. The file MUST be in the same format // as /proc//smaps or /proc//smaps_rollup bool SmapsOrRollupPssFromFile(const std::string& path, uint64_t* pss); // Same as ProcMemInfo::StatusVmRSS but reads the statistics directly from a file. // The file MUST be in the same format as /proc//status. bool StatusVmRSSFromFile(const std::string& path, uint64_t* rss); // The output format that can be specified by user. enum class Format { INVALID = 0, RAW, JSON, CSV }; Format GetFormat(std::string_view arg); std::string EscapeCsvString(const std::string& raw); std::string EscapeJsonString(const std::string& raw); } // namespace meminfo } // namespace android