diff --git a/libmeminfo/include/meminfo/meminfo.h b/libmeminfo/include/meminfo/meminfo.h index c328648f3..809054bd8 100644 --- a/libmeminfo/include/meminfo/meminfo.h +++ b/libmeminfo/include/meminfo/meminfo.h @@ -31,6 +31,8 @@ struct MemUsage { uint64_t pss; uint64_t uss; + uint64_t swap; + uint64_t private_clean; uint64_t private_dirty; uint64_t shared_clean; @@ -41,6 +43,7 @@ struct MemUsage { rss(0), pss(0), uss(0), + swap(0), private_clean(0), private_dirty(0), shared_clean(0), @@ -49,7 +52,7 @@ struct MemUsage { ~MemUsage() = default; void clear() { - vss = rss = pss = uss = 0; + vss = rss = pss = uss = swap = 0; private_clean = private_dirty = shared_clean = shared_dirty = 0; } }; diff --git a/libmeminfo/include/meminfo/procmeminfo.h b/libmeminfo/include/meminfo/procmeminfo.h index b37c56bcc..dd599128d 100644 --- a/libmeminfo/include/meminfo/procmeminfo.h +++ b/libmeminfo/include/meminfo/procmeminfo.h @@ -34,6 +34,7 @@ class ProcMemInfo final { const std::vector& Maps(); const MemUsage& Usage(); const MemUsage& Wss(); + const std::vector& SwapOffsets() const; bool WssReset(); ~ProcMemInfo() = default; @@ -49,6 +50,7 @@ class ProcMemInfo final { MemUsage usage_; MemUsage wss_; + std::vector swap_offsets_; }; } // namespace meminfo diff --git a/libmeminfo/include/meminfo/sysmeminfo.h b/libmeminfo/include/meminfo/sysmeminfo.h index f5e05bd0e..87e14642b 100644 --- a/libmeminfo/include/meminfo/sysmeminfo.h +++ b/libmeminfo/include/meminfo/sysmeminfo.h @@ -28,6 +28,22 @@ namespace meminfo { class SysMemInfo final { // System or Global memory accounting public: + static constexpr const char* kMemTotal = "MemTotal:"; + static constexpr const char* kMemFree = "MemFree:"; + static constexpr const char* kMemBuffers = "Buffers:"; + static constexpr const char* kMemCached = "Cached:"; + static constexpr const char* kMemShmem = "Shmem:"; + static constexpr const char* kMemSlab = "Slab:"; + static constexpr const char* kMemSReclaim = "SReclaimable:"; + static constexpr const char* kMemSUnreclaim = "SUnreclaim:"; + static constexpr const char* kMemSwapTotal = "SwapTotal:"; + static constexpr const char* kMemSwapFree = "SwapFree:"; + static constexpr const char* kMemZram = "Zram:"; + static constexpr const char* kMemMapped = "Mapped:"; + static constexpr const char* kMemVmallocUsed = "VmallocUsed:"; + static constexpr const char* kMemPageTables = "PageTables:"; + static constexpr const char* kMemKernelStack = "KernelStack:"; + static const std::vector kDefaultSysMemInfoTags; SysMemInfo() = default; @@ -38,21 +54,21 @@ class SysMemInfo final { const std::string& path = "/proc/meminfo"); // getters - uint64_t mem_total_kb() { return mem_in_kb_["MemTotal:"]; } - uint64_t mem_free_kb() { return mem_in_kb_["MemFree:"]; } - uint64_t mem_buffers_kb() { return mem_in_kb_["Buffers:"]; } - uint64_t mem_cached_kb() { return mem_in_kb_["Cached:"]; } - uint64_t mem_shmem_kb() { return mem_in_kb_["Shmem:"]; } - uint64_t mem_slab_kb() { return mem_in_kb_["Slab:"]; } - uint64_t mem_slab_reclailmable_kb() { return mem_in_kb_["SReclaimable:"]; } - uint64_t mem_slab_unreclaimable_kb() { return mem_in_kb_["SUnreclaim:"]; } - uint64_t mem_swap_kb() { return mem_in_kb_["SwapTotal:"]; } - uint64_t mem_free_swap_kb() { return mem_in_kb_["SwapFree:"]; } - uint64_t mem_zram_kb() { return mem_in_kb_["Zram:"]; } - uint64_t mem_mapped_kb() { return mem_in_kb_["Mapped:"]; } - uint64_t mem_vmalloc_used_kb() { return mem_in_kb_["VmallocUsed:"]; } - uint64_t mem_page_tables_kb() { return mem_in_kb_["PageTables:"]; } - uint64_t mem_kernel_stack_kb() { return mem_in_kb_["KernelStack:"]; } + uint64_t mem_total_kb() { return mem_in_kb_[kMemTotal]; } + uint64_t mem_free_kb() { return mem_in_kb_[kMemFree]; } + uint64_t mem_buffers_kb() { return mem_in_kb_[kMemBuffers]; } + uint64_t mem_cached_kb() { return mem_in_kb_[kMemCached]; } + uint64_t mem_shmem_kb() { return mem_in_kb_[kMemShmem]; } + uint64_t mem_slab_kb() { return mem_in_kb_[kMemSlab]; } + uint64_t mem_slab_reclailmable_kb() { return mem_in_kb_[kMemSReclaim]; } + uint64_t mem_slab_unreclaimable_kb() { return mem_in_kb_[kMemSUnreclaim]; } + uint64_t mem_swap_kb() { return mem_in_kb_[kMemSwapTotal]; } + uint64_t mem_swap_free_kb() { return mem_in_kb_[kMemSwapFree]; } + uint64_t mem_zram_kb() { return mem_in_kb_[kMemZram]; } + uint64_t mem_mapped_kb() { return mem_in_kb_[kMemMapped]; } + uint64_t mem_vmalloc_used_kb() { return mem_in_kb_[kMemVmallocUsed]; } + uint64_t mem_page_tables_kb() { return mem_in_kb_[kMemPageTables]; } + uint64_t mem_kernel_stack_kb() { return mem_in_kb_[kMemPageTables]; } private: std::map mem_in_kb_; diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp index 7a2be4172..f973694e2 100644 --- a/libmeminfo/libmeminfo_test.cpp +++ b/libmeminfo/libmeminfo_test.cpp @@ -73,7 +73,7 @@ TEST_F(ValidateProcMemInfo, TestMapsEquality) { } } -TEST_F(ValidateProcMemInfo, TestMapsUsage) { +TEST_F(ValidateProcMemInfo, TestMaps) { const std::vector& maps = proc_mem->Maps(); ASSERT_FALSE(maps.empty()); ASSERT_EQ(proc->num_maps, maps.size()); @@ -96,6 +96,30 @@ TEST_F(ValidateProcMemInfo, TestMapsUsage) { EXPECT_EQ(proc_usage.uss, proc_mem->Usage().uss); } +TEST_F(ValidateProcMemInfo, TestSwapUsage) { + const std::vector& maps = proc_mem->Maps(); + ASSERT_FALSE(maps.empty()); + ASSERT_EQ(proc->num_maps, maps.size()); + + pm_memusage_t map_usage, proc_usage; + pm_memusage_zero(&map_usage); + pm_memusage_zero(&proc_usage); + for (size_t i = 0; i < maps.size(); i++) { + ASSERT_EQ(0, pm_map_usage(proc->maps[i], &map_usage)); + EXPECT_EQ(map_usage.swap, maps[i].usage.swap) << "SWAP mismatch for map: " << maps[i].name; + pm_memusage_add(&proc_usage, &map_usage); + } + + EXPECT_EQ(proc_usage.swap, proc_mem->Usage().swap); +} + +TEST_F(ValidateProcMemInfo, TestSwapOffsets) { + const MemUsage& proc_usage = proc_mem->Usage(); + const std::vector& swap_offsets = proc_mem->SwapOffsets(); + + EXPECT_EQ(proc_usage.swap / getpagesize(), swap_offsets.size()); +} + class ValidateProcMemInfoWss : public ::testing::Test { protected: void SetUp() override { diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp index fe91d250b..e3839346a 100644 --- a/libmeminfo/procmeminfo.cpp +++ b/libmeminfo/procmeminfo.cpp @@ -44,6 +44,8 @@ static void add_mem_usage(MemUsage* to, const MemUsage& from) { to->pss += from.pss; to->uss += from.uss; + to->swap += from.swap; + to->private_clean += from.private_clean; to->private_dirty += from.private_dirty; @@ -76,6 +78,10 @@ const MemUsage& ProcMemInfo::Wss() { return wss_; } +const std::vector& ProcMemInfo::SwapOffsets() const { + return swap_offsets_; +} + bool ProcMemInfo::WssReset() { if (!get_wss_) { LOG(ERROR) << "Trying to reset working set from a memory usage counting object"; @@ -115,8 +121,8 @@ bool ProcMemInfo::ReadMaps(bool get_wss) { for (auto& vma : maps_) { if (!ReadVmaStats(pagemap_fd.get(), vma, get_wss)) { - LOG(ERROR) << "Failed to read page map for vma " << vma.name << "[" << vma.start - << "-" << vma.end << "]"; + LOG(ERROR) << "Failed to read page map for vma " << vma.name << "[" << vma.start << "-" + << vma.end << "]"; maps_.clear(); return false; } @@ -153,7 +159,8 @@ bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss) { if (!PAGE_PRESENT(p) && !PAGE_SWAPPED(p)) continue; if (PAGE_SWAPPED(p)) { - // TODO: do what's needed for swapped pages + vma.usage.swap += pagesz; + swap_offsets_.emplace_back(PAGE_SWAP_OFFSET(p)); continue; } diff --git a/libmeminfo/sysmeminfo.cpp b/libmeminfo/sysmeminfo.cpp index 50fa2136d..82605b681 100644 --- a/libmeminfo/sysmeminfo.cpp +++ b/libmeminfo/sysmeminfo.cpp @@ -37,9 +37,11 @@ namespace android { namespace meminfo { const std::vector SysMemInfo::kDefaultSysMemInfoTags = { - "MemTotal:", "MemFree:", "Buffers:", "Cached:", "Shmem:", - "Slab:", "SReclaimable:", "SUnreclaim:", "SwapTotal:", "SwapFree:", - "ZRam:", "Mapped:", "VmallocUsed:", "PageTables:", "KernelStack:", + SysMemInfo::kMemTotal, SysMemInfo::kMemFree, SysMemInfo::kMemBuffers, + SysMemInfo::kMemCached, SysMemInfo::kMemShmem, SysMemInfo::kMemSlab, + SysMemInfo::kMemSReclaim, SysMemInfo::kMemSUnreclaim, SysMemInfo::kMemSwapTotal, + SysMemInfo::kMemSwapFree, SysMemInfo::kMemZram, SysMemInfo::kMemMapped, + SysMemInfo::kMemVmallocUsed, SysMemInfo::kMemPageTables, SysMemInfo::kMemKernelStack, }; bool SysMemInfo::ReadMemInfo(const std::string& path) { @@ -99,6 +101,7 @@ bool SysMemInfo::ReadMemInfo(const std::vector& tags, const std::st buffer[len] = '\0'; char* p = buffer; uint32_t found = 0; + uint32_t lineno = 0; while (*p && found < tags.size()) { for (auto& tag : tags) { if (strncmp(p, tag.c_str(), tag.size()) == 0) { @@ -107,7 +110,7 @@ bool SysMemInfo::ReadMemInfo(const std::vector& tags, const std::st char* endptr = nullptr; mem_in_kb_[tag] = strtoull(p, &endptr, 10); if (p == endptr) { - PLOG(ERROR) << "Failed to parse line in file: " << path; + PLOG(ERROR) << "Failed to parse line:" << lineno + 1 << " in file: " << path; return false; } p = endptr; @@ -119,6 +122,7 @@ bool SysMemInfo::ReadMemInfo(const std::vector& tags, const std::st p++; } if (*p) p++; + lineno++; } return true;