improve logging, indentation
[oweals/gnunet.git] / src / set / gnunet-set-ibf-profiler.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012 GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file set/gnunet-set-ibf-profiler.c
23  * @brief tool for profiling the invertible bloom filter implementation
24  * @author Florian Dold
25  */
26
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29
30 #include "ibf.h"
31
32 static unsigned int asize = 10;
33 static unsigned int bsize = 10;
34 static unsigned int csize = 10;
35 static unsigned int hash_num = 4;
36 static unsigned int ibf_size = 80;
37
38 /* FIXME: add parameter for this */
39 static enum GNUNET_CRYPTO_Quality random_quality = GNUNET_CRYPTO_QUALITY_WEAK;
40
41 static struct GNUNET_CONTAINER_MultiHashMap *set_a;
42 static struct GNUNET_CONTAINER_MultiHashMap *set_b;
43 /* common elements in a and b */
44 static struct GNUNET_CONTAINER_MultiHashMap *set_c;
45
46 static struct GNUNET_CONTAINER_MultiHashMap *key_to_hashcode;
47
48 static struct InvertibleBloomFilter *ibf_a;
49 static struct InvertibleBloomFilter *ibf_b;
50
51
52 static void
53 register_hashcode (struct GNUNET_HashCode *hash)
54 {
55   struct GNUNET_HashCode replicated;
56   struct IBF_Key key;
57   key = ibf_key_from_hashcode (hash);
58   ibf_hashcode_from_key (key, &replicated);
59   (void) GNUNET_CONTAINER_multihashmap_put (key_to_hashcode,
60                                             &replicated,
61                                             GNUNET_memdup (hash, sizeof *hash),
62                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
63 }
64
65
66 static void
67 iter_hashcodes (struct IBF_Key key,
68                 GNUNET_CONTAINER_HashMapIterator iter,
69                 void *cls)
70 {
71   struct GNUNET_HashCode replicated;
72
73   ibf_hashcode_from_key (key, &replicated);
74   GNUNET_CONTAINER_multihashmap_get_multiple (key_to_hashcode,
75                                               &replicated,
76                                               iter, cls);
77 }
78
79
80 static int
81 insert_iterator (void *cls,
82                  const struct GNUNET_HashCode *key,
83                  void *value)
84 {
85   struct InvertibleBloomFilter *ibf = cls;
86
87   ibf_insert (ibf, ibf_key_from_hashcode (key));
88   return GNUNET_YES;
89 }
90
91
92 static int
93 remove_iterator (void *cls,
94                  const struct GNUNET_HashCode *key,
95                  void *value)
96 {
97   struct GNUNET_CONTAINER_MultiHashMap *hashmap = cls;
98   /* if remove fails, there just was a collision with another key */
99   (void) GNUNET_CONTAINER_multihashmap_remove (hashmap, value, NULL);
100   return GNUNET_YES;
101 }
102
103
104 static void
105 run (void *cls,
106      char *const *args,
107      const char *cfgfile,
108      const struct GNUNET_CONFIGURATION_Handle *cfg)
109 {
110   struct GNUNET_HashCode id;
111   struct IBF_Key ibf_key;
112   int i;
113   int side;
114   int res;
115   struct GNUNET_TIME_Absolute start_time;
116   struct GNUNET_TIME_Relative delta_time;
117
118   set_a = GNUNET_CONTAINER_multihashmap_create (((asize == 0) ? 1 : (asize + csize)),
119                                                  GNUNET_NO);
120   set_b = GNUNET_CONTAINER_multihashmap_create (((bsize == 0) ? 1 : (bsize + csize)),
121                                                 GNUNET_NO);
122   set_c = GNUNET_CONTAINER_multihashmap_create (((csize == 0) ? 1 : csize),
123                                                 GNUNET_NO);
124
125   key_to_hashcode = GNUNET_CONTAINER_multihashmap_create (((asize+bsize+csize == 0) ? 1 : (asize+bsize+csize)),
126                                                           GNUNET_NO);
127
128   printf ("hash-num=%u, size=%u, #(A-B)=%u, #(B-A)=%u, #(A&B)=%u\n",
129           hash_num, ibf_size, asize, bsize, csize);
130
131   i = 0;
132   while (i < asize)
133   {
134     GNUNET_CRYPTO_hash_create_random (random_quality, &id);
135     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_a, &id))
136       continue;
137     GNUNET_break (GNUNET_OK ==
138                   GNUNET_CONTAINER_multihashmap_put (set_a, &id, NULL,
139                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
140     register_hashcode (&id);
141     i++;
142   }
143   i = 0;
144   while (i < bsize)
145   {
146     GNUNET_CRYPTO_hash_create_random (random_quality, &id);
147     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_a, &id))
148       continue;
149     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_b, &id))
150       continue;
151     GNUNET_break (GNUNET_OK ==
152                   GNUNET_CONTAINER_multihashmap_put (set_b, &id, NULL,
153                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
154     register_hashcode (&id);
155     i++;
156   }
157   i = 0;
158   while (i < csize)
159   {
160     GNUNET_CRYPTO_hash_create_random (random_quality, &id);
161     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_a, &id))
162       continue;
163     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_b, &id))
164       continue;
165     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_c, &id))
166       continue;
167     GNUNET_break (GNUNET_OK ==
168                   GNUNET_CONTAINER_multihashmap_put (set_c, &id, NULL,
169                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
170     register_hashcode (&id);
171     i++;
172   }
173
174   ibf_a = ibf_create (ibf_size, hash_num);
175   ibf_b = ibf_create (ibf_size, hash_num);
176   if ( (NULL == ibf_a) ||
177        (NULL == ibf_b) )
178   {
179     /* insufficient memory */
180     GNUNET_break (0);
181     GNUNET_SCHEDULER_shutdown ();
182     return;
183   }
184
185
186   printf ("generated sets\n");
187
188   start_time = GNUNET_TIME_absolute_get ();
189
190   GNUNET_CONTAINER_multihashmap_iterate (set_a, &insert_iterator, ibf_a);
191   GNUNET_CONTAINER_multihashmap_iterate (set_b, &insert_iterator, ibf_b);
192   GNUNET_CONTAINER_multihashmap_iterate (set_c, &insert_iterator, ibf_a);
193   GNUNET_CONTAINER_multihashmap_iterate (set_c, &insert_iterator, ibf_b);
194
195   delta_time = GNUNET_TIME_absolute_get_duration (start_time);
196
197   printf ("encoded in: %s\n",
198           GNUNET_STRINGS_relative_time_to_string (delta_time,
199                                                   GNUNET_NO));
200
201   ibf_subtract (ibf_a, ibf_b);
202
203
204   start_time = GNUNET_TIME_absolute_get ();
205
206   for (i = 0; i <= asize + bsize; i++)
207   {
208     res = ibf_decode (ibf_a, &side, &ibf_key);
209     if (GNUNET_SYSERR == res)
210     {
211       printf ("decode failed, %u/%u elements left\n",
212          GNUNET_CONTAINER_multihashmap_size (set_a) + GNUNET_CONTAINER_multihashmap_size (set_b),
213          asize + bsize);
214       return;
215     }
216     if (GNUNET_NO == res)
217     {
218       if ((0 == GNUNET_CONTAINER_multihashmap_size (set_b)) &&
219           (0 == GNUNET_CONTAINER_multihashmap_size (set_a)))
220       {
221         delta_time = GNUNET_TIME_absolute_get_duration (start_time);
222         printf ("decoded successfully in: %s\n",
223                 GNUNET_STRINGS_relative_time_to_string (delta_time,
224                                                         GNUNET_NO));
225       }
226       else
227       {
228         printf ("decode missed elements (should never happen)\n");
229       }
230       return;
231     }
232
233     if (side == 1)
234       iter_hashcodes (ibf_key, remove_iterator, set_a);
235     if (side == -1)
236       iter_hashcodes (ibf_key, remove_iterator, set_b);
237   }
238   printf("cyclic IBF, %u/%u elements left\n",
239          GNUNET_CONTAINER_multihashmap_size (set_a) + GNUNET_CONTAINER_multihashmap_size (set_b),
240          asize + bsize);
241 }
242
243
244 int
245 main (int argc, char **argv)
246 {
247   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
248     {'A', "asize", NULL,
249      gettext_noop ("number of element in set A-B"), 1,
250      &GNUNET_GETOPT_set_uint, &asize},
251     {'B', "bsize", NULL,
252      gettext_noop ("number of element in set B-A"), 1,
253      &GNUNET_GETOPT_set_uint, &bsize},
254     {'C', "csize", NULL,
255      gettext_noop ("number of common elements in A and B"), 1,
256      &GNUNET_GETOPT_set_uint, &csize},
257     {'k', "hash-num", NULL,
258      gettext_noop ("hash num"), 1,
259      &GNUNET_GETOPT_set_uint, &hash_num},
260     {'s', "ibf-size", NULL,
261      gettext_noop ("ibf size"), 1,
262      &GNUNET_GETOPT_set_uint, &ibf_size},
263     GNUNET_GETOPT_OPTION_END
264   };
265   GNUNET_PROGRAM_run2 (argc, argv, "gnunet-consensus-ibf",
266                       "help",
267                       options, &run, NULL, GNUNET_YES);
268   return 0;
269 }