blob: fd99814a62b456eb53e5dbf0c3ff24f587b53f86 [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;
Tim Murrayac578f22018-10-15 16:26:56 -0700105 } else if (param == M_PURGE) {
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.
110 if (je_mallctl("thread.tcache.flush", nullptr, nullptr, nullptr, 0) != 0) {
111 return 0;
112 }
113
Tim Murrayac578f22018-10-15 16:26:56 -0700114 unsigned narenas;
115 size_t sz = sizeof(unsigned);
116 if (je_mallctl("arenas.narenas", &narenas, &sz, nullptr, 0) != 0) {
117 return 0;
118 }
119 char buffer[100];
120 snprintf(buffer, sizeof(buffer), "arena.%u.purge", narenas);
121 if (je_mallctl(buffer, nullptr, nullptr, nullptr, 0) != 0) {
122 return 0;
123 }
124 return 1;
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -0700125 }
126 return 0;
127}
Christopher Ferris6c619a02019-03-01 17:59:51 -0800128
129__BEGIN_DECLS
130
131size_t __mallinfo_narenas();
132size_t __mallinfo_nbins();
133struct mallinfo __mallinfo_arena_info(size_t);
134struct mallinfo __mallinfo_bin_info(size_t, size_t);
135
136__END_DECLS
137
138int je_malloc_info(int options, FILE* fp) {
139 if (options != 0) {
140 errno = EINVAL;
141 return -1;
142 }
143
144 MallocXmlElem root(fp, "malloc", "version=\"jemalloc-1\"");
145
146 // Dump all of the large allocations in the arenas.
147 for (size_t i = 0; i < __mallinfo_narenas(); i++) {
148 struct mallinfo mi = __mallinfo_arena_info(i);
149 if (mi.hblkhd != 0) {
150 MallocXmlElem arena_elem(fp, "heap", "nr=\"%d\"", i);
151 {
152 MallocXmlElem(fp, "allocated-large").Contents("%zu", mi.ordblks);
153 MallocXmlElem(fp, "allocated-huge").Contents("%zu", mi.uordblks);
154 MallocXmlElem(fp, "allocated-bins").Contents("%zu", mi.fsmblks);
155
156 size_t total = 0;
157 for (size_t j = 0; j < __mallinfo_nbins(); j++) {
158 struct mallinfo mi = __mallinfo_bin_info(i, j);
159 if (mi.ordblks != 0) {
160 MallocXmlElem bin_elem(fp, "bin", "nr=\"%d\"", j);
161 MallocXmlElem(fp, "allocated").Contents("%zu", mi.ordblks);
162 MallocXmlElem(fp, "nmalloc").Contents("%zu", mi.uordblks);
163 MallocXmlElem(fp, "ndalloc").Contents("%zu", mi.fordblks);
164 total += mi.ordblks;
165 }
166 }
167 MallocXmlElem(fp, "bins-total").Contents("%zu", total);
168 }
169 }
170 }
171
172 return 0;
173}