1 /*
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 
17 #include <errno.h>
18 #include <malloc.h>
19 #include <sys/param.h>
20 #include <unistd.h>
21 
22 #include <private/MallocXmlElem.h>
23 
24 #include "jemalloc.h"
25 
je_pvalloc(size_t bytes)26 void* je_pvalloc(size_t bytes) {
27   size_t pagesize = getpagesize();
28   size_t size = __BIONIC_ALIGN(bytes, pagesize);
29   if (size < bytes) {
30     return nullptr;
31   }
32   return je_memalign(pagesize, size);
33 }
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.
je_memalign_round_up_boundary(size_t boundary,size_t size)42 void* je_memalign_round_up_boundary(size_t boundary, size_t size) {
43   if (boundary != 0) {
44     if (!powerof2(boundary)) {
45       boundary = BIONIC_ROUND_UP_POWER_OF_2(boundary);
46     }
47   } else {
48     boundary = 1;
49   }
50   return je_memalign(boundary, size);
51 }
52 
53 #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.
je_aligned_alloc_wrapper(size_t alignment,size_t size)59 void* 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 
je_mallopt(int param,int value)67 int 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.
71     ssize_t decay_time_ms;
72     if (value) {
73       decay_time_ms = 1000;
74     } else {
75       decay_time_ms = 0;
76     }
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.
85     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) {
89       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++) {
95       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) {
101         break;
102       }
103     }
104     return 1;
105   } else if (param == M_PURGE) {
106     // 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     // Ignore the return call since this will fail if the tcache is disabled.
111     je_mallctl("thread.tcache.flush", nullptr, nullptr, nullptr, 0);
112 
113     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;
124   }
125   return 0;
126 }
127 
128 __BEGIN_DECLS
129 
130 size_t je_mallinfo_narenas();
131 size_t je_mallinfo_nbins();
132 struct mallinfo je_mallinfo_arena_info(size_t);
133 struct mallinfo je_mallinfo_bin_info(size_t, size_t);
134 
135 __END_DECLS
136 
je_malloc_info(int options,FILE * fp)137 int je_malloc_info(int options, FILE* fp) {
138   if (options != 0) {
139     errno = EINVAL;
140     return -1;
141   }
142 
143   fflush(fp);
144   int fd = fileno(fp);
145   MallocXmlElem root(fd, "malloc", "version=\"jemalloc-1\"");
146 
147   // Dump all of the large allocations in the arenas.
148   for (size_t i = 0; i < je_mallinfo_narenas(); i++) {
149     struct mallinfo mi = je_mallinfo_arena_info(i);
150     if (mi.hblkhd != 0) {
151       MallocXmlElem arena_elem(fd, "heap", "nr=\"%d\"", i);
152       {
153         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);
156 
157         size_t total = 0;
158         for (size_t j = 0; j < je_mallinfo_nbins(); j++) {
159           struct mallinfo mi = je_mallinfo_bin_info(i, j);
160           if (mi.ordblks != 0) {
161             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);
165             total += mi.ordblks;
166           }
167         }
168         MallocXmlElem(fd, "bins-total").Contents("%zu", total);
169       }
170     }
171   }
172 
173   return 0;
174 }
175