Merge "init: clean up host_init_stubs a bit"
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 64df53e..1f0e420 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -243,9 +243,10 @@
void CrasherTest::AssertDeath(int signo) {
int status;
- pid_t pid = TIMEOUT(5, waitpid(crasher_pid, &status, 0));
+ pid_t pid = TIMEOUT(10, waitpid(crasher_pid, &status, 0));
if (pid != crasher_pid) {
- printf("failed to wait for crasher (pid %d)\n", crasher_pid);
+ printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
+ strerror(errno));
sleep(100);
FAIL() << "failed to wait for crasher: " << strerror(errno);
}
diff --git a/libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp b/libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp
index 0851fb3..9a80c82 100644
--- a/libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp
+++ b/libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp
@@ -17,16 +17,17 @@
#include <dirent.h>
#include <errno.h>
#include <inttypes.h>
+#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
-#include <iostream>
#include <fstream>
+#include <iostream>
+#include <map>
+#include <set>
#include <sstream>
#include <string>
#include <vector>
-#include <map>
-#include <set>
#include <android-base/stringprintf.h>
#include <dmabufinfo/dmabufinfo.h>
@@ -43,7 +44,7 @@
exit(exit_status);
}
-static std::string GetProcessBaseName(pid_t pid) {
+static std::string GetProcessComm(const pid_t pid) {
std::string pid_path = android::base::StringPrintf("/proc/%d/comm", pid);
std::ifstream in{pid_path};
if (!in) return std::string("N/A");
@@ -53,85 +54,76 @@
return line;
}
-static void AddPidsToSet(const std::unordered_map<pid_t, int>& map, std::set<pid_t>* set)
-{
- for (auto it = map.begin(); it != map.end(); ++it)
- set->insert(it->first);
+static void AddPidsToSet(const std::unordered_map<pid_t, int>& map, std::set<pid_t>* set) {
+ for (auto it = map.begin(); it != map.end(); ++it) set->insert(it->first);
}
static void PrintDmaBufInfo(const std::vector<DmaBuffer>& bufs) {
- std::set<pid_t> pid_set;
- std::map<pid_t, int> pid_column;
-
if (bufs.empty()) {
- std::cout << "dmabuf info not found ¯\\_(ツ)_/¯" << std::endl;
+ printf("dmabuf info not found ¯\\_(ツ)_/¯\n");
return;
}
// Find all unique pids in the input vector, create a set
+ std::set<pid_t> pid_set;
for (int i = 0; i < bufs.size(); i++) {
AddPidsToSet(bufs[i].fdrefs(), &pid_set);
AddPidsToSet(bufs[i].maprefs(), &pid_set);
}
- int pid_count = 0;
-
- std::cout << "\t\t\t\t\t\t";
-
- // Create a map to convert each unique pid into a column number
- for (auto it = pid_set.begin(); it != pid_set.end(); ++it, ++pid_count) {
- pid_column.insert(std::make_pair(*it, pid_count));
- std::cout << ::android::base::StringPrintf("[pid: % 4d]\t", *it);
+ // Format the header string spaced and separated with '|'
+ printf(" Dmabuf Inode | Size | Ref Counts |");
+ for (auto pid : pid_set) {
+ printf("%16s:%-5d |", GetProcessComm(pid).c_str(), pid);
}
+ printf("\n");
- std::cout << std::endl << "\t\t\t\t\t\t";
+ // holds per-process dmabuf size in kB
+ std::map<pid_t, uint64_t> per_pid_size = {};
+ uint64_t dmabuf_total_size = 0;
- for (auto it = pid_set.begin(); it != pid_set.end(); ++it) {
- std::cout << ::android::base::StringPrintf("%16s",
- GetProcessBaseName(*it).c_str());
- }
+ // Iterate through all dmabufs and collect per-process sizes, refs
+ for (auto& buf : bufs) {
+ printf("%16ju |%13" PRIu64 " kB |%16" PRIu64 " |", static_cast<uintmax_t>(buf.inode()),
+ buf.size() / 1024, buf.total_refs());
+ // Iterate through each process to find out per-process references for each buffer,
+ // gather total size used by each process etc.
+ for (pid_t pid : pid_set) {
+ int pid_refs = 0;
+ if (buf.fdrefs().count(pid) == 1) {
+ // Get the total number of ref counts the process is holding
+ // on this buffer. We don't differentiate between mmap or fd.
+ pid_refs += buf.fdrefs().at(pid);
+ if (buf.maprefs().count(pid) == 1) {
+ pid_refs += buf.maprefs().at(pid);
+ }
+ }
- std::cout << std::endl << "\tinode\t\tsize\t\tcount\t";
- for (int i = 0; i < pid_count; i++) {
- std::cout << "fd\tmap\t";
- }
- std::cout << std::endl;
-
- auto fds = std::make_unique<int[]>(pid_count);
- auto maps = std::make_unique<int[]>(pid_count);
- auto pss = std::make_unique<long[]>(pid_count);
-
- memset(pss.get(), 0, sizeof(long) * pid_count);
-
- for (auto buf = bufs.begin(); buf != bufs.end(); ++buf) {
-
- std::cout << ::android::base::StringPrintf("%16lu\t%10" PRIu64 "\t%" PRIu64 "\t",
- buf->inode(),buf->size(), buf->count());
-
- memset(fds.get(), 0, sizeof(int) * pid_count);
- memset(maps.get(), 0, sizeof(int) * pid_count);
-
- for (auto it = buf->fdrefs().begin(); it != buf->fdrefs().end(); ++it) {
- fds[pid_column[it->first]] = it->second;
- pss[pid_column[it->first]] += buf->size() * it->second / buf->count();
+ if (pid_refs) {
+ // Add up the per-pid total size. Note that if a buffer is mapped
+ // in 2 different processes, the size will be shown as mapped or opened
+ // in both processes. This is intended for visibility.
+ //
+ // If one wants to get the total *unique* dma buffers, they can simply
+ // sum the size of all dma bufs shown by the tool
+ per_pid_size[pid] += buf.size() / 1024;
+ printf("%17d refs |", pid_refs);
+ } else {
+ printf("%22s |", "--");
+ }
}
-
- for (auto it = buf->maprefs().begin(); it != buf->maprefs().end(); ++it) {
- maps[pid_column[it->first]] = it->second;
- pss[pid_column[it->first]] += buf->size() * it->second / buf->count();
- }
-
- for (int i = 0; i < pid_count; i++) {
- std::cout << ::android::base::StringPrintf("%d\t%d\t", fds[i], maps[i]);
- }
- std::cout << std::endl;
+ dmabuf_total_size += buf.size() / 1024;
+ printf("\n");
}
- std::cout << "-----------------------------------------" << std::endl;
- std::cout << "PSS ";
- for (int i = 0; i < pid_count; i++) {
- std::cout << ::android::base::StringPrintf("%15ldK", pss[i] / 1024);
+
+ printf("------------------------------------\n");
+ printf("%-16s %13" PRIu64 " kB |%16s |", "TOTALS", dmabuf_total_size, "n/a");
+ for (auto pid : pid_set) {
+ printf("%19" PRIu64 " kB |", per_pid_size[pid]);
}
- std::cout << std::endl;
+ printf("\n");
+
+ return;
}
int main(int argc, char* argv[]) {
@@ -142,8 +134,7 @@
if (argc > 1) {
if (sscanf(argv[1], "%d", &pid) == 1) {
show_all = false;
- }
- else {
+ } else {
usage(EXIT_FAILURE);
}
}
@@ -178,8 +169,7 @@
exit(EXIT_FAILURE);
}
}
+
PrintDmaBufInfo(bufs);
return 0;
}
-
-
diff --git a/libmeminfo/pageacct.cpp b/libmeminfo/pageacct.cpp
index 0a26c08..cb17af8 100644
--- a/libmeminfo/pageacct.cpp
+++ b/libmeminfo/pageacct.cpp
@@ -81,7 +81,8 @@
if (!InitPageAcct()) return false;
}
- if (pread64(kpageflags_fd_, flags, sizeof(uint64_t), pfn * sizeof(uint64_t)) < 0) {
+ if (pread64(kpageflags_fd_, flags, sizeof(uint64_t), pfn * sizeof(uint64_t)) !=
+ sizeof(uint64_t)) {
PLOG(ERROR) << "Failed to read page flags for page " << pfn;
return false;
}
@@ -95,7 +96,8 @@
if (!InitPageAcct()) return false;
}
- if (pread64(kpagecount_fd_, mapcount, sizeof(uint64_t), pfn * sizeof(uint64_t)) < 0) {
+ if (pread64(kpagecount_fd_, mapcount, sizeof(uint64_t), pfn * sizeof(uint64_t)) !=
+ sizeof(uint64_t)) {
PLOG(ERROR) << "Failed to read map count for page " << pfn;
return false;
}
@@ -130,7 +132,7 @@
off64_t offset = pfn_to_idle_bitmap_offset(pfn);
uint64_t idle_bits;
- if (pread64(pageidle_fd_, &idle_bits, sizeof(uint64_t), offset) < 0) {
+ if (pread64(pageidle_fd_, &idle_bits, sizeof(uint64_t), offset) != sizeof(uint64_t)) {
PLOG(ERROR) << "Failed to read page idle bitmap for page " << pfn;
return -errno;
}
diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp
index 934d65c..caf6e86 100644
--- a/libmeminfo/procmeminfo.cpp
+++ b/libmeminfo/procmeminfo.cpp
@@ -27,6 +27,7 @@
#include <memory>
#include <string>
#include <utility>
+#include <vector>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -278,68 +279,89 @@
bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_pageidle) {
PageAcct& pinfo = PageAcct::Instance();
- uint64_t pagesz = getpagesize();
- uint64_t num_pages = (vma.end - vma.start) / pagesz;
-
- std::unique_ptr<uint64_t[]> pg_frames(new uint64_t[num_pages]);
- uint64_t first = vma.start / pagesz;
- if (pread64(pagemap_fd, pg_frames.get(), num_pages * sizeof(uint64_t),
- first * sizeof(uint64_t)) < 0) {
- PLOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_;
+ if (get_wss && use_pageidle && !pinfo.InitPageAcct(true)) {
+ LOG(ERROR) << "Failed to init idle page accounting";
return false;
}
- if (get_wss && use_pageidle) {
- if (!pinfo.InitPageAcct(true)) {
- LOG(ERROR) << "Failed to init idle page accounting";
- return false;
- }
- }
+ uint64_t pagesz = getpagesize();
+ size_t num_pages = (vma.end - vma.start) / pagesz;
+ size_t first_page = vma.start / pagesz;
- std::unique_ptr<uint64_t[]> pg_flags(new uint64_t[num_pages]);
- std::unique_ptr<uint64_t[]> pg_counts(new uint64_t[num_pages]);
- for (uint64_t i = 0; i < num_pages; ++i) {
+ std::vector<uint64_t> page_cache;
+ size_t cur_page_cache_index = 0;
+ size_t num_in_page_cache = 0;
+ size_t num_leftover_pages = num_pages;
+ for (size_t cur_page = first_page; cur_page < first_page + num_pages; ++cur_page) {
if (!get_wss) {
vma.usage.vss += pagesz;
}
- uint64_t p = pg_frames[i];
- if (!PAGE_PRESENT(p) && !PAGE_SWAPPED(p)) continue;
- if (PAGE_SWAPPED(p)) {
+ // Cache page map data.
+ if (cur_page_cache_index == num_in_page_cache) {
+ static constexpr size_t kMaxPages = 2048;
+ num_leftover_pages -= num_in_page_cache;
+ if (num_leftover_pages > kMaxPages) {
+ num_in_page_cache = kMaxPages;
+ } else {
+ num_in_page_cache = num_leftover_pages;
+ }
+ page_cache.resize(num_in_page_cache);
+ size_t total_bytes = page_cache.size() * sizeof(uint64_t);
+ ssize_t bytes = pread64(pagemap_fd, page_cache.data(), total_bytes,
+ cur_page * sizeof(uint64_t));
+ if (bytes != total_bytes) {
+ if (bytes == -1) {
+ PLOG(ERROR) << "Failed to read page data at offset "
+ << cur_page * sizeof(uint64_t);
+ } else {
+ LOG(ERROR) << "Failed to read page data at offset "
+ << cur_page * sizeof(uint64_t) << " read bytes " << sizeof(uint64_t)
+ << " expected bytes " << bytes;
+ }
+ return false;
+ }
+ cur_page_cache_index = 0;
+ }
+
+ uint64_t page_info = page_cache[cur_page_cache_index++];
+ if (!PAGE_PRESENT(page_info) && !PAGE_SWAPPED(page_info)) continue;
+
+ if (PAGE_SWAPPED(page_info)) {
vma.usage.swap += pagesz;
- swap_offsets_.emplace_back(PAGE_SWAP_OFFSET(p));
+ swap_offsets_.emplace_back(PAGE_SWAP_OFFSET(page_info));
continue;
}
- uint64_t page_frame = PAGE_PFN(p);
- if (!pinfo.PageFlags(page_frame, &pg_flags[i])) {
+ uint64_t page_frame = PAGE_PFN(page_info);
+ uint64_t cur_page_flags;
+ if (!pinfo.PageFlags(page_frame, &cur_page_flags)) {
LOG(ERROR) << "Failed to get page flags for " << page_frame << " in process " << pid_;
swap_offsets_.clear();
return false;
}
// skip unwanted pages from the count
- if ((pg_flags[i] & pgflags_mask_) != pgflags_) continue;
+ if ((cur_page_flags & pgflags_mask_) != pgflags_) continue;
- if (!pinfo.PageMapCount(page_frame, &pg_counts[i])) {
+ uint64_t cur_page_counts;
+ if (!pinfo.PageMapCount(page_frame, &cur_page_counts)) {
LOG(ERROR) << "Failed to get page count for " << page_frame << " in process " << pid_;
swap_offsets_.clear();
return false;
}
// Page was unmapped between the presence check at the beginning of the loop and here.
- if (pg_counts[i] == 0) {
- pg_frames[i] = 0;
- pg_flags[i] = 0;
+ if (cur_page_counts == 0) {
continue;
}
- bool is_dirty = !!(pg_flags[i] & (1 << KPF_DIRTY));
- bool is_private = (pg_counts[i] == 1);
+ bool is_dirty = !!(cur_page_flags & (1 << KPF_DIRTY));
+ bool is_private = (cur_page_counts == 1);
// Working set
if (get_wss) {
bool is_referenced = use_pageidle ? (pinfo.IsPageIdle(page_frame) == 1)
- : !!(pg_flags[i] & (1 << KPF_REFERENCED));
+ : !!(cur_page_flags & (1 << KPF_REFERENCED));
if (!is_referenced) {
continue;
}
@@ -351,7 +373,7 @@
vma.usage.rss += pagesz;
vma.usage.uss += is_private ? pagesz : 0;
- vma.usage.pss += pagesz / pg_counts[i];
+ vma.usage.pss += pagesz / cur_page_counts;
if (is_private) {
vma.usage.private_dirty += is_dirty ? pagesz : 0;
vma.usage.private_clean += is_dirty ? 0 : pagesz;
diff --git a/libmeminfo/tools/procrank.cpp b/libmeminfo/tools/procrank.cpp
index cb3757d..1e44ff9 100644
--- a/libmeminfo/tools/procrank.cpp
+++ b/libmeminfo/tools/procrank.cpp
@@ -348,7 +348,7 @@
auto rss_sort = [](ProcessRecord& a, ProcessRecord& b) {
MemUsage stats_a = show_wss ? a.Wss() : a.Usage();
MemUsage stats_b = show_wss ? b.Wss() : b.Usage();
- return reverse_sort ? stats_a.rss < stats_b.pss : stats_a.pss > stats_b.pss;
+ return reverse_sort ? stats_a.rss < stats_b.rss : stats_a.rss > stats_b.rss;
};
auto vss_sort = [](ProcessRecord& a, ProcessRecord& b) {
diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp
index 9797d76..20ae2be 100644
--- a/libprocessgroup/cgroup_map.cpp
+++ b/libprocessgroup/cgroup_map.cpp
@@ -67,11 +67,14 @@
return controller_ != nullptr;
}
-bool CgroupController::IsUsable() const {
+bool CgroupController::IsUsable() {
if (!HasValue()) return false;
- static bool enabled = (access(GetProcsFilePath("", 0, 0).c_str(), F_OK) == 0);
- return enabled;
+ if (state_ == UNKNOWN) {
+ state_ = access(GetProcsFilePath("", 0, 0).c_str(), F_OK) == 0 ? USABLE : MISSING;
+ }
+
+ return state_ == USABLE;
}
std::string CgroupController::GetTasksFilePath(const std::string& rel_path) const {
diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h
index 9350412..427d71b 100644
--- a/libprocessgroup/cgroup_map.h
+++ b/libprocessgroup/cgroup_map.h
@@ -31,20 +31,28 @@
class CgroupController {
public:
// Does not own controller
- explicit CgroupController(const ACgroupController* controller) : controller_(controller) {}
+ explicit CgroupController(const ACgroupController* controller)
+ : controller_(controller), state_(UNKNOWN) {}
uint32_t version() const;
const char* name() const;
const char* path() const;
bool HasValue() const;
- bool IsUsable() const;
+ bool IsUsable();
std::string GetTasksFilePath(const std::string& path) const;
std::string GetProcsFilePath(const std::string& path, uid_t uid, pid_t pid) const;
bool GetTaskGroup(int tid, std::string* group) const;
private:
+ enum ControllerState {
+ UNKNOWN = 0,
+ USABLE = 1,
+ MISSING = 2,
+ };
+
const ACgroupController* controller_ = nullptr;
+ ControllerState state_;
};
class CgroupMap {