blob: a2bb1dbb49042a119575d9aef55737d813fc7bc5 [file] [log] [blame]
Christopher Ferris72bbd422014-05-08 11:14:03 -07001/*
2 * Copyright (C) 2014 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
Christopher Ferrisa22f5d52019-03-01 16:40:59 -080017#include <errno.h>
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -070018#include <malloc.h>
Christopher Ferris03eebcb2014-06-13 13:57:51 -070019#include <sys/param.h>
Christopher Ferris72bbd422014-05-08 11:14:03 -070020#include <unistd.h>
21
Christopher Ferrise9a7b812023-05-11 15:36:27 -070022#include <async_safe/log.h>
Christopher Ferris6c619a02019-03-01 17:59:51 -080023#include <private/MallocXmlElem.h>
24
Christopher Ferris72bbd422014-05-08 11:14:03 -070025#include "jemalloc.h"
26
Christopher Ferrise9a7b812023-05-11 15:36:27 -070027__BEGIN_DECLS
28
29size_t je_mallinfo_narenas();
30size_t je_mallinfo_nbins();
31struct mallinfo je_mallinfo_arena_info(size_t);
32struct mallinfo je_mallinfo_bin_info(size_t, size_t);
33
34__END_DECLS
35
Christopher Ferris72bbd422014-05-08 11:14:03 -070036void* je_pvalloc(size_t bytes) {
Elliott Hughes91570ce2014-07-10 12:34:23 -070037 size_t pagesize = getpagesize();
Dan Alberta613d0d2017-10-05 16:39:33 -070038 size_t size = __BIONIC_ALIGN(bytes, pagesize);
Christopher Ferris03eebcb2014-06-13 13:57:51 -070039 if (size < bytes) {
Yi Kong32bc0fc2018-08-02 17:31:13 -070040 return nullptr;
Christopher Ferris03eebcb2014-06-13 13:57:51 -070041 }
42 return je_memalign(pagesize, size);
Christopher Ferris72bbd422014-05-08 11:14:03 -070043}
44
45#ifdef je_memalign
46#undef je_memalign
47#endif
48
49// The man page for memalign says it fails if boundary is not a power of 2,
50// but this is not true. Both glibc and dlmalloc round up to the next power
51// of 2, so we'll do the same.
52void* je_memalign_round_up_boundary(size_t boundary, size_t size) {
Christopher Ferris03eebcb2014-06-13 13:57:51 -070053 if (boundary != 0) {
54 if (!powerof2(boundary)) {
55 boundary = BIONIC_ROUND_UP_POWER_OF_2(boundary);
Christopher Ferris72bbd422014-05-08 11:14:03 -070056 }
57 } else {
58 boundary = 1;
59 }
60 return je_memalign(boundary, size);
61}
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -070062
Christopher Ferrisa22f5d52019-03-01 16:40:59 -080063#ifdef je_aligned_alloc
64#undef je_aligned_alloc
65#endif
66
67// The aligned_alloc function requires that size is a multiple of alignment.
68// jemalloc doesn't enforce this, so add enforcement here.
69void* je_aligned_alloc_wrapper(size_t alignment, size_t size) {
70 if ((size % alignment) != 0) {
71 errno = EINVAL;
72 return nullptr;
73 }
74 return je_aligned_alloc(alignment, size);
75}
76
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -070077int je_mallopt(int param, int value) {
78 // The only parameter we currently understand is M_DECAY_TIME.
79 if (param == M_DECAY_TIME) {
80 // Only support setting the value to 1 or 0.
Christopher Ferrisd73a49e2018-10-19 16:03:44 -070081 ssize_t decay_time_ms;
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -070082 if (value) {
Christopher Ferrisd73a49e2018-10-19 16:03:44 -070083 decay_time_ms = 1000;
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -070084 } else {
Christopher Ferrisd73a49e2018-10-19 16:03:44 -070085 decay_time_ms = 0;
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -070086 }
87 // First get the total number of arenas.
88 unsigned narenas;
89 size_t sz = sizeof(unsigned);
90 if (je_mallctl("arenas.narenas", &narenas, &sz, nullptr, 0) != 0) {
91 return 0;
92 }
93
94 // Set the decay time for any arenas that will be created in the future.
Christopher Ferrisd73a49e2018-10-19 16:03:44 -070095 if (je_mallctl("arenas.dirty_decay_ms", nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
96 return 0;
97 }
98 if (je_mallctl("arenas.muzzy_decay_ms", nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -070099 return 0;
100 }
101
102 // Change the decay on the already existing arenas.
103 char buffer[100];
104 for (unsigned i = 0; i < narenas; i++) {
Christopher Ferrisd73a49e2018-10-19 16:03:44 -0700105 snprintf(buffer, sizeof(buffer), "arena.%d.dirty_decay_ms", i);
106 if (je_mallctl(buffer, nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
107 break;
108 }
109 snprintf(buffer, sizeof(buffer), "arena.%d.muzzy_decay_ms", i);
110 if (je_mallctl(buffer, nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -0700111 break;
112 }
113 }
114 return 1;
Christopher Ferrisd86eb862023-02-28 12:45:54 -0800115 } else if (param == M_PURGE || param == M_PURGE_ALL) {
Christopher Ferris0f710fd2019-05-01 13:26:46 -0700116 // Only clear the current thread cache since there is no easy way to
117 // clear the caches of other threads.
118 // This must be done first so that cleared allocations get purged
119 // in the next calls.
Christopher Ferris3d0bafb2019-07-08 14:54:58 -0700120 // Ignore the return call since this will fail if the tcache is disabled.
121 je_mallctl("thread.tcache.flush", nullptr, nullptr, nullptr, 0);
Christopher Ferris0f710fd2019-05-01 13:26:46 -0700122
Tim Murrayac578f22018-10-15 16:26:56 -0700123 unsigned narenas;
124 size_t sz = sizeof(unsigned);
125 if (je_mallctl("arenas.narenas", &narenas, &sz, nullptr, 0) != 0) {
126 return 0;
127 }
128 char buffer[100];
129 snprintf(buffer, sizeof(buffer), "arena.%u.purge", narenas);
130 if (je_mallctl(buffer, nullptr, nullptr, nullptr, 0) != 0) {
131 return 0;
132 }
133 return 1;
Christopher Ferrise9a7b812023-05-11 15:36:27 -0700134 } else if (param == M_LOG_STATS) {
135 for (size_t i = 0; i < je_mallinfo_narenas(); i++) {
136 struct mallinfo mi = je_mallinfo_arena_info(i);
137 if (mi.hblkhd != 0) {
138 async_safe_format_log(ANDROID_LOG_INFO, "jemalloc",
139 "Arena %zu: large bytes %zu huge bytes %zu bin bytes %zu", i,
140 mi.ordblks, mi.uordblks, mi.fsmblks);
141
142 for (size_t j = 0; j < je_mallinfo_nbins(); j++) {
143 struct mallinfo mi = je_mallinfo_bin_info(i, j);
144 if (mi.ordblks != 0) {
145 size_t total_allocs = 1;
146 if (mi.uordblks > mi.fordblks) {
147 total_allocs = mi.uordblks - mi.fordblks;
148 }
149 size_t bin_size = mi.ordblks / total_allocs;
150 async_safe_format_log(
151 ANDROID_LOG_INFO, "jemalloc",
152 " Bin %zu (%zu bytes): allocated bytes %zu nmalloc %zu ndalloc %zu", j, bin_size,
153 mi.ordblks, mi.uordblks, mi.fordblks);
154 }
155 }
156 }
157 }
158 return 1;
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -0700159 }
Christopher Ferrise9a7b812023-05-11 15:36:27 -0700160
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -0700161 return 0;
162}
Christopher Ferris6c619a02019-03-01 17:59:51 -0800163
Christopher Ferris6c619a02019-03-01 17:59:51 -0800164int je_malloc_info(int options, FILE* fp) {
165 if (options != 0) {
166 errno = EINVAL;
167 return -1;
168 }
169
Christopher Ferrisff88fb02019-11-04 18:40:00 -0800170 fflush(fp);
171 int fd = fileno(fp);
172 MallocXmlElem root(fd, "malloc", "version=\"jemalloc-1\"");
Christopher Ferris6c619a02019-03-01 17:59:51 -0800173
174 // Dump all of the large allocations in the arenas.
Christopher Ferrisdb9706a2019-05-02 18:33:11 -0700175 for (size_t i = 0; i < je_mallinfo_narenas(); i++) {
176 struct mallinfo mi = je_mallinfo_arena_info(i);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800177 if (mi.hblkhd != 0) {
Christopher Ferrisff88fb02019-11-04 18:40:00 -0800178 MallocXmlElem arena_elem(fd, "heap", "nr=\"%d\"", i);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800179 {
Christopher Ferrisff88fb02019-11-04 18:40:00 -0800180 MallocXmlElem(fd, "allocated-large").Contents("%zu", mi.ordblks);
181 MallocXmlElem(fd, "allocated-huge").Contents("%zu", mi.uordblks);
182 MallocXmlElem(fd, "allocated-bins").Contents("%zu", mi.fsmblks);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800183
184 size_t total = 0;
Christopher Ferrisdb9706a2019-05-02 18:33:11 -0700185 for (size_t j = 0; j < je_mallinfo_nbins(); j++) {
186 struct mallinfo mi = je_mallinfo_bin_info(i, j);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800187 if (mi.ordblks != 0) {
Christopher Ferrisff88fb02019-11-04 18:40:00 -0800188 MallocXmlElem bin_elem(fd, "bin", "nr=\"%d\"", j);
189 MallocXmlElem(fd, "allocated").Contents("%zu", mi.ordblks);
190 MallocXmlElem(fd, "nmalloc").Contents("%zu", mi.uordblks);
191 MallocXmlElem(fd, "ndalloc").Contents("%zu", mi.fordblks);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800192 total += mi.ordblks;
193 }
194 }
Christopher Ferrisff88fb02019-11-04 18:40:00 -0800195 MallocXmlElem(fd, "bins-total").Contents("%zu", total);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800196 }
197 }
198 }
199
200 return 0;
201}