Initial commit of vpp code.
[vpp.git] / vppinfra / vppinfra / mheap_bootstrap.h
diff --git a/vppinfra/vppinfra/mheap_bootstrap.h b/vppinfra/vppinfra/mheap_bootstrap.h
new file mode 100644 (file)
index 0000000..989f941
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+  Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef included_mem_mheap_h
+#define included_mem_mheap_h
+
+/* Bootstrap include so that #include <vppinfra/mem.h> can include e.g.
+   <vppinfra/mheap.h> which depends on <vppinfra/vec.h>. */
+
+#include <vppinfra/vec_bootstrap.h>
+#include <vppinfra/error_bootstrap.h>
+#include <vppinfra/os.h>
+#include <vppinfra/vector.h>
+
+/* Each element in heap is immediately followed by this struct. */
+typedef struct {
+  /* Number of mheap_size_t words of user data in previous object.
+     Used to find mheap_elt_t for previous object. */
+  u32 prev_n_user_data : 31;
+
+  /* Used to mark end/start of of doubly-linked list of mheap_elt_t's. */
+#define MHEAP_N_USER_DATA_INVALID (0x7fffffff)
+
+  /* Set if previous object is free. */
+  u32 prev_is_free : 1;
+
+  /* Number of mheap_size_t words of user data that follow this object. */
+  u32 n_user_data : 31;
+
+  /* Set if this object is on free list (and therefore following free_elt
+     is valid). */
+  u32 is_free : 1;
+
+  union {
+    /* For allocated objects: user data follows.
+       User data is allocated in units of typeof (user_data[0]). */
+    u32 user_data[0];
+
+    /* For free objects, offsets of next and previous free objects of this size;
+       ~0 means end of doubly-linked list.
+       This is stored in user data (guaranteed to be at least 8 bytes)
+       but only for *free* objects. */
+    struct {
+      u32 next_uoffset, prev_uoffset;
+    } free_elt;
+  };
+} mheap_elt_t;
+
+/* Number of bytes of "overhead": e.g. not user data. */
+#define MHEAP_ELT_OVERHEAD_BYTES (sizeof (mheap_elt_t) - STRUCT_OFFSET_OF (mheap_elt_t, user_data))
+
+/* User objects must be large enough to hold 2 x u32 free offsets in free elt. */
+#define MHEAP_MIN_USER_DATA_BYTES MHEAP_ELT_OVERHEAD_BYTES
+
+/* Number of byte in user data "words". */
+#define MHEAP_USER_DATA_WORD_BYTES STRUCT_SIZE_OF (mheap_elt_t, user_data[0])
+
+typedef struct {
+  /* Address of callers: outer first, inner last. */
+  uword callers[12];
+
+  /* Count of allocations with this traceback. */
+  u32 n_allocations;
+
+  /* Count of bytes allocated with this traceback. */
+  u32 n_bytes;
+
+  /* Offset of this item */
+  uword offset;    
+} mheap_trace_t;
+
+typedef struct {
+  mheap_trace_t * traces;
+
+  /* Indices of free traces. */
+  u32 * trace_free_list;
+
+  /* Hash table mapping callers to trace index. */
+  uword * trace_by_callers;
+
+  /* Hash table mapping mheap offset to trace index. */
+  uword * trace_index_by_offset;
+} mheap_trace_main_t;
+
+  /* Small object bin i is for objects with
+       user_size >  sizeof (mheap_elt_t) + sizeof (mheap_elt_t) * (i - 1)
+       user_size <= sizeof (mheap_elt_t) + sizeof (mheap_size_t) * i. */
+#define MHEAP_LOG2_N_SMALL_OBJECT_BINS 8
+#define MHEAP_N_SMALL_OBJECT_BINS (1 << MHEAP_LOG2_N_SMALL_OBJECT_BINS)
+
+#define MHEAP_N_BINS                                                   \
+  (MHEAP_N_SMALL_OBJECT_BINS                                           \
+   + (STRUCT_BITS_OF (mheap_elt_t, user_data[0]) - MHEAP_LOG2_N_SMALL_OBJECT_BINS))
+
+typedef struct {
+  struct {
+    u64 n_search_attempts;
+    u64 n_objects_searched;
+    u64 n_objects_found;
+  } free_list;
+
+  u64 n_vector_expands;
+
+  u64 n_small_object_cache_hits;
+  u64 n_small_object_cache_attempts;
+
+  u64 n_gets, n_puts;
+  u64 n_clocks_get, n_clocks_put;
+} mheap_stats_t;
+
+/* Without vector instructions don't bother with small object cache. */
+#ifdef CLIB_HAVE_VEC128
+#define MHEAP_HAVE_SMALL_OBJECT_CACHE 0
+#else
+#define MHEAP_HAVE_SMALL_OBJECT_CACHE 0
+#endif
+
+/* For objects with align == 4 and align_offset == 0 (e.g. vector strings). */
+typedef struct {
+  union {
+#ifdef CLIB_HAVE_VEC128
+    u8x16 as_u8x16[BITS (uword) / 16];
+#endif
+
+    /* Store bin + 1; zero means unused. */
+    u8 as_u8[BITS (uword)];
+  } bins;
+
+  uword offsets[BITS (uword)];
+
+  u32 replacement_index;
+} mheap_small_object_cache_t;
+
+/* Vec header for heaps. */
+typedef struct {
+  /* User offsets for head of doubly-linked list of free objects of this size. */
+  u32 first_free_elt_uoffset_by_bin[MHEAP_N_BINS];
+
+  /* Bitmap of non-empty free list bins. */
+  uword non_empty_free_elt_heads[(MHEAP_N_BINS + BITS (uword) - 1) / BITS (uword)];
+
+  mheap_small_object_cache_t small_object_cache;
+
+  u32 flags;
+#define MHEAP_FLAG_TRACE                       (1 << 0)
+#define MHEAP_FLAG_DISABLE_VM                  (1 << 1)
+#define MHEAP_FLAG_THREAD_SAFE                 (1 << 2)
+#define MHEAP_FLAG_SMALL_OBJECT_CACHE          (1 << 3)
+#define MHEAP_FLAG_VALIDATE                    (1 << 4)
+
+  /* Lock use when MHEAP_FLAG_THREAD_SAFE is set. */
+  volatile u32 lock;
+  volatile u32 owner_cpu;
+  int recursion_count;
+
+  /* Number of allocated objects. */
+  u64 n_elts;
+
+  /* Maximum size (in bytes) this heap is allowed to grow to.
+     Set to ~0 to grow heap (via vec_resize) arbitrarily. */
+  u64 max_size;
+
+  uword vm_alloc_offset_from_header;
+  uword vm_alloc_size;
+
+  /* Each successful mheap_validate call increments this serial number.
+     Used to debug heap corruption problems.  GDB breakpoints can be
+     made conditional on validate_serial. */
+  u64 validate_serial;
+
+  mheap_trace_main_t trace_main;
+
+  mheap_stats_t stats;
+} mheap_t;
+
+always_inline mheap_t * mheap_header (u8 * v)
+{ return vec_aligned_header (v, sizeof (mheap_t), 16); }
+
+always_inline u8 * mheap_vector (mheap_t * h)
+{ return vec_aligned_header_end (h, sizeof (mheap_t), 16); }
+
+always_inline uword mheap_elt_uoffset (void * v, mheap_elt_t * e)
+{ return (uword)e->user_data - (uword)v; }
+
+always_inline mheap_elt_t * mheap_user_pointer_to_elt (void *v)
+{ return v - STRUCT_OFFSET_OF (mheap_elt_t, user_data); }
+
+/* For debugging we keep track of offsets for valid objects.
+   We make sure user is not trying to free object with invalid offset. */
+always_inline uword mheap_offset_is_valid (void * v, uword uo)
+{ return uo >= MHEAP_ELT_OVERHEAD_BYTES && uo <= vec_len (v); }
+
+always_inline mheap_elt_t * mheap_elt_at_uoffset (void * v, uword uo)
+{
+  ASSERT (mheap_offset_is_valid (v, uo));
+  return (mheap_elt_t *) (v + uo - STRUCT_OFFSET_OF (mheap_elt_t, user_data));
+}
+
+always_inline void * mheap_elt_data (void * v, mheap_elt_t * e)
+{ return v + mheap_elt_uoffset (v, e); }
+
+always_inline uword mheap_elt_data_bytes (mheap_elt_t * e)
+{ return e->n_user_data * sizeof (e->user_data[0]); }
+
+always_inline uword mheap_data_bytes (void * v, uword uo)
+{
+  mheap_elt_t * e = mheap_elt_at_uoffset (v, uo);
+  return mheap_elt_data_bytes (e);
+}
+
+#define mheap_len(v,d) (mheap_data_bytes((v),(void *) (d) - (void *) (v)) / sizeof ((d)[0]))
+
+always_inline mheap_elt_t * mheap_next_elt (mheap_elt_t * e)
+{
+  ASSERT (e->n_user_data < MHEAP_N_USER_DATA_INVALID);
+  return (mheap_elt_t *) (e->user_data + e->n_user_data);
+}
+
+always_inline mheap_elt_t * mheap_prev_elt (mheap_elt_t * e)
+{
+  ASSERT (e->prev_n_user_data < MHEAP_N_USER_DATA_INVALID);
+  return ((void *) e
+         - e->prev_n_user_data * sizeof (e->user_data[0])
+         - MHEAP_ELT_OVERHEAD_BYTES);
+}
+
+/* Exported operations. */
+
+always_inline uword mheap_elts (void * v)
+{ return v ? mheap_header (v)->n_elts : 0; }
+
+always_inline uword mheap_max_size (void * v)
+{ return v ? mheap_header (v)->max_size : ~0; }
+
+/* Free previously allocated offset. */
+void mheap_put (void * v, uword offset);
+
+/* Allocate object from mheap. */
+void * mheap_get_aligned (void * v, uword size, uword align, uword align_offset,
+                         uword * offset_return);
+
+#endif /* included_mem_mheap_h */