android_system_core/libmeminfo/include/meminfo/procmeminfo.h
Christopher Ferris 504d2cce64 Optimize code that only uses PageMap call.
Some code only wants to use PageMap to determine whether pages are
mapped in to memory. Modify the code to optimize this path.

Changes:
- Add a function that doesn't read all of usage stats data for every
  map. This operation is extremely expensive, and some code doesn't
  care about it.
- Optimize the PageMap call to do a single read instead of a single
  read per page.
- Add unit tests for these changes.

Bug: 136245508

Test: Ran new unit tests.
Test: Ran procrank and verified data looks good.
Test: Ran DexDiag art tests.
Change-Id: I37d03f2584551d26cb20be3abacdb958111d4eca
2019-07-12 16:28:09 -07:00

129 lines
4.9 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.
*/
#pragma once
#include <sys/types.h>
#include <string>
#include <vector>
#include "meminfo.h"
namespace android {
namespace meminfo {
using VmaCallback = std::function<void(const Vma&)>;
class ProcMemInfo final {
// Per-process memory accounting
public:
// Reset the working set accounting of the process via /proc/<pid>/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<Vma>& 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<Vma>& MapsWithPageIdle();
// Same as Maps() except, do not read the usage stats for each map.
const std::vector<Vma>& MapsWithoutUsageStats();
// Collect all 'vma' or 'maps' from /proc/<pid>/smaps and store them in 'maps_'. 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<Vma>& Smaps(const std::string& path = "");
// This method reads /proc/<pid>/smaps and calls the callback() for each
// vma or map that it finds. The map 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);
// Used to parse either of /proc/<pid>/{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/<pid>/{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;
const std::vector<uint16_t>& SwapOffsets();
// Reads /proc/<pid>/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<uint64_t>* pagemap);
~ProcMemInfo() = default;
private:
bool ReadMaps(bool get_wss, bool use_pageidle = false, bool get_usage_stats = true);
bool ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_pageidle);
pid_t pid_;
bool get_wss_;
uint64_t pgflags_;
uint64_t pgflags_mask_;
std::vector<Vma> maps_;
MemUsage usage_;
std::vector<uint16_t> swap_offsets_;
};
// Makes callback for each 'vma' or 'map' found in file provided. The file is expected to be in the
// same format as /proc/<pid>/smaps. Returns 'false' if the file is malformed.
bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback);
// Returns if the kernel supports /proc/<pid>/smaps_rollup. Assumes that the
// calling process has access to the /proc/<pid>/smaps_rollup.
// Returns 'false' if the calling process has no permission to read the file if it exists
// of if the file doesn't exist.
bool IsSmapsRollupSupported(pid_t pid);
// Same as ProcMemInfo::SmapsOrRollup but reads the statistics directly
// from a file. The file MUST be in the same format as /proc/<pid>/smaps
// or /proc/<pid>/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/<pid>/smaps or /proc/<pid>/smaps_rollup
bool SmapsOrRollupPssFromFile(const std::string& path, uint64_t* pss);
} // namespace meminfo
} // namespace android