blob: 671c519c7007b9774c18b76ffaa8c3d45784e874
1 | /* |
2 | * Copyright (c) 2017 Amlogic, Inc. All rights reserved. |
3 | * |
4 | * This source code is subject to the terms and conditions defined in the |
5 | * file 'LICENSE' which is part of this source code package. |
6 | * |
7 | * Description: |
8 | * used for memory track. |
9 | */ |
10 | |
11 | #define LOG_TAG "memtrack_aml" |
12 | #include <errno.h> |
13 | #include <stdio.h> |
14 | #include <stdlib.h> |
15 | #include <string.h> |
16 | #include <fcntl.h> |
17 | #include <ctype.h> |
18 | #include <inttypes.h> |
19 | #include <dirent.h> |
20 | #include <stdint.h> |
21 | |
22 | #include <hardware/memtrack.h> |
23 | #include <log/log.h> |
24 | |
25 | #define DEBUG 0 |
26 | #define VMALLOCION "/proc/ion/vmalloc_ion" |
27 | #define GPUT8X "/sys/kernel/debug/mali0/ctx" |
28 | #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) |
29 | |
30 | static struct hw_module_methods_t memtrack_module_methods = { |
31 | .open = NULL, |
32 | }; |
33 | |
34 | struct memtrack_record record_templates[] = { |
35 | { |
36 | .flags = MEMTRACK_FLAG_SMAPS_UNACCOUNTED | |
37 | MEMTRACK_FLAG_PRIVATE | |
38 | MEMTRACK_FLAG_NONSECURE, |
39 | }, |
40 | |
41 | /* |
42 | { |
43 | .flags = MEMTRACK_FLAG_SMAPS_ACCOUNTED | |
44 | MEMTRACK_FLAG_PRIVATE | |
45 | MEMTRACK_FLAG_NONSECURE, |
46 | }, |
47 | */ |
48 | }; |
49 | |
50 | // just return 0 |
51 | int aml_memtrack_init(const struct memtrack_module *module) |
52 | { |
53 | return 0; |
54 | } |
55 | |
56 | /* |
57 | * find the userid of process @pid |
58 | * return the userid if success, or return -1 if not |
59 | */ |
60 | static int memtrack_find_userid(int pid) |
61 | { |
62 | FILE *fp; |
63 | char line[1024]; |
64 | char tmp[128]; |
65 | int userid; |
66 | |
67 | sprintf(tmp, "/proc/%d/status", pid); |
68 | if ((fp=fopen(tmp, "r")) == NULL) { |
69 | if (DEBUG) ALOGD("open file %s error %s", tmp, strerror(errno)); |
70 | return -1; |
71 | } |
72 | |
73 | while (fgets(line, sizeof(line), fp) != NULL) { |
74 | if (sscanf(line, "Uid: %d", &userid) == 1) { |
75 | fclose(fp); |
76 | return userid; |
77 | } |
78 | } |
79 | |
80 | // should never reach here |
81 | fclose(fp); |
82 | return -1; |
83 | } |
84 | |
85 | static unsigned int memtrack_read_smaps(FILE *fp) |
86 | { |
87 | char line[1024]; |
88 | unsigned int size, sum = 0; |
89 | int skip, done = 0; |
90 | |
91 | uint64_t start; |
92 | uint64_t end = 0; |
93 | int len; |
94 | char *name; |
95 | int nameLen, name_pos; |
96 | |
97 | if(fgets(line, sizeof(line), fp) == 0) { |
98 | return 0; |
99 | } |
100 | |
101 | while (!done) { |
102 | skip = 0; |
103 | |
104 | len = strlen(line); |
105 | if (len < 1) |
106 | return 0; |
107 | |
108 | line[--len] = 0; |
109 | |
110 | if (sscanf(line, "%"SCNx64 "-%"SCNx64 " %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) { |
111 | skip = 1; |
112 | } else { |
113 | while (isspace(line[name_pos])) { |
114 | name_pos += 1; |
115 | } |
116 | name = line + name_pos; |
117 | nameLen = strlen(name); |
118 | |
119 | if (nameLen >= 8 && |
120 | (!strncmp(name, "/dev/mali", 6) || !strncmp(name, "/dev/ump", 6))) { |
121 | skip = 0; |
122 | } else { |
123 | skip = 1; |
124 | } |
125 | |
126 | } |
127 | |
128 | while (1) { |
129 | if (fgets(line, 1024, fp) == 0) { |
130 | done = 1; |
131 | break; |
132 | } |
133 | |
134 | if(!skip) { |
135 | if (line[0] == 'S' && sscanf(line, "Size: %d kB", &size) == 1) { |
136 | sum += size; |
137 | } |
138 | } |
139 | |
140 | if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d", &start, &end) == 2) { |
141 | // looks like a new mapping |
142 | // example: "10000000-10001000 ---p 10000000 00:00 0" |
143 | break; |
144 | } |
145 | } |
146 | } |
147 | |
148 | // converted into Bytes |
149 | return (sum * 1024); |
150 | } |
151 | |
152 | // mali t82x t83x |
153 | static int memtrack_get_gpuT8X(char *path) |
154 | { |
155 | FILE *file; |
156 | char line[1024]; |
157 | |
158 | int gpu_size = 0; |
159 | |
160 | if ((file = fopen(path, "r")) == NULL) { |
161 | if (DEBUG) ALOGD("open file %s error %s", path, strerror(errno)); |
162 | return 0; |
163 | } |
164 | |
165 | while (fgets(line, sizeof(line), file) != NULL) { |
166 | if (sscanf(line, "Total allocated memory: %d", &gpu_size) != 1) |
167 | continue; |
168 | else |
169 | break; |
170 | } |
171 | fclose(file); |
172 | return gpu_size; |
173 | } |
174 | |
175 | static unsigned int memtrack_get_gpuMem(int pid) |
176 | { |
177 | FILE *fp; |
178 | char *cp, tmp[128]; |
179 | unsigned int result; |
180 | |
181 | DIR *gpudir; |
182 | struct dirent *dir; |
183 | int gpid = -1; |
184 | |
185 | gpudir = opendir(GPUT8X); |
186 | if (!gpudir) { |
187 | if (DEBUG) |
188 | ALOGD("open %s error %s\n", GPUT8X, strerror(errno)); |
189 | sprintf(tmp, "/proc/%d/smaps", pid); |
190 | fp = fopen(tmp, "r"); |
191 | if (fp == NULL) { |
192 | if (DEBUG) ALOGD("open file %s error %s", tmp, strerror(errno)); |
193 | return 0; |
194 | } |
195 | result = memtrack_read_smaps(fp); |
196 | |
197 | fclose(fp); |
198 | return result; |
199 | } else { |
200 | while ((dir = readdir(gpudir))) { |
201 | strcpy(tmp, dir->d_name); |
202 | if ((cp=strchr(tmp, '_'))) { |
203 | *cp = '\0'; |
204 | gpid = atoi(tmp); |
205 | if (gpid == pid) { |
206 | sprintf(tmp, GPUT8X"/%s/%s", dir->d_name, "mem_profile"); |
207 | result = memtrack_get_gpuT8X(tmp); |
208 | closedir(gpudir); |
209 | return result; |
210 | } |
211 | } |
212 | } |
213 | closedir(gpudir); |
214 | } |
215 | return 0; |
216 | } |
217 | |
218 | static int memtrack_get_memory(pid_t pid, enum memtrack_type type, |
219 | struct memtrack_record *records, |
220 | size_t *num_records) |
221 | { |
222 | FILE *fp; |
223 | FILE *ion_fp; |
224 | char line[1024]; |
225 | char tmp[128]; |
226 | unsigned int mali_inuse = 0; |
227 | unsigned int size; |
228 | size_t unaccounted_size = 0; |
229 | |
230 | char ion_name[128]; |
231 | int ion_pid; |
232 | unsigned int ion_size; |
233 | unsigned int gpu_size; |
234 | |
235 | |
236 | // ALOGD("type is %d, pid is %d\n", type, pid); |
237 | size_t allocated_records = ARRAY_SIZE(record_templates); |
238 | *num_records = ARRAY_SIZE(record_templates); |
239 | |
240 | if (records == NULL) { |
241 | return 0; |
242 | } |
243 | |
244 | memcpy(records, record_templates, sizeof(struct memtrack_record) * allocated_records); |
245 | |
246 | if (type == MEMTRACK_TYPE_GL) { |
247 | // find the user id of the process, only support calculate the non root process |
248 | int ret = memtrack_find_userid(pid); |
249 | if (ret <= 0) { |
250 | return -1; |
251 | } |
252 | gpu_size = memtrack_get_gpuMem(pid); |
253 | unaccounted_size += gpu_size; |
254 | } else if (type == MEMTRACK_TYPE_GRAPHICS) { |
255 | sprintf(tmp, VMALLOCION); |
256 | if ((ion_fp = fopen(tmp, "r")) == NULL) { |
257 | if (DEBUG) ALOGD("open file %s error %s", tmp, strerror(errno)); |
258 | return -errno; |
259 | } |
260 | |
261 | while(fgets(line, sizeof(line), ion_fp) != NULL) { |
262 | if (sscanf(line, "%s%d%u", ion_name, &ion_pid, &ion_size) != 3) { |
263 | continue; |
264 | } else { |
265 | if (ion_pid == pid) { |
266 | unaccounted_size += ion_size; |
267 | } |
268 | } |
269 | |
270 | } |
271 | |
272 | fclose(ion_fp); |
273 | } |
274 | |
275 | if (allocated_records > 0) { |
276 | records[0].size_in_bytes = unaccounted_size; |
277 | // ALOGD("graphic %u\n", unaccounted_size); |
278 | } |
279 | |
280 | return 0; |
281 | } |
282 | |
283 | int aml_memtrack_get_memory(const struct memtrack_module *module, |
284 | pid_t pid, |
285 | int type, |
286 | struct memtrack_record *records, |
287 | size_t *num_records) |
288 | { |
289 | if (pid <= 0) |
290 | return -EINVAL; |
291 | |
292 | if (type == MEMTRACK_TYPE_GL || type == MEMTRACK_TYPE_GRAPHICS) |
293 | return memtrack_get_memory(pid, type, records, num_records); |
294 | else |
295 | return -ENODEV; |
296 | } |
297 | |
298 | |
299 | struct memtrack_module HAL_MODULE_INFO_SYM = { |
300 | common: { |
301 | tag: HARDWARE_MODULE_TAG, |
302 | module_api_version: MEMTRACK_MODULE_API_VERSION_0_1, |
303 | hal_api_version: HARDWARE_HAL_API_VERSION, |
304 | id: MEMTRACK_HARDWARE_MODULE_ID, |
305 | name: "aml Memory Tracker HAL", |
306 | author: "amlogic", |
307 | methods: &memtrack_module_methods, |
308 | }, |
309 | |
310 | init: aml_memtrack_init, |
311 | getMemory: aml_memtrack_get_memory, |
312 | }; |
313 |