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