From fd79d4305a7b7d0fcc5da5dcdb59de044fcc6b95 Mon Sep 17 00:00:00 2001 From: Erick Reyes Date: Wed, 30 Jan 2019 19:12:03 -0800 Subject: [PATCH] meminfo: add tools/dmabufinfo_dump to dmabufinfo Adding tool to dump the dmabuf information using the dmabufinfo library. Test: run "dmabuf_dump" and "dmabuf_dump " on crosshatch Bug: 63860998 Change-Id: I16fe0a701deb5086ca0e1a8ceecb70dbc17934e6 Signed-off-by: Erick Reyes --- libmeminfo/libdmabufinfo/tools/Android.bp | 31 +++ .../libdmabufinfo/tools/dmabuf_dump.cpp | 185 ++++++++++++++++++ 2 files changed, 216 insertions(+) create mode 100644 libmeminfo/libdmabufinfo/tools/Android.bp create mode 100644 libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp diff --git a/libmeminfo/libdmabufinfo/tools/Android.bp b/libmeminfo/libdmabufinfo/tools/Android.bp new file mode 100644 index 000000000..339583e1f --- /dev/null +++ b/libmeminfo/libdmabufinfo/tools/Android.bp @@ -0,0 +1,31 @@ +// Copyright (C) 2019 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. + +cc_binary { + name: "dmabuf_dump", + cflags: [ + "-Wall", + "-Werror", + ], + + srcs: ["dmabuf_dump.cpp"], + shared_libs: [ + "libbase", + "libmeminfo", + ], + static_libs: [ + "libdmabufinfo", + "libc++fs", + ], +} \ No newline at end of file diff --git a/libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp b/libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp new file mode 100644 index 000000000..223c001ae --- /dev/null +++ b/libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2019 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. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using DmaBuffer = ::android::dmabufinfo::DmaBuffer; + +[[noreturn]] static void usage(int exit_status) { + fprintf(stderr, + "Usage: %s [PID] \n" + "\t If PID is supplied, the dmabuf information for this process is shown.\n" + "\t Otherwise, shows the information for all processes.\n", + getprogname()); + + exit(exit_status); +} + +static std::string GetProcessBaseName(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"); + std::string line; + std::getline(in, line); + if (!in) return std::string("N/A"); + return line; +} + +static void AddPidsToSet(const std::unordered_map& map, std::set* set) +{ + for (auto it = map.begin(); it != map.end(); ++it) + set->insert(it->first); +} + +static void PrintDmaBufInfo(const std::vector& bufs) { + std::set pid_set; + std::map pid_column; + + if (bufs.empty()) { + std::cout << "dmabuf info not found ¯\\_(ツ)_/¯" << std::endl; + return; + } + + // Find all unique pids in the input vector, create a 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); + } + + std::cout << std::endl << "\t\t\t\t\t\t"; + + for (auto it = pid_set.begin(); it != pid_set.end(); ++it) { + std::cout << ::android::base::StringPrintf("%16s", + GetProcessBaseName(*it).c_str()); + } + + 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(pid_count); + auto maps = std::make_unique(pid_count); + auto pss = std::make_unique(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%lu\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(); + } + + 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; + } + std::cout << "-----------------------------------------" << std::endl; + std::cout << "PSS "; + for (int i = 0; i < pid_count; i++) { + std::cout << ::android::base::StringPrintf("%15ldK", pss[i] / 1024); + } + std::cout << std::endl; +} + +int main(int argc, char* argv[]) { + pid_t pid = -1; + std::vector bufs; + bool show_all = true; + + if (argc > 1) { + if (sscanf(argv[1], "%d", &pid) == 1) { + show_all = false; + } + else { + usage(EXIT_FAILURE); + } + } + + if (show_all) { + if (!ReadDmaBufInfo(&bufs)) { + std::cerr << "Unable to read DEBUGFS dmabuf info" << std::endl; + exit(EXIT_FAILURE); + } + std::unique_ptr dir(opendir("/proc"), closedir); + if (!dir) { + std::cerr << "Failed to open /proc directory" << std::endl; + exit(EXIT_FAILURE); + } + struct dirent* dent; + while ((dent = readdir(dir.get()))) { + if (dent->d_type != DT_DIR) continue; + + int matched = sscanf(dent->d_name, "%d", &pid); + if (matched != 1) { + continue; + } + + if (!AppendDmaBufInfo(pid, &bufs)) { + std::cerr << "Unable to read dmabuf info for pid " << pid << std::endl; + exit(EXIT_FAILURE); + } + } + } else { + if (!ReadDmaBufInfo(pid, &bufs)) { + std::cerr << "Unable to read dmabuf info" << std::endl; + exit(EXIT_FAILURE); + } + } + PrintDmaBufInfo(bufs); + return 0; +} + +