Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 18f181e2 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 5706862 from 41d77405 to qt-c2f2-release

Change-Id: Ice29352585860190c243ea785bd51924504428aa
parents 422b776f 41d77405
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -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>
@@ -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
@@ -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()) &&
@@ -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_;
@@ -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);
    }
    }
};
};


+178 −97
Original line number Original line Diff line number Diff line
@@ -16,17 +16,19 @@


#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 <stdlib.h>
#include <stdlib.h>
#include <unistd.h>
#include <unistd.h>


#include <iostream>
#include <fstream>
#include <fstream>
#include <iostream>
#include <map>
#include <set>
#include <sstream>
#include <sstream>
#include <string>
#include <string>
#include <vector>
#include <vector>
#include <map>
#include <set>


#include <android-base/stringprintf.h>
#include <android-base/stringprintf.h>
#include <dmabufinfo/dmabufinfo.h>
#include <dmabufinfo/dmabufinfo.h>
@@ -35,15 +37,16 @@ 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);
}
}


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::string pid_path = android::base::StringPrintf("/proc/%d/comm", pid);
    std::ifstream in{pid_path};
    std::ifstream in{pid_path};
    if (!in) return std::string("N/A");
    if (!in) return std::string("N/A");
@@ -53,133 +56,211 @@ static std::string GetProcessBaseName(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) {
    std::set<pid_t> pid_set;
    std::map<pid_t, int> pid_column;

    if (bufs.empty()) {
    if (bufs.empty()) {
        std::cout << "dmabuf info not found ¯\\_(ツ)_/¯" << std::endl;
        printf("dmabuf info not found ¯\\_(ツ)_/¯\n");
        return;
        return;
    }
    }


    // Find all unique pids in the input vector, create a set
    // Find all unique pids in the input vector, create a set
    for (int i = 0; i < bufs.size(); i++) {
    std::set<pid_t> pid_set;
        AddPidsToSet(bufs[i].fdrefs(), &pid_set);
    for (auto& buf : bufs) {
        AddPidsToSet(bufs[i].maprefs(), &pid_set);
        pid_set.insert(buf.pids().begin(), buf.pids().end());
    }
    }


    int pid_count = 0;
    // Format the header string spaced and separated with '|'

    printf("    Dmabuf Inode |            Size |      Ref Counts |");
    std::cout << "\t\t\t\t\t\t";
    for (auto pid : pid_set) {

        printf("%16s:%-5d |", GetProcessComm(pid).c_str(), pid);
    // 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);
    }
    }

    printf("\n");
    std::cout << std::endl << "\t\t\t\t\t\t";


    // holds per-process dmabuf size in kB
    for (auto it = pid_set.begin(); it != pid_set.end(); ++it) {
    std::map<pid_t, uint64_t> per_pid_size = {};
        std::cout << ::android::base::StringPrintf("%16s",
    uint64_t dmabuf_total_size = 0;
            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",
            if (pid_refs) {
            buf->inode(),buf->size(), buf->count());
                // 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 |", "--");
            }
        }
        dmabuf_total_size += buf.size() / 1024;
        printf("\n");
    }


        memset(fds.get(), 0, sizeof(int) * pid_count);
    printf("------------------------------------\n");
        memset(maps.get(), 0, sizeof(int) * pid_count);
    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]);
    }
    printf("\n");


        for (auto it = buf->fdrefs().begin(); it != buf->fdrefs().end(); ++it) {
    return;
            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) {
static void PrintDmaBufPerProcess(const std::vector<DmaBuffer>& bufs) {
            maps[pid_column[it->first]] = it->second;
    if (bufs.empty()) {
            pss[pid_column[it->first]] += buf->size() * it->second / buf->count();
        printf("dmabuf info not found ¯\\_(ツ)_/¯\n");
        return;
    }
    }


        for (int i = 0; i < pid_count; i++) {
    // Create a reverse map from pid to dmabufs
            std::cout << ::android::base::StringPrintf("%d\t%d\t", fds[i], maps[i]);
    std::unordered_map<pid_t, std::set<ino_t>> pid_to_inodes = {};
    uint64_t total_size = 0;  // Total size of dmabufs in the system
    uint64_t kernel_rss = 0;  // Total size of dmabufs NOT mapped or opened by a process
    for (auto& buf : bufs) {
        for (auto pid : buf.pids()) {
            pid_to_inodes[pid].insert(buf.inode());
        }
        }
        std::cout << std::endl;
        total_size += buf.size();
        if (buf.fdrefs().empty() && buf.maprefs().empty()) {
            kernel_rss += buf.size();
        }
        }
    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;
    // 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;
    }
    }


int main(int argc, char* argv[]) {
    uint64_t total_rss = 0, total_pss = 0;
    pid_t pid = -1;
    for (auto& [pid, inodes] : pid_to_inodes) {
    std::vector<DmaBuffer> bufs;
        uint64_t pss = 0;
    bool show_all = true;
        uint64_t rss = 0;


    if (argc > 1) {
        printf("%16s:%-5d\n", GetProcessComm(pid).c_str(), pid);
        if (sscanf(argv[1], "%d", &pid) == 1) {
        printf("%22s %16s %16s %16s %16s\n", "Name", "Rss", "Pss", "nr_procs", "Inode");
            show_all = false;
        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();
        }
        }
        else {
        printf("%22s %13" PRIu64 " kB %13" PRIu64 " kB %16s\n", "PROCESS TOTAL", rss / 1024,
            usage(EXIT_FAILURE);
               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);
}
}


    if (show_all) {
static bool ReadDmaBufs(std::vector<DmaBuffer>* bufs) {
        if (!ReadDmaBufInfo(&bufs)) {
    bufs->clear();
            std::cerr << "debugfs entry for dmabuf not available, skipping" << std::endl;

            bufs.clear();
    if (!ReadDmaBufInfo(bufs)) {
        fprintf(stderr, "debugfs entry for dmabuf not available, skipping\n");
        return false;
    }
    }

    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);
    }
    }
    PrintDmaBufInfo(bufs);

    // Show the old dmabuf table, inode x process
    if (show_table) {
        PrintDmaBufTable(bufs);
        return 0;
        return 0;
    }
    }


    PrintDmaBufPerProcess(bufs);


    return 0;
}