LCOV - code coverage report
Current view: top level - tests - test-cmap.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 105 297 35.4 %
Date: 2016-09-14 01:02:56 Functions: 12 25 48.0 %
Branches: 46 164 28.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2008, 2009, 2010, 2013, 2014, 2016 Nicira, Inc.
       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                 :            : /* A non-exhaustive test for some of the functions and macros declared in
      18                 :            :  * cmap.h. */
      19                 :            : 
      20                 :            : #include <config.h>
      21                 :            : #undef NDEBUG
      22                 :            : #include "cmap.h"
      23                 :            : #include <assert.h>
      24                 :            : #include <getopt.h>
      25                 :            : #include <string.h>
      26                 :            : #include "bitmap.h"
      27                 :            : #include "command-line.h"
      28                 :            : #include "fat-rwlock.h"
      29                 :            : #include "hash.h"
      30                 :            : #include "openvswitch/hmap.h"
      31                 :            : #include "ovstest.h"
      32                 :            : #include "ovs-thread.h"
      33                 :            : #include "random.h"
      34                 :            : #include "timeval.h"
      35                 :            : #include "util.h"
      36                 :            : 
      37                 :            : /* Sample cmap element. */
      38                 :            : struct element {
      39                 :            :     int value;
      40                 :            :     struct cmap_node node;
      41                 :            : };
      42                 :            : 
      43                 :            : typedef size_t hash_func(int value);
      44                 :            : 
      45                 :            : static int
      46                 :  131218675 : compare_ints(const void *a_, const void *b_)
      47                 :            : {
      48                 :  131218675 :     const int *a = a_;
      49                 :  131218675 :     const int *b = b_;
      50         [ +  + ]:  131218675 :     return *a < *b ? -1 : *a > *b;
      51                 :            : }
      52                 :            : 
      53                 :            : /* Verifies that 'cmap' contains exactly the 'n' values in 'values'. */
      54                 :            : static void
      55                 :       9000 : check_cmap(struct cmap *cmap, const int values[], size_t n,
      56                 :            :            hash_func *hash)
      57                 :            : {
      58                 :            :     int *sort_values, *cmap_values, *cmap_values2;
      59                 :            :     const struct element *e;
      60                 :            :     size_t i, batch_size;
      61                 :            : 
      62                 :       9000 :     struct cmap_position pos = { 0, 0, 0 };
      63                 :            :     struct cmap_node *node;
      64                 :            : 
      65                 :            :     /* Check that all the values are there in iteration. */
      66                 :       9000 :     sort_values = xmalloc(sizeof *sort_values * n);
      67                 :       9000 :     cmap_values = xmalloc(sizeof *sort_values * n);
      68                 :       9000 :     cmap_values2 = xmalloc(sizeof *sort_values * n);
      69                 :            : 
      70                 :            :     /* Here we test cursor iteration */
      71                 :       9000 :     i = 0;
      72 [ +  + ][ +  + ]:    6009000 :     CMAP_FOR_EACH (e, node, cmap) {
      73         [ -  + ]:    6000000 :         assert(i < n);
      74                 :    6000000 :         cmap_values[i++] = e->value;
      75                 :            :     }
      76         [ -  + ]:       9000 :     assert(i == n);
      77                 :            : 
      78                 :            :     /* Here we test iteration with cmap_next_position() */
      79                 :       9000 :     i = 0;
      80         [ +  + ]:    6009000 :     while ((node = cmap_next_position(cmap, &pos))) {
      81                 :    6000000 :         struct element *e = NULL;
      82                 :    6000000 :         e = OBJECT_CONTAINING(node, e, node);
      83                 :            : 
      84         [ -  + ]:    6000000 :         assert(i < n);
      85                 :    6000000 :         cmap_values2[i++] = e->value;
      86                 :            :     }
      87         [ -  + ]:       9000 :     assert(i == n);
      88                 :            : 
      89                 :       9000 :     memcpy(sort_values, values, sizeof *sort_values * n);
      90                 :       9000 :     qsort(sort_values, n, sizeof *sort_values, compare_ints);
      91                 :       9000 :     qsort(cmap_values, n, sizeof *cmap_values, compare_ints);
      92                 :       9000 :     qsort(cmap_values2, n, sizeof *cmap_values2, compare_ints);
      93                 :            : 
      94         [ +  + ]:    6009000 :     for (i = 0; i < n; i++) {
      95         [ -  + ]:    6000000 :         assert(sort_values[i] == cmap_values[i]);
      96         [ -  + ]:    6000000 :         assert(sort_values[i] == cmap_values2[i]);
      97                 :            :     }
      98                 :            : 
      99                 :       9000 :     free(cmap_values2);
     100                 :       9000 :     free(cmap_values);
     101                 :       9000 :     free(sort_values);
     102                 :            : 
     103                 :            :     /* Check that all the values are there in lookup. */
     104         [ +  + ]:    6009000 :     for (i = 0; i < n; i++) {
     105                 :    6000000 :         size_t count = 0;
     106                 :            : 
     107         [ +  + ]: 1676667000 :         CMAP_FOR_EACH_WITH_HASH (e, node, hash(values[i]), cmap) {
     108                 : 1670667000 :             count += e->value == values[i];
     109                 :            :         }
     110         [ -  + ]:    6000000 :         assert(count == 1);
     111                 :            :     }
     112                 :            : 
     113                 :            :     /* Check that all the values are there in batched lookup. */
     114                 :       9000 :     batch_size = n % BITMAP_ULONG_BITS + 1;
     115         [ +  + ]:     308145 :     for (i = 0; i < n; i += batch_size) {
     116                 :            :         unsigned long map;
     117                 :            :         uint32_t hashes[sizeof map * CHAR_BIT];
     118                 :            :         const struct cmap_node *nodes[sizeof map * CHAR_BIT];
     119                 :     299145 :         size_t count = 0;
     120                 :            :         int k, j;
     121                 :            : 
     122                 :     299145 :         j = MIN(n - i, batch_size); /* Actual batch size. */
     123                 :     299145 :         map = ~0UL >> (BITMAP_ULONG_BITS - j);
     124                 :            : 
     125         [ +  + ]:    6299145 :         for (k = 0; k < j; k++) {
     126                 :    6000000 :             hashes[k] = hash(values[i + k]);
     127                 :            :         }
     128                 :     299145 :         map = cmap_find_batch(cmap, map, hashes, nodes);
     129                 :            : 
     130         [ +  + ]:    6299145 :         ULLONG_FOR_EACH_1(k, map) {
     131                 :            :             struct element *e;
     132                 :            : 
     133         [ +  + ]: 1676667000 :             CMAP_NODE_FOR_EACH (e, node, nodes[k]) {
     134                 : 1670667000 :                 count += e->value == values[i + k];
     135                 :            :             }
     136                 :            :         }
     137         [ -  + ]:     299145 :         assert(count == j); /* j elements in a batch. */
     138                 :            :     }
     139                 :            : 
     140                 :            :     /* Check that cmap_first() returns NULL only when cmap_is_empty(). */
     141         [ -  + ]:       9000 :     assert(!cmap_first(cmap) == cmap_is_empty(cmap));
     142                 :            : 
     143                 :            :     /* Check counters. */
     144         [ -  + ]:       9000 :     assert(cmap_is_empty(cmap) == !n);
     145         [ -  + ]:       9000 :     assert(cmap_count(cmap) == n);
     146                 :       9000 : }
     147                 :            : 
     148                 :            : static void
     149                 :          6 : shuffle(int *p, size_t n)
     150                 :            : {
     151         [ +  + ]:       6000 :     for (; n > 1; n--, p++) {
     152                 :       5994 :         int *q = &p[random_range(n)];
     153                 :       5994 :         int tmp = *p;
     154                 :       5994 :         *p = *q;
     155                 :       5994 :         *q = tmp;
     156                 :            :     }
     157                 :          6 : }
     158                 :            : 
     159                 :            : /* Prints the values in 'cmap', plus 'name' as a title. */
     160                 :            : static void OVS_UNUSED
     161                 :          0 : print_cmap(const char *name, struct cmap *cmap)
     162                 :            : {
     163                 :            :     struct cmap_cursor cursor;
     164                 :            :     struct element *e;
     165                 :            : 
     166                 :          0 :     printf("%s:", name);
     167 [ #  # ][ #  # ]:          0 :     CMAP_CURSOR_FOR_EACH (e, node, &cursor, cmap) {
     168                 :          0 :         printf(" %d", e->value);
     169                 :            :     }
     170                 :          0 :     printf("\n");
     171                 :          0 : }
     172                 :            : 
     173                 :            : /* Prints the 'n' values in 'values', plus 'name' as a title. */
     174                 :            : static void OVS_UNUSED
     175                 :          0 : print_ints(const char *name, const int *values, size_t n)
     176                 :            : {
     177                 :            :     size_t i;
     178                 :            : 
     179                 :          0 :     printf("%s:", name);
     180         [ #  # ]:          0 :     for (i = 0; i < n; i++) {
     181                 :          0 :         printf(" %d", values[i]);
     182                 :            :     }
     183                 :          0 :     printf("\n");
     184                 :          0 : }
     185                 :            : 
     186                 :            : static size_t
     187                 :    4003000 : identity_hash(int value)
     188                 :            : {
     189                 :    4003000 :     return value;
     190                 :            : }
     191                 :            : 
     192                 :            : static size_t
     193                 :    4003000 : good_hash(int value)
     194                 :            : {
     195                 :    4003000 :     return hash_int(value, 0x1234abcd);
     196                 :            : }
     197                 :            : 
     198                 :            : static size_t
     199                 :    4003000 : constant_hash(int value OVS_UNUSED)
     200                 :            : {
     201                 :    4003000 :     return 123;
     202                 :            : }
     203                 :            : 
     204                 :            : /* Tests basic cmap insertion and deletion. */
     205                 :            : static void
     206                 :          3 : test_cmap_insert_replace_delete(hash_func *hash)
     207                 :            : {
     208                 :            :     enum { N_ELEMS = 1000 };
     209                 :            : 
     210                 :            :     struct element elements[N_ELEMS];
     211                 :            :     struct element copies[N_ELEMS];
     212                 :            :     int values[N_ELEMS];
     213                 :          3 :     struct cmap cmap = CMAP_INITIALIZER;
     214                 :            :     size_t i;
     215                 :            : 
     216         [ +  + ]:       3003 :     for (i = 0; i < N_ELEMS; i++) {
     217                 :       3000 :         elements[i].value = i;
     218                 :       3000 :         cmap_insert(&cmap, &elements[i].node, hash(i));
     219                 :       3000 :         values[i] = i;
     220                 :       3000 :         check_cmap(&cmap, values, i + 1, hash);
     221                 :            :     }
     222                 :          3 :     shuffle(values, N_ELEMS);
     223         [ +  + ]:       3003 :     for (i = 0; i < N_ELEMS; i++) {
     224                 :       3000 :         copies[values[i]].value = values[i];
     225                 :       3000 :         cmap_replace(&cmap, &elements[values[i]].node,
     226                 :       3000 :                      &copies[values[i]].node, hash(values[i]));
     227                 :       3000 :         check_cmap(&cmap, values, N_ELEMS, hash);
     228                 :            :     }
     229                 :          3 :     shuffle(values, N_ELEMS);
     230         [ +  + ]:       3003 :     for (i = 0; i < N_ELEMS; i++) {
     231                 :       3000 :         cmap_remove(&cmap, &copies[values[i]].node, hash(values[i]));
     232                 :       3000 :         check_cmap(&cmap, values + (i + 1), N_ELEMS - (i + 1), hash);
     233                 :            :     }
     234                 :          3 :     cmap_destroy(&cmap);
     235                 :          3 : }
     236                 :            : 
     237                 :            : static void
     238                 :          1 : run_test(void (*function)(hash_func *))
     239                 :            : {
     240                 :          1 :     hash_func *hash_funcs[] = { identity_hash, good_hash, constant_hash };
     241                 :            :     size_t i;
     242                 :            : 
     243         [ +  + ]:          4 :     for (i = 0; i < ARRAY_SIZE(hash_funcs); i++) {
     244                 :          3 :         function(hash_funcs[i]);
     245                 :          3 :         printf(".");
     246                 :          3 :         fflush(stdout);
     247                 :            :     }
     248                 :          1 : }
     249                 :            : 
     250                 :            : static void
     251                 :          1 : run_tests(struct ovs_cmdl_context *ctx)
     252                 :            : {
     253                 :            :     int n;
     254                 :            :     int i;
     255                 :            : 
     256         [ +  - ]:          1 :     n = ctx->argc >= 2 ? atoi(ctx->argv[1]) : 100;
     257         [ +  + ]:          2 :     for (i = 0; i < n; i++) {
     258                 :          1 :         run_test(test_cmap_insert_replace_delete);
     259                 :            :     }
     260                 :          1 :     printf("\n");
     261                 :          1 : }
     262                 :            : 
     263                 :            : static int n_elems;             /* Number of elements to insert. */
     264                 :            : static int n_threads;           /* Number of threads to search and mutate. */
     265                 :            : static uint32_t mutation_frac;  /* % mutations, as fraction of UINT32_MAX. */
     266                 :            : static int n_batch;             /* Number of elements in each batch. */
     267                 :            : 
     268                 :            : #define N_BATCH_MAX BITMAP_ULONG_BITS
     269                 :            : 
     270                 :            : static void benchmark_cmap(void);
     271                 :            : static void benchmark_cmap_batched(void);
     272                 :            : static void benchmark_hmap(void);
     273                 :            : 
     274                 :            : static int
     275                 :          0 : elapsed(const struct timeval *start)
     276                 :            : {
     277                 :            :     struct timeval end;
     278                 :            : 
     279                 :          0 :     xgettimeofday(&end);
     280                 :          0 :     return timeval_to_msec(&end) - timeval_to_msec(start);
     281                 :            : }
     282                 :            : 
     283                 :            : static void
     284                 :          0 : run_benchmarks(struct ovs_cmdl_context *ctx)
     285                 :            : {
     286                 :          0 :     n_elems = strtol(ctx->argv[1], NULL, 10);
     287                 :          0 :     n_threads = strtol(ctx->argv[2], NULL, 10);
     288                 :          0 :     mutation_frac = strtod(ctx->argv[3], NULL) / 100.0 * UINT32_MAX;
     289         [ #  # ]:          0 :     n_batch = ctx->argc > 4 ? strtol(ctx->argv[4], NULL, 10) : 1;
     290                 :            : 
     291         [ #  # ]:          0 :     if (n_batch > N_BATCH_MAX) {
     292                 :          0 :         n_batch = N_BATCH_MAX;
     293                 :            :     }
     294                 :          0 :     printf("Benchmarking with n=%d, %d threads, %.2f%% mutations, batch size %d:\n",
     295                 :          0 :            n_elems, n_threads, (double) mutation_frac / UINT32_MAX * 100.,
     296                 :            :            n_batch);
     297                 :            : 
     298         [ #  # ]:          0 :     if (n_batch > 0) {
     299                 :          0 :         benchmark_cmap_batched();
     300                 :            :     }
     301                 :          0 :     putchar('\n');
     302                 :          0 :     benchmark_cmap();
     303                 :          0 :     putchar('\n');
     304                 :          0 :     benchmark_hmap();
     305                 :          0 : }
     306                 :            : 
     307                 :            : /* cmap benchmark. */
     308                 :            : 
     309                 :            : static struct element *
     310                 :          0 : find(const struct cmap *cmap, int value)
     311                 :            : {
     312                 :            :     struct element *e;
     313                 :            : 
     314         [ #  # ]:          0 :     CMAP_FOR_EACH_WITH_HASH (e, node, hash_int(value, 0), cmap) {
     315         [ #  # ]:          0 :         if (e->value == value) {
     316                 :          0 :             return e;
     317                 :            :         }
     318                 :            :     }
     319                 :          0 :     return NULL;
     320                 :            : }
     321                 :            : 
     322                 :            : struct cmap_aux {
     323                 :            :     struct ovs_mutex mutex;
     324                 :            :     struct cmap *cmap;
     325                 :            : };
     326                 :            : 
     327                 :            : static void *
     328                 :          0 : search_cmap(void *aux_)
     329                 :            : {
     330                 :          0 :     struct cmap_aux *aux = aux_;
     331                 :            :     size_t i;
     332                 :            : 
     333         [ #  # ]:          0 :     if (mutation_frac) {
     334         [ #  # ]:          0 :         for (i = 0; i < n_elems; i++) {
     335                 :            :             struct element *e;
     336                 :            : 
     337         [ #  # ]:          0 :             if (random_uint32() < mutation_frac) {
     338                 :          0 :                 ovs_mutex_lock(&aux->mutex);
     339                 :          0 :                 e = find(aux->cmap, i);
     340         [ #  # ]:          0 :                 if (e) {
     341                 :          0 :                     cmap_remove(aux->cmap, &e->node, hash_int(e->value, 0));
     342                 :            :                 }
     343                 :          0 :                 ovs_mutex_unlock(&aux->mutex);
     344                 :            :             } else {
     345                 :          0 :                 ignore(find(aux->cmap, i));
     346                 :            :             }
     347                 :            :         }
     348                 :            :     } else {
     349         [ #  # ]:          0 :         for (i = 0; i < n_elems; i++) {
     350                 :          0 :             ignore(find(aux->cmap, i));
     351                 :            :         }
     352                 :            :     }
     353                 :          0 :     return NULL;
     354                 :            : }
     355                 :            : 
     356                 :            : static void
     357                 :          0 : benchmark_cmap(void)
     358                 :            : {
     359                 :            :     struct element *elements;
     360                 :            :     struct cmap cmap;
     361                 :            :     struct element *e;
     362                 :            :     struct timeval start;
     363                 :            :     pthread_t *threads;
     364                 :            :     struct cmap_aux aux;
     365                 :            :     size_t i;
     366                 :            : 
     367                 :          0 :     elements = xmalloc(n_elems * sizeof *elements);
     368                 :            : 
     369                 :            :     /* Insertions. */
     370                 :          0 :     xgettimeofday(&start);
     371                 :          0 :     cmap_init(&cmap);
     372         [ #  # ]:          0 :     for (i = 0; i < n_elems; i++) {
     373                 :          0 :         elements[i].value = i;
     374                 :          0 :         cmap_insert(&cmap, &elements[i].node, hash_int(i, 0));
     375                 :            :     }
     376                 :          0 :     printf("cmap insert:  %5d ms\n", elapsed(&start));
     377                 :            : 
     378                 :            :     /* Iteration. */
     379                 :          0 :     xgettimeofday(&start);
     380 [ #  # ][ #  # ]:          0 :     CMAP_FOR_EACH (e, node, &cmap) {
     381                 :          0 :         ignore(e);
     382                 :            :     }
     383                 :          0 :     printf("cmap iterate: %5d ms\n", elapsed(&start));
     384                 :            : 
     385                 :            :     /* Search and mutation. */
     386                 :          0 :     xgettimeofday(&start);
     387                 :          0 :     aux.cmap = &cmap;
     388                 :          0 :     ovs_mutex_init(&aux.mutex);
     389                 :          0 :     threads = xmalloc(n_threads * sizeof *threads);
     390         [ #  # ]:          0 :     for (i = 0; i < n_threads; i++) {
     391                 :          0 :         threads[i] = ovs_thread_create("search", search_cmap, &aux);
     392                 :            :     }
     393         [ #  # ]:          0 :     for (i = 0; i < n_threads; i++) {
     394                 :          0 :         xpthread_join(threads[i], NULL);
     395                 :            :     }
     396                 :          0 :     free(threads);
     397                 :          0 :     printf("cmap search:  %5d ms\n", elapsed(&start));
     398                 :            : 
     399                 :            :     /* Destruction. */
     400                 :          0 :     xgettimeofday(&start);
     401 [ #  # ][ #  # ]:          0 :     CMAP_FOR_EACH (e, node, &cmap) {
     402                 :          0 :         cmap_remove(&cmap, &e->node, hash_int(e->value, 0));
     403                 :            :     }
     404                 :          0 :     cmap_destroy(&cmap);
     405                 :          0 :     printf("cmap destroy: %5d ms\n", elapsed(&start));
     406                 :            : 
     407                 :          0 :     free(elements);
     408                 :          0 : }
     409                 :            : 
     410                 :            : static size_t
     411                 :          0 : find_batch(const struct cmap *cmap, const int value)
     412                 :            : {
     413                 :            :     size_t i, ret;
     414                 :          0 :     const size_t end = MIN(n_batch, n_elems - value);
     415                 :          0 :     unsigned long map = ~0;
     416                 :            :     uint32_t hashes[N_BATCH_MAX];
     417                 :            :     const struct cmap_node *nodes[N_BATCH_MAX];
     418                 :            : 
     419         [ #  # ]:          0 :     if (mutation_frac) {
     420         [ #  # ]:          0 :         for (i = 0; i < end; i++) {
     421         [ #  # ]:          0 :             if (random_uint32() < mutation_frac) {
     422                 :          0 :                 break;
     423                 :            :             }
     424                 :          0 :             hashes[i] = hash_int(value + i, 0);
     425                 :            :         }
     426                 :            :     } else {
     427         [ #  # ]:          0 :         for (i = 0; i < end; i++) {
     428                 :          0 :             hashes[i] = hash_int(value + i, 0);
     429                 :            :         }
     430                 :            :     }
     431                 :            : 
     432                 :          0 :     ret = i;
     433                 :            : 
     434                 :          0 :     map >>= BITMAP_ULONG_BITS - i; /* Clear excess bits. */
     435                 :          0 :     map = cmap_find_batch(cmap, map, hashes, nodes);
     436                 :            : 
     437         [ #  # ]:          0 :     ULLONG_FOR_EACH_1(i, map) {
     438                 :            :         struct element *e;
     439                 :            : 
     440         [ #  # ]:          0 :         CMAP_NODE_FOR_EACH (e, node, nodes[i]) {
     441         [ #  # ]:          0 :             if (OVS_LIKELY(e->value == value + i)) {
     442                 :          0 :                 ignore(e); /* Found result. */
     443                 :          0 :                 break;
     444                 :            :             }
     445                 :            :         }
     446                 :            :     }
     447                 :          0 :     return ret;
     448                 :            : }
     449                 :            : 
     450                 :            : static void *
     451                 :          0 : search_cmap_batched(void *aux_)
     452                 :            : {
     453                 :          0 :     struct cmap_aux *aux = aux_;
     454                 :          0 :     size_t i = 0, j;
     455                 :            : 
     456                 :            :     for (;;) {
     457                 :            :         struct element *e;
     458                 :            : 
     459                 :          0 :         j = find_batch(aux->cmap, i);
     460                 :          0 :         i += j;
     461         [ #  # ]:          0 :         if (i >= n_elems) {
     462                 :          0 :             break;
     463                 :            :         }
     464         [ #  # ]:          0 :         if (j < n_batch) {
     465                 :          0 :             ovs_mutex_lock(&aux->mutex);
     466                 :          0 :             e = find(aux->cmap, i);
     467         [ #  # ]:          0 :             if (e) {
     468                 :          0 :                 cmap_remove(aux->cmap, &e->node, hash_int(e->value, 0));
     469                 :            :             }
     470                 :          0 :             ovs_mutex_unlock(&aux->mutex);
     471                 :            :         }
     472                 :          0 :     }
     473                 :            : 
     474                 :          0 :     return NULL;
     475                 :            : }
     476                 :            : 
     477                 :            : static void
     478                 :          0 : benchmark_cmap_batched(void)
     479                 :            : {
     480                 :            :     struct element *elements;
     481                 :            :     struct cmap cmap;
     482                 :            :     struct element *e;
     483                 :            :     struct timeval start;
     484                 :            :     pthread_t *threads;
     485                 :            :     struct cmap_aux aux;
     486                 :            :     size_t i;
     487                 :            : 
     488                 :          0 :     elements = xmalloc(n_elems * sizeof *elements);
     489                 :            : 
     490                 :            :     /* Insertions. */
     491                 :          0 :     xgettimeofday(&start);
     492                 :          0 :     cmap_init(&cmap);
     493         [ #  # ]:          0 :     for (i = 0; i < n_elems; i++) {
     494                 :          0 :         elements[i].value = i;
     495                 :          0 :         cmap_insert(&cmap, &elements[i].node, hash_int(i, 0));
     496                 :            :     }
     497                 :          0 :     printf("cmap insert:  %5d ms\n", elapsed(&start));
     498                 :            : 
     499                 :            :     /* Iteration. */
     500                 :          0 :     xgettimeofday(&start);
     501 [ #  # ][ #  # ]:          0 :     CMAP_FOR_EACH (e, node, &cmap) {
     502                 :          0 :         ignore(e);
     503                 :            :     }
     504                 :          0 :     printf("cmap iterate: %5d ms\n", elapsed(&start));
     505                 :            : 
     506                 :            :     /* Search and mutation. */
     507                 :          0 :     xgettimeofday(&start);
     508                 :          0 :     aux.cmap = &cmap;
     509                 :          0 :     ovs_mutex_init(&aux.mutex);
     510                 :          0 :     threads = xmalloc(n_threads * sizeof *threads);
     511         [ #  # ]:          0 :     for (i = 0; i < n_threads; i++) {
     512                 :          0 :         threads[i] = ovs_thread_create("search", search_cmap_batched, &aux);
     513                 :            :     }
     514         [ #  # ]:          0 :     for (i = 0; i < n_threads; i++) {
     515                 :          0 :         xpthread_join(threads[i], NULL);
     516                 :            :     }
     517                 :          0 :     free(threads);
     518                 :          0 :     printf("batch search: %5d ms\n", elapsed(&start));
     519                 :            : 
     520                 :            :     /* Destruction. */
     521                 :          0 :     xgettimeofday(&start);
     522 [ #  # ][ #  # ]:          0 :     CMAP_FOR_EACH (e, node, &cmap) {
     523                 :          0 :         cmap_remove(&cmap, &e->node, hash_int(e->value, 0));
     524                 :            :     }
     525                 :          0 :     cmap_destroy(&cmap);
     526                 :          0 :     printf("cmap destroy: %5d ms\n", elapsed(&start));
     527                 :            : 
     528                 :          0 :     free(elements);
     529                 :          0 : }
     530                 :            : 
     531                 :            : /* hmap benchmark. */
     532                 :            : struct helement {
     533                 :            :     int value;
     534                 :            :     struct hmap_node node;
     535                 :            : };
     536                 :            : 
     537                 :            : static struct helement *
     538                 :          0 : hfind(const struct hmap *hmap, int value)
     539                 :            : {
     540                 :            :     struct helement *e;
     541                 :            : 
     542 [ #  # ][ #  # ]:          0 :     HMAP_FOR_EACH_WITH_HASH (e, node, hash_int(value, 0), hmap) {
     543         [ #  # ]:          0 :         if (e->value == value) {
     544                 :          0 :             return e;
     545                 :            :         }
     546                 :            :     }
     547                 :          0 :     return NULL;
     548                 :            : }
     549                 :            : 
     550                 :            : struct hmap_aux {
     551                 :            :     struct hmap *hmap;
     552                 :            :     struct fat_rwlock fatlock;
     553                 :            : };
     554                 :            : 
     555                 :            : static void *
     556                 :          0 : search_hmap(void *aux_)
     557                 :            : {
     558                 :          0 :     struct hmap_aux *aux = aux_;
     559                 :            :     size_t i;
     560                 :            : 
     561         [ #  # ]:          0 :     if (mutation_frac) {
     562         [ #  # ]:          0 :         for (i = 0; i < n_elems; i++) {
     563         [ #  # ]:          0 :             if (random_uint32() < mutation_frac) {
     564                 :            :                 struct helement *e;
     565                 :            : 
     566                 :          0 :                 fat_rwlock_wrlock(&aux->fatlock);
     567                 :          0 :                 e = hfind(aux->hmap, i);
     568         [ #  # ]:          0 :                 if (e) {
     569                 :          0 :                     hmap_remove(aux->hmap, &e->node);
     570                 :            :                 }
     571                 :          0 :                 fat_rwlock_unlock(&aux->fatlock);
     572                 :            :             } else {
     573                 :          0 :                 fat_rwlock_rdlock(&aux->fatlock);
     574                 :          0 :                 ignore(hfind(aux->hmap, i));
     575                 :          0 :                 fat_rwlock_unlock(&aux->fatlock);
     576                 :            :             }
     577                 :            :         }
     578                 :            :     } else {
     579         [ #  # ]:          0 :         for (i = 0; i < n_elems; i++) {
     580                 :          0 :             ignore(hfind(aux->hmap, i));
     581                 :            :         }
     582                 :            :     }
     583                 :          0 :     return NULL;
     584                 :            : }
     585                 :            : 
     586                 :            : static void
     587                 :          0 : benchmark_hmap(void)
     588                 :            : {
     589                 :            :     struct helement *elements;
     590                 :            :     struct hmap hmap;
     591                 :            :     struct helement *e, *next;
     592                 :            :     struct timeval start;
     593                 :            :     pthread_t *threads;
     594                 :            :     struct hmap_aux aux;
     595                 :            :     size_t i;
     596                 :            : 
     597                 :          0 :     elements = xmalloc(n_elems * sizeof *elements);
     598                 :            : 
     599                 :          0 :     xgettimeofday(&start);
     600                 :          0 :     hmap_init(&hmap);
     601         [ #  # ]:          0 :     for (i = 0; i < n_elems; i++) {
     602                 :          0 :         elements[i].value = i;
     603                 :          0 :         hmap_insert(&hmap, &elements[i].node, hash_int(i, 0));
     604                 :            :     }
     605                 :            : 
     606                 :          0 :     printf("hmap insert:  %5d ms\n", elapsed(&start));
     607                 :            : 
     608                 :          0 :     xgettimeofday(&start);
     609 [ #  # ][ #  # ]:          0 :     HMAP_FOR_EACH (e, node, &hmap) {
     610                 :          0 :         ignore(e);
     611                 :            :     }
     612                 :          0 :     printf("hmap iterate: %5d ms\n", elapsed(&start));
     613                 :            : 
     614                 :          0 :     xgettimeofday(&start);
     615                 :          0 :     aux.hmap = &hmap;
     616                 :          0 :     fat_rwlock_init(&aux.fatlock);
     617                 :          0 :     threads = xmalloc(n_threads * sizeof *threads);
     618         [ #  # ]:          0 :     for (i = 0; i < n_threads; i++) {
     619                 :          0 :         threads[i] = ovs_thread_create("search", search_hmap, &aux);
     620                 :            :     }
     621         [ #  # ]:          0 :     for (i = 0; i < n_threads; i++) {
     622                 :          0 :         xpthread_join(threads[i], NULL);
     623                 :            :     }
     624                 :          0 :     free(threads);
     625                 :          0 :     printf("hmap search:  %5d ms\n", elapsed(&start));
     626                 :            : 
     627                 :            :     /* Destruction. */
     628                 :          0 :     xgettimeofday(&start);
     629 [ #  # ][ #  # ]:          0 :     HMAP_FOR_EACH_SAFE (e, next, node, &hmap) {
                 [ #  # ]
     630                 :          0 :         hmap_remove(&hmap, &e->node);
     631                 :            :     }
     632                 :          0 :     hmap_destroy(&hmap);
     633                 :          0 :     printf("hmap destroy: %5d ms\n", elapsed(&start));
     634                 :            : 
     635                 :          0 :     free(elements);
     636                 :          0 : }
     637                 :            : 
     638                 :            : static const struct ovs_cmdl_command commands[] = {
     639                 :            :     {"check", NULL, 0, 1, run_tests, OVS_RO},
     640                 :            :     {"benchmark", NULL, 3, 4, run_benchmarks, OVS_RO},
     641                 :            :     {NULL, NULL, 0, 0, NULL, OVS_RO},
     642                 :            : };
     643                 :            : 
     644                 :            : static void
     645                 :          1 : test_cmap_main(int argc, char *argv[])
     646                 :            : {
     647                 :          3 :     struct ovs_cmdl_context ctx = {
     648                 :          1 :         .argc = argc - optind,
     649                 :          1 :         .argv = argv + optind,
     650                 :            :     };
     651                 :            : 
     652                 :          1 :     set_program_name(argv[0]);
     653                 :          1 :     ovs_cmdl_run_command(&ctx, commands);
     654                 :          1 : }
     655                 :            : 
     656                 :       1176 : OVSTEST_REGISTER("test-cmap", test_cmap_main);

Generated by: LCOV version 1.12