vppinfra: allocate bihash virtual space on demand 46/20546/4
authorDave Barach <dave@barachs.net>
Mon, 8 Jul 2019 16:25:38 +0000 (12:25 -0400)
committerFlorin Coras <florin.coras@gmail.com>
Tue, 9 Jul 2019 02:23:00 +0000 (02:23 +0000)
Reduces the vpp image virtual size by multiple gigabytes

Add a "show bihash" command which displays configured and current
virtual space in use by bihash tables.

Modify the .py test framework to call "show bihash" on test tear-down

Type: refactor

Change-Id: Ifc1b7e2c43d29bbef645f6802fa29ff8ef09940c
Signed-off-by: Dave Barach <dave@barachs.net>
src/vnet/ip/ip4_reassembly.c
src/vnet/ip/ip6_reassembly.c
src/vnet/l2/l2_fib.c
src/vpp/vnet/main.c
src/vppinfra/CMakeLists.txt
src/vppinfra/bihash_all_vector.c [new file with mode: 0644]
src/vppinfra/bihash_template.c
src/vppinfra/bihash_template.h
test/framework.py

index d5f0b8a..b894c3b 100644 (file)
@@ -1291,6 +1291,7 @@ ip4_reass_set (u32 timeout_ms, u32 max_reassemblies,
          clib_bihash_free_16_8 (&ip4_reass_main.hash);
          clib_memcpy_fast (&ip4_reass_main.hash, &new_hash,
                            sizeof (ip4_reass_main.hash));
+         clib_bihash_copied (&ip4_reass_main.hash, &new_hash);
        }
     }
   return 0;
index a8b6d2c..7b0d84d 100644 (file)
@@ -1270,6 +1270,7 @@ ip6_reass_set (u32 timeout_ms, u32 max_reassemblies,
          clib_bihash_free_48_8 (&ip6_reass_main.hash);
          clib_memcpy_fast (&ip6_reass_main.hash, &new_hash,
                            sizeof (ip6_reass_main.hash));
+         clib_bihash_copied (&ip6_reass_main.hash, &new_hash);
        }
     }
   return 0;
index fc518fe..b7646ca 100644 (file)
@@ -1000,6 +1000,10 @@ l2fib_scan (vlib_main_t * vm, f64 start_time, u8 event_only)
   vl_api_l2_macs_event_t *mp = 0;
   vl_api_registration_t *reg = 0;
 
