1 #include <fstream>
2 #include <sstream>
3 #include <regex>
4 #include <vector>
5 #include <algorithm>
6
7 #include <cerrno>
8 #include <sys/stat.h>
9
10 #include <hardware/memtrack.h>
11 #include <hardware/exynos/ion.h>
12
13 #include "memtrack_exynos.h"
14
15 using namespace std;
16
17 #define NUM_AVAILABLE_FLAGS 4U
18 static unsigned int available_flags [NUM_AVAILABLE_FLAGS] = {
19 MEMTRACK_FLAG_SMAPS_UNACCOUNTED | MEMTRACK_FLAG_SHARED_PSS | MEMTRACK_FLAG_SYSTEM | MEMTRACK_FLAG_NONSECURE,
20 MEMTRACK_FLAG_SMAPS_UNACCOUNTED | MEMTRACK_FLAG_SHARED_PSS | MEMTRACK_FLAG_DEDICATED | MEMTRACK_FLAG_NONSECURE,
21 MEMTRACK_FLAG_SMAPS_UNACCOUNTED | MEMTRACK_FLAG_SHARED_PSS | MEMTRACK_FLAG_SYSTEM | MEMTRACK_FLAG_SECURE,
22 MEMTRACK_FLAG_SMAPS_UNACCOUNTED | MEMTRACK_FLAG_SHARED_PSS | MEMTRACK_FLAG_DEDICATED| MEMTRACK_FLAG_SECURE,
23 };
24
25 struct DmabufBuffer {
26 unsigned int id;
27 unsigned int type;
28 size_t size;
29 size_t pss;
DmabufBufferDmabufBuffer30 DmabufBuffer(unsigned int _id, size_t _size, size_t _pss)
31 : id(_id), type(MEMTRACK_FLAG_SMAPS_UNACCOUNTED | MEMTRACK_FLAG_SHARED_PSS), size(_size), pss(_pss)
32 { }
setPoolTypeDmabufBuffer33 void setPoolType(string _type) { type |= (_type == "carveout") ? MEMTRACK_FLAG_DEDICATED : MEMTRACK_FLAG_SYSTEM; }
setFlagsDmabufBuffer34 void setFlags(unsigned int flags) { type |= (flags & ION_FLAG_PROTECTED) ? MEMTRACK_FLAG_SECURE : MEMTRACK_FLAG_NONSECURE; }
35 };
36
37 const char DMABUF_FOOTPRINT_PATH[] = "/sys/kernel/debug/dma_buf/footprint/";
build_dmabuf_footprint(vector<DmabufBuffer> & buffers,pid_t pid)38 static bool build_dmabuf_footprint(vector<DmabufBuffer> &buffers, pid_t pid)
39 {
40 ostringstream dmabuf_path;
41 dmabuf_path << DMABUF_FOOTPRINT_PATH << pid;
42
43 ifstream dmabuf(dmabuf_path.str());
44 if (!dmabuf)
45 return false;
46 //
47 // exp_name size share
48 // ion-102 69271552 34635776
49 regex rex("\\s*ion-(\\d+)\\s+(\\d+)\\s+(\\d+).*");
50 smatch mch;
51 // 1-id, 2-size, 3-pss
52 for (string line; getline(dmabuf, line); )
53 if (regex_match(line, mch, rex))
54 buffers.emplace_back(stoul(mch[1], 0, 10), stoul(mch[2], 0, 10), stoul(mch[3], 0, 10));
55
56 return true;
57 }
58
59 const char ION_BUFFERS_PATH[] = "/sys/kernel/debug/ion/buffers";
complete_dmabuf_footprint(int type,vector<DmabufBuffer> & buffers)60 static bool complete_dmabuf_footprint(int type, vector<DmabufBuffer> &buffers)
61 {
62 ifstream ion(ION_BUFFERS_PATH);
63 if (!ion)
64 return false;
65
66 // [ id] heap heaptype flags size(kb) : iommu_mapped...
67 // [ 106] ion_system_heap system 0x40 16912 : 19080000.dsim(0)
68 regex rexion("\\[ *(\\d+)\\] +[[:alnum:]\\-_]+ +(\\w+) +([x[:xdigit:]]+) +(\\d+).*");
69 smatch mch;
70 // 1-id, 2-heaptype, 3-flags, 4-size
71 for (string line; getline(ion, line); ) {
72 if (regex_match(line, mch, rexion)) {
73 unsigned int id = stoul(mch[1], 0, 10);
74 unsigned int flags = stoul(mch[3], 0, 16);
75 size_t len = stoul(mch[4], 0, 10) * 1024;
76 auto elem = find_if(begin(buffers), end(buffers), [id, len] (auto &item) {
77 return (item.id == id) && (item.size == len);
78 });
79 // passes if type = OTHER && not flag & hwrender or type == GRAPHIC && flag & hwrender
80 if ((elem != end(buffers)) && ((type == MEMTRACK_TYPE_OTHER) == !(flags & ION_FLAG_MAY_HWRENDER))) {
81 elem->setFlags(flags);
82 elem->setPoolType(mch[2]);
83 }
84 }
85 }
86
87 return true;
88 }
89
dmabuf_memtrack_get_memory(pid_t pid,int type,struct memtrack_record * records,size_t * num_records)90 int dmabuf_memtrack_get_memory(pid_t pid, int type, struct memtrack_record *records, size_t *num_records)
91 {
92 if ((type != MEMTRACK_TYPE_OTHER) && (type != MEMTRACK_TYPE_GRAPHICS))
93 return -ENODEV;
94
95 if (*num_records == 0) {
96 *num_records = NUM_AVAILABLE_FLAGS;
97 return 0;
98 }
99
100 *num_records = (*num_records < NUM_AVAILABLE_FLAGS) ? *num_records : NUM_AVAILABLE_FLAGS;
101
102 for (size_t i = 0; i < *num_records; i++) {
103 records[i].size_in_bytes = 0;
104 records[i].flags = available_flags[i];
105 }
106
107 vector<DmabufBuffer> buffers;
108
109 if (!build_dmabuf_footprint(buffers, pid))
110 return -ENODEV;
111
112 if (buffers.size() == 0)
113 return 0;
114
115 if (!complete_dmabuf_footprint(type, buffers))
116 return -ENODEV;
117
118 for (auto item: buffers) {
119 for (size_t i = 0; i < *num_records; i++) {
120 if (item.type == available_flags[i]) {
121 records[i].size_in_bytes += item.pss;
122 break;
123 }
124 }
125 }
126
127 return 0;
128 }
129