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

Commit 302a259f authored by Erick Reyes's avatar Erick Reyes
Browse files

meminfo: handle multiple buffer references in dmabufinfo



Change the dmabufinfo library to handle multiple references to the same
buffer across PIDs by doing these changes:

- Add function AppendDmaBufInfo: appends the information for a specific
PID to an existing DmaBuffer vector
- Change the way fd/map references to a buffer belonging to a PID are
stored in DmaBuffer from vector<pid_t> to unorderedmap<pid_t, int>
- When parsing proc/%pid/{maps|fds}, look up the buffer by inode and
update the data if found

Test: builds
Bug: 63860998

Change-Id: If22feea772f182086ae3446b46d626a750674b1f
Signed-off-by: default avatarErick Reyes <erickreyes@google.com>
parent 2cbdc561
Loading
Loading
Loading
Loading
+20 −2
Original line number Original line Diff line number Diff line
@@ -119,9 +119,23 @@ static bool ReadDmaBufFdRefs(pid_t pid, std::vector<DmaBuffer>* dmabufs) {
            return false;
            return false;
        }
        }


        DmaBuffer& buf =
        uint64_t inode = sb.st_ino;
        auto buf = std::find_if(dmabufs->begin(), dmabufs->end(),
                                [&inode](const DmaBuffer& dbuf) { return dbuf.inode() == inode; });
        if (buf != dmabufs->end()) {
            if (buf->name() == "" || buf->name() == "<unknown>")
                buf->SetName(name);
            if (buf->exporter() == "" || buf->exporter() == "<unknown>")
                buf->SetExporter(exporter);
            if (buf->count() == 0)
                buf->SetCount(count);
            buf->AddFdRef(pid);
            return true;
        }

        DmaBuffer& db =
                dmabufs->emplace_back(sb.st_ino, sb.st_blocks * 512, count, exporter, name);
                dmabufs->emplace_back(sb.st_ino, sb.st_blocks * 512, count, exporter, name);
        buf.AddFdRef(pid);
        db.AddFdRef(pid);
    }
    }


    return true;
    return true;
