summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Cross2013-09-06 18:41:40 -0500
committerColin Cross2013-09-06 20:18:35 -0500
commitfc600e49bf9e0977b8e91642480e065bd95f2670 (patch)
tree1726cfb3ba8257f0f6155a25191be8fe1f51a2fb /libmemtrack
parentf34861346d5c207912075fba9874090e4c947869 (diff)
downloadplatform-system-core-fc600e49bf9e0977b8e91642480e065bd95f2670.tar.gz
platform-system-core-fc600e49bf9e0977b8e91642480e065bd95f2670.tar.xz
platform-system-core-fc600e49bf9e0977b8e91642480e065bd95f2670.zip
Initial libmemtrack
libmemtrack is an interface to a device-specific Memory Tracker HAL to account for memory that may not show up in the normal memory usage tools that walk /proc/pid/maps. Bug: 10294768 Change-Id: I436f6799898df0bf8bf29747be3bc9dea5721185
Diffstat (limited to 'libmemtrack')
-rw-r--r--libmemtrack/Android.mk20
-rw-r--r--libmemtrack/include/memtrack.h138
-rw-r--r--libmemtrack/memtrack.c200
-rw-r--r--libmemtrack/memtrack_test.c145
4 files changed, 503 insertions, 0 deletions
diff --git a/libmemtrack/Android.mk b/libmemtrack/Android.mk
new file mode 100644
index 000000000..c23b6f410
--- /dev/null
+++ b/libmemtrack/Android.mk
@@ -0,0 +1,20 @@
1# Copyright 2013 The Android Open Source Project
2
3LOCAL_PATH:= $(call my-dir)
4
5include $(CLEAR_VARS)
6LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
7LOCAL_SRC_FILES := memtrack.c
8LOCAL_MODULE := libmemtrack
9LOCAL_C_INCLUDES += $(LOCAL_PATH)/include hardware/libhardware/include
10LOCAL_SHARED_LIBRARIES := libhardware liblog
11LOCAL_CFLAGS := -Wall -Werror
12include $(BUILD_SHARED_LIBRARY)
13
14include $(CLEAR_VARS)
15LOCAL_SRC_FILES := memtrack_test.c
16LOCAL_MODULE := memtrack_test
17LOCAL_C_INCLUDES := $(call include-path-for, libpagemap)
18LOCAL_SHARED_LIBRARIES := libmemtrack libpagemap
19LOCAL_CFLAGS := -Wall -Werror
20include $(BUILD_EXECUTABLE)
diff --git a/libmemtrack/include/memtrack.h b/libmemtrack/include/memtrack.h
new file mode 100644
index 000000000..d6b370b22
--- /dev/null
+++ b/libmemtrack/include/memtrack.h
@@ -0,0 +1,138 @@
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#ifndef _LIBMEMTRACK_MEMTRACK_H_
18#define _LIBMEMTRACK_MEMTRACK_H_
19
20#include <sys/types.h>
21#include <stddef.h>
22
23/**
24 * struct memtrack_proc
25 *
26 * an opaque handle to the memory stats on a process.
27 * Created with memtrack_proc_new, destroyed by
28 * memtrack_proc_destroy. Can be reused multiple times with
29 * memtrack_proc_get.
30 */
31struct memtrack_proc;
32
33/**
34 * memtrack_init
35 *
36 * Must be called once before calling any other functions. After this function
37 * is called, everything else is thread-safe.
38 *
39 * Returns 0 on success, -errno on error.
40 */
41int memtrack_init(void);
42
43/**
44 * memtrack_proc_new
45 *
46 * Return a new handle to hold process memory stats.
47 *
48 * Returns NULL on error.
49 */
50struct memtrack_proc *memtrack_proc_new(void);
51
52/**
53 * memtrack_proc_destroy
54 *
55 * Free all memory associated with a process memory stats handle.
56 */
57void memtrack_proc_destroy(struct memtrack_proc *p);
58
59/**
60 * memtrack_proc_get
61 *
62 * Fill a process memory stats handle with data about the given pid. Can be
63 * called on a handle that was just allocated with memtrack_proc_new,
64 * or on a handle that has been previously passed to memtrack_proc_get
65 * to replace the data with new data on the same or another process. It is
66 * expected that the second call on the same handle should not require
67 * allocating any new memory.
68 *
69 * Returns 0 on success, -errno on error.
70 */
71int memtrack_proc_get(struct memtrack_proc *p, pid_t pid);
72
73/**
74 * memtrack_proc_graphics_total
75 *
76 * Return total amount of memory that has been allocated for use as window
77 * buffers. Does not differentiate between memory that has already been
78 * accounted for by reading /proc/pid/smaps and memory that has not been
79 * accounted for.
80 *
81 * Returns non-negative size in bytes on success, -errno on error.
82 */
83ssize_t memtrack_proc_graphics_total(struct memtrack_proc *p);
84
85/**
86 * memtrack_proc_graphics_pss
87 *
88 * Return total amount of memory that has been allocated for use as window
89 * buffers, but has not already been accounted for by reading /proc/pid/smaps.
90 * Memory that is shared across processes may already be divided by the
91 * number of processes that share it (preferred), or may be charged in full to
92 * every process that shares it, depending on the capabilities of the driver.
93 *
94 * Returns non-negative size in bytes on success, -errno on error.
95 */
96ssize_t memtrack_proc_graphics_pss(struct memtrack_proc *p);
97
98/**
99 * memtrack_proc_gl_total
100 *
101 * Same as memtrack_proc_graphics_total, but counts GL memory (which
102 * should not overlap with graphics memory) instead of graphics memory.
103 *
104 * Returns non-negative size in bytes on success, -errno on error.
105 */
106ssize_t memtrack_proc_gl_total(struct memtrack_proc *p);
107
108/**
109 * memtrack_proc_gl_pss
110 *
111 * Same as memtrack_proc_graphics_total, but counts GL memory (which
112 * should not overlap with graphics memory) instead of graphics memory.
113 *
114 * Returns non-negative size in bytes on success, -errno on error.
115 */
116ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p);
117
118/**
119 * memtrack_proc_gl_total
120 *
121 * Same as memtrack_proc_graphics_total, but counts miscellaneous memory
122 * not tracked by gl or graphics calls above.
123 *
124 * Returns non-negative size in bytes on success, -errno on error.
125 */
126ssize_t memtrack_proc_other_total(struct memtrack_proc *p);
127
128/**
129 * memtrack_proc_gl_pss
130 *
131 * Same as memtrack_proc_graphics_total, but counts miscellaneous memory
132 * not tracked by gl or graphics calls above.
133 *
134 * Returns non-negative size in bytes on success, -errno on error.
135 */
136ssize_t memtrack_proc_other_pss(struct memtrack_proc *p);
137
138#endif
diff --git a/libmemtrack/memtrack.c b/libmemtrack/memtrack.c
new file mode 100644
index 000000000..2b2651a28
--- /dev/null
+++ b/libmemtrack/memtrack.c
@@ -0,0 +1,200 @@
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.h>
18
19#define LOG_TAG "memtrack"
20
21#include <log/log.h>
22
23#include <hardware/memtrack.h>
24
25#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
26
27static const memtrack_module_t *module;
28
29struct memtrack_proc {
30 pid_t pid;
31 struct memtrack_proc_type {
32 enum memtrack_type type;
33 size_t num_records;
34 size_t allocated_records;
35 struct memtrack_record *records;
36 } types[MEMTRACK_NUM_TYPES];
37};
38
39int memtrack_init(void)
40{
41 int err;
42
43 if (module) {
44 return 0;
45 }
46
47 err = hw_get_module(MEMTRACK_HARDWARE_MODULE_ID,
48 (hw_module_t const**)&module);
49 if (err) {
50 ALOGE("Couldn't load %s module (%s)", MEMTRACK_HARDWARE_MODULE_ID,
51 strerror(-err));
52 return err;
53 }
54
55 return module->init(module);
56}
57
58struct memtrack_proc *memtrack_proc_new(void)
59{
60 if (!module) {
61 return NULL;
62 }
63
64 return calloc(sizeof(struct memtrack_proc), 1);
65}
66
67void memtrack_proc_destroy(struct memtrack_proc *p)
68{
69 enum memtrack_type i;
70
71 if (p) {
72 for (i = 0; i < MEMTRACK_NUM_TYPES; i++) {
73 free(p->types[i].records);
74 }
75 }
76 free(p);
77}
78
79static int memtrack_proc_get_type(struct memtrack_proc_type *t,
80 pid_t pid, enum memtrack_type type)
81{
82 size_t num_records = t->num_records;
83 int ret;
84
85retry:
86 ret = module->getMemory(module, pid, type, t->records, &num_records);
87 if (ret) {
88 t->num_records = 0;
89 return ret;
90 }
91 if (num_records > t->allocated_records) {
92 /* Need more records than allocated */
93 free(t->records);
94 t->records = calloc(sizeof(*t->records), num_records);
95 if (!t->records) {
96 return -ENOMEM;
97 }
98 t->allocated_records = num_records;
99 goto retry;
100 }
101 t->num_records = num_records;
102
103 return 0;
104}
105
106/* TODO: sanity checks on return values from HALs:
107 * make sure no records have invalid flags set
108 * - unknown flags
109 * - too many flags of a single category
110 * - missing ACCOUNTED/UNACCOUNTED
111 * make sure there are not overlapping SHARED and SHARED_PSS records
112 */
113static int memtrack_proc_sanity_check(struct memtrack_proc *p)
114{
115 (void)p;
116 return 0;
117}
118
119int memtrack_proc_get(struct memtrack_proc *p, pid_t pid)
120{
121 enum memtrack_type i;
122
123 if (!module) {
124 return -EINVAL;
125 }
126
127 if (!p) {
128 return -EINVAL;
129 }
130
131 p->pid = pid;
132 for (i = 0; i < MEMTRACK_NUM_TYPES; i++) {
133 memtrack_proc_get_type(&p->types[i], pid, i);
134 }
135
136 return memtrack_proc_sanity_check(p);
137}
138
139static ssize_t memtrack_proc_sum(struct memtrack_proc *p,
140 enum memtrack_type types[], size_t num_types,
141 unsigned int flags)
142{
143 ssize_t sum = 0;
144 size_t i;
145 size_t j;
146
147 for (i = 0; i < num_types; i++) {
148 enum memtrack_type type = types[i];
149 for (j = 0; j < p->types[type].num_records; j++) {
150 if ((p->types[type].records[j].flags & flags) == flags) {
151 sum += p->types[type].records[j].size_in_bytes;
152 }
153 }
154 }
155
156 return sum;
157}
158
159ssize_t memtrack_proc_graphics_total(struct memtrack_proc *p)
160{
161 enum memtrack_type types[] = { MEMTRACK_TYPE_GRAPHICS };
162 return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
163}
164
165ssize_t memtrack_proc_graphics_pss(struct memtrack_proc *p)
166{
167 enum memtrack_type types[] = { MEMTRACK_TYPE_GRAPHICS };
168 return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
169 MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
170}
171
172ssize_t memtrack_proc_gl_total(struct memtrack_proc *p)
173{
174 enum memtrack_type types[] = { MEMTRACK_TYPE_GL };
175 return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
176}
177
178ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p)
179{
180 enum memtrack_type types[] = { MEMTRACK_TYPE_GL };
181 return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
182 MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
183}
184
185ssize_t memtrack_proc_other_total(struct memtrack_proc *p)
186{
187 enum memtrack_type types[] = { MEMTRACK_TYPE_MULTIMEDIA,
188 MEMTRACK_TYPE_CAMERA,
189 MEMTRACK_TYPE_OTHER };
190 return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
191}
192
193ssize_t memtrack_proc_other_pss(struct memtrack_proc *p)
194{
195 enum memtrack_type types[] = { MEMTRACK_TYPE_MULTIMEDIA,
196 MEMTRACK_TYPE_CAMERA,
197 MEMTRACK_TYPE_OTHER };
198 return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
199 MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
200}
diff --git a/libmemtrack/memtrack_test.c b/libmemtrack/memtrack_test.c
new file mode 100644
index 000000000..f306f67f1
--- /dev/null
+++ b/libmemtrack/memtrack_test.c
@@ -0,0 +1,145 @@
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 <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/types.h>
21
22#include <memtrack.h>
23
24#include <pagemap/pagemap.h>
25
26#define DIV_ROUND_UP(x,y) (((x) + (y) - 1) / (y))
27
28static int getprocname(pid_t pid, char *buf, int len) {
29 char *filename;
30 FILE *f;
31 int rc = 0;
32 static const char* unknown_cmdline = "<unknown>";
33
34 if (len <= 0) {
35 return -1;
36 }
37
38 if (asprintf(&filename, "/proc/%zd/cmdline", pid) < 0) {
39 rc = 1;
40 goto exit;
41 }
42
43 f = fopen(filename, "r");
44 if (f == NULL) {
45 rc = 2;
46 goto releasefilename;
47 }
48
49 if (fgets(buf, len, f) == NULL) {
50 rc = 3;
51 goto closefile;
52 }
53
54closefile:
55 (void) fclose(f);
56releasefilename:
57 free(filename);
58exit:
59 if (rc != 0) {
60 /*
61 * The process went away before we could read its process name. Try
62 * to give the user "<unknown>" here, but otherwise they get to look
63 * at a blank.
64 */
65 if (strlcpy(buf, unknown_cmdline, (size_t)len) >= (size_t)len) {
66 rc = 4;
67 }
68 }
69
70 return rc;
71}
72
73int main(int argc, char *argv[])
74{
75 int ret;
76 pm_kernel_t *ker;
77 size_t num_procs;
78 pid_t *pids;
79 struct memtrack_proc *p;
80 size_t i;
81
82 (void)argc;
83 (void)argv;
84
85 ret = memtrack_init();
86 if (ret < 0) {
87 fprintf(stderr, "failed to initialize HAL: %s (%d)\n", strerror(-ret), ret);
88 exit(EXIT_FAILURE);
89 }
90
91 ret = pm_kernel_create(&ker);
92 if (ret) {
93 fprintf(stderr, "Error creating kernel interface -- "
94 "does this kernel have pagemap?\n");
95 exit(EXIT_FAILURE);
96 }
97
98 ret = pm_kernel_pids(ker, &pids, &num_procs);
99 if (ret) {
100 fprintf(stderr, "Error listing processes.\n");
101 exit(EXIT_FAILURE);
102 }
103
104 p = memtrack_proc_new();
105 if (ret) {
106 fprintf(stderr, "failed to create memtrack process handle\n");
107 exit(EXIT_FAILURE);
108 }
109
110 for (i = 0; i < num_procs; i++) {
111 pid_t pid = pids[i];
112 char cmdline[256];
113 size_t v1;
114 size_t v2;
115 size_t v3;
116 size_t v4;
117 size_t v5;
118 size_t v6;
119
120 getprocname(pid, cmdline, (int)sizeof(cmdline));
121
122 ret = memtrack_proc_get(p, pid);
123 if (ret) {
124 fprintf(stderr, "failed to get memory info for pid %d: %s (%d)\n",
125 pid, strerror(-ret), ret);
126 continue;
127 }
128
129 v1 = DIV_ROUND_UP(memtrack_proc_graphics_total(p), 1024);
130 v2 = DIV_ROUND_UP(memtrack_proc_graphics_pss(p), 1024);
131 v3 = DIV_ROUND_UP(memtrack_proc_gl_total(p), 1024);
132 v4 = DIV_ROUND_UP(memtrack_proc_gl_pss(p), 1024);
133 v5 = DIV_ROUND_UP(memtrack_proc_other_total(p), 1024);
134 v6 = DIV_ROUND_UP(memtrack_proc_other_pss(p), 1024);
135
136 if (v1 | v2 | v3 | v4 | v5 | v6) {
137 printf("%5d %6zu %6zu %6zu %6zu %6zu %6zu %s\n", pid,
138 v1, v2, v3, v4, v5, v6, cmdline);
139 }
140 }
141
142 memtrack_proc_destroy(p);
143
144 return 0;
145}