summaryrefslogtreecommitdiffstats
path: root/src/vppinfra/test_flowhash_template.c
blob: 19ac4edf2e2638dfe96975a10b26b4e0abba2b6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.hi
/*
 * 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/time.h>
#include <vppinfra/cache.h>
#include <vppinfra/error.h>

#include <vppinfra/heap.h>
#include <vppinfra/format.h>
#include <vppinfra/random.h>
#include <vppinfra/hash.h>

#include <vppinfra/flowhash_8_8.h>

/* Not actually tested here. But included for compilation purposes. */
#include <vppinfra/flowhash_24_16.h>

typedef struct
{
  u64 seed;
  u32 fixed_entries;
  u32 collision_buckets;
  u32 nitems;
  u32 iterations;
  u32 prefetch;
  int non_random_keys;
  uword *key_hash;
  flowhash_lkey_8_8_t *keys;
  flowhash_8_8_t *hash;
  clib_time_t clib_time;
  unformat_input_t *input;
} test_main_t;

test_main_t test_main;

static clib_error_t *
test_flowhash (test_main_t * tm)
{
  f64 before, delta;
  u64 total;
  u32 overflow;
  int i, j;
  uword *p;
  tm->hash = flowhash_alloc_8_8 (tm->fixed_entries, tm->collision_buckets);
  if (tm->hash == NULL)
    return clib_error_return (0, "Could not alloc hash");

  fformat (stdout, "Allocated hash memory size: %llu\n",
	   flowhash_memory_size (tm->hash));

  fformat (stdout, "Pick %lld unique %s keys...\n",
	   tm->nitems, tm->non_random_keys ? "non-random" : "random");

  for (i = 0; i < tm->nitems; i++)
    {
      flowhash_lkey_8_8_t rndkey;
      if (tm->non_random_keys == 0)
	{
	again:
	  rndkey.as_u64[0] = random_u64 (&tm->seed);
	  if ((p = hash_get (tm->key_hash, rndkey.as_u64[0])))
	    goto again;
	}
      else
	rndkey.as_u64[0] = (u64) (i + 1) << 16;

      hash_set (tm->key_hash, rndkey.as_u64[0], i + 1);
      vec_add1 (tm->keys, rndkey);
    }

  hash_free (tm->key_hash);

  /* Additions */
  overflow = 0;
  before = clib_time_now (&tm->clib_time);
  fformat (stdout, "Adding %u items...\n", tm->nitems);
  for (i = 0; i < tm->nitems; i++)
    {
      u32 hash = flowhash_hash_8_8 (&tm->keys[i]);
      u32 ei;
      flowhash_get_8_8 (tm->hash, &tm->keys[i], hash, 1, &ei);
      if (flowhash_is_overflow (ei))
	overflow++;

      /* Set value (No matter if success) */
      flowhash_value (tm->hash, ei)->as_u64[0] = i + 1;

      /* Save value until time > 1 */
      flowhash_timeout (tm->hash, ei) = 1;
    }

  delta = clib_time_now (&tm->clib_time) - before;
  total = tm->nitems;
  fformat (stdout, "%lld additions in %.6f seconds\n", total, delta);
  if (delta > 0)
    fformat (stdout, "%.f additions per second\n", ((f64) total) / delta);

  fformat (stdout, "%u elements in table\n", flowhash_elts_8_8 (tm->hash, 1));
  fformat (stdout, "Flowhash counters:\n");
  fformat (stdout, "  collision-lookup: %lu\n",
	   tm->hash->collision_lookup_counter);
  fformat (stdout, "  not-enough-buckets: %lu\n",
	   tm->hash->not_enough_buckets_counter);
  fformat (stdout, "  overflows: %lu\n", overflow);

  /* Lookups (very similar to additions) */
  overflow = 0;
  before = clib_time_now (&tm->clib_time);
  fformat (stdout, "Looking up %u items %u times...\n", tm->nitems,
	   tm->iterations);

  for (j = 0; j < tm->iterations; j++)
    {
      i = 0;
      if (tm->prefetch)
	for (; i < tm->nitems - tm->prefetch; i++)
	  {
	    u32 ei;
	    u32 hash = flowhash_hash_8_8 (&tm->keys[i + tm->prefetch]);
	    flowhash_prefetch (tm->hash, hash);
	    hash = flowhash_hash_8_8 (&tm->keys[i]);
	    flowhash_get_8_8 (tm->hash, &tm->keys[i], hash, 1, &ei);
	    if (flowhash_is_overflow (ei))
	      overflow++;
	    else if (flowhash_timeout (tm->hash, ei) != 1)
	      clib_warning ("Key not found: %lld\n", tm->keys[i].as_u64[0]);
	    else if (flowhash_value (tm->hash, ei)->as_u64[0] != i + 1)
	      clib_warning ("Value mismatch for key %lld\n",
			    tm->keys[i].as_u64[0]);
	  }

      for (; i < tm->nitems; i++)
	{
	  u32 ei;
	  u32 hash = flowhash_hash_8_8 (&tm->keys[i]);
	  flowhash_get_8_8 (tm->hash, &tm->keys[i], hash, 1, &ei);
	  if (flowhash_is_overflow (ei))
	    overflow++;
	  else if (flowhash_timeout (tm->hash, ei) != 1)
	    clib_warning ("Key not found: %lld\n", tm->keys[i].as_u64[0]);
	  else if (flowhash_value (tm->hash, ei)->as_u64[0] != i + 1)
	    clib_warning ("Value mismatch for key %lld\n",
			  tm->keys[i].as_u64[0]);
	}
    }

  delta = clib_time_now (&tm->clib_time) - before;
  total = tm->nitems * tm->iterations;
  fformat (stdout, "%lld lookups in %.6f seconds\n", total, delta);
  if (delta > 0)
    fformat (stdout, "%.f lookups per second\n", ((f64) total) / delta);

  /* Delete */
  for (i = 0; i < tm->nitems; i++)
    {
      u32 hash = flowhash_hash_8_8 (&tm->keys[i]);
      u32 ei;
      flowhash_get_8_8 (tm->hash, &tm->keys[i], hash, 1, &ei);
      flowhash_timeout (tm->hash, ei) = 0;
    }

  fformat (stdout, "%u elements in table\n", flowhash_elts_8_8 (tm->hash, 1));

  vec_free (tm->keys);
  flowhash_free_8_8 (tm->hash);

  return NULL;
}

