fix for quota loading
[oweals/gnunet.git] / src / ats / perf_ats_solver.c
1 /*
2  This file is part of GNUnet.
3  (C) 2010,2011 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18  Boston, MA 02111-1307, USA.
19  */
20 /**
21  * @file ats/perf_ats_solver.c
22  * @brief generic performance test for ATS solvers
23  * @author Christian Grothoff
24  * @author Matthias Wachs
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_statistics_service.h"
29 #include "gnunet-service-ats_addresses.h"
30 #include "gnunet-service-ats_normalization.h"
31 #include "gnunet_ats_service.h"
32 #include "gnunet_ats_plugin.h"
33 #include "test_ats_api_common.h"
34
35 #define DEFAULT_PEERS_START     100
36 #define DEFAULT_PEERS_END       100
37 #define DEFAULT_ADDRESSES       10
38 #define DEFAULT_ATS_COUNT       2
39
40 /**
41  * Handle for ATS address component
42  */
43 struct PerfHandle
44 {
45   struct PerfPeer *peers;
46
47   /**
48    * #peers to start benchmarking with
49    */
50   int N_peers_start;
51
52   /**
53    * #peers to end benchmarking with
54    */
55   int N_peers_end;
56
57   /**
58    * #addresses to benchmarking with
59    */
60   int N_address;
61
62   int opt_numeric;
63   int opt_dump;
64   int opt_update_percent;
65   int opt_update_quantity;
66
67   char *ats_string;
68
69   /**
70    *
71    */
72   struct GNUNET_STATISTICS_Handle *stat;
73
74   /**
75    * A multihashmap to store all addresses
76    */
77   struct GNUNET_CONTAINER_MultiPeerMap *addresses;
78
79
80   /**
81    * Configured ATS solver
82    */
83   int ats_mode;
84
85   /**
86    *  Solver handle
87    */
88   void *solver;
89
90   /**
91    * Address suggestion requests DLL head
92    */
93   struct GAS_Addresses_Suggestion_Requests *r_head;
94
95   /**
96    * Address suggestion requests DLL tail
97    */
98   struct GAS_Addresses_Suggestion_Requests *r_tail;
99
100   /* Solver functions */
101   struct GNUNET_ATS_PluginEnvironment env;
102
103   char *plugin;
104 };
105
106 struct PerfPeer
107 {
108   struct GNUNET_PeerIdentity id;
109
110   struct ATS_Address *head;
111   struct ATS_Address *tail;
112 };
113
114 static struct PerfHandle ph;
115
116 /**
117  * Return value
118  */
119 static int ret;
120
121
122 /**
123  * ATS information
124  */
125 //static struct GNUNET_ATS_Information ats[2];
126
127
128 static void
129 end_now (int res)
130 {
131   if (NULL != ph.stat)
132   {
133     GNUNET_STATISTICS_destroy (ph.stat, GNUNET_NO);
134     ph.stat = NULL;
135   }
136   /*
137    if (NULL != addresses)
138    {
139    GNUNET_CONTAINER_multihashmap_iterate (addresses, &addr_it, NULL);
140    GNUNET_CONTAINER_multihashmap_destroy (addresses);
141    addresses = NULL ;
142    }*/
143   if (NULL != ph.peers)
144   {
145     GNUNET_free(ph.peers);
146   }
147
148   GAS_normalization_stop ();
149   ret = res;
150 }
151
152
153 static void
154 perf_create_peer (int cp)
155 {
156   /*
157   GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
158       &ph.peers[cp].id.);*/
159   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Creating peer #%u: %s \n", cp,
160       GNUNET_i2s (&ph.peers[cp].id));
161 }
162
163
164
165 static void
166 update_single_addresses (struct ATS_Address *cur)
167 {
168   int r_type;
169   int r_val;
170
171   r_type = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2);
172   switch (r_type)
173   {
174   case 0:
175     r_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
176     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
177         "Updating peer `%s' address %p type %s val %u\n",
178         GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DELAY", r_val);
179     ph.env.sf.s_address_update_property (ph.solver, cur,
180         GNUNET_ATS_QUALITY_NET_DELAY,
181         r_val, (double) (100 + r_val / 100));
182     break;
183   case 1:
184     r_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 10);
185
186     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
187         "Updating peer `%s' address %p type %s val %u\n",
188         GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DISTANCE", r_val);
189     ph.env.sf.s_address_update_property (ph.solver, cur,
190         GNUNET_ATS_QUALITY_NET_DISTANCE,
191         r_val, (double) (100 + r_val) / 100);
192     break;
193   default:
194     break;
195   }
196   ph.env.sf.s_address_update_inuse (ph.solver, cur, GNUNET_YES);
197 }
198
199
200
201 static void
202 bandwidth_changed_cb (void *cls, struct ATS_Address *address)
203 {
204   return;
205 }
206
207 const double *
208 get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
209 {
210   return GAS_normalization_get_preferences (id);
211 }
212
213
214 const double *
215 get_property_cb (void *cls, const struct ATS_Address *address)
216 {
217   return GAS_normalization_get_properties ((struct ATS_Address *) address);
218 }
219
220 static void
221 normalized_property_changed_cb (void *cls, struct ATS_Address *peer,
222     uint32_t type, double prop_rel)
223 {
224   /* TODO */
225 }
226
227 static void
228 address_initial_update (void *solver,
229     struct GNUNET_CONTAINER_MultiPeerMap * addresses,
230     struct ATS_Address *address)
231 {
232   ph.env.sf.s_address_update_property (solver, address, GNUNET_ATS_QUALITY_NET_DELAY,
233       100,
234       (double) (100 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100))
235           / 100);
236
237   ph.env.sf.s_address_update_property (solver, address,
238       GNUNET_ATS_QUALITY_NET_DISTANCE, 10,
239       (double) (100 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100))
240           / 100);
241 }
242
243 static void
244 update_addresses (unsigned int cp, unsigned int ca, unsigned int up_q)
245 {
246   struct ATS_Address *cur;
247   int c_peer;
248   int c_select;
249   int c_addr;
250   int r;
251
252   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
253       "Updating addresses %u addresses per peer \n", up_q);
254   unsigned int m[ca];
255
256   for (c_peer = 0; c_peer < cp; c_peer++)
257   {
258     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Updating peer `%s'\n",
259         GNUNET_i2s (&ph.peers[c_peer].id));
260     for (c_select = 0; c_select < ca; c_select++)
261       m[c_select] = 0;
262     c_select = 0;
263     while (c_select < ph.opt_update_quantity)
264     {
265       r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, ca);
266       if (0 == m[r])
267       {
268         m[r] = 1;
269         c_select++;
270       }
271     }
272
273     c_addr = 0;
274     for (cur = ph.peers[c_peer].head; NULL != cur; cur = cur->next)
275     {
276       if (1 == m[c_addr])
277         update_single_addresses (cur);
278       c_addr++;
279     }
280   }
281 }
282
283
284 static struct ATS_Address *
285 perf_create_address (int cp, int ca)
286 {
287   struct ATS_Address *a;
288   a = create_address (&ph.peers[cp].id, "Test 1", "test 1", strlen ("test 1") + 1,
289       0);
290   GNUNET_CONTAINER_DLL_insert(ph.peers[cp].head, ph.peers[cp].tail, a);
291   GNUNET_CONTAINER_multipeermap_put (ph.addresses, &ph.peers[cp].id, a,
292       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
293   return a;
294 }
295
296 static void
297 check ()
298 {
299   struct ATS_Address *cur;
300   struct ATS_Address *next;
301   int cp;
302   int ca;
303   int count_p = ph.N_peers_end;
304   int count_a = ph.N_address;
305   struct ATS_Address * cur_addr;
306   ph.peers = GNUNET_malloc ((count_p) * sizeof (struct PerfPeer));
307
308   for (cp = 0; cp < count_p; cp++)
309     perf_create_peer (cp);
310
311   for (cp = 0; cp < count_p; cp++)
312   {
313     for (ca = 0; ca < count_a; ca++)
314     {
315       cur_addr = perf_create_address (cp, ca);
316       /* add address */
317       ph.env.sf.s_add (ph.solver, cur_addr, GNUNET_ATS_NET_LAN);
318       address_initial_update (ph.solver, ph.addresses, cur_addr);
319       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
320           "Adding address for peer %u address %u\n", cp, ca);
321     }
322     //ph.env.sf.s_get (ph.solver, &ph.peers[cp].id);
323     if (cp + 1 >= ph.N_peers_start)
324     {
325       /* Solve */
326       if ((0 < ph.opt_update_quantity) || (0 < ph.opt_update_percent))
327       {
328         /* Update */
329         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
330             "Updating problem with %u peers and %u addresses\n", cp + 1, ca);
331         //ph.env.sf.s_bulk_start (ph.solver);
332         //update_addresses (cp + 1, ca, ph.opt_update_quantity);
333         //ph.env.sf.s_bulk_stop (ph.solver);
334       }
335     }
336   }
337   for (cp = 0; cp < count_p; cp++)
338   {
339     for (cur = ph.peers[cp].head; cur != NULL ; cur = next)
340     {
341       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
342           "Deleting addresses for peer %u\n", cp);
343       ph.env.sf.s_del (ph.solver, cur, GNUNET_NO);
344       next = cur->next;
345       GNUNET_CONTAINER_DLL_remove(ph.peers[cp].head, ph.peers[cp].tail, cur);
346       GNUNET_free(cur);
347     }
348
349   }
350   GNUNET_free(ph.peers);
351 }
352
353
354 static void
355 run (void *cls, char * const *args, const char *cfgfile,
356     const struct GNUNET_CONFIGURATION_Handle *cfg)
357 {
358   GNUNET_log_setup ("perf-ats", "WARNING", NULL);
359   char *sep;
360   char *src_filename = GNUNET_strdup (__FILE__);
361   char *test_filename = cls;
362   char *solver;
363   char *plugin;
364   unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
365   unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
366   int c;
367
368   /* Extract test name */
369   if (NULL == (sep  = (strstr (src_filename,".c"))))
370   {
371     GNUNET_break (0);
372     ret = 1;
373     return;
374   }
375   sep[0] = '\0';
376
377   if (NULL != (sep = strstr (test_filename, ".exe")))
378     sep[0] = '\0';
379
380   if (NULL == (solver = strstr (test_filename, src_filename)))
381   {
382     GNUNET_break (0);
383     ret = 1;
384     return ;
385   }
386   solver += strlen (src_filename) +1;
387
388   if (0 == strcmp(solver, "proportional"))
389   {
390     ph.ats_mode = MODE_PROPORTIONAL;
391     ph.ats_string = "proportional";
392   }
393   else if (0 == strcmp(solver, "mlp"))
394   {
395     ph.ats_mode = MODE_MLP;
396     ph.ats_string = "mlp";
397   }
398   else if ((0 == strcmp(solver, "ril")))
399   {
400     ph.ats_mode = MODE_RIL;
401     ph.ats_string = "ril";
402   }
403   else
404   {
405     GNUNET_free (src_filename);
406     GNUNET_break (0);
407     ret = 1;
408     return ;
409   }
410   GNUNET_free (src_filename);
411
412   /* Calculcate peers */
413   if ((0 == ph.N_peers_start) && (0 == ph.N_peers_end))
414   {
415     ph.N_peers_start = DEFAULT_PEERS_START;
416     ph.N_peers_end = DEFAULT_PEERS_END;
417   }
418   if (0 == ph.N_address)
419     ph.N_address = DEFAULT_ADDRESSES;
420
421   if (ph.opt_update_quantity > ph.N_address)
422   {
423     fprintf (stderr,
424         _("Trying to update more addresses than we have per peer! (%u vs %u)"),
425         ph.opt_update_quantity, ph.N_address);
426     exit (1);
427   }
428
429   if (ph.N_peers_start != ph.N_peers_end)
430     fprintf (stderr, "Benchmarking solver `%s' with %u to %u peers and %u addresses\n",
431         ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address);
432   else
433     fprintf (stderr, "Benchmarking solver `%s' with %u peers and %u addresses\n",
434         ph.ats_string, ph.N_peers_end, ph.N_address);
435
436   /* Load quotas */
437   if (GNUNET_ATS_NetworkTypeCount != load_quotas (cfg,
438       quotas_out, quotas_in, GNUNET_ATS_NetworkTypeCount))
439   {
440     GNUNET_break(0);
441     end_now (1);
442     return;
443   }
444
445   /* Load solver */
446   ph.env.cfg = cfg;
447   ph.stat = GNUNET_STATISTICS_create ("ats", cfg);
448   ph.env.stats = ph.stat;
449   ph.addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
450   ph.env.addresses = ph.addresses;
451   ph.env.bandwidth_changed_cb = bandwidth_changed_cb;
452   ph.env.get_preferences = &get_preferences_cb;
453   ph.env.get_property = &get_property_cb;
454   ph.env.network_count = GNUNET_ATS_NetworkTypeCount;
455   int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
456   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
457   {
458     ph.env.networks[c] = networks[c];
459     ph.env.out_quota[c] = quotas_out[c];
460     ph.env.in_quota[c] = quotas_in[c];
461     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loading network quotas: `%s' %llu %llu \n",
462         GNUNET_ATS_print_network_type(ph.env.networks[c]),
463         ph.env.out_quota[c],
464         ph.env.in_quota[c]);
465   }
466   GAS_normalization_start (NULL, NULL, &normalized_property_changed_cb, NULL );
467
468
469   GNUNET_asprintf (&plugin, "libgnunet_plugin_ats_%s", ph.ats_string);
470   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initializing solver `%s' `%s'\n"), ph.ats_string, plugin);
471   if  (NULL == (ph.solver = GNUNET_PLUGIN_load (plugin, &ph.env)))
472   {
473     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver `%s'!\n"), plugin);
474     ret = 1;
475     return;
476   }
477
478   /* Do work */
479   check ();
480
481   /* Unload solver*/
482   GNUNET_PLUGIN_unload (plugin, ph.solver);
483   GNUNET_free (plugin);
484   ph.solver = NULL;
485 }
486
487 int
488 main (int argc, char *argv[])
489 {
490   /* extract command line arguments */
491   ph.opt_dump = GNUNET_NO;
492   ph.opt_update_quantity = 0;
493   ph.opt_update_percent = 0;
494   ph.N_peers_start = 0;
495   ph.N_peers_end = 0;
496   ph.N_address = 0;
497   ph.ats_string = NULL;
498
499   static struct GNUNET_GETOPT_CommandLineOption options[] = {
500       { 'a', "addresses", NULL,
501           gettext_noop ("addresses to use"),
502           1, &GNUNET_GETOPT_set_uint, &ph.N_address },
503       { 's', "start", NULL,
504           gettext_noop ("start with peer"),
505           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_start },
506       { 'e', "end", NULL,
507           gettext_noop ("end with peer"),
508           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_end },
509       { 'p', "percentage", NULL,
510           gettext_noop ("update a fix percentage of addresses"),
511           1, &GNUNET_GETOPT_set_uint, &ph.opt_update_percent },
512       { 'q', "quantity", NULL,
513           gettext_noop ("update a fix quantity of addresses"),
514           1, &GNUNET_GETOPT_set_uint, &ph.opt_update_quantity },
515       GNUNET_GETOPT_OPTION_END
516   };
517
518   GNUNET_PROGRAM_run (argc, argv, argv[0], NULL, options, &run, argv[0]);
519
520   return ret;
521 }
522
523 /* end of file perf_ats_solver.c */