+  /* Don't scan the l2 fib if it hasn't been instantiated yet */
+  if (alloc_arena (h) == 0)
+    return 0.0;
+
   if (client)
     {
       mp = allocate_mac_evt_buf (client, cl_idx);
index 5100d5c..673120a 100644 (file)
@@ -415,6 +415,87 @@ vlib_app_num_thread_stacks_needed (void)
  * messages!
  */
 
+#include <vppinfra/bihash_8_8.h>
+
+typedef struct
+{
+  u8 *name;
+  u64 actual_virt_size;
+  u64 configured_virt_size;
+} name_sort_t;
+
+static int
+name_sort_cmp (void *a1, void *a2)
+{
+  name_sort_t *n1 = a1;
+  name_sort_t *n2 = a2;
+
+  return strcmp ((char *) n1->name, (char *) n2->name);
+}
+
+static clib_error_t *
+show_bihash_command_fn (vlib_main_t * vm,
+                       unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+  int i;
+  clib_bihash_8_8_t *h;
+  u64 total_actual_virt_size = 0;
+  u64 total_configured_virt_size = 0;
+  u64 actual_virt_size;
+  u64 configured_virt_size;
+  name_sort_t *names = 0;
+  name_sort_t *this;
+  int verbose = 0;
+
+  if (unformat (input, "verbose"))
+    verbose = 1;
+
+  for (i = 0; i < vec_len (clib_all_bihashes); i++)
+    {
+      h = (clib_bihash_8_8_t *) clib_all_bihashes[i];
+      if (alloc_arena (h) || verbose)
+       {
+         vec_add2 (names, this, 1);
+         this->name = format (0, "%s%c", h->name, 0);
+         configured_virt_size = h->memory_size;
+         actual_virt_size = alloc_arena (h) ? h->memory_size : 0ULL;
+         this->actual_virt_size = actual_virt_size;
+         this->configured_virt_size = configured_virt_size;
+         total_actual_virt_size += actual_virt_size;
+         total_configured_virt_size += configured_virt_size;
+       }
+    }
+
+  vec_sort_with_function (names, name_sort_cmp);
+
+  vlib_cli_output (vm, "%-30s %8s %s", "Name", "Actual", "Configured");
+
+  for (i = 0; i < vec_len (names); i++)
+    {
+      vlib_cli_output (vm, "%-30s %8U %U", names[i].name,
+                      format_memory_size,
+                      names[i].actual_virt_size,
+                      format_memory_size, names[i].configured_virt_size);
+      vec_free (names[i].name);
+    }
+
+  vec_free (names);
+
+  vlib_cli_output (vm, "%-30s %8U %U", "Total",
+                  format_memory_size, total_actual_virt_size,
+                  format_memory_size, total_configured_virt_size);
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_bihash_command, static) =
+{
+  .path = "show bihash",
+  .short_help = "show bihash",
+  .function = show_bihash_command_fn,
+};
+/* *INDENT-ON* */
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
index a42bcb8..d8b302c 100644 (file)
@@ -40,6 +40,7 @@ install(
 ##############################################################################
 set(VPPINFRA_SRCS
   backtrace.c
+  bihash_all_vector.c
   cpu.c
   cuckoo_template.c
   elf.c
diff --git a/src/vppinfra/bihash_all_vector.c b/src/vppinfra/bihash_all_vector.c
new file mode 100644 (file)
index 0000000..b6c64a3
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#include <vppinfra/mem.h>
+
+/* Vector of all bihashes */
+void **clib_all_bihashes;
+static void **clib_all_bihash_heap;
+
+void *
+clib_all_bihash_set_heap (void)
+{
+  if (PREDICT_FALSE (clib_all_bihash_heap == 0))
+    clib_all_bihash_heap = clib_mem_get_heap ();
+
+  return clib_mem_set_heap (clib_all_bihash_heap);
+}
+
+/*
+ * Leave it to Beaver to change the size of a bihash
+ * by making a clone in a stack local and then copying it...
+ */
+void
+clib_bihash_copied (void *dst, void *src)
+{
+  int i;
+
+  for (i = 0; i < vec_len (clib_all_bihashes); i++)
+    {
+      if (clib_all_bihashes[i] == src)
+       {
+         clib_all_bihashes[i] = dst;
+         return;
+       }
+    }
+  clib_warning ("Couldn't find bihash copy source %llx!", src);
+}
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index a10dee0..bf6be83 100644 (file)
@@ -32,17 +32,33 @@ static inline void *BV (alloc_aligned) (BVT (clib_bihash) * h, uword nbytes)
   return (void *) (uword) (rv + alloc_arena (h));
 }
 
+void BV (clib_bihash_instantiate) (BVT (clib_bihash) * h)
+{
+  uword bucket_size;
+
+  alloc_arena (h) = (uword) clib_mem_vm_alloc (h->memory_size);
+  alloc_arena_next (h) = 0;
+  alloc_arena_size (h) = h->memory_size;
+
+  bucket_size = h->nbuckets * sizeof (h->buckets[0]);
+  h->buckets = BV (alloc_aligned) (h, bucket_size);
+
+  h->alloc_lock = BV (alloc_aligned) (h, CLIB_CACHE_LINE_BYTES);
+  h->alloc_lock[0] = 0;
+}
 
 void BV (clib_bihash_init)
   (BVT (clib_bihash) * h, char *name, u32 nbuckets, uword memory_size)
 {
-  uword bucket_size;
-
+  int i;
+  void *oldheap;
   nbuckets = 1 << (max_log2 (nbuckets));
 
   h->name = (u8 *) name;
   h->nbuckets = nbuckets;
   h->log2_nbuckets = max_log2 (nbuckets);
+  h->memory_size = memory_size;
+  alloc_arena (h) = 0;
 
   /*
    * Make sure the requested size is rational. The max table
@@ -51,18 +67,21 @@ void BV (clib_bihash_init)
    * the offset by CLIB_LOG2_CACHE_LINE_BYTES...
    */
   ASSERT (memory_size < (1ULL << BIHASH_BUCKET_OFFSET_BITS));
+  h->fmt_fn = NULL;
 
-  alloc_arena (h) = (uword) clib_mem_vm_alloc (memory_size);
-  alloc_arena_next (h) = 0;
-  alloc_arena_size (h) = memory_size;
+  /* Add this hash table to the list */
+  for (i = 0; i < vec_len (clib_all_bihashes); i++)
+    if (clib_all_bihashes[i] == h)
+      return;
 
-  bucket_size = nbuckets * sizeof (h->buckets[0]);
-  h->buckets = BV (alloc_aligned) (h, bucket_size);
+  /* Unfortunately, the heap push/pop is required.... */
+  oldheap = clib_all_bihash_set_heap ();
+  vec_add1 (clib_all_bihashes, (void *) h);
+  clib_mem_set_heap (oldheap);
 
-  h->alloc_lock = BV (alloc_aligned) (h, CLIB_CACHE_LINE_BYTES);
-  h->alloc_lock[0] = 0;
-
-  h->fmt_fn = NULL;
+#if BIHASH_INSTANTIATE_IMMEDIATELY
+  BV (clib_bihash_instantiate) (h);
+#endif
 }
 
 #if BIHASH_32_64_SVM
@@ -195,6 +214,11 @@ void BV (clib_bihash_set_kvp_format_fn) (BVT (clib_bihash) * h,
 
 void BV (clib_bihash_free) (BVT (clib_bihash) * h)
 {
+  int i;
+
+  if (PREDICT_FALSE (alloc_arena (h) == 0))
+    goto never_initialized;
+
   vec_free (h->working_copies);
   vec_free (h->working_copy_lengths);
 #if BIHASH_32_64_SVM == 0
@@ -204,7 +228,18 @@ void BV (clib_bihash_free) (BVT (clib_bihash) * h)
     (void) close (h->memfd);
 #endif
   clib_mem_vm_free ((void *) (uword) (alloc_arena (h)), alloc_arena_size (h));
+never_initialized:
   clib_memset (h, 0, sizeof (*h));
+  for (i = 0; i < vec_len (clib_all_bihashes); i++)
+    {
+      if ((void *) h == clib_all_bihashes[i])
+       {
+         vec_delete (clib_all_bihashes, 1, i);
+         return;
+       }
+    }
+  clib_warning ("Couldn't find hash table %llx on clib_all_bihashes...",
+               (u64) h);
 }
 
 static
@@ -417,6 +452,14 @@ static inline int BV (clib_bihash_add_del_inline)
   int mark_bucket_linear;
   int resplit_once;
 
+  /* Create the table (is_add=1), or flunk the request now (is_add=0) */
+  if (PREDICT_FALSE (alloc_arena (h) == 0))
+    {
+      if (is_add == 0)
+       return (-1);
+      BV (clib_bihash_instantiate) (h);
+    }
+
   hash = BV (clib_bihash_hash) (add_v);
 
   bucket_index = hash & (h->nbuckets - 1);
@@ -678,6 +721,9 @@ int BV (clib_bihash_search)
 
   ASSERT (valuep);
 
+  if (PREDICT_FALSE (alloc_arena (h) == 0))
+    return -1;
+
   hash = BV (clib_bihash_hash) (search_key);
 
   bucket_index = hash & (h->nbuckets - 1);
@@ -726,6 +772,9 @@ u8 *BV (format_bihash) (u8 * s, va_list * args)
 
   s = format (s, "Hash table %s\n", h->name ? h->name : (u8 *) "(unnamed)");
 
+  if (PREDICT_FALSE (alloc_arena (h) == 0))
+    return format (s, "[empty, uninitialized]");
+
   for (i = 0; i < h->nbuckets; i++)
     {
       b = &h->buckets[i];
@@ -820,6 +869,9 @@ void BV (clib_bihash_foreach_key_value_pair)
   BVT (clib_bihash_value) * v;
   void (*fp) (BVT (clib_bihash_kv) *, void *) = callback;
 
+  if (PREDICT_FALSE (alloc_arena (h) == 0))
+    return;
+
   for (i = 0; i < h->nbuckets; i++)
     {
       b = &h->buckets[i];
index d145b61..2e2ba91 100644 (file)
@@ -129,6 +129,7 @@ BVS (clib_bihash)
 
   u32 nbuckets;
   u32 log2_nbuckets;
+  u64 memory_size;
   u8 *name;
 
   u64 *freelists;
@@ -157,6 +158,8 @@ BVS (clib_bihash)
 
 } BVT (clib_bihash);
 
+extern void **clib_all_bihashes;
+
 #if BIHASH_32_64_SVM
 #undef alloc_arena_next
 #undef alloc_arena_size
@@ -313,6 +316,8 @@ int BV (clib_bihash_search) (BVT (clib_bihash) * h,
 
 void BV (clib_bihash_foreach_key_value_pair) (BVT (clib_bihash) * h,
                                              void *callback, void *arg);
+void *clib_all_bihash_set_heap (void);
+void clib_bihash_copied (void *dst, void *src);
 
 format_function_t BV (format_bihash);
 format_function_t BV (format_bihash_kvp);
@@ -326,6 +331,9 @@ static inline int BV (clib_bihash_search_inline_with_hash)
   BVT (clib_bihash_bucket) * b;
   int i, limit;
 
+  if (PREDICT_FALSE (alloc_arena (h) == 0))
+    return -1;
+
   bucket_index = hash & (h->nbuckets - 1);
   b = &h->buckets[bucket_index];
 
@@ -389,6 +397,9 @@ static inline void BV (clib_bihash_prefetch_data)
   BVT (clib_bihash_value) * v;
   BVT (clib_bihash_bucket) * b;
 
+  if (PREDICT_FALSE (alloc_arena (h) == 0))
+    return;
+
   bucket_index = hash & (h->nbuckets - 1);
   b = &h->buckets[bucket_index];
 
@@ -414,6 +425,9 @@ static inline int BV (clib_bihash_search_inline_2_with_hash)
 
   ASSERT (valuep);
 
+  if (PREDICT_FALSE (alloc_arena (h) == 0))
+    return -1;
+
   bucket_index = hash & (h->nbuckets - 1);
   b = &h->buckets[bucket_index];
 
index 4bc64a1..6bed1eb 100644 (file)
@@ -656,6 +656,7 @@ class VppTestCase(unittest.TestCase):
                 self.logger.info(self.statistics.set_errors_str())
                 self.logger.info(self.vapi.ppcli("show run"))
                 self.logger.info(self.vapi.ppcli("show log"))
+                self.logger.info(self.vapi.ppcli("show bihash"))
                 self.logger.info("Logging testcase specific show commands.")
                 self.show_commands_at_teardown()
                 self.registry.remove_vpp_config(self.logger)