minor fixes and log level changes
[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     1
36 #define DEFAULT_PEERS_END       1
37 #define DEFAULT_ADDRESSES       1
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_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
158       &ph.peers[cp].id, sizeof (struct GNUNET_PeerIdentity));
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   int bulk_running;
306   struct ATS_Address * cur_addr;
307   ph.peers = GNUNET_malloc ((count_p) * sizeof (struct PerfPeer));
308
309   for (cp = 0; cp < count_p; cp++)
310     perf_create_peer (cp);
311   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
312       "Added %u peers\n", cp);
313
314   /* Set initial bulk start to not solve */
315   ph.env.sf.s_bulk_start (ph.solver);
316   bulk_running = GNUNET_YES;
317
318   for (cp = 0; cp < count_p; cp++)
319   {
320     for (ca = 0; ca < count_a; ca++)
321     {
322       cur_addr = perf_create_address (cp, ca);
323       /* add address */
324       ph.env.sf.s_add (ph.solver, cur_addr, GNUNET_ATS_NET_LAN);
325       address_initial_update (ph.solver, ph.addresses, cur_addr);
326       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
327           "Adding address for peer %u address %u\n", cp, ca);
328     }
329     ph.env.sf.s_get (ph.solver, &ph.peers[cp].id);
330
331     if (cp + 1 >= ph.N_peers_start)
332     {
333       /* Disable bulk to solve the problem */
334       if (GNUNET_YES == bulk_running)
335       {
336         ph.env.sf.s_bulk_stop (ph.solver);
337         bulk_running = GNUNET_NO;
338       }
339
340       /* Problem should be solved here */
341
342       /* Disable bulk to solve the problem */
343       if (GNUNET_NO == bulk_running)
344       {
345         ph.env.sf.s_bulk_start (ph.solver);
346         bulk_running = GNUNET_YES;
347       }
348
349 #if 0
350       if ((0 < ph.opt_update_quantity) || (0 < ph.opt_update_percent))
351       {
352         /* Update */
353         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
354             "Updating problem with %u peers and %u addresses\n", cp + 1, ca);
355         //ph.env.sf.s_bulk_start (ph.solver);
356         //update_addresses (cp + 1, ca, ph.opt_update_quantity);
357         //ph.env.sf.s_bulk_stop (ph.solver);
358       }
359 #endif
360     }
361   }
362   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
363       "Done, cleaning up addresses\n");
364   for (cp = 0; cp < count_p; cp++)
365   {
366     for (cur = ph.peers[cp].head; cur != NULL ; cur = next)
367     {
368       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
369           "Deleting addresses for peer %u\n", cp);
370       ph.env.sf.s_del (ph.solver, cur, GNUNET_NO);
371       next = cur->next;
372       GNUNET_CONTAINER_DLL_remove(ph.peers[cp].head, ph.peers[cp].tail, cur);
373       GNUNET_free(cur);
374     }
375
376   }
377   GNUNET_free(ph.peers);
378 }
379
380
381 static void
382 run (void *cls, char * const *args, const char *cfgfile,
383     const struct GNUNET_CONFIGURATION_Handle *cfg)
384 {
385   GNUNET_log_setup ("perf-ats-solver", "WARNING", NULL);
386   char *sep;
387   char *src_filename = GNUNET_strdup (__FILE__);
388   char *test_filename = cls;
389   char *solver;
390   char *plugin;
391   unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
392   unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
393   int c;
394
395   /* Extract test name */
396   if (NULL == (sep  = (strstr (src_filename,".c"))))
397   {
398     GNUNET_break (0);
399     ret = 1;
400     return;
401   }
402   sep[0] = '\0';
403
404   if (NULL != (sep = strstr (test_filename, ".exe")))
405     sep[0] = '\0';
406
407   if (NULL == (solver = strstr (test_filename, src_filename)))
408   {
409     GNUNET_break (0);
410     ret = 1;
411     return ;
412   }
413   solver += strlen (src_filename) +1;
414
415   if (0 == strcmp(solver, "proportional"))
416   {
417     ph.ats_mode = MODE_PROPORTIONAL;
418     ph.ats_string = "proportional";
419   }
420   else if (0 == strcmp(solver, "mlp"))
421   {
422     ph.ats_mode = MODE_MLP;
423     ph.ats_string = "mlp";
424   }
425   else if ((0 == strcmp(solver, "ril")))
426   {
427     ph.ats_mode = MODE_RIL;
428     ph.ats_string = "ril";
429   }
430   else
431   {
432     GNUNET_free (src_filename);
433     GNUNET_break (0);
434     ret = 1;
435     return ;
436   }
437   GNUNET_free (src_filename);
438
439   /* Calculcate peers */
440   if ((0 == ph.N_peers_start) && (0 == ph.N_peers_end))
441   {
442     ph.N_peers_start = DEFAULT_PEERS_START;
443     ph.N_peers_end = DEFAULT_PEERS_END;
444   }
445   if (0 == ph.N_address)
446     ph.N_address = DEFAULT_ADDRESSES;
447
448   if (ph.opt_update_quantity > ph.N_address)
449   {
450     fprintf (stderr,
451         _("Trying to update more addresses than we have per peer! (%u vs %u)"),
452         ph.opt_update_quantity, ph.N_address);
453     exit (1);
454   }
455
456   if (ph.N_peers_start != ph.N_peers_end)
457     fprintf (stderr, "Benchmarking solver `%s' with %u to %u peers and %u addresses\n",
458         ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address);
459   else
460     fprintf (stderr, "Benchmarking solver `%s' with %u peers and %u addresses\n",
461         ph.ats_string, ph.N_peers_end, ph.N_address);
462
463   /* Load quotas */
464   if (GNUNET_ATS_NetworkTypeCount != load_quotas (cfg,
465       quotas_out, quotas_in, GNUNET_ATS_NetworkTypeCount))
466   {
467     GNUNET_break(0);
468     end_now (1);
469     return;
470   }
471
472   /* Load solver */
473   ph.env.cfg = cfg;
474   ph.stat = GNUNET_STATISTICS_create ("ats", cfg);
475   ph.env.stats = ph.stat;
476   ph.addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
477   ph.env.addresses = ph.addresses;
478   ph.env.bandwidth_changed_cb = bandwidth_changed_cb;
479   ph.env.get_preferences = &get_preferences_cb;
480   ph.env.get_property = &get_property_cb;
481   ph.env.network_count = GNUNET_ATS_NetworkTypeCount;
482   int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
483   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
484   {
485     ph.env.networks[c] = networks[c];
486     ph.env.out_quota[c] = quotas_out[c];
487     ph.env.in_quota[c] = quotas_in[c];
488     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loading network quotas: `%s' %llu %llu \n",
489         GNUNET_ATS_print_network_type(ph.env.networks[c]),
490         ph.env.out_quota[c],
491         ph.env.in_quota[c]);
492   }
493   GAS_normalization_start (NULL, NULL, &normalized_property_changed_cb, NULL );
494
495   GNUNET_asprintf (&plugin, "libgnunet_plugin_ats_%s", ph.ats_string);
496   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initializing solver `%s'\n"), ph.ats_string);
497   if  (NULL == (ph.solver = GNUNET_PLUGIN_load (plugin, &ph.env)))
498   {
499     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver `%s'!\n"), plugin);
500     ret = 1;
501     return;
502   }
503
504   /* Do work */
505   check ();
506
507   /* Unload solver*/
508   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Unloading solver `%s'\n"), ph.ats_string);
509   GNUNET_PLUGIN_unload (plugin, ph.solver);
510   GNUNET_free (plugin);
511   ph.solver = NULL;
512 }
513
514 int
515 main (int argc, char *argv[])
516 {
517   /* extract command line arguments */
518   ph.opt_dump = GNUNET_NO;
519   ph.opt_update_quantity = 0;
520   ph.opt_update_percent = 0;
521   ph.N_peers_start = 0;
522   ph.N_peers_end = 0;
523   ph.N_address = 0;
524   ph.ats_string = NULL;
525
526   static struct GNUNET_GETOPT_CommandLineOption options[] = {
527       { 'a', "addresses", NULL,
528           gettext_noop ("addresses to use"),
529           1, &GNUNET_GETOPT_set_uint, &ph.N_address },
530       { 's', "start", NULL,
531           gettext_noop ("start with peer"),
532           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_start },
533       { 'e', "end", NULL,
534           gettext_noop ("end with peer"),
535           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_end },
536       { 'p', "percentage", NULL,
537           gettext_noop ("update a fix percentage of addresses"),
538           1, &GNUNET_GETOPT_set_uint, &ph.opt_update_percent },
539       { 'q', "quantity", NULL,
540           gettext_noop ("update a fix quantity of addresses"),
541           1, &GNUNET_GETOPT_set_uint, &ph.opt_update_quantity },
542       GNUNET_GETOPT_OPTION_END
543   };
544
545   GNUNET_PROGRAM_run (argc, argv, argv[0], NULL, options, &run, argv[0]);
546
547   return ret;
548 }
549
550 /* end of file perf_ats_solver.c */