631594b06fbe0c65445a7d727cab8c3763edf7ff
[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     10
36 #define DEFAULT_PEERS_END       10
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   /**
46    * Performance peers
47    */
48   struct PerfPeer *peers;
49
50   /**
51    *  Solver handle
52    */
53   void *solver;
54
55   /**
56    * Statistics stat;
57    */
58   struct GNUNET_STATISTICS_Handle *stat;
59
60   /**
61    * A multihashmap to store all addresses
62    */
63   struct GNUNET_CONTAINER_MultiPeerMap *addresses;
64
65   /**
66    * Solver functions
67    * */
68   struct GNUNET_ATS_PluginEnvironment env;
69
70   struct Result *head;
71
72   struct Result *tail;
73
74   struct Result *current_result;
75
76   int current_p;
77   int current_a;
78
79   /**
80    * Solver description as string
81    */
82   char *ats_string;
83
84   /**
85    * Configured ATS solver
86    */
87   int ats_mode;
88
89   /**
90    * #peers to start benchmarking with
91    */
92   int N_peers_start;
93
94   /**
95    * #peers to end benchmarking with
96    */
97   int N_peers_end;
98
99   /**
100    * #addresses to benchmarking with
101    */
102   int N_address;
103
104   /**
105    * Percentage of peers to update
106    */
107   int opt_update_percent;
108
109   /**
110    * Number of peers to update
111    */
112   int opt_update_quantity;
113
114   /**
115    * Is a bulk operation running?
116    */
117   int bulk_running;
118
119   /**
120    * Is a bulk operation running?
121    */
122   int expecting_solution;
123 };
124
125 struct Result
126 {
127   struct Result *prev;
128   struct Result *next;
129
130   int peers;
131   int addresses;
132
133   struct GNUNET_TIME_Relative d_setup;
134   struct GNUNET_TIME_Relative d_lp;
135   struct GNUNET_TIME_Relative d_mlp;
136   struct GNUNET_TIME_Relative d_total;
137
138   struct GNUNET_TIME_Absolute s_setup;
139   struct GNUNET_TIME_Absolute s_lp;
140   struct GNUNET_TIME_Absolute s_mlp;
141   struct GNUNET_TIME_Absolute s_total;
142
143   struct GNUNET_TIME_Absolute e_setup;
144   struct GNUNET_TIME_Absolute e_lp;
145   struct GNUNET_TIME_Absolute e_mlp;
146   struct GNUNET_TIME_Absolute e_total;
147 };
148
149 struct PerfPeer
150 {
151   struct GNUNET_PeerIdentity id;
152
153   struct ATS_Address *head;
154   struct ATS_Address *tail;
155 };
156
157 static struct PerfHandle ph;
158
159 /**
160  * Return value
161  */
162 static int ret;
163
164
165 /**
166  * ATS information
167  */
168 //static struct GNUNET_ATS_Information ats[2];
169
170
171 static void
172 end_now (int res)
173 {
174   if (NULL != ph.stat)
175   {
176     GNUNET_STATISTICS_destroy (ph.stat, GNUNET_NO);
177     ph.stat = NULL;
178   }
179   /*
180    if (NULL != addresses)
181    {
182    GNUNET_CONTAINER_multihashmap_iterate (addresses, &addr_it, NULL);
183    GNUNET_CONTAINER_multihashmap_destroy (addresses);
184    addresses = NULL ;
185    }*/
186   if (NULL != ph.peers)
187   {
188     GNUNET_free(ph.peers);
189   }
190
191   GAS_normalization_stop ();
192   ret = res;
193 }
194
195
196 static void
197 perf_create_peer (int cp)
198 {
199
200   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
201       &ph.peers[cp].id, sizeof (struct GNUNET_PeerIdentity));
202   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Creating peer #%u: %s \n", cp,
203       GNUNET_i2s (&ph.peers[cp].id));
204 }
205
206
207
208 static void
209 perf_update_address (struct ATS_Address *cur)
210 {
211   int r_type;
212   int r_val;
213
214   r_type = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2);
215   switch (r_type)
216   {
217   case 0:
218     r_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
219     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
220         "Updating peer `%s' address %p type %s val %u\n",
221         GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DELAY", r_val);
222     ph.env.sf.s_address_update_property (ph.solver, cur,
223         GNUNET_ATS_QUALITY_NET_DELAY,
224         r_val, (double) (100 + r_val / 100));
225     break;
226   case 1:
227     r_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 10);
228
229     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
230         "Updating peer `%s' address %p type %s val %u\n",
231         GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DISTANCE", r_val);
232     ph.env.sf.s_address_update_property (ph.solver, cur,
233         GNUNET_ATS_QUALITY_NET_DISTANCE,
234         r_val, (double) (100 + r_val) / 100);
235     break;
236   default:
237     break;
238   }
239   ph.env.sf.s_address_update_inuse (ph.solver, cur, GNUNET_YES);
240 }
241
242
243
244 static void
245 bandwidth_changed_cb (void *cls, struct ATS_Address *address)
246 {
247   if (0 == ntohl(address->assigned_bw_out.value__) &&
248       0 == ntohl(address->assigned_bw_in.value__))
249     return;
250
251   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
252       "Bandwidth changed addresses %s %p to %llu Bps out / %llu Bps in\n",
253       GNUNET_i2s (&address->peer),
254       address,
255       ntohl(address->assigned_bw_out.value__),
256       ntohl(address->assigned_bw_in.value__));
257   if (GNUNET_YES == ph.bulk_running)
258     GNUNET_break (0);
259   return;
260 }
261
262 const double *
263 get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
264 {
265   return GAS_normalization_get_preferences (id);
266 }
267
268
269 const double *
270 get_property_cb (void *cls, const struct ATS_Address *address)
271 {
272   return GAS_normalization_get_properties ((struct ATS_Address *) address);
273 }
274
275 static void
276 normalized_property_changed_cb (void *cls, struct ATS_Address *peer,
277     uint32_t type, double prop_rel)
278 {
279   /* TODO */
280 }
281
282 static void
283 perf_address_initial_update (void *solver,
284     struct GNUNET_CONTAINER_MultiPeerMap * addresses,
285     struct ATS_Address *address)
286 {
287   ph.env.sf.s_address_update_property (solver, address, GNUNET_ATS_QUALITY_NET_DELAY,
288       100,
289       (double) (100 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100))
290           / 100);
291
292   ph.env.sf.s_address_update_property (solver, address,
293       GNUNET_ATS_QUALITY_NET_DISTANCE, 10,
294       (double) (100 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100))
295           / 100);
296 }
297
298 static void
299 perf_update_all_addresses (unsigned int cp, unsigned int ca, unsigned int up_q)
300 {
301   struct ATS_Address *cur;
302   int c_peer;
303   int c_select;
304   int c_addr;
305   int r;
306
307   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
308       "Updating addresses %u addresses per peer \n", up_q);
309   unsigned int m[ca];
310
311   for (c_peer = 0; c_peer < cp; c_peer++)
312   {
313     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Updating peer `%s'\n",
314         GNUNET_i2s (&ph.peers[c_peer].id));
315     for (c_select = 0; c_select < ca; c_select++)
316       m[c_select] = 0;
317     c_select = 0;
318     while (c_select < ph.opt_update_quantity)
319     {
320       r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, ca);
321       if (0 == m[r])
322       {
323         m[r] = 1;
324         c_select++;
325       }
326     }
327
328     c_addr = 0;
329     for (cur = ph.peers[c_peer].head; NULL != cur; cur = cur->next)
330     {
331       if (1 == m[c_addr])
332         perf_update_address (cur);
333       c_addr++;
334     }
335   }
336 }
337
338
339 static struct ATS_Address *
340 perf_create_address (int cp, int ca)
341 {
342   struct ATS_Address *a;
343   a = create_address (&ph.peers[cp].id,
344       "Test 1", "test 1", strlen ("test 1") + 1, 0);
345   GNUNET_CONTAINER_DLL_insert (ph.peers[cp].head, ph.peers[cp].tail, a);
346   GNUNET_CONTAINER_multipeermap_put (ph.addresses, &ph.peers[cp].id, a,
347       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
348   return a;
349 }
350
351 static void
352 solver_info_cb (void *cls, enum GAS_Solver_Operation op,
353     enum GAS_Solver_Status stat)
354 {
355
356   struct Result *tmp;
357   switch (op)
358   {
359
360   case GAS_OP_SOLVE_START:
361     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
362         "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_START",
363         (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
364     if (GNUNET_NO == ph.expecting_solution)
365     {
366       GNUNET_break(0);
367       return;
368     }
369     if ((GAS_STAT_SUCCESS == stat) && (NULL == ph.current_result))
370     {
371       /* Create new result */
372       tmp = GNUNET_malloc (sizeof (struct Result));
373       ph.current_result = tmp;
374       GNUNET_CONTAINER_DLL_insert_tail(ph.head, ph.tail, tmp);
375       ph.current_result->addresses = ph.current_a;
376       ph.current_result->peers = ph.current_p;
377       ph.current_result->s_total = GNUNET_TIME_absolute_get ();
378       ph.current_result->d_total = GNUNET_TIME_relative_get_forever_ ();
379       ph.current_result->d_setup = GNUNET_TIME_relative_get_forever_ ();
380       ph.current_result->d_lp = GNUNET_TIME_relative_get_forever_ ();
381       ph.current_result->d_mlp = GNUNET_TIME_relative_get_forever_ ();
382     }
383
384     break;
385
386   case GAS_OP_SOLVE_STOP:
387     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
388         "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_STOP",
389         (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
390
391     if (NULL != ph.current_result)
392     {
393       /* Finalize result */
394       ph.current_result->e_total = GNUNET_TIME_absolute_get ();
395       ph.current_result->d_total = GNUNET_TIME_absolute_get_difference (
396           ph.current_result->s_total, ph.current_result->e_total);
397     }
398     ph.current_result = NULL;
399     break;
400
401   case GAS_OP_SOLVE_SETUP_START:
402     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
403         "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_START",
404         (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
405     if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
406     {
407       GNUNET_break(0);
408       return;
409     }
410     ph.current_result->s_setup = GNUNET_TIME_absolute_get ();
411     break;
412
413   case GAS_OP_SOLVE_SETUP_STOP:
414     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
415         "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_STOP",
416         (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
417
418     if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
419     {
420       GNUNET_break(0);
421       return;
422     }
423     ph.current_result->e_setup = GNUNET_TIME_absolute_get ();
424     ph.current_result->d_setup = GNUNET_TIME_absolute_get_difference (
425         ph.current_result->s_setup, ph.current_result->e_setup);
426     break;
427
428   case GAS_OP_SOLVE_LP_START:
429     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
430         "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_START",
431         (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
432
433     if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
434     {
435       GNUNET_break(0);
436       return;
437     }
438     ph.current_result->s_lp = GNUNET_TIME_absolute_get ();
439     break;
440
441   case GAS_OP_SOLVE_LP_STOP:
442     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
443         "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_STOP",
444         (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
445     if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
446     {
447       GNUNET_break(0);
448       return;
449     }
450     ph.current_result->e_lp = GNUNET_TIME_absolute_get ();
451     ph.current_result->d_lp = GNUNET_TIME_absolute_get_difference (
452         ph.current_result->s_lp, ph.current_result->e_lp);
453     break;
454
455     break;
456
457   case GAS_OP_SOLVE_MLP_START:
458     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
459         "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_START",
460         (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
461     if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
462     {
463       GNUNET_break(0);
464       return;
465     }
466     ph.current_result->s_mlp = GNUNET_TIME_absolute_get ();
467     break;
468
469   case GAS_OP_SOLVE_MLP_STOP:
470     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
471         "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_STOP",
472         (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
473     if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
474     {
475       GNUNET_break(0);
476       return;
477     }
478     ph.current_result->e_mlp = GNUNET_TIME_absolute_get ();
479     ph.current_result->d_mlp = GNUNET_TIME_absolute_get_difference (
480         ph.current_result->s_mlp, ph.current_result->e_mlp);
481     break;
482   default:
483     break;
484   }
485 }
486
487 static void
488 evaluate ()
489 {
490   struct Result *cur;
491   struct Result *next;
492
493   next = ph.head;
494   while (NULL != (cur = next))
495   {
496     next = cur->next;
497
498     if (GNUNET_TIME_relative_get_forever_().rel_value_us != cur->d_total.rel_value_us)
499     {
500       fprintf (stderr, "Total time to solve for %u peers %u addresses: %llu us\n",
501           cur->peers, cur->addresses, (unsigned long long )cur->d_total.rel_value_us);
502     }
503     if (GNUNET_TIME_relative_get_forever_().rel_value_us != cur->d_setup.rel_value_us)
504     {
505       fprintf (stderr, "Total time to setup %u peers %u addresses: %llu us\n",
506           cur->peers, cur->addresses, (unsigned long long )cur->d_setup.rel_value_us);
507     }
508     if (GNUNET_TIME_relative_get_forever_().rel_value_us != cur->d_lp.rel_value_us)
509     {
510       fprintf (stderr, "Total time to solve LP for %u peers %u addresses: %llu us\n",
511           cur->peers, cur->addresses, (unsigned long long )cur->d_mlp.rel_value_us);
512     }
513     if (GNUNET_TIME_relative_get_forever_().rel_value_us != cur->d_mlp.rel_value_us)
514     {
515       fprintf (stderr, "Total time to solve MLP for %u peers %u addresses: %llu us\n",
516           cur->peers, cur->addresses, (unsigned long long )cur->d_lp.rel_value_us);
517     }
518
519     GNUNET_CONTAINER_DLL_remove (ph.head, ph.tail, cur);
520     GNUNET_free (cur);
521   }
522 }
523
524 static void
525 perf_run ()
526 {
527   struct ATS_Address *cur;
528   struct ATS_Address *next;
529   int cp;
530   int ca;
531   int count_p = ph.N_peers_end;
532   int count_a = ph.N_address;
533   struct ATS_Address * cur_addr;
534
535
536   ph.peers = GNUNET_malloc ((count_p) * sizeof (struct PerfPeer));
537
538   for (cp = 0; cp < count_p; cp++)
539     perf_create_peer (cp);
540   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
541       "Added %u peers\n", cp);
542
543   /* Set initial bulk start to not solve */
544   ph.env.sf.s_bulk_start (ph.solver);
545   ph.bulk_running = GNUNET_YES;
546
547   for (cp = 0; cp < count_p; cp++)
548   {
549     for (ca = 0; ca < count_a; ca++)
550     {
551       cur_addr = perf_create_address (cp, ca);
552       /* Add address */
553       ph.env.sf.s_add (ph.solver, cur_addr, GNUNET_ATS_NET_LAN);
554       perf_address_initial_update (ph.solver, ph.addresses, cur_addr);
555       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
556           "Adding address for peer %u address %u\n", cp, ca);
557     }
558     /* Notify solver about request */
559     ph.env.sf.s_get (ph.solver, &ph.peers[cp].id);
560
561     if (cp + 1 >= ph.N_peers_start)
562     {
563       /* Disable bulk to solve the problem */
564       if (GNUNET_YES == ph.bulk_running)
565       {
566         ph.bulk_running = GNUNET_NO;
567         ph.expecting_solution = GNUNET_YES;
568         ph.current_p = cp + 1;
569         ph.current_a = ca;
570         ph.env.sf.s_bulk_stop (ph.solver);
571       }
572       else
573       {
574         GNUNET_break (0);
575       }
576
577       /* Problem is solved by the solver here due to unlocking */
578
579       ph.expecting_solution = GNUNET_NO;
580       /* Disable bulk to solve the problem */
581       if (GNUNET_NO == ph.bulk_running)
582       {
583         ph.env.sf.s_bulk_start (ph.solver);
584         ph.bulk_running = GNUNET_YES;
585       }
586 #if 0
587       if ((0 < ph.opt_update_quantity) || (0 < ph.opt_update_percent))
588       {
589         /* Update */
590         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
591             "Updating problem with %u peers and %u addresses\n", cp + 1, ca);
592         //ph.env.sf.s_bulk_start (ph.solver);
593         //update_addresses (cp + 1, ca, ph.opt_update_quantity);
594         //ph.env.sf.s_bulk_stop (ph.solver);
595       }
596 #endif
597     }
598   }
599   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
600       "Done, cleaning up addresses\n");
601   if (GNUNET_NO == ph.bulk_running)
602   {
603     ph.env.sf.s_bulk_start (ph.solver);
604     ph.bulk_running = GNUNET_YES;
605   }
606
607   for (cp = 0; cp < count_p; cp++)
608   {
609     for (cur = ph.peers[cp].head; cur != NULL ; cur = next)
610     {
611       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
612           "Deleting addresses for peer %u\n", cp);
613       GNUNET_CONTAINER_multipeermap_remove (ph.addresses, &ph.peers[cp].id, cur);
614       ph.env.sf.s_del (ph.solver, cur, GNUNET_NO);
615       next = cur->next;
616       GNUNET_CONTAINER_DLL_remove(ph.peers[cp].head, ph.peers[cp].tail, cur);
617       GNUNET_free(cur);
618     }
619
620   }
621   GNUNET_free(ph.peers);
622
623   evaluate ();
624 }
625
626
627 static void
628 run (void *cls, char * const *args, const char *cfgfile,
629     const struct GNUNET_CONFIGURATION_Handle *cfg)
630 {
631   GNUNET_log_setup ("perf-ats-solver", "WARNING", NULL);
632   char *sep;
633   char *src_filename = GNUNET_strdup (__FILE__);
634   char *test_filename = cls;
635   char *solver;
636   char *plugin;
637   unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
638   unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
639   int c;
640
641   /* Extract test name */
642   if (NULL == (sep  = (strstr (src_filename,".c"))))
643   {
644     GNUNET_break (0);
645     ret = 1;
646     return;
647   }
648   sep[0] = '\0';
649
650   if (NULL != (sep = strstr (test_filename, ".exe")))
651     sep[0] = '\0';
652
653   if (NULL == (solver = strstr (test_filename, src_filename)))
654   {
655     GNUNET_break (0);
656     ret = 1;
657     return ;
658   }
659   solver += strlen (src_filename) +1;
660
661   if (0 == strcmp(solver, "proportional"))
662   {
663     ph.ats_mode = MODE_PROPORTIONAL;
664     ph.ats_string = "proportional";
665   }
666   else if (0 == strcmp(solver, "mlp"))
667   {
668     ph.ats_mode = MODE_MLP;
669     ph.ats_string = "mlp";
670   }
671   else if ((0 == strcmp(solver, "ril")))
672   {
673     ph.ats_mode = MODE_RIL;
674     ph.ats_string = "ril";
675   }
676   else
677   {
678     GNUNET_free (src_filename);
679     GNUNET_break (0);
680     ret = 1;
681     return ;
682   }
683   GNUNET_free (src_filename);
684
685   /* Calculcate peers */
686   if ((0 == ph.N_peers_start) && (0 == ph.N_peers_end))
687   {
688     ph.N_peers_start = DEFAULT_PEERS_START;
689     ph.N_peers_end = DEFAULT_PEERS_END;
690   }
691   if (0 == ph.N_address)
692     ph.N_address = DEFAULT_ADDRESSES;
693
694   if (ph.opt_update_quantity > ph.N_address)
695   {
696     fprintf (stderr,
697         _("Trying to update more addresses than we have per peer! (%u vs %u)"),
698         ph.opt_update_quantity, ph.N_address);
699     exit (1);
700   }
701
702   if (ph.N_peers_start != ph.N_peers_end)
703     fprintf (stderr, "Benchmarking solver `%s' with %u to %u peers and %u addresses\n",
704         ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address);
705   else
706     fprintf (stderr, "Benchmarking solver `%s' with %u peers and %u addresses\n",
707         ph.ats_string, ph.N_peers_end, ph.N_address);
708
709   /* Load quotas */
710   if (GNUNET_ATS_NetworkTypeCount != load_quotas (cfg,
711       quotas_out, quotas_in, GNUNET_ATS_NetworkTypeCount))
712   {
713     GNUNET_break(0);
714     end_now (1);
715     return;
716   }
717
718   /* Load solver */
719   ph.env.cfg = cfg;
720   ph.stat = GNUNET_STATISTICS_create ("ats", cfg);
721   ph.env.stats = ph.stat;
722   ph.addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
723   ph.env.addresses = ph.addresses;
724   ph.env.bandwidth_changed_cb = bandwidth_changed_cb;
725   ph.env.get_preferences = &get_preferences_cb;
726   ph.env.get_property = &get_property_cb;
727   ph.env.network_count = GNUNET_ATS_NetworkTypeCount;
728   ph.env.info_cb = &solver_info_cb;
729   ph.env.info_cb_cls = NULL;
730
731   int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
732   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
733   {
734     ph.env.networks[c] = networks[c];
735     ph.env.out_quota[c] = quotas_out[c];
736     ph.env.in_quota[c] = quotas_in[c];
737     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loading network quotas: `%s' %llu %llu \n",
738         GNUNET_ATS_print_network_type(ph.env.networks[c]),
739         ph.env.out_quota[c],
740         ph.env.in_quota[c]);
741   }
742   GAS_normalization_start (NULL, NULL, &normalized_property_changed_cb, NULL );
743
744   GNUNET_asprintf (&plugin, "libgnunet_plugin_ats_%s", ph.ats_string);
745   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initializing solver `%s'\n"), ph.ats_string);
746   if  (NULL == (ph.solver = GNUNET_PLUGIN_load (plugin, &ph.env)))
747   {
748     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver `%s'!\n"), plugin);
749     ret = 1;
750     return;
751   }
752
753   /* Do work */
754   perf_run ();
755
756   /* Unload solver*/
757   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Unloading solver `%s'\n"), ph.ats_string);
758   GNUNET_PLUGIN_unload (plugin, ph.solver);
759   GNUNET_free (plugin);
760   ph.solver = NULL;
761 }
762
763 int
764 main (int argc, char *argv[])
765 {
766   /* extract command line arguments */
767   ph.opt_update_quantity = 0;
768   ph.opt_update_percent = 0;
769   ph.N_peers_start = 0;
770   ph.N_peers_end = 0;
771   ph.N_address = 0;
772   ph.ats_string = NULL;
773
774   static struct GNUNET_GETOPT_CommandLineOption options[] = {
775       { 'a', "addresses", NULL,
776           gettext_noop ("addresses to use"),
777           1, &GNUNET_GETOPT_set_uint, &ph.N_address },
778       { 's', "start", NULL,
779           gettext_noop ("start with peer"),
780           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_start },
781       { 'e', "end", NULL,
782           gettext_noop ("end with peer"),
783           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_end },
784       { 'p', "percentage", NULL,
785           gettext_noop ("update a fix percentage of addresses"),
786           1, &GNUNET_GETOPT_set_uint, &ph.opt_update_percent },
787       { 'q', "quantity", NULL,
788           gettext_noop ("update a fix quantity of addresses"),
789           1, &GNUNET_GETOPT_set_uint, &ph.opt_update_quantity },
790       GNUNET_GETOPT_OPTION_END
791   };
792
793   GNUNET_PROGRAM_run (argc, argv, argv[0], NULL, options, &run, argv[0]);
794
795   return ret;
796 }
797
798 /* end of file perf_ats_solver.c */