blob: ce3f31420312423f247bc6152795e1c3ce7000b4 [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 Ferris6c619a02019-03-01 17:59:51 -080022#include <private/MallocXmlElem.h>
23
Christopher Ferris72bbd422014-05-08 11:14:03 -070024#include "jemalloc.h"
25
26void* je_pvalloc(size_t bytes) {
Elliott Hughes91570ce2014-07-10 12:34:23 -070027 size_t pagesize = getpagesize();
Dan Alberta613d0d2017-10-05 16:39:33 -070028 size_t size = __BIONIC_ALIGN(bytes, pagesize);
Christopher Ferris03eebcb2014-06-13 13:57:51 -070029 if (size < bytes) {
Yi Kong32bc0fc2018-08-02 17:31:13 -070030 return nullptr;
Christopher Ferris03eebcb2014-06-13 13:57:51 -070031 }
32 return je_memalign(pagesize, size);
Christopher Ferris72bbd422014-05-08 11:14:03 -070033}
34
35#ifdef je_memalign
36#undef je_memalign
37#endif
38
39// The man page for memalign says it fails if boundary is not a power of 2,
40// but this is not true. Both glibc and dlmalloc round up to the next power
41// of 2, so we'll do the same.
42void* je_memalign_round_up_boundary(size_t boundary, size_t size) {
Christopher Ferris03eebcb2014-06-13 13:57:51 -070043 if (boundary != 0) {
44 if (!powerof2(boundary)) {
45 boundary = BIONIC_ROUND_UP_POWER_OF_2(boundary);
Christopher Ferris72bbd422014-05-08 11:14:03 -070046 }
47 } else {
48 boundary = 1;
49 }
50 return je_memalign(boundary, size);
51}
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -070052
Christopher Ferrisa22f5d52019-03-01 16:40:59 -080053#ifdef je_aligned_alloc
54#undef je_aligned_alloc
55#endif
56
57// The aligned_alloc function requires that size is a multiple of alignment.
58// jemalloc doesn't enforce this, so add enforcement here.
59void* je_aligned_alloc_wrapper(size_t alignment, size_t size) {
60 if ((size % alignment) != 0) {
61 errno = EINVAL;
62 return nullptr;
63 }
64 return je_aligned_alloc(alignment, size);
65}
66
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -070067int je_mallopt(int param, int value) {
68 // The only parameter we currently understand is M_DECAY_TIME.
69 if (param == M_DECAY_TIME) {
70 // Only support setting the value to 1 or 0.
Christopher Ferrisd73a49e2018-10-19 16:03:44 -070071 ssize_t decay_time_ms;
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -070072 if (value) {
Christopher Ferrisd73a49e2018-10-19 16:03:44 -070073 decay_time_ms = 1000;
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -070074 } else {
Christopher Ferrisd73a49e2018-10-19 16:03:44 -070075 decay_time_ms = 0;
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -070076 }
77 // First get the total number of arenas.
78 unsigned narenas;
79 size_t sz = sizeof(unsigned);
80 if (je_mallctl("arenas.narenas", &narenas, &sz, nullptr, 0) != 0) {
81 return 0;
82 }
83
84 // Set the decay time for any arenas that will be created in the future.
Christopher Ferrisd73a49e2018-10-19 16:03:44 -070085 if (je_mallctl("arenas.dirty_decay_ms", nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
86 return 0;
87 }
88 if (je_mallctl("arenas.muzzy_decay_ms", nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -070089 return 0;
90 }
91
92 // Change the decay on the already existing arenas.
93 char buffer[100];
94 for (unsigned i = 0; i < narenas; i++) {
Christopher Ferrisd73a49e2018-10-19 16:03:44 -070095 snprintf(buffer, sizeof(buffer), "arena.%d.dirty_decay_ms", i);
96 if (je_mallctl(buffer, nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
97 break;
98 }
99 snprintf(buffer, sizeof(buffer), "arena.%d.muzzy_decay_ms", i);
100 if (je_mallctl(buffer, nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -0700101 break;
102 }
103 }
104 return 1;
Christopher Ferrisd86eb862023-02-28 12:45:54 -0800105 } else if (param == M_PURGE || param == M_PURGE_ALL) {
Christopher Ferris0f710fd2019-05-01 13:26:46 -0700106 // Only clear the current thread cache since there is no easy way to
107 // clear the caches of other threads.
108 // This must be done first so that cleared allocations get purged
109 // in the next calls.
Christopher Ferris3d0bafb2019-07-08 14:54:58 -0700110 // Ignore the return call since this will fail if the tcache is disabled.
111 je_mallctl("thread.tcache.flush", nullptr, nullptr, nullptr, 0);
Christopher Ferris0f710fd2019-05-01 13:26:46 -0700112
Tim Murrayac578f22018-10-15 16:26:56 -0700113 unsigned narenas;
114 size_t sz = sizeof(unsigned);
115 if (je_mallctl("arenas.narenas", &narenas, &sz, nullptr, 0) != 0) {
116 return 0;
117 }
118 char buffer[100];
119 snprintf(buffer, sizeof(buffer), "arena.%u.purge", narenas);
120 if (je_mallctl(buffer, nullptr, nullptr, nullptr, 0) != 0) {
121 return 0;
122 }
123 return 1;
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -0700124 }
125 return 0;
126}
Christopher Ferris6c619a02019-03-01 17:59:51 -0800127
128__BEGIN_DECLS
129
Christopher Ferrisdb9706a2019-05-02 18:33:11 -0700130size_t je_mallinfo_narenas();
131size_t je_mallinfo_nbins();
132struct mallinfo je_mallinfo_arena_info(size_t);
133struct mallinfo je_mallinfo_bin_info(size_t, size_t);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800134
135__END_DECLS
136
137int je_malloc_info(int options, FILE* fp) {
138 if (options != 0) {
139 errno = EINVAL;
140 return -1;
141 }
142
Christopher Ferrisff88fb02019-11-04 18:40:00 -0800143 fflush(fp);
144 int fd = fileno(fp);
145 MallocXmlElem root(fd, "malloc", "version=\"jemalloc-1\"");
Christopher Ferris6c619a02019-03-01 17:59:51 -0800146
147 // Dump all of the large allocations in the arenas.
Christopher Ferrisdb9706a2019-05-02 18:33:11 -0700148 for (size_t i = 0; i < je_mallinfo_narenas(); i++) {
149 struct mallinfo mi = je_mallinfo_arena_info(i);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800150 if (mi.hblkhd != 0) {
Christopher Ferrisff88fb02019-11-04 18:40:00 -0800151 MallocXmlElem arena_elem(fd, "heap", "nr=\"%d\"", i);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800152 {
Christopher Ferrisff88fb02019-11-04 18:40:00 -0800153 MallocXmlElem(fd, "allocated-large").Contents("%zu", mi.ordblks);
154 MallocXmlElem(fd, "allocated-huge").Contents("%zu", mi.uordblks);
155 MallocXmlElem(fd, "allocated-bins").Contents("%zu", mi.fsmblks);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800156
157 size_t total = 0;
Christopher Ferrisdb9706a2019-05-02 18:33:11 -0700158 for (size_t j = 0; j < je_mallinfo_nbins(); j++) {
159 struct mallinfo mi = je_mallinfo_bin_info(i, j);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800160 if (mi.ordblks != 0) {
Christopher Ferrisff88fb02019-11-04 18:40:00 -0800161 MallocXmlElem bin_elem(fd, "bin", "nr=\"%d\"", j);
162 MallocXmlElem(fd, "allocated").Contents("%zu", mi.ordblks);
163 MallocXmlElem(fd, "nmalloc").Contents("%zu", mi.uordblks);
164 MallocXmlElem(fd, "ndalloc").Contents("%zu", mi.fordblks);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800165 total += mi.ordblks;
166 }
167 }
Christopher Ferrisff88fb02019-11-04 18:40:00 -0800168 MallocXmlElem(fd, "bins-total").Contents("%zu", total);
Christopher Ferris6c619a02019-03-01 17:59:51 -0800169 }
170 }
171 }
172
173 return 0;
174}