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 <memtrack/memtrack.h>
18
19 #define LOG_TAG "memtrack"
20
21 #include <log/log.h>
22
23 #include <errno.h>
24 #include <malloc.h>
25 #include <string.h>
26
27 #include <hardware/memtrack.h>
28
29 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
30
31 static const memtrack_module_t *module;
32
33 struct memtrack_proc {
34 pid_t pid;
35 struct memtrack_proc_type {
36 enum memtrack_type type;
37 size_t num_records;
38 size_t allocated_records;
39 struct memtrack_record *records;
40 } types[MEMTRACK_NUM_TYPES];
41 };
42
memtrack_init(void)43 int memtrack_init(void)
44 {
45 int err;
46
47 if (module) {
48 return 0;
49 }
50
51 err = hw_get_module(MEMTRACK_HARDWARE_MODULE_ID,
52 (hw_module_t const**)&module);
53 if (err) {
54 ALOGE("Couldn't load %s module (%s)", MEMTRACK_HARDWARE_MODULE_ID,
55 strerror(-err));
56 return err;
57 }
58
59 return module->init(module);
60 }
61
memtrack_proc_new(void)62 struct memtrack_proc *memtrack_proc_new(void)
63 {
64 if (!module) {
65 return NULL;
66 }
67
68 return calloc(sizeof(struct memtrack_proc), 1);
69 }
70
memtrack_proc_destroy(struct memtrack_proc * p)71 void memtrack_proc_destroy(struct memtrack_proc *p)
72 {
73 enum memtrack_type i;
74
75 if (p) {
76 for (i = 0; i < MEMTRACK_NUM_TYPES; i++) {
77 free(p->types[i].records);
78 }
79 }
80 free(p);
81 }
82
memtrack_proc_get_type(struct memtrack_proc_type * t,pid_t pid,enum memtrack_type type)83 static int memtrack_proc_get_type(struct memtrack_proc_type *t,
84 pid_t pid, enum memtrack_type type)
85 {
86 size_t num_records = t->num_records;
87 int ret;
88
89 retry:
90 ret = module->getMemory(module, pid, type, t->records, &num_records);
91 if (ret) {
92 t->num_records = 0;
93 return ret;
94 }
95 if (num_records > t->allocated_records) {
96 /* Need more records than allocated */
97 free(t->records);
98 t->records = calloc(sizeof(*t->records), num_records);
99 if (!t->records) {
100 return -ENOMEM;
101 }
102 t->allocated_records = num_records;
103 goto retry;
104 }
105 t->num_records = num_records;
106
107 return 0;
108 }
109
110 /* TODO: sanity checks on return values from HALs:
111 * make sure no records have invalid flags set
112 * - unknown flags
113 * - too many flags of a single category
114 * - missing ACCOUNTED/UNACCOUNTED
115 * make sure there are not overlapping SHARED and SHARED_PSS records
116 */
memtrack_proc_sanity_check(struct memtrack_proc * p)117 static int memtrack_proc_sanity_check(struct memtrack_proc *p)
118 {
119 (void)p;
120 return 0;
121 }
122
memtrack_proc_get(struct memtrack_proc * p,pid_t pid)123 int memtrack_proc_get(struct memtrack_proc *p, pid_t pid)
124 {
125 enum memtrack_type i;
126
127 if (!module) {
128 return -EINVAL;
129 }
130
131 if (!p) {
132 return -EINVAL;
133 }
134
135 p->pid = pid;
136 for (i = 0; i < MEMTRACK_NUM_TYPES; i++) {
137 memtrack_proc_get_type(&p->types[i], pid, i);
138 }
139
140 return memtrack_proc_sanity_check(p);
141 }
142
memtrack_proc_sum(struct memtrack_proc * p,enum memtrack_type types[],size_t num_types,unsigned int flags)143 static ssize_t memtrack_proc_sum(struct memtrack_proc *p,
144 enum memtrack_type types[], size_t num_types,
145 unsigned int flags)
146 {
147 ssize_t sum = 0;
148 size_t i;
149 size_t j;
150
151 for (i = 0; i < num_types; i++) {
152 enum memtrack_type type = types[i];
153 for (j = 0; j < p->types[type].num_records; j++) {
154 if ((p->types[type].records[j].flags & flags) == flags) {
155 sum += p->types[type].records[j].size_in_bytes;
156 }
157 }
158 }
159
160 return sum;
161 }
162
memtrack_proc_graphics_total(struct memtrack_proc * p)163 ssize_t memtrack_proc_graphics_total(struct memtrack_proc *p)
164 {
165 enum memtrack_type types[] = { MEMTRACK_TYPE_GRAPHICS };
166 return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
167 }
168
memtrack_proc_graphics_pss(struct memtrack_proc * p)169 ssize_t memtrack_proc_graphics_pss(struct memtrack_proc *p)
170 {
171 enum memtrack_type types[] = { MEMTRACK_TYPE_GRAPHICS };
172 return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
173 MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
174 }
175
memtrack_proc_gl_total(struct memtrack_proc * p)176 ssize_t memtrack_proc_gl_total(struct memtrack_proc *p)
177 {
178 enum memtrack_type types[] = { MEMTRACK_TYPE_GL };
179 return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
180 }
181
memtrack_proc_gl_pss(struct memtrack_proc * p)182 ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p)
183 {
184 enum memtrack_type types[] = { MEMTRACK_TYPE_GL };
185 return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
186 MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
187 }
188
memtrack_proc_other_total(struct memtrack_proc * p)189 ssize_t memtrack_proc_other_total(struct memtrack_proc *p)
190 {
191 enum memtrack_type types[] = { MEMTRACK_TYPE_MULTIMEDIA,
192 MEMTRACK_TYPE_CAMERA,
193 MEMTRACK_TYPE_OTHER };
194 return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
195 }
196
memtrack_proc_other_pss(struct memtrack_proc * p)197 ssize_t memtrack_proc_other_pss(struct memtrack_proc *p)
198 {
199 enum memtrack_type types[] = { MEMTRACK_TYPE_MULTIMEDIA,
200 MEMTRACK_TYPE_CAMERA,
201 MEMTRACK_TYPE_OTHER };
202 return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
203 MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
204 }
205