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