do not use NBO internally
[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_UPDATE_PERCENTAGE       20
36 #define DEFAULT_PEERS_START     10
37 #define DEFAULT_PEERS_END       10
38 #define DEFAULT_ADDRESSES       10
39 #define DEFAULT_ATS_COUNT       2
40
41
42 /**
43  * Handle for ATS address component
44  */
45 struct PerfHandle
46 {
47   /**
48    * Performance peers
49    */
50   struct PerfPeer *peers;
51
52   /**
53    *  Solver handle
54    */
55   void *solver;
56
57   /**
58    * Statistics stat;
59    */
60   struct GNUNET_STATISTICS_Handle *stat;
61
62   /**
63    * A multihashmap to store all addresses
64    */
65   struct GNUNET_CONTAINER_MultiPeerMap *addresses;
66
67   /**
68    * Solver functions
69    * */
70   struct GNUNET_ATS_PluginEnvironment env;
71
72   /**
73    * Array for results for each iteration with length iterations
74    */
75   struct Iteration *iterations_results;
76
77   /**
78    * The current result
79    */
80   struct Result *current_result;
81
82   /**
83    * Current number of peers benchmarked
84    */
85   int current_p;
86
87   /**
88    * Current number of addresses benchmarked
89    */
90   int current_a;
91
92   /**
93    * Solver description as string
94    */
95   char *ats_string;
96
97   /**
98    * Configured ATS solver
99    */
100   int ats_mode;
101
102   /**
103    * #peers to start benchmarking with
104    */
105   int N_peers_start;
106
107   /**
108    * #peers to end benchmarking with
109    */
110   int N_peers_end;
111
112   /**
113    * #addresses to benchmarking with
114    */
115   int N_address;
116
117   /**
118    * Percentage of peers to update
119    */
120   int opt_update_percent;
121
122   /**
123    * Create gnuplot file
124    */
125   int create_datafile;
126
127   /**
128    * Measure updates
129    */
130   int measure_updates;
131
132   /**
133    * Number of iterations
134    */
135   int total_iterations;
136
137   /**
138    * Current iteration
139    */
140   int current_iteration;
141
142   /**
143    * Is a bulk operation running?
144    */
145   int bulk_running;
146
147   /**
148    * Is a bulk operation running?
149    */
150   int expecting_solution;
151
152   /**
153    * Was the problem just updates?
154    */
155   int performed_update;
156 };
157
158 /**
159  * Data structure to store results for a single iteration
160  */
161 struct Iteration
162 {
163   struct Result **results_array;
164
165   struct Result **update_results_array;
166 };
167
168
169 /**
170  * Result for a solver calculcation
171  */
172 struct Result
173 {
174   /**
175    * Previous element in the linked list
176    */
177   struct Result *prev;
178
179   /**
180    * Next element in the linked list
181    */
182   struct Result *next;
183
184   /**
185    * Number of peers this solution included
186    */
187   int peers;
188
189   /**
190    * Number of addresses per peer this solution included
191    */
192   int addresses;
193
194   /**
195    * Is this an update or a full solution
196    */
197   int update;
198
199   /**
200    * Was the solution valid or did the solver fail
201    */
202   int valid;
203
204   /**
205    * Result of the solver
206    */
207   enum GAS_Solver_Additional_Information info;
208
209   /**
210    * Duration of setting up the problem in the solver
211    */
212   struct GNUNET_TIME_Relative d_setup_full;
213
214   /**
215    * Duration of solving the LP problem in the solver
216    * MLP solver only
217    */
218   struct GNUNET_TIME_Relative d_lp_full;
219
220   /**
221    * Duration of solving the MLP problem in the solver
222    * MLP solver only
223    */
224   struct GNUNET_TIME_Relative d_mlp_full;
225
226   /**
227    * Duration of solving whole problem in the solver
228    */
229   struct GNUNET_TIME_Relative d_total_full;
230
231   /**
232    * Start time of setting up the problem in the solver
233    */
234   struct GNUNET_TIME_Absolute s_setup;
235
236   /**
237    * Start time of solving the LP problem in the solver
238    * MLP solver only
239    */
240   struct GNUNET_TIME_Absolute s_lp;
241
242   /**
243    * Start time of solving the MLP problem in the solver
244    * MLP solver only
245    */
246   struct GNUNET_TIME_Absolute s_mlp;
247
248   /**
249    * Start time of solving whole problem in the solver
250    */
251   struct GNUNET_TIME_Absolute s_total;
252
253   /**
254    * End time of setting up the problem in the solver
255    */
256   struct GNUNET_TIME_Absolute e_setup;
257
258   /**
259    * End time of solving the LP problem in the solver
260    * MLP solver only
261    */
262   struct GNUNET_TIME_Absolute e_lp;
263
264   /**
265    * End time of solving the MLP problem in the solver
266    * MLP solver only
267    */
268   struct GNUNET_TIME_Absolute e_mlp;
269
270   /**
271    * End time of solving whole problem in the solver
272    */
273   struct GNUNET_TIME_Absolute e_total;
274 };
275
276 /**
277  * Peer used for the benchmarking
278  */
279 struct PerfPeer
280 {
281   /**
282    * Peer identitity
283    */
284   struct GNUNET_PeerIdentity id;
285
286   /**
287    * Head of linked list of addresses used with this peer
288    */
289   struct ATS_Address *head;
290
291   /**
292    * Head of linked list of addresses used with this peer
293    */
294   struct ATS_Address *tail;
295 };
296
297
298 /**
299  * ATS performance handle
300  */
301 static struct PerfHandle ph;
302
303 /**
304  * Return value
305  */
306 static int ret;
307
308
309 /**
310  * Do shutdown
311  */
312 static void
313 end_now (int res)
314 {
315   if (NULL != ph.stat)
316   {
317     GNUNET_STATISTICS_destroy (ph.stat, GNUNET_NO);
318     ph.stat = NULL;
319   }
320
321   GNUNET_free_non_null (ph.peers);
322   GNUNET_free_non_null (ph.iterations_results);
323
324   GAS_normalization_stop ();
325   ret = res;
326 }
327
328
329 /**
330  * Create a peer used for benchmarking
331  *
332  * @param cp the number of the peer
333  */
334 static void
335 perf_create_peer (int cp)
336 {
337
338   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
339       &ph.peers[cp].id, sizeof (struct GNUNET_PeerIdentity));
340   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Creating peer #%u: %s \n", cp,
341       GNUNET_i2s (&ph.peers[cp].id));
342 }
343
344
345 /**
346  * Perform an update for an address
347  *
348  * @param cur the address to update
349  */
350 static void
351 perf_update_address (struct ATS_Address *cur)
352 {
353   int r_type;
354   int abs_val;
355   double rel_val;
356
357   r_type = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2);
358   switch (r_type)
359   {
360   case 0:
361     abs_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
362     rel_val = (100 + (double) abs_val) / 100;
363
364     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
365         "Updating peer `%s' address %p type %s abs val %u rel val %.3f\n",
366         GNUNET_i2s (&cur->peer), cur,
367         "GNUNET_ATS_QUALITY_NET_DELAY",
368         abs_val, rel_val);
369     ph.env.sf.s_address_update_property (ph.solver, cur,
370         GNUNET_ATS_QUALITY_NET_DELAY,
371         abs_val, rel_val);
372     break;
373   case 1:
374     abs_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 10);
375     rel_val = (100 + (double) abs_val) / 100;
376
377     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
378         "Updating peer `%s' address %p type %s abs val %u rel val %.3f\n",
379         GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DISTANCE",
380         abs_val, rel_val);
381     ph.env.sf.s_address_update_property (ph.solver, cur,
382         GNUNET_ATS_QUALITY_NET_DISTANCE,
383         abs_val, rel_val);
384     break;
385   default:
386     break;
387   }
388   ph.env.sf.s_address_update_inuse (ph.solver, cur, GNUNET_YES);
389 }
390
391
392 static void
393 bandwidth_changed_cb (void *cls,
394                       struct ATS_Address *address)
395 {
396   if ( (0 == address->assigned_bw_out) && (0 == address->assigned_bw_in) )
397     return;
398
399   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
400               "Bandwidth changed addresses %s %p to %u Bps out / %u Bps in\n",
401               GNUNET_i2s (&address->peer),
402               address,
403               address->assigned_bw_out,
404               address->assigned_bw_in);
405   if (GNUNET_YES == ph.bulk_running)
406     GNUNET_break (0);
407   return;
408 }
409
410
411 const double *
412 get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
413 {
414   return GAS_normalization_get_preferences_by_peer (id);
415 }
416
417
418 const double *
419 get_property_cb (void *cls, const struct ATS_Address *address)
420 {
421   return GAS_normalization_get_properties ((struct ATS_Address *) address);
422 }
423
424 static void
425 normalized_property_changed_cb (void *cls, struct ATS_Address *peer,
426     uint32_t type, double prop_rel)
427 {
428   /* TODO */
429 }
430
431 static void
432 perf_address_initial_update (void *solver,
433     struct GNUNET_CONTAINER_MultiPeerMap * addresses,
434     struct ATS_Address *address)
435 {
436   double delay;
437   double distance;
438   uint32_t random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
439   delay = (100 + (double) random) / 100;
440   ph.env.sf.s_address_update_property (solver, address, GNUNET_ATS_QUALITY_NET_DELAY,
441       100,  delay);
442
443   random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
444   distance = (100 + (double) random) / 100;
445
446   ph.env.sf.s_address_update_property (solver, address,
447       GNUNET_ATS_QUALITY_NET_DISTANCE, 10, distance);
448
449   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
450       "Initial update address %p : %.2f  %.2f\n", address, delay, distance);
451 }
452
453 /**
454  * Update a certain percentage of peers
455  *
456  * @param cp the current number of peers
457  * @param ca the current number of addresses
458  * @param percentage_peers the percentage of peers to update
459  */
460
461 static void
462 perf_update_all_addresses (unsigned int cp, unsigned int ca, unsigned int percentage_peers)
463 {
464   struct ATS_Address *cur_address;
465   int c_peer;
466   int c_select;
467   int c_cur_p;
468   int c_cur_a;
469   int r;
470   int count;
471   unsigned int m[cp];
472
473   count = cp * ((double) percentage_peers / 100);
474   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
475       "Updating %u of %u peers \n", count, cp);
476
477   for (c_peer = 0; c_peer < cp; c_peer++)
478     m[c_peer] = 0;
479
480   c_select = 0;
481
482   while (c_select < count)
483   {
484     r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, cp);
485     if (0 == m[r])
486     {
487       m[r] = 1;
488       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
489           "Updating peer [%u] \n", r);
490       c_select++;
491     }
492   }
493   for (c_cur_p = 0; c_cur_p < cp; c_cur_p++)
494   {
495     if (1 == m[c_cur_p])
496     {
497       r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, ca);
498       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
499           "Updating peer [%u] address [%u]\n", c_cur_p, r);
500
501       c_cur_a = 0;
502       for (cur_address = ph.peers[c_cur_p].head; NULL != cur_address; cur_address = cur_address->next)
503       {
504         if (c_cur_a == r)
505           perf_update_address (cur_address);
506         c_cur_a ++;
507       }
508     }
509   }
510 }
511
512 /**
513  * Create an address for a peer
514  *
515  * @param cp index of the peer
516  * @param ca index of the address
517  * @return the address
518  */
519 static struct ATS_Address *
520 perf_create_address (int cp, int ca)
521 {
522   struct ATS_Address *a;
523   a = create_address (&ph.peers[cp].id,
524       "Test 1", "test 1", strlen ("test 1") + 1, 0);
525   GNUNET_CONTAINER_DLL_insert (ph.peers[cp].head, ph.peers[cp].tail, a);
526   GNUNET_CONTAINER_multipeermap_put (ph.addresses, &ph.peers[cp].id, a,
527       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
528   return a;
529 }
530
531
532 /**
533  * Information callback for the solver
534  *
535  * @param op the solver operation
536  * @param stat status of the solver operation
537  * @param add additional solver information
538  */
539 static void
540 solver_info_cb (void *cls,
541     enum GAS_Solver_Operation op,
542     enum GAS_Solver_Status stat,
543     enum GAS_Solver_Additional_Information add)
544 {
545   char *add_info;
546   switch (add) {
547     case GAS_INFO_NONE:
548       add_info = "GAS_INFO_NONE";
549       break;
550     case GAS_INFO_FULL:
551       add_info = "GAS_INFO_MLP_FULL";
552       break;
553     case GAS_INFO_UPDATED:
554       add_info = "GAS_INFO_MLP_UPDATED";
555       break;
556     case GAS_INFO_PROP_ALL:
557       add_info = "GAS_INFO_PROP_ALL";
558       break;
559     case GAS_INFO_PROP_SINGLE:
560       add_info = "GAS_INFO_PROP_SINGLE";
561       break;
562     default:
563       add_info = "INVALID";
564       break;
565   }
566
567   struct Result *tmp;
568   switch (op)
569   {
570     case GAS_OP_SOLVE_START:
571       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
572           "Solver notifies `%s' with result `%s' `%s'\n", "GAS_OP_SOLVE_START",
573           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
574       if (GNUNET_NO == ph.expecting_solution)
575       {
576         /* We do not expect a solution at the moment */
577         GNUNET_break (0);
578         return;
579       }
580
581       if ((GAS_STAT_SUCCESS == stat) && (NULL == ph.current_result))
582       {
583         tmp = GNUNET_new (struct Result);
584         /* Create new result */
585         if ((add == GAS_INFO_UPDATED) || (GNUNET_YES == ph.performed_update))
586         {
587           ph.current_result = tmp;
588           //fprintf (stderr,"UPDATE %u %u\n",ph.current_iteration-1, ph.current_p);
589           ph.iterations_results[ph.current_iteration-1].update_results_array[ph.current_p] = tmp;
590         }
591         else
592         {
593           ph.current_result = tmp;
594           //fprintf (stderr,"FULL %u %u\n",ph.current_iteration-1, ph.current_p);
595           ph.iterations_results[ph.current_iteration-1].results_array[ph.current_p] = tmp;
596         }
597
598         ph.current_result->addresses = ph.current_a;
599         ph.current_result->peers = ph.current_p;
600         ph.current_result->s_total = GNUNET_TIME_absolute_get();
601         ph.current_result->d_total_full = GNUNET_TIME_UNIT_FOREVER_REL;
602         ph.current_result->d_setup_full = GNUNET_TIME_UNIT_FOREVER_REL;
603         ph.current_result->d_lp_full = GNUNET_TIME_UNIT_FOREVER_REL;
604         ph.current_result->d_mlp_full = GNUNET_TIME_UNIT_FOREVER_REL;
605         ph.current_result->info = add;
606         if ((add == GAS_INFO_UPDATED) || (GNUNET_YES == ph.performed_update))
607         {
608           ph.current_result->update = GNUNET_YES;
609         }
610         else
611         {
612           ph.current_result->update = GNUNET_NO;
613         }
614
615       }
616       return;
617     case GAS_OP_SOLVE_STOP:
618       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
619           "Solver notifies `%s' with result `%s', `%s'\n", "GAS_OP_SOLVE_STOP",
620           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
621       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
622       {
623         /* We do not expect a solution at the moment */
624         GNUNET_break (0);
625         return;
626       }
627
628       if (GAS_STAT_SUCCESS == stat)
629         ph.current_result->valid = GNUNET_YES;
630       else
631         ph.current_result->valid = GNUNET_NO;
632
633       if (NULL != ph.current_result)
634       {
635         /* Finalize result */
636         ph.current_result->e_total = GNUNET_TIME_absolute_get ();
637         ph.current_result->d_total_full = GNUNET_TIME_absolute_get_difference (
638             ph.current_result->s_total, ph.current_result->e_total);
639       }
640       ph.current_result = NULL;
641       return;
642
643     case GAS_OP_SOLVE_SETUP_START:
644       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
645           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_START",
646           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
647       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
648       {
649         GNUNET_break(0);
650         return;
651       }
652
653       if (GAS_STAT_SUCCESS == stat)
654         ph.current_result->valid = GNUNET_YES;
655       else
656         ph.current_result->valid = GNUNET_NO;
657
658       ph.current_result->s_setup = GNUNET_TIME_absolute_get ();
659       return;
660
661     case GAS_OP_SOLVE_SETUP_STOP:
662       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
663           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_STOP",
664           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
665       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
666       {
667         GNUNET_break(0);
668         return;
669       }
670
671       if (GAS_STAT_SUCCESS == stat)
672         ph.current_result->valid = GNUNET_YES;
673       else
674         ph.current_result->valid = GNUNET_NO;
675
676       ph.current_result->e_setup = GNUNET_TIME_absolute_get ();
677       ph.current_result->d_setup_full = GNUNET_TIME_absolute_get_difference (
678           ph.current_result->s_setup, ph.current_result->e_setup);
679       return;
680
681     case GAS_OP_SOLVE_MLP_LP_START:
682       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
683           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_START",
684           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
685       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
686       {
687         GNUNET_break(0);
688         return;
689       }
690
691       if (GAS_STAT_SUCCESS == stat)
692         ph.current_result->valid = GNUNET_YES;
693       else
694         ph.current_result->valid = GNUNET_NO;
695
696       ph.current_result->s_lp = GNUNET_TIME_absolute_get ();
697       return;
698     case GAS_OP_SOLVE_MLP_LP_STOP:
699       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
700           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_STOP",
701           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
702       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
703       {
704         GNUNET_break(0);
705         return;
706       }
707
708       if (GAS_STAT_SUCCESS == stat)
709         ph.current_result->valid = GNUNET_YES;
710       else
711         ph.current_result->valid = GNUNET_NO;
712
713       ph.current_result->e_lp = GNUNET_TIME_absolute_get ();
714       ph.current_result->d_lp_full = GNUNET_TIME_absolute_get_difference (
715           ph.current_result->s_lp, ph.current_result->e_lp);
716       return;
717
718     case GAS_OP_SOLVE_MLP_MLP_START:
719       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
720           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_START",
721           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
722       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
723       {
724         GNUNET_break(0);
725         return;
726       }
727
728       if (GAS_STAT_SUCCESS == stat)
729         ph.current_result->valid = GNUNET_YES;
730       else
731         ph.current_result->valid = GNUNET_NO;
732
733       ph.current_result->s_mlp = GNUNET_TIME_absolute_get ();
734       return;
735     case GAS_OP_SOLVE_MLP_MLP_STOP:
736       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
737           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_STOP",
738           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
739       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
740       {
741         GNUNET_break(0);
742         return;
743       }
744
745       if (GAS_STAT_SUCCESS == stat)
746         ph.current_result->valid = GNUNET_YES;
747       else
748         ph.current_result->valid = GNUNET_NO;
749
750       ph.current_result->e_mlp = GNUNET_TIME_absolute_get ();
751       ph.current_result->d_mlp_full = GNUNET_TIME_absolute_get_difference (
752       ph.current_result->s_mlp, ph.current_result->e_mlp);
753       return;
754     case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
755       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
756           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
757           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
758       return;
759     case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
760       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
761           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
762           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
763       if (GAS_STAT_SUCCESS != stat)
764       {
765         GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
766             "Solver `%s' failed to update problem with %u peers and %u address!\n",
767             ph.ats_string, ph.current_p, ph.current_a);
768       }
769
770       return;
771     default:
772       break;
773     }
774 }
775
776 /**
777  * Evaluate results for a specific iteration
778  *
779  * @param iteration the iteration to evaluate
780  */
781 static void
782 evaluate (int iteration)
783 {
784   struct Result *cur;
785   int cp;
786
787   for (cp = ph.N_peers_start; cp <= ph.N_peers_end; cp ++)
788   {
789     cur  = ph.iterations_results[ph.current_iteration-1].results_array[cp];
790     if (0 == cp)
791       continue;
792     if (NULL == cur)
793     {
794       GNUNET_break (0);
795       fprintf (stderr,
796                "Missing result for %u peers\n", cp);
797     }
798
799
800     if (GNUNET_NO == cur->valid)
801     {
802       fprintf (stderr,
803                "Total time to solve %s for %u peers %u addresses: %s\n",
804                (GNUNET_YES == cur->update) ? "updated" : "full",
805                cur->peers, cur->addresses, "Failed to solve!");
806       continue;
807     }
808
809
810     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_total_full.rel_value_us)
811     {
812       fprintf (stderr,
813          "Total time to solve %s for %u peers %u addresses: %llu us\n",
814          (GNUNET_YES == cur->update) ? "updated" : "full",
815          cur->peers, cur->addresses,
816          (unsigned long long) cur->d_total_full.rel_value_us);
817     }
818
819
820     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_setup_full.rel_value_us)
821     {
822       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
823           "Total time to setup %s %u peers %u addresses: %llu us\n",
824           (GNUNET_YES == cur->update) ? "updated" : "full",
825           cur->peers, cur->addresses,
826           (unsigned long long) cur->d_setup_full.rel_value_us);
827     }
828
829     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_lp_full.rel_value_us)
830     {
831       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
832          "Total time to solve %s LP for %u peers %u addresses: %llu us\n",
833          (GNUNET_YES == cur->update) ? "updated" : "full",
834          cur->peers,
835          cur->addresses,
836          (unsigned long long )cur->d_lp_full.rel_value_us);
837     }
838
839     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_mlp_full.rel_value_us)
840     {
841       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
842           "Total time to solve %s MLP for %u peers %u addresses: %llu us\n",
843           (GNUNET_YES == cur->update) ? "updated" : "full",
844           cur->peers, cur->addresses,
845           (unsigned long long )cur->d_mlp_full.rel_value_us);
846     }
847   }
848
849 }
850
851 /**
852  * Evaluate average results for all iterations
853  */
854 static void
855 write_all_iterations (void)
856 {
857   int c_iteration;
858   int c_peer;
859
860   struct GNUNET_DISK_FileHandle *f_full;
861   struct GNUNET_DISK_FileHandle *f_update;
862   char * data_fn_full;
863   char * data_fn_update;
864   char * data;
865
866   f_full = NULL;
867   f_update = NULL;
868
869   data_fn_full = NULL;
870
871   if (GNUNET_NO == ph.create_datafile)
872     return;
873
874   GNUNET_asprintf (&data_fn_full,
875                    "perf_%s_full_%u-%u_%u_%u.data",
876                    ph.ats_string,
877                    ph.total_iterations,
878                    ph.N_peers_start,
879                    ph.N_peers_end,
880                    ph.N_address);
881   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
882               "Using data file `%s'\n",
883               data_fn_full);
884
885   f_full = GNUNET_DISK_file_open (data_fn_full,
886       GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
887       GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
888   if (NULL == f_full)
889   {
890     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
891                 "Cannot open data file `%s'\n",
892                 data_fn_full);
893     GNUNET_free (data_fn_full);
894     return;
895   }
896
897   data = "#peers;addresses;time total in us;#time setup in us;#time lp in us;#time mlp in us;\n";
898   if (GNUNET_SYSERR == GNUNET_DISK_file_write(f_full, data, strlen(data)))
899     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
900                 "Cannot write data to log file `%s'\n",
901                 data_fn_full);
902
903   data_fn_update = NULL;
904   if (GNUNET_YES == ph.measure_updates)
905   {
906     GNUNET_asprintf (&data_fn_update, "perf_%s_update_%u-%u_%u_%u.data",
907         ph.ats_string,
908         ph.total_iterations,
909         ph.N_peers_start,
910         ph.N_peers_end,
911         ph.N_address);
912     f_update = GNUNET_DISK_file_open (data_fn_update,
913         GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
914         GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
915     if (NULL == f_update)
916     {
917       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
918                   "Cannot open gnuplot file `%s'\n", data_fn_update);
919       GNUNET_free (data_fn_update);
920       if (NULL != f_full)
921         GNUNET_DISK_file_close (f_full);
922       GNUNET_free (data_fn_full);
923       return;
924     }
925
926     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
927                 "Using update data file `%s'\n",
928                 data_fn_update);
929
930     data = "#peers;addresses;time total in us;#time setup in us;#time lp in us;#time mlp in us;\n";
931     if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_update, data, strlen(data)))
932       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
933                   "Cannot write data to log file `%s'\n",
934                   data_fn_update);
935   }
936
937   for (c_peer = ph.N_peers_start; c_peer <= ph.N_peers_end; c_peer ++)
938   {
939     char * data_str;
940     char * data_tmp;
941     char * data_upd_str;
942     char * data_upd_tmp;
943     GNUNET_asprintf(&data_str, "%u;%u",c_peer, ph.N_address);
944     if (ph.measure_updates)
945       GNUNET_asprintf(&data_upd_str, "%u;%u",c_peer, ph.N_address);
946     for (c_iteration = 0; c_iteration < ph.total_iterations; c_iteration ++)
947     {
948       struct Result *cur_full_res;
949       struct Result *cur_upd_res;
950
951
952
953       //fprintf (stderr, "P: %u I: %u  == %p \n", c_peer, c_iteration, cur_res);
954       cur_full_res = ph.iterations_results[c_iteration].results_array[c_peer];
955       if (c_peer == 0)
956         continue;
957       if (NULL == cur_full_res)
958         continue;
959
960       if (ph.measure_updates)
961       {
962         cur_upd_res = ph.iterations_results[c_iteration].update_results_array[c_peer];
963         data_upd_tmp = GNUNET_strdup (data_upd_str);
964         GNUNET_free (data_upd_str);
965         if (GNUNET_YES == cur_full_res->valid)
966         {
967           GNUNET_asprintf (&data_upd_str, "%s;%llu", data_upd_tmp,
968             (NULL == cur_upd_res) ? 0 : cur_upd_res->d_total_full.rel_value_us);
969         }
970         else
971         {
972             GNUNET_asprintf (&data_upd_str, "%s;", data_upd_tmp);
973         }
974         GNUNET_free (data_upd_tmp);
975
976       }
977
978       //fprintf (stderr, "P: %u I: %u: P %i  A %i\n", c_peer, c_iteration, cur_res->peers, cur_res->addresses);
979       //fprintf (stderr, "D total: %llu\n", (long long unsigned int) cur_res->d_total.rel_value_us);
980
981       data_tmp = GNUNET_strdup (data_str);
982       GNUNET_free (data_str);
983       if (GNUNET_YES == cur_full_res->valid)
984       {
985           GNUNET_asprintf (&data_str, "%s;%llu", data_tmp,
986               cur_full_res->d_total_full.rel_value_us);
987       }
988       else
989       {
990           GNUNET_asprintf (&data_str, "%s;", data_tmp);
991       }
992
993       GNUNET_free (data_tmp);
994     }
995     data_tmp = GNUNET_strdup (data_str);
996     GNUNET_free (data_str);
997     GNUNET_asprintf (&data_str, "%s\n", data_tmp);
998     GNUNET_free (data_tmp);
999
1000     fprintf (stderr, "Result full solution: %s\n", data_str);
1001     if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_full, data_str, strlen(data_str)))
1002       GNUNET_break (0);
1003     GNUNET_free (data_str);
1004
1005     if (ph.measure_updates)
1006     {
1007       data_upd_tmp = GNUNET_strdup (data_upd_str);
1008       GNUNET_free (data_upd_str);
1009       GNUNET_asprintf (&data_upd_str, "%s\n", data_upd_tmp);
1010       GNUNET_free (data_upd_tmp);
1011
1012       fprintf (stderr, "Result updated solution: `%s'\n", data_upd_str);
1013       if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_update, data_upd_str, strlen(data_upd_str)))
1014         GNUNET_break (0);
1015       GNUNET_free (data_upd_str);
1016     }
1017   }
1018
1019   if ((NULL != f_full) && (GNUNET_SYSERR == GNUNET_DISK_file_close (f_full)))
1020     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n",
1021         data_fn_full);
1022   GNUNET_free_non_null (data_fn_full);
1023
1024   if ((NULL != f_update) && (GNUNET_SYSERR == GNUNET_DISK_file_close (f_update)))
1025     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n",
1026         data_fn_update);
1027   GNUNET_free_non_null (data_fn_update);
1028 }
1029
1030 /**
1031  * Run a performance iteration
1032  */
1033
1034 static void
1035 perf_run_iteration (void)
1036 {
1037   struct ATS_Address *cur;
1038   struct ATS_Address *next;
1039   int cp;
1040   int ca;
1041   int count_p = ph.N_peers_end;
1042   int count_a = ph.N_address;
1043   struct ATS_Address * cur_addr;
1044   uint32_t net;
1045
1046   ph.iterations_results[ph.current_iteration-1].results_array = GNUNET_malloc ((count_p + 1) * sizeof (struct Result *));
1047   if (ph.measure_updates)
1048     ph.iterations_results[ph.current_iteration-1].update_results_array = GNUNET_malloc ((count_p + 1) * sizeof (struct Result *));
1049   ph.peers = GNUNET_malloc ((count_p) * sizeof (struct PerfPeer));
1050   for (cp = 0; cp < count_p; cp++)
1051     perf_create_peer (cp);
1052   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1053       "Iteration %u of %u, added %u peers\n", ph.current_iteration, ph.total_iterations, cp);
1054
1055   for (cp = 0; cp < count_p; cp++)
1056   {
1057     fprintf (stderr,"%u..", cp);
1058     if (GNUNET_NO == ph.bulk_running)
1059     {
1060       ph.bulk_running = GNUNET_YES;
1061       ph.env.sf.s_bulk_start (ph.solver);
1062     }
1063     ph.current_p = cp + 1;
1064     for (ca = 0; ca < count_a; ca++)
1065     {
1066       cur_addr = perf_create_address (cp, ca);
1067       /* Add address */
1068
1069       /* Random network selection */
1070       //net = 1 + GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_ATS_NetworkTypeCount - 1);
1071       /* Random equally distributed network selection */
1072       net = 1 + (ca %  (GNUNET_ATS_NetworkTypeCount - 1));
1073       /* fprintf (stderr, "Network: %u `%s'\n",
1074        * mod_net , GNUNET_ATS_print_network_type(mod_net)); */
1075
1076       cur_addr->atsi = GNUNET_new (struct GNUNET_ATS_Information);
1077       cur_addr->atsi_count = 1;
1078       cur_addr->atsi[0].type = htonl (GNUNET_ATS_NETWORK_TYPE);
1079       cur_addr->atsi[0].value = htonl (net);
1080       ph.env.sf.s_add (ph.solver, cur_addr, net);
1081
1082       ph.current_a = ca + 1;
1083       perf_address_initial_update (ph.solver, ph.addresses, cur_addr);
1084       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1085           "Adding address for peer %u address %u in network %s\n", cp, ca,
1086           GNUNET_ATS_print_network_type(net));
1087     }
1088     /* Notify solver about request */
1089     ph.env.sf.s_get (ph.solver, &ph.peers[cp].id);
1090
1091     if (cp + 1 >= ph.N_peers_start)
1092     {
1093       /* Disable bulk to solve the problem */
1094       if (GNUNET_YES == ph.bulk_running)
1095       {
1096         ph.expecting_solution = GNUNET_YES;
1097         ph.bulk_running = GNUNET_NO;
1098         ph.env.sf.s_bulk_stop (ph.solver);
1099       }
1100       else
1101         GNUNET_break (0);
1102
1103       /* Problem is solved by the solver here due to unlocking */
1104       ph.expecting_solution = GNUNET_NO;
1105
1106       /* Update the problem */
1107       if ((0 < ph.opt_update_percent) && (GNUNET_YES == ph.measure_updates))
1108       {
1109         /* Update */
1110         GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1111             "Updating problem with %u peers and %u addresses\n", cp + 1, ca);
1112
1113         ph.expecting_solution = GNUNET_YES;
1114         ph.performed_update = GNUNET_YES;
1115         if (GNUNET_NO == ph.bulk_running)
1116         {
1117           ph.bulk_running = GNUNET_YES;
1118           ph.env.sf.s_bulk_start (ph.solver);
1119         }
1120         perf_update_all_addresses (cp + 1, ca, ph.opt_update_percent);
1121         ph.bulk_running = GNUNET_NO;
1122         ph.env.sf.s_bulk_stop (ph.solver);
1123         /* Problem is solved by the solver here due to unlocking */
1124         ph.performed_update = GNUNET_NO;
1125         ph.expecting_solution = GNUNET_NO;
1126       }
1127       GNUNET_assert (GNUNET_NO == ph.bulk_running);
1128     }
1129   }
1130   fprintf (stderr,"\n");
1131   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1132       "Done, cleaning up addresses\n");
1133   if (GNUNET_NO == ph.bulk_running)
1134   {
1135     ph.env.sf.s_bulk_start (ph.solver);
1136     ph.bulk_running = GNUNET_YES;
1137   }
1138
1139   for (cp = 0; cp < count_p; cp++)
1140   {
1141     for (cur = ph.peers[cp].head; cur != NULL ; cur = next)
1142     {
1143       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1144           "Deleting addresses for peer %u\n", cp);
1145       GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove (ph.addresses,
1146           &ph.peers[cp].id, cur));
1147       ph.env.sf.s_del (ph.solver, cur, GNUNET_NO);
1148       next = cur->next;
1149       GNUNET_CONTAINER_DLL_remove(ph.peers[cp].head, ph.peers[cp].tail, cur);
1150       GNUNET_free_non_null (cur->atsi);
1151       GNUNET_free (cur);
1152     }
1153   }
1154
1155   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1156       "Iteration done\n");
1157   GNUNET_free(ph.peers);
1158 }
1159
1160
1161 static void
1162 run (void *cls, char * const *args, const char *cfgfile,
1163     const struct GNUNET_CONFIGURATION_Handle *cfg)
1164 {
1165   GNUNET_log_setup ("perf-ats-solver", "WARNING", NULL);
1166   char *sep;
1167   char *src_filename = GNUNET_strdup (__FILE__);
1168   char *test_filename = cls;
1169   char *solver;
1170   char *plugin;
1171   struct GNUNET_CONFIGURATION_Handle *solver_cfg;
1172   unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
1173   unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
1174   int c;
1175   int c2;
1176
1177   /* Extract test name */
1178   if (NULL == (sep  = (strstr (src_filename,".c"))))
1179   {
1180     GNUNET_free (src_filename);
1181     GNUNET_break (0);
1182     ret = 1;
1183     return ;
1184   }
1185   sep[0] = '\0';
1186
1187   if (NULL != (sep = strstr (test_filename, ".exe")))
1188     sep[0] = '\0';
1189
1190   if (NULL == (solver = strstr (test_filename, src_filename)))
1191   {
1192     GNUNET_free (src_filename);
1193     GNUNET_break (0);
1194     ret = 1;
1195     return ;
1196   }
1197   solver += strlen (src_filename) +1;
1198
1199   if (0 == strcmp(solver, "proportional"))
1200   {
1201     ph.ats_mode = MODE_PROPORTIONAL;
1202     ph.ats_string = "proportional";
1203   }
1204   else if (0 == strcmp(solver, "mlp"))
1205   {
1206     ph.ats_mode = MODE_MLP;
1207     ph.ats_string = "mlp";
1208   }
1209   else if ((0 == strcmp(solver, "ril")))
1210   {
1211     ph.ats_mode = MODE_RIL;
1212     ph.ats_string = "ril";
1213   }
1214   else
1215   {
1216     GNUNET_free (src_filename);
1217     GNUNET_break (0);
1218     ret = 1;
1219     return ;
1220   }
1221   GNUNET_free (src_filename);
1222
1223   /* Calculcate peers */
1224   if ((0 == ph.N_peers_start) && (0 == ph.N_peers_end))
1225   {
1226     ph.N_peers_start = DEFAULT_PEERS_START;
1227     ph.N_peers_end = DEFAULT_PEERS_END;
1228   }
1229   if (0 == ph.N_address)
1230     ph.N_address = DEFAULT_ADDRESSES;
1231
1232
1233   if (ph.N_peers_start != ph.N_peers_end)
1234     fprintf (stderr, "Benchmarking solver `%s' with %u to %u peers and %u addresses in %u iterations\n",
1235         ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address, ph.total_iterations);
1236   else
1237     fprintf (stderr, "Benchmarking solver `%s' with %u peers and %u addresses in %u iterations\n",
1238         ph.ats_string, ph.N_peers_end, ph.N_address, ph.total_iterations);
1239
1240   if (0 == ph.opt_update_percent)
1241     ph.opt_update_percent = DEFAULT_UPDATE_PERCENTAGE;
1242
1243   /* Load quotas */
1244   solver_cfg = GNUNET_CONFIGURATION_create();
1245   if ((NULL == solver_cfg) || (GNUNET_SYSERR == (GNUNET_CONFIGURATION_load ( solver_cfg, "perf_ats_solver.conf"))))
1246   {
1247     GNUNET_break(0);
1248     end_now (1);
1249     return;
1250   }
1251   if (GNUNET_ATS_NetworkTypeCount != load_quotas (solver_cfg,
1252       quotas_out, quotas_in, GNUNET_ATS_NetworkTypeCount))
1253   {
1254     GNUNET_break(0);
1255     end_now (1);
1256     return;
1257   }
1258
1259   /* Create array of DLL to store results for iterations */
1260   ph.iterations_results = GNUNET_malloc (sizeof (struct Iteration) * ph.total_iterations);
1261
1262   /* Load solver */
1263   ph.env.cfg = solver_cfg;
1264   ph.stat = GNUNET_STATISTICS_create ("ats", cfg);
1265   ph.env.stats = ph.stat;
1266   ph.addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
1267   ph.env.addresses = ph.addresses;
1268   ph.env.bandwidth_changed_cb = bandwidth_changed_cb;
1269   ph.env.get_preferences = &get_preferences_cb;
1270   ph.env.get_property = &get_property_cb;
1271   ph.env.network_count = GNUNET_ATS_NetworkTypeCount;
1272   ph.env.info_cb = &solver_info_cb;
1273   ph.env.info_cb_cls = NULL;
1274
1275   int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
1276   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
1277   {
1278     ph.env.networks[c] = networks[c];
1279     ph.env.out_quota[c] = quotas_out[c];
1280     ph.env.in_quota[c] = quotas_in[c];
1281     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loading network quotas: `%s' %llu %llu \n",
1282         GNUNET_ATS_print_network_type(ph.env.networks[c]),
1283         ph.env.out_quota[c],
1284         ph.env.in_quota[c]);
1285   }
1286   GAS_normalization_start (NULL, NULL, &normalized_property_changed_cb, NULL );
1287
1288   GNUNET_asprintf (&plugin, "libgnunet_plugin_ats_%s", ph.ats_string);
1289   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initializing solver `%s'\n"), ph.ats_string);
1290   if  (NULL == (ph.solver = GNUNET_PLUGIN_load (plugin, &ph.env)))
1291   {
1292     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver `%s'!\n"), plugin);
1293     ret = 1;
1294     return;
1295   }
1296
1297   /* Do the benchmark */
1298   for (ph.current_iteration = 1; ph.current_iteration <= ph.total_iterations; ph.current_iteration++)
1299   {
1300     fprintf (stderr, "Iteration %u of %u starting\n", ph.current_iteration, ph.total_iterations);
1301     perf_run_iteration ();
1302     evaluate (ph.current_iteration);
1303     fprintf (stderr, "Iteration %u of %u done\n", ph.current_iteration, ph.total_iterations);
1304   }
1305   if (ph.create_datafile)
1306     write_all_iterations ();
1307
1308   /* Unload solver*/
1309   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Unloading solver `%s'\n"), ph.ats_string);
1310   GNUNET_PLUGIN_unload (plugin, ph.solver);
1311   GNUNET_free (plugin);
1312   for (c = 0; c < ph.total_iterations; c++ )
1313   {
1314     for (c2 = ph.N_peers_start; c2 < ph.N_peers_end; c2++ )
1315     {
1316       if (0 == c2)
1317         continue;
1318       if (ph.measure_updates)
1319         GNUNET_free_non_null (ph.iterations_results[c].update_results_array[c2]);
1320       GNUNET_free (ph.iterations_results[c].results_array[c2]);
1321     }
1322     if (ph.measure_updates)
1323       GNUNET_free (ph.iterations_results[c].update_results_array);
1324     GNUNET_free(ph.iterations_results[c].results_array);
1325   }
1326   GNUNET_free (ph.iterations_results);
1327
1328   GNUNET_CONFIGURATION_destroy (solver_cfg);
1329   GNUNET_STATISTICS_destroy (ph.stat, GNUNET_NO);
1330   ph.solver = NULL;
1331 }
1332
1333 /**
1334  * Main function of the benchmark
1335  *
1336  * @param argc argument count
1337  * @param argv argument values
1338  */
1339 int
1340 main (int argc, char *argv[])
1341 {
1342   /* extract command line arguments */
1343   ph.opt_update_percent = 0;
1344   ph.N_peers_start = 0;
1345   ph.N_peers_end = 0;
1346   ph.N_address = 0;
1347   ph.ats_string = NULL;
1348   ph.create_datafile = GNUNET_NO;
1349   ph.measure_updates = GNUNET_NO;
1350   ph.total_iterations = 1;
1351
1352   static struct GNUNET_GETOPT_CommandLineOption options[] = {
1353       { 'a', "addresses", NULL,
1354           gettext_noop ("addresses to use"),
1355           1, &GNUNET_GETOPT_set_uint, &ph.N_address },
1356       { 's', "start", NULL,
1357           gettext_noop ("start with peer"),
1358           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_start },
1359       { 'e', "end", NULL,
1360           gettext_noop ("end with peer"),
1361           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_end },
1362       { 'i', "iterations", NULL,
1363           gettext_noop ("number of iterations used for averaging (default: 1)"),
1364           1, &GNUNET_GETOPT_set_uint, &ph.total_iterations },
1365       { 'p', "percentage", NULL,
1366           gettext_noop ("update a fix percentage of addresses"),
1367           1, &GNUNET_GETOPT_set_uint, &ph.opt_update_percent },
1368       { 'd', "data", NULL,
1369           gettext_noop ("create data file"),
1370           0, &GNUNET_GETOPT_set_one, &ph.create_datafile},
1371       { 'u', "update", NULL,
1372           gettext_noop ("measure updates"),
1373           0, &GNUNET_GETOPT_set_one, &ph.measure_updates},
1374       GNUNET_GETOPT_OPTION_END
1375   };
1376
1377   GNUNET_PROGRAM_run (argc, argv, argv[0], NULL, options, &run, argv[0]);
1378   return ret;
1379 }
1380
1381 /* end of file perf_ats_solver.c */