clib_error_t *
test_flowhash_main (test_main_t * tm)
{
  unformat_input_t *i = tm->input;
  clib_error_t *error;

  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (i, "seed %u", &tm->seed))
	;
      else if (unformat (i, "fixed-entries %d", &tm->fixed_entries))
	;
      else if (unformat (i, "collision-buckets %d", &tm->collision_buckets))
	;
      else if (unformat (i, "non-random-keys"))
	tm->non_random_keys = 1;
      else if (unformat (i, "nitems %d", &tm->nitems))
	;
      else if (unformat (i, "prefetch %d", &tm->prefetch))
	;
      else if (unformat (i, "iterations %d", &tm->iterations))
	;
      else
	return clib_error_return (0, "unknown input '%U'",
				  format_unformat_error, i);
    }

  error = test_flowhash (tm);
  return error;
}

#ifdef CLIB_UNIX
int
main (int argc, char *argv[])
{

  unformat_input_t i;
  clib_error_t *error;
  test_main_t *tm = &test_main;

  clib_mem_init (0, 3ULL << 30);

  tm->fixed_entries = 8 << 20;
  tm->collision_buckets = 1 << 20;
  tm->seed = 0xdeadf00l;
  tm->iterations = 1;
  tm->input = &i;
  tm->nitems = 1000;
  tm->non_random_keys = 0;
  tm->key_hash = hash_create (0, sizeof (uword));
  tm->prefetch = 0;
  clib_time_init (&tm->clib_time);

  unformat_init_command_line (&i, argv);
  error = test_flowhash_main (tm);
  unformat_free (&i);

  if (error)
    {
      clib_error_report (error);
      return 1;
    }
  return 0;

  return 0;
}
#endif /* CLIB_UNIX */


/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */