blob: 1bbdb296cdb94f9c15a87d183dedbb97069d80aa [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) {
Chia-hung Duan6abb4062024-04-17 19:08:48 -070080 // Only support setting the value to -1 or 0 or 1.
Christopher Ferrisd73a49e2018-10-19 16:03:44 -070081 ssize_t decay_time_ms;
Chia-hung Duan6abb4062024-04-17 19:08:48 -070082 if (value < 0) {
83 // Given that SSIZE_MAX may not be supported in jemalloc, set this to a
84 // sufficiently large number that essentially disables the decay timer.
85 decay_time_ms = 10000000;
86 } else if (value) {
Christopher Ferrisd73a49e2018-10-19 16:03:44 -070087 decay_time_ms = 1000;
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -070088 } else {
Christopher Ferrisd73a49e2018-10-19 16:03:44 -070089 decay_time_ms = 0;
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -070090 }
91 // First get the total number of arenas.
92 unsigned narenas;
93 size_t sz = sizeof(unsigned);
94 if (je_mallctl("arenas.narenas", &narenas, &sz, nullptr, 0) != 0) {
95 return 0;
96 }
97
98 // Set the decay time for any arenas that will be created in the future.
Christopher Ferrisd73a49e2018-10-19 16:03:44 -070099 if (je_mallctl("arenas.dirty_decay_ms", nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
100 return 0;
101 }
102 if (je_mallctl("arenas.muzzy_decay_ms", nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -0700103 return 0;
104 }
105
106 // Change the decay on the already existing arenas.
107 char buffer[100];
108 for (unsigned i = 0; i < narenas; i++) {
Christopher Ferrisd73a49e2018-10-19 16:03:44 -0700109 snprintf(buffer, sizeof(buffer), "arena.%d.dirty_decay_ms", i);
110 if (je_mallctl(buffer, nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
111 break;
112 }
113 snprintf(buffer, sizeof(buffer), "arena.%d.muzzy_decay_ms", i);
114 if (je_mallctl(buffer, nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -0700115 break;
116 }
117 }
118 return 1;
Christopher Ferrisd86eb862023-02-28 12:45:54 -0800119 } else if (param == M_PURGE || param == M_PURGE_ALL) {
Christopher Ferris0f710fd2019-05-01 13:26:46 -0700120 // Only clear the current thread cache since there is no easy way to
121 // clear the caches of other threads.
122 // This must be done first so that cleared allocations get purged
123 // in the next calls.
Christopher Ferris3d0bafb2019-07-08 14:54:58 -0700124 // Ignore the return call since this will fail if the tcache is disabled.
125 je_mallctl("thread.tcache.flush", nullptr, nullptr, nullptr, 0);
Christopher Ferris0f710fd2019-05-01 13:26:46 -0700126
Tim Murrayac578f22018-10-15 16:26:56 -0700127 unsigned narenas;
128 size_t sz = sizeof(unsigned);
129 if (je_mallctl("arenas.narenas", &narenas, &sz, nullptr, 0) != 0) {
130 return 0;
131 }
132 char buffer[100];
133 snprintf(buffer, sizeof(buffer), "arena.%u.purge", narenas);
134 if (je_mallctl(buffer, nullptr, nullptr, nullptr, 0) != 0) {
135 return 0;
136 }
137 return 1;
Christopher Ferrise9a7b812023-05-11 15:36:27 -0700138 } else if (param == M_LOG_STATS) {
139 for (size_t i = 0; i < je_mallinfo_narenas(); i++) {
140 struct mallinfo mi = je_mallinfo_arena_info(i);
141 if (mi.hblkhd != 0) {
142 async_safe_format_log(ANDROID_LOG_INFO, "jemalloc",
143 "Arena %zu: large bytes %zu huge bytes %zu bin bytes %zu", i,
144 mi.ordblks, mi.uordblks, mi.fsmblks);
145
146 for (size_t j = 0; j < je_mallinfo_nbins(); j++) {
147 struct mallinfo mi = je_mallinfo_bin_info(i, j);
148 if (mi.ordblks != 0) {
149 size_t total_allocs = 1;
150 if (mi.uordblks > mi.fordblks) {
151 total_allocs = mi.uordblks - mi.fordblks;
152 }
153 size_t bin_size = mi.ordblks / total_allocs;
154 async_safe_format_log(
155 ANDROID_LOG_INFO, "jemalloc",
156 " Bin %zu (%zu bytes): allocated bytes %zu nmalloc %zu ndalloc %zu", j, bin_size,
157 mi.ordblks, mi.uordblks, mi.fordblks);
158 }
159 }
160 }
161 }
162 return 1;
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -0700163 }
Christopher Ferrise9a7b812023-05-11 15:36:27 -0700164
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -0700165 return 0;
166}
Christopher Ferris6c619a02019-03-01 17:59:51 -0800167
Christopher Ferris6c619a02019-03-01 17:59:51 -0800168int je_malloc_info(int options, FILE* fp) {
169 if (options != 0) {
170 errno = EINVAL;
171 return -1;
172 }
173
Christopher Ferrisff88fb02019-11-04 18:40:00 -0800174 fflush(fp);
175 int fd = fileno(fp);
176 MallocXmlElem root(fd, "malloc", "version=\"jemalloc-1\"");
Christopher Ferris6c619a02019-03-01 17:59:51 -0800177
178 // Dump all of the large allocations in the arenas.
Christopher Ferrisdb9706a2019-05-02 18:33:11 -0700179 for (size_t i = 0; i < je_mallinfo_narenas(); i++) {
180 struct mallinfo mi = je_mallinfo_arena_info(i);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800181 if (mi.hblkhd != 0) {
Christopher Ferrisff88fb02019-11-04 18:40:00 -0800182 MallocXmlElem arena_elem(fd, "heap", "nr=\"%d\"", i);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800183 {
Christopher Ferrisff88fb02019-11-04 18:40:00 -0800184 MallocXmlElem(fd, "allocated-large").Contents("%zu", mi.ordblks);
185 MallocXmlElem(fd, "allocated-huge").Contents("%zu", mi.uordblks);
186 MallocXmlElem(fd, "allocated-bins").Contents("%zu", mi.fsmblks);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800187
188 size_t total = 0;
Christopher Ferrisdb9706a2019-05-02 18:33:11 -0700189 for (size_t j = 0; j < je_mallinfo_nbins(); j++) {
190 struct mallinfo mi = je_mallinfo_bin_info(i, j);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800191 if (mi.ordblks != 0) {
Christopher Ferrisff88fb02019-11-04 18:40:00 -0800192 MallocXmlElem bin_elem(fd, "bin", "nr=\"%d\"", j);
193 MallocXmlElem(fd, "allocated").Contents("%zu", mi.ordblks);
194 MallocXmlElem(fd, "nmalloc").Contents("%zu", mi.uordblks);
195 MallocXmlElem(fd, "ndalloc").Contents("%zu", mi.fordblks);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800196 total += mi.ordblks;
197 }
198 }
Christopher Ferrisff88fb02019-11-04 18:40:00 -0800199 MallocXmlElem(fd, "bins-total").Contents("%zu", total);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800200 }
201 }
202 }
203
204 return 0;
205}