blob: 38f0ac84fa974e1d7e70f1f98c12d657b3473541 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
17
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
25
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
28
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36*/
37
38#ifndef included_mem_mheap_h
39#define included_mem_mheap_h
40
41/* Bootstrap include so that #include <vppinfra/mem.h> can include e.g.
42 <vppinfra/mheap.h> which depends on <vppinfra/vec.h>. */
43
44#include <vppinfra/vec_bootstrap.h>
45#include <vppinfra/error_bootstrap.h>
46#include <vppinfra/os.h>
47#include <vppinfra/vector.h>
48
49/* Each element in heap is immediately followed by this struct. */
Dave Barachc3799992016-08-15 11:12:27 -040050typedef struct
51{
Ed Warnickecb9cada2015-12-08 15:45:58 -070052 /* Number of mheap_size_t words of user data in previous object.
53 Used to find mheap_elt_t for previous object. */
Dave Barachb3d93da2016-08-03 14:34:38 -040054#if CLIB_VEC64 > 0
Dave Barachc3799992016-08-15 11:12:27 -040055 u64 prev_n_user_data:63;
Dave Barachb3d93da2016-08-03 14:34:38 -040056
57 /* Used to mark end/start of of doubly-linked list of mheap_elt_t's. */
58#define MHEAP_N_USER_DATA_INVALID (0x7fffffffffffffffULL)
59#define MHEAP_GROUNDED (~0ULL)
60
61 /* Set if previous object is free. */
Dave Barachc3799992016-08-15 11:12:27 -040062 u64 prev_is_free:1;
Dave Barachb3d93da2016-08-03 14:34:38 -040063
64 /* Number of mheap_size_t words of user data that follow this object. */
Dave Barachc3799992016-08-15 11:12:27 -040065 u64 n_user_data:63;
Dave Barachb3d93da2016-08-03 14:34:38 -040066
67 /* Set if this object is on free list (and therefore following free_elt
68 is valid). */
Dave Barachc3799992016-08-15 11:12:27 -040069 u64 is_free:1;
Dave Barachb3d93da2016-08-03 14:34:38 -040070
71#else
Dave Barachc3799992016-08-15 11:12:27 -040072 u32 prev_n_user_data:31;
Ed Warnickecb9cada2015-12-08 15:45:58 -070073
74 /* Used to mark end/start of of doubly-linked list of mheap_elt_t's. */
75#define MHEAP_N_USER_DATA_INVALID (0x7fffffff)
Dave Barachb3d93da2016-08-03 14:34:38 -040076#define MHEAP_GROUNDED (~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -070077
78 /* Set if previous object is free. */
Dave Barachc3799992016-08-15 11:12:27 -040079 u32 prev_is_free:1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070080
81 /* Number of mheap_size_t words of user data that follow this object. */
Dave Barachc3799992016-08-15 11:12:27 -040082 u32 n_user_data:31;
Ed Warnickecb9cada2015-12-08 15:45:58 -070083
84 /* Set if this object is on free list (and therefore following free_elt
85 is valid). */
Dave Barachc3799992016-08-15 11:12:27 -040086 u32 is_free:1;
Dave Barachb3d93da2016-08-03 14:34:38 -040087#endif
Dave Barachc3799992016-08-15 11:12:27 -040088
89 union
90 {
Dave Barachb3d93da2016-08-03 14:34:38 -040091#if CLIB_VEC64 > 0
92 /* For allocated objects: user data follows.
93 User data is allocated in units of typeof (user_data[0]). */
94 u64 user_data[0];
95
96 /* For free objects, offsets of next and previous free objects of this size;
97 ~0 means end of doubly-linked list.
98 This is stored in user data (guaranteed to be at least 8 bytes)
99 but only for *free* objects. */
Dave Barachc3799992016-08-15 11:12:27 -0400100 struct
101 {
Dave Barachb3d93da2016-08-03 14:34:38 -0400102 u64 next_uoffset, prev_uoffset;
103 } free_elt;
104#else
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105 /* For allocated objects: user data follows.
106 User data is allocated in units of typeof (user_data[0]). */
107 u32 user_data[0];
108
109 /* For free objects, offsets of next and previous free objects of this size;
110 ~0 means end of doubly-linked list.
111 This is stored in user data (guaranteed to be at least 8 bytes)
112 but only for *free* objects. */
Dave Barachc3799992016-08-15 11:12:27 -0400113 struct
114 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115 u32 next_uoffset, prev_uoffset;
116 } free_elt;
Dave Barachb3d93da2016-08-03 14:34:38 -0400117#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700118 };
119} mheap_elt_t;
120
121/* Number of bytes of "overhead": e.g. not user data. */
122#define MHEAP_ELT_OVERHEAD_BYTES (sizeof (mheap_elt_t) - STRUCT_OFFSET_OF (mheap_elt_t, user_data))
123
124/* User objects must be large enough to hold 2 x u32 free offsets in free elt. */
125#define MHEAP_MIN_USER_DATA_BYTES MHEAP_ELT_OVERHEAD_BYTES
126
127/* Number of byte in user data "words". */
128#define MHEAP_USER_DATA_WORD_BYTES STRUCT_SIZE_OF (mheap_elt_t, user_data[0])
129
Dave Barachc3799992016-08-15 11:12:27 -0400130typedef struct
131{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700132 /* Address of callers: outer first, inner last. */
133 uword callers[12];
134
135 /* Count of allocations with this traceback. */
Dave Barachb3d93da2016-08-03 14:34:38 -0400136#if CLIB_VEC64 > 0
137 u64 n_allocations;
138#else
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139 u32 n_allocations;
Dave Barachb3d93da2016-08-03 14:34:38 -0400140#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700141
142 /* Count of bytes allocated with this traceback. */
143 u32 n_bytes;
144
145 /* Offset of this item */
Dave Barachc3799992016-08-15 11:12:27 -0400146 uword offset;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700147} mheap_trace_t;
148
Dave Barachc3799992016-08-15 11:12:27 -0400149typedef struct
150{
151 mheap_trace_t *traces;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700152
153 /* Indices of free traces. */
Dave Barachc3799992016-08-15 11:12:27 -0400154 u32 *trace_free_list;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700155
156 /* Hash table mapping callers to trace index. */
Dave Barachc3799992016-08-15 11:12:27 -0400157 uword *trace_by_callers;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700158
159 /* Hash table mapping mheap offset to trace index. */
Dave Barachc3799992016-08-15 11:12:27 -0400160 uword *trace_index_by_offset;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700161} mheap_trace_main_t;
162
Dave Barachba7ddfe2017-05-17 20:20:50 -0400163/* Without vector instructions don't bother with small object cache. */
164#ifdef CLIB_HAVE_VEC128
165#define MHEAP_HAVE_SMALL_OBJECT_CACHE 1
166#else
167#define MHEAP_HAVE_SMALL_OBJECT_CACHE 0
168#endif
169
Ed Warnickecb9cada2015-12-08 15:45:58 -0700170 /* Small object bin i is for objects with
Dave Barachc3799992016-08-15 11:12:27 -0400171 user_size > sizeof (mheap_elt_t) + sizeof (mheap_elt_t) * (i - 1)
172 user_size <= sizeof (mheap_elt_t) + sizeof (mheap_size_t) * i. */
Dave Barachba7ddfe2017-05-17 20:20:50 -0400173#if MHEAP_HAVE_SMALL_OBJECT_CACHE > 0
Ed Warnickecb9cada2015-12-08 15:45:58 -0700174#define MHEAP_LOG2_N_SMALL_OBJECT_BINS 8
175#define MHEAP_N_SMALL_OBJECT_BINS (1 << MHEAP_LOG2_N_SMALL_OBJECT_BINS)
Dave Barachba7ddfe2017-05-17 20:20:50 -0400176#else
177#define MHEAP_LOG2_N_SMALL_OBJECT_BINS 0
178#define MHEAP_N_SMALL_OBJECT_BINS 0
179#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700180
181#define MHEAP_N_BINS \
182 (MHEAP_N_SMALL_OBJECT_BINS \
183 + (STRUCT_BITS_OF (mheap_elt_t, user_data[0]) - MHEAP_LOG2_N_SMALL_OBJECT_BINS))
184
Dave Barachc3799992016-08-15 11:12:27 -0400185typedef struct
186{
187 struct
188 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700189 u64 n_search_attempts;
190 u64 n_objects_searched;
191 u64 n_objects_found;
192 } free_list;
193
194 u64 n_vector_expands;
195
196 u64 n_small_object_cache_hits;
197 u64 n_small_object_cache_attempts;
198
199 u64 n_gets, n_puts;
200 u64 n_clocks_get, n_clocks_put;
201} mheap_stats_t;
202
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203/* For objects with align == 4 and align_offset == 0 (e.g. vector strings). */
Dave Barachc3799992016-08-15 11:12:27 -0400204typedef struct
205{
206 union
207 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208#ifdef CLIB_HAVE_VEC128
209 u8x16 as_u8x16[BITS (uword) / 16];
210#endif
211
212 /* Store bin + 1; zero means unused. */
213 u8 as_u8[BITS (uword)];
214 } bins;
215
216 uword offsets[BITS (uword)];
217
218 u32 replacement_index;
219} mheap_small_object_cache_t;
220
221/* Vec header for heaps. */
Dave Barachc3799992016-08-15 11:12:27 -0400222typedef struct
223{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224 /* User offsets for head of doubly-linked list of free objects of this size. */
Dave Barachb3d93da2016-08-03 14:34:38 -0400225#if CLIB_VEC64 > 0
226 u64 first_free_elt_uoffset_by_bin[MHEAP_N_BINS];
227#else
Ed Warnickecb9cada2015-12-08 15:45:58 -0700228 u32 first_free_elt_uoffset_by_bin[MHEAP_N_BINS];
Dave Barachb3d93da2016-08-03 14:34:38 -0400229#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700230
231 /* Bitmap of non-empty free list bins. */
Dave Barachc3799992016-08-15 11:12:27 -0400232 uword non_empty_free_elt_heads[(MHEAP_N_BINS + BITS (uword) - 1) /
233 BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234
235 mheap_small_object_cache_t small_object_cache;
236
237 u32 flags;
238#define MHEAP_FLAG_TRACE (1 << 0)
239#define MHEAP_FLAG_DISABLE_VM (1 << 1)
240#define MHEAP_FLAG_THREAD_SAFE (1 << 2)
241#define MHEAP_FLAG_SMALL_OBJECT_CACHE (1 << 3)
242#define MHEAP_FLAG_VALIDATE (1 << 4)
243
244 /* Lock use when MHEAP_FLAG_THREAD_SAFE is set. */
245 volatile u32 lock;
246 volatile u32 owner_cpu;
247 int recursion_count;
248
249 /* Number of allocated objects. */
250 u64 n_elts;
251
252 /* Maximum size (in bytes) this heap is allowed to grow to.
253 Set to ~0 to grow heap (via vec_resize) arbitrarily. */
254 u64 max_size;
255
256 uword vm_alloc_offset_from_header;
257 uword vm_alloc_size;
258
259 /* Each successful mheap_validate call increments this serial number.
260 Used to debug heap corruption problems. GDB breakpoints can be
261 made conditional on validate_serial. */
262 u64 validate_serial;
263
264 mheap_trace_main_t trace_main;
265
266 mheap_stats_t stats;
267} mheap_t;
268
Dave Barachc3799992016-08-15 11:12:27 -0400269always_inline mheap_t *
270mheap_header (u8 * v)
271{
272 return vec_aligned_header (v, sizeof (mheap_t), 16);
273}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274
Dave Barachc3799992016-08-15 11:12:27 -0400275always_inline u8 *
276mheap_vector (mheap_t * h)
277{
278 return vec_aligned_header_end (h, sizeof (mheap_t), 16);
279}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700280
Dave Barachc3799992016-08-15 11:12:27 -0400281always_inline uword
282mheap_elt_uoffset (void *v, mheap_elt_t * e)
283{
284 return (uword) e->user_data - (uword) v;
285}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700286
Dave Barachc3799992016-08-15 11:12:27 -0400287always_inline mheap_elt_t *
288mheap_user_pointer_to_elt (void *v)
289{
290 return v - STRUCT_OFFSET_OF (mheap_elt_t, user_data);
291}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700292
293/* For debugging we keep track of offsets for valid objects.
294 We make sure user is not trying to free object with invalid offset. */
Dave Barachc3799992016-08-15 11:12:27 -0400295always_inline uword
296mheap_offset_is_valid (void *v, uword uo)
297{
298 return uo >= MHEAP_ELT_OVERHEAD_BYTES && uo <= vec_len (v);
299}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700300
Dave Barachc3799992016-08-15 11:12:27 -0400301always_inline mheap_elt_t *
302mheap_elt_at_uoffset (void *v, uword uo)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700303{
304 ASSERT (mheap_offset_is_valid (v, uo));
305 return (mheap_elt_t *) (v + uo - STRUCT_OFFSET_OF (mheap_elt_t, user_data));
306}
307
Dave Barachc3799992016-08-15 11:12:27 -0400308always_inline void *
309mheap_elt_data (void *v, mheap_elt_t * e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700310{
Dave Barachc3799992016-08-15 11:12:27 -0400311 return v + mheap_elt_uoffset (v, e);
312}
313
314always_inline uword
315mheap_elt_data_bytes (mheap_elt_t * e)
316{
317 return e->n_user_data * sizeof (e->user_data[0]);
318}
319
320always_inline uword
321mheap_data_bytes (void *v, uword uo)
322{
323 mheap_elt_t *e = mheap_elt_at_uoffset (v, uo);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700324 return mheap_elt_data_bytes (e);
325}
326
327#define mheap_len(v,d) (mheap_data_bytes((v),(void *) (d) - (void *) (v)) / sizeof ((d)[0]))
328
Dave Barachc3799992016-08-15 11:12:27 -0400329always_inline mheap_elt_t *
330mheap_next_elt (mheap_elt_t * e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700331{
332 ASSERT (e->n_user_data < MHEAP_N_USER_DATA_INVALID);
333 return (mheap_elt_t *) (e->user_data + e->n_user_data);
334}
335
Dave Barachc3799992016-08-15 11:12:27 -0400336always_inline mheap_elt_t *
337mheap_prev_elt (mheap_elt_t * e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700338{
339 ASSERT (e->prev_n_user_data < MHEAP_N_USER_DATA_INVALID);
340 return ((void *) e
341 - e->prev_n_user_data * sizeof (e->user_data[0])
342 - MHEAP_ELT_OVERHEAD_BYTES);
343}
344
345/* Exported operations. */
346
Dave Barachc3799992016-08-15 11:12:27 -0400347always_inline uword
348mheap_elts (void *v)
349{
350 return v ? mheap_header (v)->n_elts : 0;
351}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352
Dave Barachc3799992016-08-15 11:12:27 -0400353always_inline uword
354mheap_max_size (void *v)
355{
356 return v ? mheap_header (v)->max_size : ~0;
357}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700358
359/* Free previously allocated offset. */
Dave Barachc3799992016-08-15 11:12:27 -0400360void mheap_put (void *v, uword offset);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700361
362/* Allocate object from mheap. */
Dave Barachc3799992016-08-15 11:12:27 -0400363void *mheap_get_aligned (void *v, uword size, uword align, uword align_offset,
364 uword * offset_return);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700365
366#endif /* included_mem_mheap_h */
Dave Barachc3799992016-08-15 11:12:27 -0400367
368/*
369 * fd.io coding-style-patch-verification: ON
370 *
371 * Local Variables:
372 * eval: (c-set-style "gnu")
373 * End:
374 */