Loading libmeminfo/libdmabufinfo/include/dmabufinfo/dmabufinfo.h +6 −0 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <sys/types.h> #include <sys/types.h> #include <unistd.h> #include <unistd.h> #include <set> #include <string> #include <string> #include <vector> #include <vector> #include <unordered_map> #include <unordered_map> Loading @@ -33,6 +34,7 @@ struct DmaBuffer { : inode_(inode), size_(size), count_(count), exporter_(exporter), name_(name) { : inode_(inode), size_(size), count_(count), exporter_(exporter), name_(name) { total_refs_ = 0; total_refs_ = 0; } } DmaBuffer() = default; ~DmaBuffer() = default; ~DmaBuffer() = default; // Adds one file descriptor reference for the given pid // Adds one file descriptor reference for the given pid Loading @@ -54,11 +56,13 @@ struct DmaBuffer { ino_t inode() const { return inode_; } ino_t inode() const { return inode_; } uint64_t total_refs() const { return total_refs_; } uint64_t total_refs() const { return total_refs_; } uint64_t count() const { return count_; }; uint64_t count() const { return count_; }; const std::set<pid_t>& pids() const { return pids_; } const std::string& name() const { return name_; } const std::string& name() const { return name_; } const std::string& exporter() const { return exporter_; } const std::string& exporter() const { return exporter_; } void SetName(const std::string& name) { name_ = name; } void SetName(const std::string& name) { name_ = name; } void SetExporter(const std::string& exporter) { exporter_ = exporter; } void SetExporter(const std::string& exporter) { exporter_ = exporter; } void SetCount(uint64_t count) { count_ = count; } void SetCount(uint64_t count) { count_ = count; } uint64_t Pss() const { return size_ / pids_.size(); } bool operator==(const DmaBuffer& rhs) { bool operator==(const DmaBuffer& rhs) { return (inode_ == rhs.inode()) && (size_ == rhs.size()) && (name_ == rhs.name()) && return (inode_ == rhs.inode()) && (size_ == rhs.size()) && (name_ == rhs.name()) && Loading @@ -70,6 +74,7 @@ struct DmaBuffer { uint64_t size_; uint64_t size_; uint64_t count_; uint64_t count_; uint64_t total_refs_; uint64_t total_refs_; std::set<pid_t> pids_; std::string exporter_; std::string exporter_; std::string name_; std::string name_; std::unordered_map<pid_t, int> fdrefs_; std::unordered_map<pid_t, int> fdrefs_; Loading @@ -80,6 +85,7 @@ struct DmaBuffer { auto [it, inserted] = map->insert(std::make_pair(pid, 1)); auto [it, inserted] = map->insert(std::make_pair(pid, 1)); if (!inserted) if (!inserted) it->second++; it->second++; pids_.insert(pid); } } }; }; Loading libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp +133 −42 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <dirent.h> #include <dirent.h> #include <errno.h> #include <errno.h> #include <getopt.h> #include <inttypes.h> #include <inttypes.h> #include <stdio.h> #include <stdio.h> #include <stdlib.h> #include <stdlib.h> Loading @@ -36,9 +37,10 @@ using DmaBuffer = ::android::dmabufinfo::DmaBuffer; [[noreturn]] static void usage(int exit_status) { [[noreturn]] static void usage(int exit_status) { fprintf(stderr, fprintf(stderr, "Usage: %s [PID] \n" "Usage: %s [-ah] [PID] \n" "\t If PID is supplied, the dmabuf information for this process is shown.\n" "-a\t show all dma buffers (ion) in big table, [buffer x process] grid \n" "\t Otherwise, shows the information for all processes.\n", "-h\t show this help\n" " \t If PID is supplied, the dmabuf information for that process is shown.\n", getprogname()); getprogname()); exit(exit_status); exit(exit_status); Loading @@ -54,11 +56,7 @@ static std::string GetProcessComm(const pid_t pid) { return line; return line; } } static void AddPidsToSet(const std::unordered_map<pid_t, int>& map, std::set<pid_t>* set) { static void PrintDmaBufTable(const std::vector<DmaBuffer>& bufs) { for (auto it = map.begin(); it != map.end(); ++it) set->insert(it->first); } static void PrintDmaBufInfo(const std::vector<DmaBuffer>& bufs) { if (bufs.empty()) { if (bufs.empty()) { printf("dmabuf info not found ¯\\_(ツ)_/¯\n"); printf("dmabuf info not found ¯\\_(ツ)_/¯\n"); return; return; Loading @@ -66,9 +64,8 @@ static void PrintDmaBufInfo(const std::vector<DmaBuffer>& bufs) { // Find all unique pids in the input vector, create a set // Find all unique pids in the input vector, create a set std::set<pid_t> pid_set; std::set<pid_t> pid_set; for (int i = 0; i < bufs.size(); i++) { for (auto& buf : bufs) { AddPidsToSet(bufs[i].fdrefs(), &pid_set); pid_set.insert(buf.pids().begin(), buf.pids().end()); AddPidsToSet(bufs[i].maprefs(), &pid_set); } } // Format the header string spaced and separated with '|' // Format the header string spaced and separated with '|' Loading Loading @@ -126,50 +123,144 @@ static void PrintDmaBufInfo(const std::vector<DmaBuffer>& bufs) { return; return; } } int main(int argc, char* argv[]) { static void PrintDmaBufPerProcess(const std::vector<DmaBuffer>& bufs) { pid_t pid = -1; if (bufs.empty()) { std::vector<DmaBuffer> bufs; printf("dmabuf info not found ¯\\_(ツ)_/¯\n"); bool show_all = true; return; } if (argc > 1) { // Create a reverse map from pid to dmabufs if (sscanf(argv[1], "%d", &pid) == 1) { std::unordered_map<pid_t, std::set<ino_t>> pid_to_inodes = {}; show_all = false; uint64_t total_size = 0; // Total size of dmabufs in the system } else { uint64_t kernel_rss = 0; // Total size of dmabufs NOT mapped or opened by a process usage(EXIT_FAILURE); for (auto& buf : bufs) { for (auto pid : buf.pids()) { pid_to_inodes[pid].insert(buf.inode()); } } total_size += buf.size(); if (buf.fdrefs().empty() && buf.maprefs().empty()) { kernel_rss += buf.size(); } } } // Create an inode to dmabuf map. We know inodes are unique.. std::unordered_map<ino_t, DmaBuffer> inode_to_dmabuf; for (auto buf : bufs) { inode_to_dmabuf[buf.inode()] = buf; } uint64_t total_rss = 0, total_pss = 0; for (auto& [pid, inodes] : pid_to_inodes) { uint64_t pss = 0; uint64_t rss = 0; printf("%16s:%-5d\n", GetProcessComm(pid).c_str(), pid); printf("%22s %16s %16s %16s %16s\n", "Name", "Rss", "Pss", "nr_procs", "Inode"); for (auto& inode : inodes) { DmaBuffer& buf = inode_to_dmabuf[inode]; printf("%22s %13" PRIu64 " kB %13" PRIu64 " kB %16zu %16" PRIuMAX "\n", buf.name().empty() ? "<unknown>" : buf.name().c_str(), buf.size() / 1024, buf.Pss() / 1024, buf.pids().size(), static_cast<uintmax_t>(buf.inode())); rss += buf.size(); pss += buf.Pss(); } printf("%22s %13" PRIu64 " kB %13" PRIu64 " kB %16s\n", "PROCESS TOTAL", rss / 1024, pss / 1024, ""); printf("----------------------\n"); total_rss += rss; total_pss += pss; } printf("dmabuf total: %" PRIu64 " kB kernel_rss: %" PRIu64 " kB userspace_rss: %" PRIu64 " kB userspace_pss: %" PRIu64 " kB\n ", total_size / 1024, kernel_rss / 1024, total_rss / 1024, total_pss / 1024); } static bool ReadDmaBufs(std::vector<DmaBuffer>* bufs) { bufs->clear(); if (show_all) { if (!ReadDmaBufInfo(bufs)) { if (!ReadDmaBufInfo(&bufs)) { fprintf(stderr, "debugfs entry for dmabuf not available, skipping\n"); std::cerr << "debugfs entry for dmabuf not available, skipping" << std::endl; return false; bufs.clear(); } } std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir("/proc"), closedir); std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir("/proc"), closedir); if (!dir) { if (!dir) { std::cerr << "Failed to open /proc directory" << std::endl; fprintf(stderr, "Failed to open /proc directory\n"); exit(EXIT_FAILURE); bufs->clear(); return false; } } struct dirent* dent; struct dirent* dent; while ((dent = readdir(dir.get()))) { while ((dent = readdir(dir.get()))) { if (dent->d_type != DT_DIR) continue; if (dent->d_type != DT_DIR) continue; int matched = sscanf(dent->d_name, "%d", &pid); int pid = atoi(dent->d_name); if (matched != 1) { if (pid == 0) { continue; continue; } } if (!AppendDmaBufInfo(pid, &bufs)) { if (!AppendDmaBufInfo(pid, bufs)) { std::cerr << "Unable to read dmabuf info for pid " << pid << std::endl; fprintf(stderr, "Unable to read dmabuf info for pid %d\n", pid); exit(EXIT_FAILURE); bufs->clear(); return false; } } } } } else { return true; } int main(int argc, char* argv[]) { struct option longopts[] = {{"all", no_argument, nullptr, 'a'}, {"help", no_argument, nullptr, 'h'}, {0, 0, nullptr, 0}}; int opt; bool show_table = false; while ((opt = getopt_long(argc, argv, "ah", longopts, nullptr)) != -1) { switch (opt) { case 'a': show_table = true; break; case 'h': usage(EXIT_SUCCESS); default: usage(EXIT_FAILURE); } } pid_t pid = -1; if (optind < argc) { if (show_table) { fprintf(stderr, "Invalid arguments: -a does not need arguments\n"); usage(EXIT_FAILURE); } if (optind != (argc - 1)) { fprintf(stderr, "Invalid arguments - only one [PID] argument is allowed\n"); usage(EXIT_FAILURE); } pid = atoi(argv[optind]); if (pid == 0) { fprintf(stderr, "Invalid process id %s\n", argv[optind]); usage(EXIT_FAILURE); } } std::vector<DmaBuffer> bufs; if (pid != -1) { if (!ReadDmaBufInfo(pid, &bufs)) { if (!ReadDmaBufInfo(pid, &bufs)) { std::cerr << "Unable to read dmabuf info" << std::endl; fprintf(stderr, "Unable to read dmabuf info for %d\n", pid); exit(EXIT_FAILURE); exit(EXIT_FAILURE); } } } else { if (!ReadDmaBufs(&bufs)) exit(EXIT_FAILURE); } // Show the old dmabuf table, inode x process if (show_table) { PrintDmaBufTable(bufs); return 0; } } PrintDmaBufInfo(bufs); PrintDmaBufPerProcess(bufs); return 0; return 0; } } Loading
libmeminfo/libdmabufinfo/include/dmabufinfo/dmabufinfo.h +6 −0 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <sys/types.h> #include <sys/types.h> #include <unistd.h> #include <unistd.h> #include <set> #include <string> #include <string> #include <vector> #include <vector> #include <unordered_map> #include <unordered_map> Loading @@ -33,6 +34,7 @@ struct DmaBuffer { : inode_(inode), size_(size), count_(count), exporter_(exporter), name_(name) { : inode_(inode), size_(size), count_(count), exporter_(exporter), name_(name) { total_refs_ = 0; total_refs_ = 0; } } DmaBuffer() = default; ~DmaBuffer() = default; ~DmaBuffer() = default; // Adds one file descriptor reference for the given pid // Adds one file descriptor reference for the given pid Loading @@ -54,11 +56,13 @@ struct DmaBuffer { ino_t inode() const { return inode_; } ino_t inode() const { return inode_; } uint64_t total_refs() const { return total_refs_; } uint64_t total_refs() const { return total_refs_; } uint64_t count() const { return count_; }; uint64_t count() const { return count_; }; const std::set<pid_t>& pids() const { return pids_; } const std::string& name() const { return name_; } const std::string& name() const { return name_; } const std::string& exporter() const { return exporter_; } const std::string& exporter() const { return exporter_; } void SetName(const std::string& name) { name_ = name; } void SetName(const std::string& name) { name_ = name; } void SetExporter(const std::string& exporter) { exporter_ = exporter; } void SetExporter(const std::string& exporter) { exporter_ = exporter; } void SetCount(uint64_t count) { count_ = count; } void SetCount(uint64_t count) { count_ = count; } uint64_t Pss() const { return size_ / pids_.size(); } bool operator==(const DmaBuffer& rhs) { bool operator==(const DmaBuffer& rhs) { return (inode_ == rhs.inode()) && (size_ == rhs.size()) && (name_ == rhs.name()) && return (inode_ == rhs.inode()) && (size_ == rhs.size()) && (name_ == rhs.name()) && Loading @@ -70,6 +74,7 @@ struct DmaBuffer { uint64_t size_; uint64_t size_; uint64_t count_; uint64_t count_; uint64_t total_refs_; uint64_t total_refs_; std::set<pid_t> pids_; std::string exporter_; std::string exporter_; std::string name_; std::string name_; std::unordered_map<pid_t, int> fdrefs_; std::unordered_map<pid_t, int> fdrefs_; Loading @@ -80,6 +85,7 @@ struct DmaBuffer { auto [it, inserted] = map->insert(std::make_pair(pid, 1)); auto [it, inserted] = map->insert(std::make_pair(pid, 1)); if (!inserted) if (!inserted) it->second++; it->second++; pids_.insert(pid); } } }; }; Loading
libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp +133 −42 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <dirent.h> #include <dirent.h> #include <errno.h> #include <errno.h> #include <getopt.h> #include <inttypes.h> #include <inttypes.h> #include <stdio.h> #include <stdio.h> #include <stdlib.h> #include <stdlib.h> Loading @@ -36,9 +37,10 @@ using DmaBuffer = ::android::dmabufinfo::DmaBuffer; [[noreturn]] static void usage(int exit_status) { [[noreturn]] static void usage(int exit_status) { fprintf(stderr, fprintf(stderr, "Usage: %s [PID] \n" "Usage: %s [-ah] [PID] \n" "\t If PID is supplied, the dmabuf information for this process is shown.\n" "-a\t show all dma buffers (ion) in big table, [buffer x process] grid \n" "\t Otherwise, shows the information for all processes.\n", "-h\t show this help\n" " \t If PID is supplied, the dmabuf information for that process is shown.\n", getprogname()); getprogname()); exit(exit_status); exit(exit_status); Loading @@ -54,11 +56,7 @@ static std::string GetProcessComm(const pid_t pid) { return line; return line; } } static void AddPidsToSet(const std::unordered_map<pid_t, int>& map, std::set<pid_t>* set) { static void PrintDmaBufTable(const std::vector<DmaBuffer>& bufs) { for (auto it = map.begin(); it != map.end(); ++it) set->insert(it->first); } static void PrintDmaBufInfo(const std::vector<DmaBuffer>& bufs) { if (bufs.empty()) { if (bufs.empty()) { printf("dmabuf info not found ¯\\_(ツ)_/¯\n"); printf("dmabuf info not found ¯\\_(ツ)_/¯\n"); return; return; Loading @@ -66,9 +64,8 @@ static void PrintDmaBufInfo(const std::vector<DmaBuffer>& bufs) { // Find all unique pids in the input vector, create a set // Find all unique pids in the input vector, create a set std::set<pid_t> pid_set; std::set<pid_t> pid_set; for (int i = 0; i < bufs.size(); i++) { for (auto& buf : bufs) { AddPidsToSet(bufs[i].fdrefs(), &pid_set); pid_set.insert(buf.pids().begin(), buf.pids().end()); AddPidsToSet(bufs[i].maprefs(), &pid_set); } } // Format the header string spaced and separated with '|' // Format the header string spaced and separated with '|' Loading Loading @@ -126,50 +123,144 @@ static void PrintDmaBufInfo(const std::vector<DmaBuffer>& bufs) { return; return; } } int main(int argc, char* argv[]) { static void PrintDmaBufPerProcess(const std::vector<DmaBuffer>& bufs) { pid_t pid = -1; if (bufs.empty()) { std::vector<DmaBuffer> bufs; printf("dmabuf info not found ¯\\_(ツ)_/¯\n"); bool show_all = true; return; } if (argc > 1) { // Create a reverse map from pid to dmabufs if (sscanf(argv[1], "%d", &pid) == 1) { std::unordered_map<pid_t, std::set<ino_t>> pid_to_inodes = {}; show_all = false; uint64_t total_size = 0; // Total size of dmabufs in the system } else { uint64_t kernel_rss = 0; // Total size of dmabufs NOT mapped or opened by a process usage(EXIT_FAILURE); for (auto& buf : bufs) { for (auto pid : buf.pids()) { pid_to_inodes[pid].insert(buf.inode()); } } total_size += buf.size(); if (buf.fdrefs().empty() && buf.maprefs().empty()) { kernel_rss += buf.size(); } } } // Create an inode to dmabuf map. We know inodes are unique.. std::unordered_map<ino_t, DmaBuffer> inode_to_dmabuf; for (auto buf : bufs) { inode_to_dmabuf[buf.inode()] = buf; } uint64_t total_rss = 0, total_pss = 0; for (auto& [pid, inodes] : pid_to_inodes) { uint64_t pss = 0; uint64_t rss = 0; printf("%16s:%-5d\n", GetProcessComm(pid).c_str(), pid); printf("%22s %16s %16s %16s %16s\n", "Name", "Rss", "Pss", "nr_procs", "Inode"); for (auto& inode : inodes) { DmaBuffer& buf = inode_to_dmabuf[inode]; printf("%22s %13" PRIu64 " kB %13" PRIu64 " kB %16zu %16" PRIuMAX "\n", buf.name().empty() ? "<unknown>" : buf.name().c_str(), buf.size() / 1024, buf.Pss() / 1024, buf.pids().size(), static_cast<uintmax_t>(buf.inode())); rss += buf.size(); pss += buf.Pss(); } printf("%22s %13" PRIu64 " kB %13" PRIu64 " kB %16s\n", "PROCESS TOTAL", rss / 1024, pss / 1024, ""); printf("----------------------\n"); total_rss += rss; total_pss += pss; } printf("dmabuf total: %" PRIu64 " kB kernel_rss: %" PRIu64 " kB userspace_rss: %" PRIu64 " kB userspace_pss: %" PRIu64 " kB\n ", total_size / 1024, kernel_rss / 1024, total_rss / 1024, total_pss / 1024); } static bool ReadDmaBufs(std::vector<DmaBuffer>* bufs) { bufs->clear(); if (show_all) { if (!ReadDmaBufInfo(bufs)) { if (!ReadDmaBufInfo(&bufs)) { fprintf(stderr, "debugfs entry for dmabuf not available, skipping\n"); std::cerr << "debugfs entry for dmabuf not available, skipping" << std::endl; return false; bufs.clear(); } } std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir("/proc"), closedir); std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir("/proc"), closedir); if (!dir) { if (!dir) { std::cerr << "Failed to open /proc directory" << std::endl; fprintf(stderr, "Failed to open /proc directory\n"); exit(EXIT_FAILURE); bufs->clear(); return false; } } struct dirent* dent; struct dirent* dent; while ((dent = readdir(dir.get()))) { while ((dent = readdir(dir.get()))) { if (dent->d_type != DT_DIR) continue; if (dent->d_type != DT_DIR) continue; int matched = sscanf(dent->d_name, "%d", &pid); int pid = atoi(dent->d_name); if (matched != 1) { if (pid == 0) { continue; continue; } } if (!AppendDmaBufInfo(pid, &bufs)) { if (!AppendDmaBufInfo(pid, bufs)) { std::cerr << "Unable to read dmabuf info for pid " << pid << std::endl; fprintf(stderr, "Unable to read dmabuf info for pid %d\n", pid); exit(EXIT_FAILURE); bufs->clear(); return false; } } } } } else { return true; } int main(int argc, char* argv[]) { struct option longopts[] = {{"all", no_argument, nullptr, 'a'}, {"help", no_argument, nullptr, 'h'}, {0, 0, nullptr, 0}}; int opt; bool show_table = false; while ((opt = getopt_long(argc, argv, "ah", longopts, nullptr)) != -1) { switch (opt) { case 'a': show_table = true; break; case 'h': usage(EXIT_SUCCESS); default: usage(EXIT_FAILURE); } } pid_t pid = -1; if (optind < argc) { if (show_table) { fprintf(stderr, "Invalid arguments: -a does not need arguments\n"); usage(EXIT_FAILURE); } if (optind != (argc - 1)) { fprintf(stderr, "Invalid arguments - only one [PID] argument is allowed\n"); usage(EXIT_FAILURE); } pid = atoi(argv[optind]); if (pid == 0) { fprintf(stderr, "Invalid process id %s\n", argv[optind]); usage(EXIT_FAILURE); } } std::vector<DmaBuffer> bufs; if (pid != -1) { if (!ReadDmaBufInfo(pid, &bufs)) { if (!ReadDmaBufInfo(pid, &bufs)) { std::cerr << "Unable to read dmabuf info" << std::endl; fprintf(stderr, "Unable to read dmabuf info for %d\n", pid); exit(EXIT_FAILURE); exit(EXIT_FAILURE); } } } else { if (!ReadDmaBufs(&bufs)) exit(EXIT_FAILURE); } // Show the old dmabuf table, inode x process if (show_table) { PrintDmaBufTable(bufs); return 0; } } PrintDmaBufInfo(bufs); PrintDmaBufPerProcess(bufs); return 0; return 0; } }