@@ -225,6 +239,10 @@ bool ReadDmaBufInfo(std::vector<DmaBuffer>* dmabufs, const std::string& path) {


bool ReadDmaBufInfo(pid_t pid, std::vector<DmaBuffer>* dmabufs) {
bool ReadDmaBufInfo(pid_t pid, std::vector<DmaBuffer>* dmabufs) {
    dmabufs->clear();
    dmabufs->clear();
    return AppendDmaBufInfo(pid, dmabufs);
}

bool AppendDmaBufInfo(pid_t pid, std::vector<DmaBuffer>* dmabufs) {
    if (!ReadDmaBufFdRefs(pid, dmabufs)) {
    if (!ReadDmaBufFdRefs(pid, dmabufs)) {
        LOG(ERROR) << "Failed to read dmabuf fd references";
        LOG(ERROR) << "Failed to read dmabuf fd references";
        return false;
        return false;
+7 −8
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@


#include <string>
#include <string>
#include <vector>
#include <vector>
#include <unordered_map>


#include <android-base/file.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/logging.h>
@@ -61,18 +62,16 @@ struct ion_heap_data {


#define EXPECT_PID_IN_FDREFS(_bufptr, _pid, _expect)                         \
#define EXPECT_PID_IN_FDREFS(_bufptr, _pid, _expect)                         \
    do {                                                                     \
    do {                                                                     \
        const std::vector<pid_t>& _fdrefs = _bufptr->fdrefs();               \
        const std::unordered_map<pid_t, int>& _fdrefs = _bufptr->fdrefs();   \
        auto _ref = std::find_if(_fdrefs.begin(), _fdrefs.end(),             \
        auto _ref = _fdrefs.find(_pid);                                      \
                                 [&](const pid_t& p) { return p == _pid; }); \
        EXPECT_EQ((_ref != _fdrefs.end()), _expect);                         \
        EXPECT_EQ((_ref == _fdrefs.end()), _expect);                         \
    } while (0)
    } while (0)


#define EXPECT_PID_IN_MAPREFS(_bufptr, _pid, _expect)                        \
#define EXPECT_PID_IN_MAPREFS(_bufptr, _pid, _expect)                        \
    do {                                                                     \
    do {                                                                     \
        const std::vector<pid_t>& _maprefs = _bufptr->maprefs();             \
        const std::unordered_map<pid_t, int>& _maprefs = _bufptr->maprefs(); \
        auto _ref = std::find_if(_maprefs.begin(), _maprefs.end(),           \
        auto _ref = _maprefs.find(_pid);                                     \
                                 [&](const pid_t& p) { return p == _pid; }); \
        EXPECT_EQ((_ref != _maprefs.end()), _expect);                        \
        EXPECT_EQ((_ref == _maprefs.end()), _expect);                        \
    } while (0)
    } while (0)


TEST(DmaBufInfoParser, TestReadDmaBufInfo) {
TEST(DmaBufInfoParser, TestReadDmaBufInfo) {
+31 −6
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@


#include <string>
#include <string>
#include <vector>
#include <vector>
#include <unordered_map>


namespace android {
namespace android {
namespace dmabufinfo {
namespace dmabufinfo {
@@ -33,20 +34,27 @@ struct DmaBuffer {
    ~DmaBuffer() = default;
    ~DmaBuffer() = default;


    // Adds one file descriptor reference for the given pid
    // Adds one file descriptor reference for the given pid
    void AddFdRef(pid_t pid) { fdrefs_.emplace_back(pid); }
    void AddFdRef(pid_t pid) {
        AddRefToPidMap(pid, &fdrefs_);
    }


    // Adds one map reference for the given pid
    // Adds one map reference for the given pid
    void AddMapRef(pid_t pid) { maprefs_.emplace_back(pid); }
    void AddMapRef(pid_t pid) {
        AddRefToPidMap(pid, &maprefs_);
    }


    // Getters for each property
    // Getters for each property
    uint64_t size() { return size_; }
    uint64_t size() { return size_; }
    const std::vector<pid_t>& fdrefs() const { return fdrefs_; }
    const std::unordered_map<pid_t, int>& fdrefs() const { return fdrefs_; }
    const std::vector<pid_t>& maprefs() const { return maprefs_; }
    const std::unordered_map<pid_t, int>& maprefs() const { return maprefs_; }
    ino_t inode() const { return inode_; }
    ino_t inode() const { return inode_; }
    uint64_t total_refs() const { return fdrefs_.size() + maprefs_.size(); }
    uint64_t total_refs() const { return fdrefs_.size() + maprefs_.size(); }
    uint64_t count() const { return count_; };
    uint64_t count() const { return count_; };
    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 SetExporter(const std::string& exporter) { exporter_ = exporter; }
    void SetCount(uint64_t count) { count_ = count; }


  private:
  private:
    ino_t inode_;
    ino_t inode_;
@@ -54,20 +62,37 @@ struct DmaBuffer {
    uint64_t count_;
    uint64_t count_;
    std::string exporter_;
    std::string exporter_;
    std::string name_;
    std::string name_;
    std::vector<pid_t> fdrefs_;
    std::unordered_map<pid_t, int> fdrefs_;
    std::vector<pid_t> maprefs_;
    std::unordered_map<pid_t, int> maprefs_;
    void AddRefToPidMap(pid_t pid, std::unordered_map<pid_t, int>* map) {
        // The first time we find a ref, we set the ref count to 1
        // otherwise, increment the existing ref count
        auto [it, inserted] = map->insert(std::make_pair(pid, 1));
        if (!inserted)
            it->second++;
    }
};
};


// Read and return current dma buf objects from
// Read and return current dma buf objects from
// DEBUGFS/dma_buf/bufinfo. The references to each dma buffer are not
// DEBUGFS/dma_buf/bufinfo. The references to each dma buffer are not
// populated here and will return an empty vector.
// populated here and will return an empty vector.
//
// Returns false if something went wrong with the function, true otherwise.
// Returns false if something went wrong with the function, true otherwise.
bool ReadDmaBufInfo(std::vector<DmaBuffer>* dmabufs,
bool ReadDmaBufInfo(std::vector<DmaBuffer>* dmabufs,
                    const std::string& path = "/sys/kernel/debug/dma_buf/bufinfo");
                    const std::string& path = "/sys/kernel/debug/dma_buf/bufinfo");



// Read and return dmabuf objects for a given process without the help
// Read and return dmabuf objects for a given process without the help
// of DEBUGFS
// of DEBUGFS
//
// Returns false if something went wrong with the function, true otherwise.
bool ReadDmaBufInfo(pid_t pid, std::vector<DmaBuffer>* dmabufs);
bool ReadDmaBufInfo(pid_t pid, std::vector<DmaBuffer>* dmabufs);


// Append dmabuf objects for a given process without the help
// of DEBUGFS to an existing vector
//
// Returns false if something went wrong with the function, true otherwise.
bool AppendDmaBufInfo(pid_t pid, std::vector<DmaBuffer>* dmabufs);

}  // namespace dmabufinfo
}  // namespace dmabufinfo
}  // namespace android
}  // namespace android