1 /*
2 * Copyright (C) 2013 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 #include <errno.h>
18 #include <stdbool.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <sys/mman.h>
22 #include <log/log.h>
23
24 #include <hardware/memtrack.h>
25
26 #include "memtrack_exynos.h"
27
28 /* Following includes added for directory parsing. */
29 #include <sys/types.h>
30 #include <dirent.h>
31
32 /* Some general defines. */
33 #define MALI_DEBUG_FS_PATH "/d/mali/mem/"
34 #define MALI_DEBUG_MEM_FILE "/mem_profile"
35
36 #define MAX_FILES_PER_PID 8
37 #define MAX_FILES_PER_NAME 32
38 static int libmemtrack_gbl_input_filename_counter = 0;
39 static char libmemtrack_gbl_input_filename[MAX_FILES_PER_PID][MAX_FILES_PER_NAME];
40
41 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
42 #define min(x, y) ((x) < (y) ? (x) : (y))
43
44 struct memtrack_record record_templates[] = {
45 {
46 .flags = MEMTRACK_FLAG_SMAPS_ACCOUNTED |
47 MEMTRACK_FLAG_PRIVATE |
48 MEMTRACK_FLAG_NONSECURE,
49 },
50 {
51 .flags = MEMTRACK_FLAG_SMAPS_UNACCOUNTED |
52 MEMTRACK_FLAG_PRIVATE |
53 MEMTRACK_FLAG_NONSECURE,
54 },
55 };
56
scan_directory_for_filenames(pid_t pid)57 static void scan_directory_for_filenames(pid_t pid)
58 {
59 /* As per ARM, there can be multiple files */
60 DIR *directory;
61 struct dirent *entries;
62 char pid_string[12] = {0};
63 int pid_index = 0;
64
65 /* Open directory. */
66 directory = opendir(MALI_DEBUG_FS_PATH);
67
68 sprintf(pid_string, "%d", pid);
69 for (pid_index = 0; pid_index < 12; pid_index++) {
70 if (pid_string[pid_index] == 0) {
71 pid_string[pid_index] = '_';
72 break;
73 }
74 }
75
76 libmemtrack_gbl_input_filename_counter = 0;
77
78 if (directory != NULL) {
79 /* Keep reading the directory. */
80 while ((entries = readdir(directory))) {
81 /* Check if the PID is present in the direcotry entry.
82 * If it is present, then keep the filename for reading
83 * contents. Also concatenate the directory path, so that
84 * file can be opened.
85 * */
86 if (!strncmp(entries->d_name, pid_string, strlen(pid_string))) {
87 snprintf(&libmemtrack_gbl_input_filename[libmemtrack_gbl_input_filename_counter][0], MAX_FILES_PER_NAME, "%s%s%s", MALI_DEBUG_FS_PATH, entries->d_name, MALI_DEBUG_MEM_FILE);
88 libmemtrack_gbl_input_filename_counter++;
89 }
90 }
91 /* Close directory before leaving. */
92 (void) closedir(directory);
93 } else {
94 ALOGE("libmemtrack-hw -- Couldn't open the directory - %s \r\n", MALI_DEBUG_FS_PATH);
95 }
96
97 return;
98 }
99
mali_memtrack_get_memory(pid_t pid,int __unused type,struct memtrack_record * records,size_t * num_records)100 int mali_memtrack_get_memory(pid_t pid, int __unused type,
101 struct memtrack_record *records,
102 size_t *num_records)
103 {
104 size_t allocated_records = min(*num_records, ARRAY_SIZE(record_templates));
105 FILE *fp;
106 int local_count;
107 long long int temp_val = 0, total_memory_size = 0, native_buf_mem_size = 0;
108 bool native_buffer_read = false;
109 char line[1024] = {0};
110
111 *num_records = ARRAY_SIZE(record_templates);
112
113 /* fastpath to return the necessary number of records */
114 if (allocated_records == 0) {
115 return 0;
116 }
117
118 memcpy(records, record_templates,
119 sizeof(struct memtrack_record) * allocated_records);
120
121 /* First, scan the directoy. */
122 scan_directory_for_filenames(pid);
123
124 local_count = 0;
125 total_memory_size = 0;
126 native_buf_mem_size = 0;
127
128 while (local_count < libmemtrack_gbl_input_filename_counter) {
129 fp = fopen(&libmemtrack_gbl_input_filename[local_count][0], "r");
130
131 if (fp == NULL) {
132 /* Unable to open the file. Either move to next file, or
133 * return to caller. */
134 local_count++;
135 continue;
136 }
137
138 while (1) {
139 char memory_type[16] = {0};
140 char memory_type_2[16] = {0};
141 int ret = 0;
142
143 if (native_buffer_read == false) {
144 if (fgets(line, sizeof(line), fp) == NULL) {
145 if (native_buffer_read == false) {
146 /* Unable to read Native buffer.
147 * Probably DDK doesn't support Native Buffer.
148 * Reset to start of file and look for Total
149 * Memory. */
150 fseek(fp, 0, SEEK_SET);
151
152 /* Also, set Native buffer flag and memory sizes. */
153 native_buffer_read = true;
154 continue;
155 }
156 }
157
158 /* Search for Total memory. */
159 /* Format:
160 *
161 * Channel: Native Buffer (Total memory: 44285952)
162 *
163 */
164 ret = sscanf(line, "%*s %15s %15s %*s %*s %lld \n", memory_type, memory_type_2, &temp_val);
165
166 if (ret != 3)
167 continue;
168
169 if ((strcmp(memory_type, "Native") == 0) &&
170 (strcmp(memory_type_2, "Buffer") == 0)) {
171 /* Set native buffer memory read flag to true. */
172 native_buffer_read = true;
173 if ((INT64_MAX - temp_val) > native_buf_mem_size)
174 native_buf_mem_size += temp_val;
175 else
176 native_buf_mem_size = INT64_MAX;
177 } else {
178 /* Ignore case. Nothing to do here. */
179 /* Continue reading file until NativeBuffer is found. */
180 }
181 } else {
182 if (fgets(line, sizeof(line), fp) == NULL) {
183 /* Unable to find, so break the loop here.*/
184 break;
185 }
186
187 /* Search for Total memory. */
188 /* Format:
189 *
190 * Total allocated memory: 36146960
191 *
192 */
193 ret = sscanf(line, "%15s %*s %*s %lld \n", memory_type, &temp_val);
194
195 if (ret != 2)
196 continue;
197
198 if (strcmp(memory_type, "Total") == 0) {
199 /* Store total memory. */
200 if ((INT64_MAX - temp_val) > total_memory_size)
201 total_memory_size += temp_val;
202 else
203 total_memory_size = INT64_MAX;
204 } else {
205 /* Ignore case. Nothing to do here. */
206 }
207 } /* end if (native_buffer_read == false) */
208
209 } /* End while(1) */
210
211 if (fp != NULL) {
212 /* Close the opened file. */
213 fclose(fp);
214
215 /* Reset some of the local variables here. */
216 fp = NULL;
217 native_buffer_read = false;
218 }
219
220 /* Manage local variables and counters. */
221 local_count++;
222
223 } /* while (local_count <= libmemtrack_gbl_input_filename_counter) */
224
225 /* Arrange and return memory size details. */
226 if (allocated_records > 0)
227 records[0].size_in_bytes = 0;
228
229 if (allocated_records > 1)
230 {
231 if (native_buf_mem_size >= 0 && total_memory_size > native_buf_mem_size)
232 records[1].size_in_bytes = total_memory_size - native_buf_mem_size;
233 else
234 records[1].size_in_bytes = 0;
235 }
236
237 return 0;
238 }
239