1 /* 2 * Copyright (C) 2023 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 <cstdint> 23 #include <map> 24 #include <string> 25 26 #include <dmabufinfo/dmabuf_sysfs_stats.h> 27 #include <dmabufinfo/dmabufinfo.h> 28 29 class DmabufOutputHelper { 30 public: 31 virtual ~DmabufOutputHelper() = default; 32 33 // Table buffer x process 34 virtual void BufTableMainHeaders() = 0; 35 virtual void BufTableProcessHeader(const pid_t pid, const std::string& process) = 0; 36 virtual void BufTableStats(const android::dmabufinfo::DmaBuffer& buf) = 0; 37 virtual void BufTableProcessSize(int pid_fdrefs, int pid_maprefs) = 0; BufTableTotalHeader()38 virtual void BufTableTotalHeader() {} BufTableTotalProcessHeader(const pid_t pid,const std::string & process)39 virtual void BufTableTotalProcessHeader([[maybe_unused]] const pid_t pid, 40 [[maybe_unused]] const std::string& process) {} 41 virtual void BufTableTotalStats(const uint64_t dmabuf_total_size) = 0; 42 virtual void BufTableTotalProcessStats(const uint64_t pid_size) = 0; 43 44 // Per Process 45 virtual void PerProcessHeader(const std::string& process, const pid_t pid) = 0; 46 virtual void PerProcessBufStats(const android::dmabufinfo::DmaBuffer& buf) = 0; 47 virtual void PerProcessTotalStat(const uint64_t pss, const uint64_t rss) = 0; 48 virtual void TotalProcessesStats(const uint64_t& total_rss, const uint64_t& total_pss, 49 const uint64_t& userspace_size, 50 const uint64_t& kernel_rss) = 0; 51 52 // Per-buffer (Sysfs) 53 virtual void PerBufferHeader() = 0; 54 virtual void PerBufferStats(const android::dmabufinfo::DmabufInfo& bufInfo) = 0; 55 56 virtual void ExporterHeader() = 0; 57 virtual void ExporterStats(const std::string& exporter, 58 const android::dmabufinfo::DmabufTotal& dmaBufTotal) = 0; 59 60 virtual void SysfsBufTotalStats(const android::dmabufinfo::DmabufSysfsStats& stats) = 0; 61 }; 62 63 class CsvOutput final : public DmabufOutputHelper { 64 public: 65 // Table buffer x process BufTableMainHeaders()66 void BufTableMainHeaders() override { 67 printf("\"Dmabuf Inode\",\"Size(kB)\",\"Fd Ref Counts\",\"Map Ref Counts\""); 68 } BufTableProcessHeader(const pid_t pid,const std::string & process)69 void BufTableProcessHeader(const pid_t pid, const std::string& process) override { 70 printf(",\"%s:%d\"", process.c_str(), pid); 71 } 72 BufTableStats(const android::dmabufinfo::DmaBuffer & buf)73 void BufTableStats(const android::dmabufinfo::DmaBuffer& buf) override { 74 printf("%ju,%" PRIu64 ",%zu,%zu", static_cast<uintmax_t>(buf.inode()), buf.size() / 1024, 75 buf.fdrefs().size(), buf.maprefs().size()); 76 } BufTableProcessSize(int pid_fdrefs,int pid_maprefs)77 void BufTableProcessSize(int pid_fdrefs, int pid_maprefs) override { 78 if (pid_fdrefs || pid_maprefs) 79 printf(",\"%d(%d) refs\"", pid_fdrefs, pid_maprefs); 80 else 81 printf(",\"\""); 82 } 83 BufTableTotalHeader()84 void BufTableTotalHeader() override { printf("\"Total Size(kB)\","); } 85 BufTableTotalProcessHeader(const pid_t pid,const std::string & process)86 void BufTableTotalProcessHeader(const pid_t pid, const std::string& process) override { 87 printf("\"%s:%d size(kB)\",", process.c_str(), pid); 88 } 89 BufTableTotalStats(const uint64_t dmabuf_total_size)90 void BufTableTotalStats(const uint64_t dmabuf_total_size) override { 91 printf("\n%" PRIu64 "", dmabuf_total_size); 92 } 93 BufTableTotalProcessStats(const uint64_t pid_size)94 void BufTableTotalProcessStats(const uint64_t pid_size) override { 95 printf(",%" PRIu64 "", pid_size); 96 } 97 98 // Per Process PerProcessHeader(const std::string & process,const pid_t pid)99 void PerProcessHeader(const std::string& process, const pid_t pid) override { 100 printf("\t%s:%d\n", process.c_str(), pid); 101 printf("\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n", 102 "Name", "Rss(kB)", "Pss(kB)", "nr_procs", "Inode", "Exporter"); 103 } 104 PerProcessBufStats(const android::dmabufinfo::DmaBuffer & buf)105 void PerProcessBufStats(const android::dmabufinfo::DmaBuffer& buf) override { 106 printf("\"%s\",%" PRIu64 ",%" PRIu64 ",%zu,%" PRIuMAX ",%s" "\n", 107 buf.name().empty() ? "<unknown>" : buf.name().c_str(), buf.size() / 1024, 108 buf.Pss() / 1024, buf.pids().size(), static_cast<uintmax_t>(buf.inode()), 109 buf.exporter().empty() ? "<unknown>" : buf.exporter().c_str()); 110 } 111 PerProcessTotalStat(const uint64_t pss,const uint64_t rss)112 void PerProcessTotalStat(const uint64_t pss, const uint64_t rss) override { 113 printf("\nPROCESS TOTAL\n"); 114 printf("\"Rss total(kB)\",\"Pss total(kB)\"\n"); 115 printf("%" PRIu64 ",%" PRIu64 "\n", rss / 1024, pss / 1024); 116 } 117 TotalProcessesStats(const uint64_t & total_rss,const uint64_t & total_pss,const uint64_t & userspace_size,const uint64_t & kernel_rss)118 void TotalProcessesStats(const uint64_t& total_rss, const uint64_t& total_pss, 119 const uint64_t& userspace_size, const uint64_t& kernel_rss) override { 120 printf("\tTOTALS\n"); 121 // Headers 122 printf("\"dmabuf total (kB)\",\"kernel_rss (kB)\",\"userspace_rss " 123 "(kB)\",\"userspace_pss (kB)\"\n"); 124 // Stats 125 printf("%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 "\n", 126 (userspace_size + kernel_rss) / 1024, kernel_rss / 1024, total_rss / 1024, 127 total_pss / 1024); 128 } 129 130 // Per-buffer (Sysfs) PerBufferHeader()131 void PerBufferHeader() override { 132 printf("\"Dmabuf Inode\",\"Size(bytes)\",\"Exporter Name\"\n"); 133 } 134 PerBufferStats(const android::dmabufinfo::DmabufInfo & bufInfo)135 void PerBufferStats(const android::dmabufinfo::DmabufInfo& bufInfo) override { 136 printf("%lu,%" PRIu64 ",\"%s\"\n", bufInfo.inode, bufInfo.size, bufInfo.exp_name.c_str()); 137 } 138 ExporterHeader()139 void ExporterHeader() override { 140 printf("\"%s\",\"%s\",\"%s\"\n", "Exporter Name", "Total Count", "Total Size(bytes)"); 141 } 142 ExporterStats(const std::string & exporter,const android::dmabufinfo::DmabufTotal & dmaBufTotal)143 void ExporterStats(const std::string& exporter, 144 const android::dmabufinfo::DmabufTotal& dmaBufTotal) override { 145 printf("\"%s\",%u,%" PRIu64 "\n", exporter.c_str(), dmaBufTotal.buffer_count, 146 dmaBufTotal.size); 147 } 148 SysfsBufTotalStats(const android::dmabufinfo::DmabufSysfsStats & stats)149 void SysfsBufTotalStats(const android::dmabufinfo::DmabufSysfsStats& stats) override { 150 printf("\"%s\",\"%s\"\n", "Total DMA-BUF count", "Total DMA-BUF size(bytes)"); 151 printf("%u,%" PRIu64 "\n", stats.total_count(), stats.total_size()); 152 } 153 }; 154 155 class RawOutput final : public DmabufOutputHelper { 156 public: 157 // Table buffer x process BufTableMainHeaders()158 void BufTableMainHeaders() override { 159 printf(" Dmabuf Inode | Size | Fd Ref Counts | Map Ref Counts |"); 160 } BufTableProcessHeader(const pid_t pid,const std::string & process)161 void BufTableProcessHeader(const pid_t pid, const std::string& process) override { 162 printf("%16s:%-5d |", process.c_str(), pid); 163 } 164 BufTableStats(const android::dmabufinfo::DmaBuffer & buf)165 void BufTableStats(const android::dmabufinfo::DmaBuffer& buf) override { 166 printf("%16ju |%13" PRIu64 " kB |%16zu |%16zu |", static_cast<uintmax_t>(buf.inode()), 167 buf.size() / 1024, buf.fdrefs().size(), buf.maprefs().size()); 168 } 169 BufTableProcessSize(int pid_fdrefs,int pid_maprefs)170 void BufTableProcessSize(int pid_fdrefs, int pid_maprefs) override { 171 if (pid_fdrefs || pid_maprefs) 172 printf("%9d(%6d) refs |", pid_fdrefs, pid_maprefs); 173 else 174 printf("%22s |", "--"); 175 } 176 BufTableTotalStats(const uint64_t dmabuf_total_size)177 void BufTableTotalStats(const uint64_t dmabuf_total_size) override { 178 printf("%-16s %13" PRIu64 " kB |%16s |%16s |", "TOTALS", dmabuf_total_size, "n/a", "n/a"); 179 }; 180 BufTableTotalProcessStats(const uint64_t pid_size)181 void BufTableTotalProcessStats(const uint64_t pid_size) override { 182 printf("%19" PRIu64 " kB |", pid_size); 183 } 184 185 // PerProcess PerProcessHeader(const std::string & process,const pid_t pid)186 void PerProcessHeader(const std::string& process, const pid_t pid) override { 187 printf("%16s:%-5d\n", process.c_str(), pid); 188 printf("%22s %16s %16s %16s %16s %22s\n", 189 "Name", "Rss", "Pss", "nr_procs", "Inode", "Exporter"); 190 } 191 PerProcessBufStats(const android::dmabufinfo::DmaBuffer & buf)192 void PerProcessBufStats(const android::dmabufinfo::DmaBuffer& buf) override { 193 printf("%22s %13" PRIu64 " kB %13" PRIu64 " kB %16zu %16" PRIuMAX " %22s" "\n", 194 buf.name().empty() ? "<unknown>" : buf.name().c_str(), buf.size() / 1024, 195 buf.Pss() / 1024, buf.pids().size(), static_cast<uintmax_t>(buf.inode()), 196 buf.exporter().empty() ? "<unknown>" : buf.exporter().c_str()); 197 } PerProcessTotalStat(const uint64_t pss,const uint64_t rss)198 void PerProcessTotalStat(const uint64_t pss, const uint64_t rss) override { 199 printf("%22s %13" PRIu64 " kB %13" PRIu64 " kB %16s\n", "PROCESS TOTAL", rss / 1024, 200 pss / 1024, ""); 201 } 202 TotalProcessesStats(const uint64_t & total_rss,const uint64_t & total_pss,const uint64_t & userspace_size,const uint64_t & kernel_rss)203 void TotalProcessesStats(const uint64_t& total_rss, const uint64_t& total_pss, 204 const uint64_t& userspace_size, const uint64_t& kernel_rss) override { 205 printf("dmabuf total: %" PRIu64 " kB kernel_rss: %" PRIu64 " kB userspace_rss: %" PRIu64 206 " kB userspace_pss: %" PRIu64 " kB\n ", 207 (userspace_size + kernel_rss) / 1024, kernel_rss / 1024, total_rss / 1024, 208 total_pss / 1024); 209 } 210 211 // Per-buffer (Sysfs) PerBufferHeader()212 void PerBufferHeader() override { 213 printf(" Dmabuf Inode | Size(bytes) | Exporter Name |\n"); 214 } 215 PerBufferStats(const android::dmabufinfo::DmabufInfo & bufInfo)216 void PerBufferStats(const android::dmabufinfo::DmabufInfo& bufInfo) override { 217 printf("%16lu |%16" PRIu64 " | %16s \n", bufInfo.inode, bufInfo.size, 218 bufInfo.exp_name.c_str()); 219 } 220 ExporterHeader()221 void ExporterHeader() override { 222 printf(" Exporter Name | Total Count | Total Size(bytes) |\n"); 223 } ExporterStats(const std::string & exporter,const android::dmabufinfo::DmabufTotal & dmaBufTotal)224 void ExporterStats(const std::string& exporter, 225 const android::dmabufinfo::DmabufTotal& dmaBufTotal) override { 226 printf("%32s | %12u| %" PRIu64 "\n", exporter.c_str(), dmaBufTotal.buffer_count, 227 dmaBufTotal.size); 228 } 229 SysfsBufTotalStats(const android::dmabufinfo::DmabufSysfsStats & stats)230 void SysfsBufTotalStats(const android::dmabufinfo::DmabufSysfsStats& stats) override { 231 printf("Total DMA-BUF count: %u, Total DMA-BUF size(bytes): %" PRIu64 "\n", 232 stats.total_count(), stats.total_size()); 233 } 234 }; 235