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