next steps to generic perf test
[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 int count_p;
118 int count_a;
119
120 /**
121  * Return value
122  */
123 static int ret;
124
125
126 /**
127  * ATS information
128  */
129 //static struct GNUNET_ATS_Information ats[2];
130
131
132 static void
133 end_now (int res)
134 {
135   if (NULL != ph.stat)
136   {
137     GNUNET_STATISTICS_destroy (ph.stat, GNUNET_NO);
138     ph.stat = NULL;
139   }
140   /*
141    if (NULL != addresses)
142    {
143    GNUNET_CONTAINER_multihashmap_iterate (addresses, &addr_it, NULL);
144    GNUNET_CONTAINER_multihashmap_destroy (addresses);
145    addresses = NULL ;
146    }*/
147   if (NULL != ph.peers)
148   {
149     GNUNET_free(ph.peers);
150   }
151
152   GAS_normalization_stop ();
153   ret = res;
154 }
155
156
157 static void
158 perf_create_peer (int cp)
159 {
160   /*
161   GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
162       &ph.peers[cp].id.);*/
163   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Creating peer #%u: %s \n", cp,
164       GNUNET_i2s (&ph.peers[cp].id));
165 }
166
167
168
169 static void
170 update_single_addresses (struct ATS_Address *cur)
171 {
172   int r_type;
173   int r_val;
174
175   r_type = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2);
176   switch (r_type)
177   {
178   case 0:
179     r_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
180     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
181         "Updating peer `%s' address %p type %s val %u\n",
182         GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DELAY", r_val);
183     ph.env.sf.s_address_update_property (ph.solver, cur,
184         GNUNET_ATS_QUALITY_NET_DELAY,
185         r_val, (double) (100 + r_val / 100));
186     break;
187   case 1:
188     r_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 10);
189
190     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
191         "Updating peer `%s' address %p type %s val %u\n",
192         GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DISTANCE", r_val);
193     ph.env.sf.s_address_update_property (ph.solver, cur,
194         GNUNET_ATS_QUALITY_NET_DISTANCE,
195         r_val, (double) (100 + r_val) / 100);
196     break;
197   default:
198     break;
199   }
200   ph.env.sf.s_address_update_inuse (ph.solver, cur, GNUNET_YES);
201 }
202
203
204
205 static void
206 bandwidth_changed_cb (void *cls, struct ATS_Address *address)
207 {
208   return;
209 }
210
211 const double *
212 get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
213 {
214   return GAS_normalization_get_preferences (id);
215 }
216
217
218 const double *
219 get_property_cb (void *cls, const struct ATS_Address *address)
220 {
221   return GAS_normalization_get_properties ((struct ATS_Address *) address);
222 }
223
224 static void
225 normalized_property_changed_cb (void *cls, struct ATS_Address *peer,
226     uint32_t type, double prop_rel)
227 {
228   /* TODO */
229 }
230
231 static void
232 address_initial_update (void *solver,
233     struct GNUNET_CONTAINER_MultiPeerMap * addresses,
234     struct ATS_Address *address)
235 {
236   ph.env.sf.s_address_update_property (solver, address, GNUNET_ATS_QUALITY_NET_DELAY,
237       100,
238       (double) (100 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100))
239           / 100);
240
241   ph.env.sf.s_address_update_property (solver, address,
242       GNUNET_ATS_QUALITY_NET_DISTANCE, 10,
243       (double) (100 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100))
244           / 100);
245 }
246
247 static void
248 update_addresses (unsigned int cp, unsigned int ca, unsigned int up_q)
249 {
250   struct ATS_Address *cur;
251   int c_peer;
252   int c_select;
253   int c_addr;
254   int r;
255
256   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
257       "Updating addresses %u addresses per peer \n", up_q);
258   unsigned int m[ca];
259
260   for (c_peer = 0; c_peer < cp; c_peer++)
261   {
262     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Updating peer `%s'\n",
263         GNUNET_i2s (&ph.peers[c_peer].id));
264     for (c_select = 0; c_select < ca; c_select++)
265       m[c_select] = 0;
266     c_select = 0;
267     while (c_select < ph.opt_update_quantity)
268     {
269       r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, ca);
270       if (0 == m[r])
271       {
272         m[r] = 1;
273         c_select++;
274       }
275     }
276
277     c_addr = 0;
278     for (cur = ph.peers[c_peer].head; NULL != cur; cur = cur->next)
279     {
280       if (1 == m[c_addr])
281         update_single_addresses (cur);
282       c_addr++;
283     }
284   }
285 }
286
287
288 static struct ATS_Address *
289 perf_create_address (int cp, int ca)
290 {
291   struct ATS_Address *a;
292   a = create_address (&ph.peers[cp].id, "Test 1", "test 1", strlen ("test 1") + 1,
293       0);
294   GNUNET_CONTAINER_DLL_insert(ph.peers[cp].head, ph.peers[cp].tail, a);
295   GNUNET_CONTAINER_multipeermap_put (ph.addresses, &ph.peers[cp].id, a,
296       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
297   return a;
298 }
299
300 static void
301 check ()
302 {
303   struct ATS_Address *cur;
304   struct ATS_Address *next;
305   int cp;
306   int ca;
307   int count_p = ph.N_peers_end;
308   int count_a = ph.N_address;
309   struct ATS_Address * cur_addr;
310   ph.peers = GNUNET_malloc ((count_p) * sizeof (struct PerfPeer));
311
312   for (cp = 0; cp < count_p; cp++)
313     perf_create_peer (cp);
314
315   for (cp = 0; cp < count_p; cp++)
316   {
317     for (ca = 0; ca < count_a; ca++)
318     {
319       cur_addr = perf_create_address (cp, ca);
320       /* add address */
321       ph.env.sf.s_add (ph.solver, cur_addr, GNUNET_ATS_NET_LAN);
322       address_initial_update (ph.solver, ph.addresses, cur_addr);
323       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
324           "Adding address for peer %u address %u\n", cp, ca);
325     }
326     //ph.env.sf.s_get (ph.solver, &ph.peers[cp].id);
327     if (cp + 1 >= ph.N_peers_start)
328     {
329       /* Solve */
330       if ((0 < ph.opt_update_quantity) || (0 < ph.opt_update_percent))
331       {
332         /* Update */
333         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
334             "Updating problem with %u peers and %u addresses\n", cp + 1, ca);
335         //ph.env.sf.s_bulk_start (ph.solver);
336         //update_addresses (cp + 1, ca, ph.opt_update_quantity);
337         //ph.env.sf.s_bulk_stop (ph.solver);
338       }
339     }
340   }
341   for (cp = 0; cp < count_p; cp++)
342   {
343     for (cur = ph.peers[cp].head; cur != NULL ; cur = next)
344     {
345       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
346           "Deleting addresses for peer %u\n", cp);
347       ph.env.sf.s_del (ph.solver, cur, GNUNET_NO);
348       next = cur->next;
349       GNUNET_CONTAINER_DLL_remove(ph.peers[cp].head, ph.peers[cp].tail, cur);
350       GNUNET_free(cur);
351     }
352
353   }
354   GNUNET_free(ph.peers);
355 }
356
357
358 static void
359 run (void *cls, char * const *args, const char *cfgfile,
360     const struct GNUNET_CONFIGURATION_Handle *cfg)
361 {
362   GNUNET_log_setup ("perf-ats", "WARNING", NULL);
363   char *sep;
364   char *src_filename = GNUNET_strdup (__FILE__);
365   char *test_filename = cls;
366   char *solver;
367   char *plugin;
368   unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
369   unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
370   int c;
371
372   /* Extract test name */
373   if (NULL == (sep  = (strstr (src_filename,".c"))))
374   {
375     GNUNET_break (0);
376     ret = 1;
377     return;
378   }
379   sep[0] = '\0';
380
381   if (NULL != (sep = strstr (test_filename, ".exe")))
382     sep[0] = '\0';
383
384   if (NULL == (solver = strstr (test_filename, src_filename)))
385   {
386     GNUNET_break (0);
387     ret = 1;
388     return ;
389   }
390   solver += strlen (src_filename) +1;
391
392   if (0 == strcmp(solver, "proportional"))
393   {
394     ph.ats_mode = MODE_PROPORTIONAL;
395     ph.ats_string = "proportional";
396   }
397   else if (0 == strcmp(solver, "mlp"))
398   {
399     ph.ats_mode = MODE_MLP;
400     ph.ats_string = "mlp";
401   }
402   else if ((0 == strcmp(solver, "ril")))
403   {
404     ph.ats_mode = MODE_RIL;
405     ph.ats_string = "ril";
406   }
407   else
408   {
409     GNUNET_free (src_filename);
410     GNUNET_break (0);
411     ret = 1;
412     return ;
413   }
414   GNUNET_free (src_filename);
415
416   /* Calculcate peers */
417   if ((0 == ph.N_peers_start) && (0 == ph.N_peers_end))
418   {
419     ph.N_peers_start = DEFAULT_PEERS_START;
420     ph.N_peers_end = DEFAULT_PEERS_END;
421   }
422   if (0 == ph.N_address)
423     ph.N_address = DEFAULT_ADDRESSES;
424
425   if (ph.opt_update_quantity > ph.N_address)
426   {
427     fprintf (stderr,
428         _("Trying to update more addresses than we have per peer! (%u vs %u)"),
429         ph.opt_update_quantity, ph.N_address);
430     exit (1);
431   }
432
433   if (ph.N_peers_start != ph.N_peers_end)
434     fprintf (stderr, "Benchmarking solver `%s' with %u to %u peers and %u addresses\n",
435         ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address);
436   else
437     fprintf (stderr, "Benchmarking solver `%s' with %u peers and %u addresses\n",
438         ph.ats_string, ph.N_peers_end, ph.N_address);
439
440   /* Load quotas */
441   if (GNUNET_ATS_NetworkTypeCount != load_quotas (cfg,
442       quotas_in, quotas_in, GNUNET_ATS_NetworkTypeCount))
443   {
444     GNUNET_break(0);
445     end_now (1);
446     return;
447   }
448
449   /* Load solver */
450   ph.env.cfg = cfg;
451   ph.stat = GNUNET_STATISTICS_create ("ats", cfg);
452   ph.env.stats = ph.stat;
453   ph.addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
454   ph.env.addresses = ph.addresses;
455   ph.env.bandwidth_changed_cb = bandwidth_changed_cb;
456   ph.env.get_preferences = &get_preferences_cb;
457   ph.env.get_property = &get_property_cb;
458   ph.env.network_count = GNUNET_ATS_NetworkTypeCount;
459   int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
460   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
461   {
462     ph.env.networks[c] = networks[c];
463     ph.env.out_quota[c] = quotas_out[c];
464     ph.env.in_quota[c] = quotas_in[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 */