1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <sys/types.h> 20 #include <unistd.h> 21 22 #include <set> 23 #include <string> 24 #include <unordered_map> 25 #include <vector> 26 27 namespace android { 28 namespace dmabufinfo { 29 30 struct DmaBuffer { 31 public: DmaBufferDmaBuffer32 DmaBuffer(ino_t inode, uint64_t size, uint64_t count, const std::string& exporter, 33 const std::string& name) 34 : inode_(inode), size_(size), count_(count), exporter_(exporter), name_(name) { 35 total_refs_ = 0; 36 } 37 DmaBuffer() = default; 38 ~DmaBuffer() = default; 39 40 // Adds one file descriptor reference for the given pid AddFdRefDmaBuffer41 void AddFdRef(pid_t pid) { 42 AddRefToPidMap(pid, &fdrefs_); 43 total_refs_++; 44 } 45 46 // Adds one map reference for the given pid AddMapRefDmaBuffer47 void AddMapRef(pid_t pid) { 48 AddRefToPidMap(pid, &maprefs_); 49 total_refs_++; 50 } 51 52 // Getters for each property sizeDmaBuffer53 uint64_t size() const { return size_; } fdrefsDmaBuffer54 const std::unordered_map<pid_t, int>& fdrefs() const { return fdrefs_; } maprefsDmaBuffer55 const std::unordered_map<pid_t, int>& maprefs() const { return maprefs_; } inodeDmaBuffer56 ino_t inode() const { return inode_; } total_refsDmaBuffer57 uint64_t total_refs() const { return total_refs_; } countDmaBuffer58 uint64_t count() const { return count_; }; pidsDmaBuffer59 const std::set<pid_t>& pids() const { return pids_; } nameDmaBuffer60 const std::string& name() const { return name_; } exporterDmaBuffer61 const std::string& exporter() const { return exporter_; } SetNameDmaBuffer62 void SetName(const std::string& name) { name_ = name; } SetExporterDmaBuffer63 void SetExporter(const std::string& exporter) { exporter_ = exporter; } SetCountDmaBuffer64 void SetCount(uint64_t count) { count_ = count; } PssDmaBuffer65 uint64_t Pss(pid_t pid) const { return maprefs_.count(pid) > 0 ? size_ / maprefs_.size() : 0; } 66 67 bool operator==(const DmaBuffer& rhs) { 68 return (inode_ == rhs.inode()) && (size_ == rhs.size()) && (name_ == rhs.name()) && 69 (exporter_ == rhs.exporter()); 70 } 71 72 private: 73 ino_t inode_; 74 uint64_t size_; 75 uint64_t count_; 76 uint64_t total_refs_; 77 std::set<pid_t> pids_; 78 std::string exporter_; 79 std::string name_; 80 std::unordered_map<pid_t, int> fdrefs_; 81 std::unordered_map<pid_t, int> maprefs_; AddRefToPidMapDmaBuffer82 void AddRefToPidMap(pid_t pid, std::unordered_map<pid_t, int>* map) { 83 // The first time we find a ref, we set the ref count to 1 84 // otherwise, increment the existing ref count 85 auto [it, inserted] = map->insert(std::make_pair(pid, 1)); 86 if (!inserted) it->second++; 87 pids_.insert(pid); 88 } 89 }; 90 91 // Read and return current dma buf objects from 92 // DEBUGFS/dma_buf/bufinfo. The references to each dma buffer are not 93 // populated here and will return an empty vector. 94 // Returns false if something went wrong with the function, true otherwise. 95 bool ReadDmaBufInfo(std::vector<DmaBuffer>* dmabufs, 96 const std::string& path = "/sys/kernel/debug/dma_buf/bufinfo"); 97 98 // Read and return dmabuf objects for a given process without the help 99 // of DEBUGFS 100 // Returns false if something went wrong with the function, true otherwise. 101 bool ReadDmaBufInfo(pid_t pid, std::vector<DmaBuffer>* dmabufs, bool read_fdrefs = true, 102 const std::string& procfs_path = "/proc", 103 const std::string& dmabuf_sysfs_path = "/sys/kernel/dmabuf/buffers"); 104 105 // Appends new fd-referenced dmabuf objects from a given process to an existing vector. 106 // If the vector contains an existing element with a matching inode, the reference 107 // counts are updated. 108 // On common kernels earlier than 5.4, reading fd-referenced dmabufs of other processes 109 // is only possible if the caller has root privileges. On 5.4+ common kernels the caller 110 // can read this information with the PTRACE_MODE_READ permission. 111 // Returns true on success, otherwise false. 112 bool ReadDmaBufFdRefs(int pid, std::vector<DmaBuffer>* dmabufs, 113 const std::string& procfs_path = "/proc"); 114 115 // Appends new mapped dmabuf objects from a given process to an existing vector. 116 // If the vector contains an existing element with a matching inode, the reference 117 // counts are updated. 118 // Returns true on success, otherwise false. 119 bool ReadDmaBufMapRefs(pid_t pid, std::vector<DmaBuffer>* dmabufs, 120 const std::string& procfs_path = "/proc", 121 const std::string& dmabuf_sysfs_path = "/sys/kernel/dmabuf/buffers"); 122 123 124 125 // Get the DMA buffers PSS contribution for the specified @pid 126 // Returns true on success, false otherwise 127 bool ReadDmaBufPss(int pid, uint64_t* pss, const std::string& procfs_path = "/proc", 128 const std::string& dmabuf_sysfs_path = "/sys/kernel/dmabuf/buffers"); 129 130 } // namespace dmabufinfo 131 } // namespace android 132