6504172d94dc2605ddc2deaf6268ac02e7fa1a60
[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 == ntohl (address->assigned_bw_out.value__)) &&
397        (0 == ntohl (address->assigned_bw_in.value__)) )
398     return;
399
400   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
401               "Bandwidth changed addresses %s %p to %u Bps out / %u Bps in\n",
402               GNUNET_i2s (&address->peer),
403               address,
404               (unsigned int) ntohl (address->assigned_bw_out.value__),
405               (unsigned int) ntohl (address->assigned_bw_in.value__));
406   if (GNUNET_YES == ph.bulk_running)
407     GNUNET_break (0);
408   return;
409 }
410
411
412 const double *
413 get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
414 {
415   return GAS_normalization_get_preferences_by_peer (id);
416 }
417
418
419 const double *
420 get_property_cb (void *cls, const struct ATS_Address *address)
421 {
422   return GAS_normalization_get_properties ((struct ATS_Address *) address);
423 }
424
425 static void
426 normalized_property_changed_cb (void *cls, struct ATS_Address *peer,
427     uint32_t type, double prop_rel)
428 {
429   /* TODO */
430 }
431
432 static void
433 perf_address_initial_update (void *solver,
434     struct GNUNET_CONTAINER_MultiPeerMap * addresses,
435     struct ATS_Address *address)
436 {
437   double delay;
438   double distance;
439   uint32_t random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
440   delay = (100 + (double) random) / 100;
441   ph.env.sf.s_address_update_property (solver, address, GNUNET_ATS_QUALITY_NET_DELAY,
442       100,  delay);
443
444   random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
445   distance = (100 + (double) random) / 100;
446
447   ph.env.sf.s_address_update_property (solver, address,
448       GNUNET_ATS_QUALITY_NET_DISTANCE, 10, distance);
449
450   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
451       "Initial update address %p : %.2f  %.2f\n", address, delay, distance);
452 }
453
454 /**
455  * Update a certain percentage of peers
456  *
457  * @param cp the current number of peers
458  * @param ca the current number of addresses
459  * @param percentage_peers the percentage of peers to update
460  */
461
462 static void
463 perf_update_all_addresses (unsigned int cp, unsigned int ca, unsigned int percentage_peers)
464 {
465   struct ATS_Address *cur_address;
466   int c_peer;
467   int c_select;
468   int c_cur_p;
469   int c_cur_a;
470   int r;
471   int count;
472   unsigned int m[cp];
473
474   count = cp * ((double) percentage_peers / 100);
475   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
476       "Updating %u of %u peers \n", count, cp);
477
478   for (c_peer = 0; c_peer < cp; c_peer++)
479     m[c_peer] = 0;
480
481   c_select = 0;
482
483   while (c_select < count)
484   {
485     r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, cp);
486     if (0 == m[r])
487     {
488       m[r] = 1;
489       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
490           "Updating peer [%u] \n", r);
491       c_select++;
492     }
493   }
494   for (c_cur_p = 0; c_cur_p < cp; c_cur_p++)
495   {
496     if (1 == m[c_cur_p])
497     {
498       r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, ca);
499       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
500           "Updating peer [%u] address [%u]\n", c_cur_p, r);
501
502       c_cur_a = 0;
503       for (cur_address = ph.peers[c_cur_p].head; NULL != cur_address; cur_address = cur_address->next)
504       {
505         if (c_cur_a == r)
506           perf_update_address (cur_address);
507         c_cur_a ++;
508       }
509     }
510   }
511 }
512
513 /**
514  * Create an address for a peer
515  *
516  * @param cp index of the peer
517  * @param ca index of the address
518  * @return the address
519  */
520 static struct ATS_Address *
521 perf_create_address (int cp, int ca)
522 {
523   struct ATS_Address *a;
524   a = create_address (&ph.peers[cp].id,
525       "Test 1", "test 1", strlen ("test 1") + 1, 0);
526   GNUNET_CONTAINER_DLL_insert (ph.peers[cp].head, ph.peers[cp].tail, a);
527   GNUNET_CONTAINER_multipeermap_put (ph.addresses, &ph.peers[cp].id, a,
528       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
529   return a;
530 }
531
532
533 /**
534  * Information callback for the solver
535  *
536  * @param op the solver operation
537  * @param stat status of the solver operation
538  * @param add additional solver information
539  */
540 static void
541 solver_info_cb (void *cls,
542     enum GAS_Solver_Operation op,
543     enum GAS_Solver_Status stat,
544     enum GAS_Solver_Additional_Information add)
545 {
546   char *add_info;
547   switch (add) {
548     case GAS_INFO_NONE:
549       add_info = "GAS_INFO_NONE";
550       break;
551     case GAS_INFO_FULL:
552       add_info = "GAS_INFO_MLP_FULL";
553       break;
554     case GAS_INFO_UPDATED:
555       add_info = "GAS_INFO_MLP_UPDATED";
556       break;
557     case GAS_INFO_PROP_ALL:
558       add_info = "GAS_INFO_PROP_ALL";
559       break;
560     case GAS_INFO_PROP_SINGLE:
561       add_info = "GAS_INFO_PROP_SINGLE";
562       break;
563     default:
564       add_info = "INVALID";
565       break;
566   }
567
568   struct Result *tmp;
569   switch (op)
570   {
571     case GAS_OP_SOLVE_START:
572       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
573           "Solver notifies `%s' with result `%s' `%s'\n", "GAS_OP_SOLVE_START",
574           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
575       if (GNUNET_NO == ph.expecting_solution)
576       {
577         /* We do not expect a solution at the moment */
578         GNUNET_break (0);
579         return;
580       }
581
582       if ((GAS_STAT_SUCCESS == stat) && (NULL == ph.current_result))
583       {
584         tmp = GNUNET_new (struct Result);
585         /* Create new result */
586         if ((add == GAS_INFO_UPDATED) || (GNUNET_YES == ph.performed_update))
587         {
588           ph.current_result = tmp;
589           //fprintf (stderr,"UPDATE %u %u\n",ph.current_iteration-1, ph.current_p);
590           ph.iterations_results[ph.current_iteration-1].update_results_array[ph.current_p] = tmp;
591         }
592         else
593         {
594           ph.current_result = tmp;
595           //fprintf (stderr,"FULL %u %u\n",ph.current_iteration-1, ph.current_p);
596           ph.iterations_results[ph.current_iteration-1].results_array[ph.current_p] = tmp;
597         }
598
599         ph.current_result->addresses = ph.current_a;
600         ph.current_result->peers = ph.current_p;
601         ph.current_result->s_total = GNUNET_TIME_absolute_get();
602         ph.current_result->d_total_full = GNUNET_TIME_UNIT_FOREVER_REL;
603         ph.current_result->d_setup_full = GNUNET_TIME_UNIT_FOREVER_REL;
604         ph.current_result->d_lp_full = GNUNET_TIME_UNIT_FOREVER_REL;
605         ph.current_result->d_mlp_full = GNUNET_TIME_UNIT_FOREVER_REL;
606         ph.current_result->info = add;
607         if ((add == GAS_INFO_UPDATED) || (GNUNET_YES == ph.performed_update))
608         {
609           ph.current_result->update = GNUNET_YES;
610         }
611         else
612         {
613           ph.current_result->update = GNUNET_NO;
614         }
615
616       }
617       return;
618     case GAS_OP_SOLVE_STOP:
619       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
620           "Solver notifies `%s' with result `%s', `%s'\n", "GAS_OP_SOLVE_STOP",
621           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
622       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
623       {
624         /* We do not expect a solution at the moment */
625         GNUNET_break (0);
626         return;
627       }
628
629       if (GAS_STAT_SUCCESS == stat)
630         ph.current_result->valid = GNUNET_YES;
631       else
632         ph.current_result->valid = GNUNET_NO;
633
634       if (NULL != ph.current_result)
635       {
636         /* Finalize result */
637         ph.current_result->e_total = GNUNET_TIME_absolute_get ();
638         ph.current_result->d_total_full = GNUNET_TIME_absolute_get_difference (
639             ph.current_result->s_total, ph.current_result->e_total);
640       }
641       ph.current_result = NULL;
642       return;
643
644     case GAS_OP_SOLVE_SETUP_START:
645       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
646           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_START",
647           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
648       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
649       {
650         GNUNET_break(0);
651         return;
652       }
653
654       if (GAS_STAT_SUCCESS == stat)
655         ph.current_result->valid = GNUNET_YES;
656       else
657         ph.current_result->valid = GNUNET_NO;
658
659       ph.current_result->s_setup = GNUNET_TIME_absolute_get ();
660       return;
661
662     case GAS_OP_SOLVE_SETUP_STOP:
663       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
664           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_STOP",
665           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
666       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
667       {
668         GNUNET_break(0);
669         return;
670       }
671
672       if (GAS_STAT_SUCCESS == stat)
673         ph.current_result->valid = GNUNET_YES;
674       else
675         ph.current_result->valid = GNUNET_NO;
676
677       ph.current_result->e_setup = GNUNET_TIME_absolute_get ();
678       ph.current_result->d_setup_full = GNUNET_TIME_absolute_get_difference (
679           ph.current_result->s_setup, ph.current_result->e_setup);
680       return;
681
682     case GAS_OP_SOLVE_MLP_LP_START:
683       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
684           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_START",
685           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
686       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
687       {
688         GNUNET_break(0);
689         return;
690       }
691
692       if (GAS_STAT_SUCCESS == stat)
693         ph.current_result->valid = GNUNET_YES;
694       else
695         ph.current_result->valid = GNUNET_NO;
696
697       ph.current_result->s_lp = GNUNET_TIME_absolute_get ();
698       return;
699     case GAS_OP_SOLVE_MLP_LP_STOP:
700       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
701           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_STOP",
702           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
703       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
704       {
705         GNUNET_break(0);
706         return;
707       }
708
709       if (GAS_STAT_SUCCESS == stat)
710         ph.current_result->valid = GNUNET_YES;
711       else
712         ph.current_result->valid = GNUNET_NO;
713
714       ph.current_result->e_lp = GNUNET_TIME_absolute_get ();
715       ph.current_result->d_lp_full = GNUNET_TIME_absolute_get_difference (
716           ph.current_result->s_lp, ph.current_result->e_lp);
717       return;
718
719     case GAS_OP_SOLVE_MLP_MLP_START:
720       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
721           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_START",
722           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
723       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
724       {
725         GNUNET_break(0);
726         return;
727       }
728
729       if (GAS_STAT_SUCCESS == stat)
730         ph.current_result->valid = GNUNET_YES;
731       else
732         ph.current_result->valid = GNUNET_NO;
733
734       ph.current_result->s_mlp = GNUNET_TIME_absolute_get ();
735       return;
736     case GAS_OP_SOLVE_MLP_MLP_STOP:
737       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
738           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_STOP",
739           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
740       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
741       {
742         GNUNET_break(0);
743         return;
744       }
745
746       if (GAS_STAT_SUCCESS == stat)
747         ph.current_result->valid = GNUNET_YES;
748       else
749         ph.current_result->valid = GNUNET_NO;
750
751       ph.current_result->e_mlp = GNUNET_TIME_absolute_get ();
752       ph.current_result->d_mlp_full = GNUNET_TIME_absolute_get_difference (
753       ph.current_result->s_mlp, ph.current_result->e_mlp);
754       return;
755     case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
756       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
757           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
758           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
759       return;
760     case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
761       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
762           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
763           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
764       if (GAS_STAT_SUCCESS != stat)
765       {
766         GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
767             "Solver `%s' failed to update problem with %u peers and %u address!\n",
768             ph.ats_string, ph.current_p, ph.current_a);
769       }
770
771       return;
772     default:
773       break;
774     }
775 }
776
777 /**
778  * Evaluate results for a specific iteration
779  *
780  * @param iteration the iteration to evaluate
781  */
782 static void
783 evaluate (int iteration)
784 {
785   struct Result *cur;
786   int cp;
787
788   for (cp = ph.N_peers_start; cp <= ph.N_peers_end; cp ++)
789   {
790     cur  = ph.iterations_results[ph.current_iteration-1].results_array[cp];
791     if (0 == cp)
792       continue;
793     if (NULL == cur)
794       GNUNET_break (0);
795
796
797     if (GNUNET_NO == cur->valid)
798     {
799       fprintf (stderr,
800                "Total time to solve %s for %u peers %u addresses: %s\n",
801                (GNUNET_YES == cur->update) ? "updated" : "full",
802                cur->peers, cur->addresses, "Failed to solve!");
803       continue;
804     }
805
806
807     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_total_full.rel_value_us)
808     {
809       fprintf (stderr,
810          "Total time to solve %s for %u peers %u addresses: %llu us\n",
811          (GNUNET_YES == cur->update) ? "updated" : "full",
812          cur->peers, cur->addresses,
813          (unsigned long long) cur->d_total_full.rel_value_us);
814     }
815
816
817     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_setup_full.rel_value_us)
818     {
819       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
820           "Total time to setup %s %u peers %u addresses: %llu us\n",
821           (GNUNET_YES == cur->update) ? "updated" : "full",
822           cur->peers, cur->addresses,
823           (unsigned long long) cur->d_setup_full.rel_value_us);
824     }
825
826     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_lp_full.rel_value_us)
827     {
828       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
829          "Total time to solve %s LP for %u peers %u addresses: %llu us\n",
830          (GNUNET_YES == cur->update) ? "updated" : "full",
831          cur->peers,
832          cur->addresses,
833          (unsigned long long )cur->d_lp_full.rel_value_us);
834     }
835
836     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_mlp_full.rel_value_us)
837     {
838       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
839           "Total time to solve %s MLP for %u peers %u addresses: %llu us\n",
840           (GNUNET_YES == cur->update) ? "updated" : "full",
841           cur->peers, cur->addresses,
842           (unsigned long long )cur->d_mlp_full.rel_value_us);
843     }
844   }
845
846 }
847
848 /**
849  * Evaluate average results for all iterations
850  */
851 static void
852 write_all_iterations (void)
853 {
854   int c_iteration;
855   int c_peer;
856
857   struct GNUNET_DISK_FileHandle *f_full;
858   struct GNUNET_DISK_FileHandle *f_update;
859   char * data_fn_full;
860   char * data_fn_update;
861   char * data;
862
863   f_full = NULL;
864   f_update = NULL;
865
866   data_fn_full = NULL;
867
868   if (GNUNET_NO == ph.create_datafile)
869     return;
870
871   GNUNET_asprintf (&data_fn_full,
872                    "perf_%s_full_%u-%u_%u_%u.data",
873                    ph.ats_string,
874                    ph.total_iterations,
875                    ph.N_peers_start,
876                    ph.N_peers_end,
877                    ph.N_address);
878   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
879               "Using data file `%s'\n",
880               data_fn_full);
881
882   f_full = GNUNET_DISK_file_open (data_fn_full,
883       GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
884       GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
885   if (NULL == f_full)
886   {
887     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
888                 "Cannot open data file `%s'\n",
889                 data_fn_full);
890     GNUNET_free (data_fn_full);
891     return;
892   }
893
894   data = "#peers;addresses;time total in us;#time setup in us;#time lp in us;#time mlp in us;\n";
895   if (GNUNET_SYSERR == GNUNET_DISK_file_write(f_full, data, strlen(data)))
896     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
897                 "Cannot write data to log file `%s'\n",
898                 data_fn_full);
899
900   data_fn_update = NULL;
901   if (GNUNET_YES == ph.measure_updates)
902   {
903     GNUNET_asprintf (&data_fn_update, "perf_%s_update_%u-%u_%u_%u.data",
904         ph.ats_string,
905         ph.total_iterations,
906         ph.N_peers_start,
907         ph.N_peers_end,
908         ph.N_address);
909     f_update = GNUNET_DISK_file_open (data_fn_update,
910         GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
911         GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
912     if (NULL == f_update)
913     {
914       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
915                   "Cannot open gnuplot file `%s'\n", data_fn_update);
916       GNUNET_free (data_fn_update);
917       if (NULL != f_full)
918         GNUNET_DISK_file_close (f_full);
919       GNUNET_free (data_fn_full);
920       return;
921     }
922
923     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
924                 "Using update data file `%s'\n",
925                 data_fn_update);
926
927     data = "#peers;addresses;time total in us;#time setup in us;#time lp in us;#time mlp in us;\n";
928     if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_update, data, strlen(data)))
929       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
930                   "Cannot write data to log file `%s'\n",
931                   data_fn_update);
932   }
933
934   for (c_peer = ph.N_peers_start; c_peer <= ph.N_peers_end; c_peer ++)
935   {
936     char * data_str;
937     char * data_tmp;
938     char * data_upd_str;
939     char * data_upd_tmp;
940     GNUNET_asprintf(&data_str, "%u;%u",c_peer, ph.N_address);
941     if (ph.measure_updates)
942       GNUNET_asprintf(&data_upd_str, "%u;%u",c_peer, ph.N_address);
943     for (c_iteration = 0; c_iteration < ph.total_iterations; c_iteration ++)
944     {
945       struct Result *cur_full_res;
946       struct Result *cur_upd_res;
947
948
949
950       //fprintf (stderr, "P: %u I: %u  == %p \n", c_peer, c_iteration, cur_res);
951       cur_full_res = ph.iterations_results[c_iteration].results_array[c_peer];
952       if (c_peer == 0)
953         continue;
954       if (NULL == cur_full_res)
955         continue;
956
957       if (ph.measure_updates)
958       {
959         cur_upd_res = ph.iterations_results[c_iteration].update_results_array[c_peer];
960         data_upd_tmp = GNUNET_strdup (data_upd_str);
961         GNUNET_free (data_upd_str);
962         GNUNET_asprintf (&data_upd_str, "%s;%llu", data_upd_tmp,
963             (NULL == cur_upd_res) ? 0 : cur_upd_res->d_total_full.rel_value_us);
964         GNUNET_free (data_upd_tmp);
965
966       }
967
968       //fprintf (stderr, "P: %u I: %u: P %i  A %i\n", c_peer, c_iteration, cur_res->peers, cur_res->addresses);
969       //fprintf (stderr, "D total: %llu\n", (long long unsigned int) cur_res->d_total.rel_value_us);
970
971       data_tmp = GNUNET_strdup (data_str);
972       GNUNET_free (data_str);
973       GNUNET_asprintf (&data_str, "%s;%llu", data_tmp, cur_full_res->d_total_full.rel_value_us);
974       GNUNET_free (data_tmp);
975     }
976     data_tmp = GNUNET_strdup (data_str);
977     GNUNET_free (data_str);
978     GNUNET_asprintf (&data_str, "%s\n", data_tmp);
979     GNUNET_free (data_tmp);
980
981     fprintf (stderr, "Result full solution: %s\n", data_str);
982     if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_full, data_str, strlen(data_str)))
983       GNUNET_break (0);
984     GNUNET_free (data_str);
985
986     if (ph.measure_updates)
987     {
988       data_upd_tmp = GNUNET_strdup (data_upd_str);
989       GNUNET_free (data_upd_str);
990       GNUNET_asprintf (&data_upd_str, "%s\n", data_upd_tmp);
991       GNUNET_free (data_upd_tmp);
992
993       fprintf (stderr, "Result updated solution: %s\n", data_upd_str);
994       if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_update, data_upd_str, strlen(data_upd_str)))
995         GNUNET_break (0);
996       GNUNET_free (data_upd_str);
997     }
998   }
999
1000   if ((NULL != f_full) && (GNUNET_SYSERR == GNUNET_DISK_file_close (f_full)))
1001     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n",
1002         data_fn_full);
1003   GNUNET_free_non_null (data_fn_full);
1004
1005   if ((NULL != f_update) && (GNUNET_SYSERR == GNUNET_DISK_file_close (f_update)))
1006     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n",
1007         data_fn_update);
1008   GNUNET_free_non_null (data_fn_update);
1009 }
1010
1011 /**
1012  * Run a performance iteration
1013  */
1014
1015 static void
1016 perf_run_iteration (void)
1017 {
1018   struct ATS_Address *cur;
1019   struct ATS_Address *next;
1020   int cp;
1021   int ca;
1022   int count_p = ph.N_peers_end;
1023   int count_a = ph.N_address;
1024   struct ATS_Address * cur_addr;
1025   uint32_t net;
1026
1027   ph.iterations_results[ph.current_iteration-1].results_array = GNUNET_malloc ((count_p + 1) * sizeof (struct Result *));
1028   if (ph.measure_updates)
1029     ph.iterations_results[ph.current_iteration-1].update_results_array = GNUNET_malloc ((count_p + 1) * sizeof (struct Result *));
1030   ph.peers = GNUNET_malloc ((count_p) * sizeof (struct PerfPeer));
1031   for (cp = 0; cp < count_p; cp++)
1032     perf_create_peer (cp);
1033   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1034       "Iteration %u of %u, added %u peers\n", ph.current_iteration, ph.total_iterations, cp);
1035
1036   for (cp = 0; cp < count_p; cp++)
1037   {
1038     fprintf (stderr,"%u..", cp);
1039     if (GNUNET_NO == ph.bulk_running)
1040     {
1041       ph.bulk_running = GNUNET_YES;
1042       ph.env.sf.s_bulk_start (ph.solver);
1043     }
1044     ph.current_p = cp + 1;
1045     for (ca = 0; ca < count_a; ca++)
1046     {
1047       cur_addr = perf_create_address (cp, ca);
1048       /* Add address */
1049
1050       /* Random network selection */
1051       //net = 1 + GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_ATS_NetworkTypeCount - 1);
1052       /* Random equally distributed network selection */
1053       net = 1 + (ca %  (GNUNET_ATS_NetworkTypeCount - 1));
1054       /* fprintf (stderr, "Network: %u `%s'\n",
1055        * mod_net , GNUNET_ATS_print_network_type(mod_net)); */
1056
1057       cur_addr->atsi = GNUNET_new (struct GNUNET_ATS_Information);
1058       cur_addr->atsi_count = 1;
1059       cur_addr->atsi[0].type = htonl (GNUNET_ATS_NETWORK_TYPE);
1060       cur_addr->atsi[0].value = htonl (net);
1061       ph.env.sf.s_add (ph.solver, cur_addr, net);
1062
1063       ph.current_a = ca + 1;
1064       perf_address_initial_update (ph.solver, ph.addresses, cur_addr);
1065       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1066           "Adding address for peer %u address %u in network %s\n", cp, ca,
1067           GNUNET_ATS_print_network_type(net));
1068     }
1069     /* Notify solver about request */
1070     ph.env.sf.s_get (ph.solver, &ph.peers[cp].id);
1071
1072     if (cp + 1 >= ph.N_peers_start)
1073     {
1074       /* Disable bulk to solve the problem */
1075       if (GNUNET_YES == ph.bulk_running)
1076       {
1077         ph.expecting_solution = GNUNET_YES;
1078         ph.bulk_running = GNUNET_NO;
1079         ph.env.sf.s_bulk_stop (ph.solver);
1080       }
1081       else
1082         GNUNET_break (0);
1083
1084       /* Problem is solved by the solver here due to unlocking */
1085       ph.expecting_solution = GNUNET_NO;
1086
1087       /* Update the problem */
1088       if ((0 < ph.opt_update_percent) && (GNUNET_YES == ph.measure_updates))
1089       {
1090         /* Update */
1091         GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1092             "Updating problem with %u peers and %u addresses\n", cp + 1, ca);
1093
1094         ph.expecting_solution = GNUNET_YES;
1095         ph.performed_update = GNUNET_YES;
1096         if (GNUNET_NO == ph.bulk_running)
1097         {
1098           ph.bulk_running = GNUNET_YES;
1099           ph.env.sf.s_bulk_start (ph.solver);
1100         }
1101         perf_update_all_addresses (cp + 1, ca, ph.opt_update_percent);
1102         ph.bulk_running = GNUNET_NO;
1103         ph.env.sf.s_bulk_stop (ph.solver);
1104         /* Problem is solved by the solver here due to unlocking */
1105         ph.performed_update = GNUNET_NO;
1106         ph.expecting_solution = GNUNET_NO;
1107       }
1108       GNUNET_assert (GNUNET_NO == ph.bulk_running);
1109     }
1110   }
1111   fprintf (stderr,"\n");
1112   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1113       "Done, cleaning up addresses\n");
1114   if (GNUNET_NO == ph.bulk_running)
1115   {
1116     ph.env.sf.s_bulk_start (ph.solver);
1117     ph.bulk_running = GNUNET_YES;
1118   }
1119
1120   for (cp = 0; cp < count_p; cp++)
1121   {
1122     for (cur = ph.peers[cp].head; cur != NULL ; cur = next)
1123     {
1124       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1125           "Deleting addresses for peer %u\n", cp);
1126       GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove (ph.addresses,
1127           &ph.peers[cp].id, cur));
1128       ph.env.sf.s_del (ph.solver, cur, GNUNET_NO);
1129       next = cur->next;
1130       GNUNET_CONTAINER_DLL_remove(ph.peers[cp].head, ph.peers[cp].tail, cur);
1131       GNUNET_free_non_null (cur->atsi);
1132       GNUNET_free (cur);
1133     }
1134   }
1135
1136   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1137       "Iteration done\n");
1138   GNUNET_free(ph.peers);
1139 }
1140
1141
1142 static void
1143 run (void *cls, char * const *args, const char *cfgfile,
1144     const struct GNUNET_CONFIGURATION_Handle *cfg)
1145 {
1146   GNUNET_log_setup ("perf-ats-solver", "WARNING", NULL);
1147   char *sep;
1148   char *src_filename = GNUNET_strdup (__FILE__);
1149   char *test_filename = cls;
1150   char *solver;
1151   char *plugin;
1152   struct GNUNET_CONFIGURATION_Handle *solver_cfg;
1153   unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
1154   unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
1155   int c;
1156   int c2;
1157
1158   /* Extract test name */
1159   if (NULL == (sep  = (strstr (src_filename,".c"))))
1160   {
1161     GNUNET_free (src_filename);
1162     GNUNET_break (0);
1163     ret = 1;
1164     return ;
1165   }
1166   sep[0] = '\0';
1167
1168   if (NULL != (sep = strstr (test_filename, ".exe")))
1169     sep[0] = '\0';
1170
1171   if (NULL == (solver = strstr (test_filename, src_filename)))
1172   {
1173     GNUNET_free (src_filename);
1174     GNUNET_break (0);
1175     ret = 1;
1176     return ;
1177   }
1178   solver += strlen (src_filename) +1;
1179
1180   if (0 == strcmp(solver, "proportional"))
1181   {
1182     ph.ats_mode = MODE_PROPORTIONAL;
1183     ph.ats_string = "proportional";
1184   }
1185   else if (0 == strcmp(solver, "mlp"))
1186   {
1187     ph.ats_mode = MODE_MLP;
1188     ph.ats_string = "mlp";
1189   }
1190   else if ((0 == strcmp(solver, "ril")))
1191   {
1192     ph.ats_mode = MODE_RIL;
1193     ph.ats_string = "ril";
1194   }
1195   else
1196   {
1197     GNUNET_free (src_filename);
1198     GNUNET_break (0);
1199     ret = 1;
1200     return ;
1201   }
1202   GNUNET_free (src_filename);
1203
1204   /* Calculcate peers */
1205   if ((0 == ph.N_peers_start) && (0 == ph.N_peers_end))
1206   {
1207     ph.N_peers_start = DEFAULT_PEERS_START;
1208     ph.N_peers_end = DEFAULT_PEERS_END;
1209   }
1210   if (0 == ph.N_address)
1211     ph.N_address = DEFAULT_ADDRESSES;
1212
1213
1214   if (ph.N_peers_start != ph.N_peers_end)
1215     fprintf (stderr, "Benchmarking solver `%s' with %u to %u peers and %u addresses in %u iterations\n",
1216         ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address, ph.total_iterations);
1217   else
1218     fprintf (stderr, "Benchmarking solver `%s' with %u peers and %u addresses in %u iterations\n",
1219         ph.ats_string, ph.N_peers_end, ph.N_address, ph.total_iterations);
1220
1221   if (0 == ph.opt_update_percent)
1222     ph.opt_update_percent = DEFAULT_UPDATE_PERCENTAGE;
1223
1224   /* Load quotas */
1225   solver_cfg = GNUNET_CONFIGURATION_create();
1226   if ((NULL == solver_cfg) || (GNUNET_SYSERR == (GNUNET_CONFIGURATION_load ( solver_cfg, "perf_ats_solver.conf"))))
1227   {
1228     GNUNET_break(0);
1229     end_now (1);
1230     return;
1231   }
1232   if (GNUNET_ATS_NetworkTypeCount != load_quotas (solver_cfg,
1233       quotas_out, quotas_in, GNUNET_ATS_NetworkTypeCount))
1234   {
1235     GNUNET_break(0);
1236     end_now (1);
1237     return;
1238   }
1239
1240   /* Create array of DLL to store results for iterations */
1241   ph.iterations_results = GNUNET_malloc (sizeof (struct Iteration) * ph.total_iterations);
1242
1243   /* Load solver */
1244   ph.env.cfg = solver_cfg;
1245   ph.stat = GNUNET_STATISTICS_create ("ats", cfg);
1246   ph.env.stats = ph.stat;
1247   ph.addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
1248   ph.env.addresses = ph.addresses;
1249   ph.env.bandwidth_changed_cb = bandwidth_changed_cb;
1250   ph.env.get_preferences = &get_preferences_cb;
1251   ph.env.get_property = &get_property_cb;
1252   ph.env.network_count = GNUNET_ATS_NetworkTypeCount;
1253   ph.env.info_cb = &solver_info_cb;
1254   ph.env.info_cb_cls = NULL;
1255
1256   int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
1257   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
1258   {
1259     ph.env.networks[c] = networks[c];
1260     ph.env.out_quota[c] = quotas_out[c];
1261     ph.env.in_quota[c] = quotas_in[c];
1262     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loading network quotas: `%s' %llu %llu \n",
1263         GNUNET_ATS_print_network_type(ph.env.networks[c]),
1264         ph.env.out_quota[c],
1265         ph.env.in_quota[c]);
1266   }
1267   GAS_normalization_start (NULL, NULL, &normalized_property_changed_cb, NULL );
1268
1269   GNUNET_asprintf (&plugin, "libgnunet_plugin_ats_%s", ph.ats_string);
1270   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initializing solver `%s'\n"), ph.ats_string);
1271   if  (NULL == (ph.solver = GNUNET_PLUGIN_load (plugin, &ph.env)))
1272   {
1273     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver `%s'!\n"), plugin);
1274     ret = 1;
1275     return;
1276   }
1277
1278   /* Do the benchmark */
1279   for (ph.current_iteration = 1; ph.current_iteration <= ph.total_iterations; ph.current_iteration++)
1280   {
1281     fprintf (stderr, "Iteration %u of %u starting\n", ph.current_iteration, ph.total_iterations);
1282     perf_run_iteration ();
1283     evaluate (ph.current_iteration);
1284     fprintf (stderr, "Iteration %u of %u done\n", ph.current_iteration, ph.total_iterations);
1285   }
1286   if (ph.create_datafile)
1287     write_all_iterations ();
1288
1289   /* Unload solver*/
1290   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Unloading solver `%s'\n"), ph.ats_string);
1291   GNUNET_PLUGIN_unload (plugin, ph.solver);
1292   GNUNET_free (plugin);
1293   for (c = 0; c < ph.total_iterations; c++ )
1294   {
1295     for (c2 = ph.N_peers_start; c2 < ph.N_peers_end; c2++ )
1296     {
1297       if (0 == c2)
1298         continue;
1299       if (ph.measure_updates)
1300         GNUNET_free_non_null (ph.iterations_results[c].update_results_array[c2]);
1301       GNUNET_free (ph.iterations_results[c].results_array[c2]);
1302     }
1303     if (ph.measure_updates)
1304       GNUNET_free (ph.iterations_results[c].update_results_array);
1305     GNUNET_free(ph.iterations_results[c].results_array);
1306   }
1307   GNUNET_free (ph.iterations_results);
1308
1309   GNUNET_CONFIGURATION_destroy (solver_cfg);
1310   GNUNET_STATISTICS_destroy (ph.stat, GNUNET_NO);
1311   ph.solver = NULL;
1312 }
1313
1314 /**
1315  * Main function of the benchmark
1316  *
1317  * @param argc argument count
1318  * @param argv argument values
1319  */
1320 int
1321 main (int argc, char *argv[])
1322 {
1323   /* extract command line arguments */
1324   ph.opt_update_percent = 0;
1325   ph.N_peers_start = 0;
1326   ph.N_peers_end = 0;
1327   ph.N_address = 0;
1328   ph.ats_string = NULL;
1329   ph.create_datafile = GNUNET_NO;
1330   ph.measure_updates = GNUNET_NO;
1331   ph.total_iterations = 1;
1332
1333   static struct GNUNET_GETOPT_CommandLineOption options[] = {
1334       { 'a', "addresses", NULL,
1335           gettext_noop ("addresses to use"),
1336           1, &GNUNET_GETOPT_set_uint, &ph.N_address },
1337       { 's', "start", NULL,
1338           gettext_noop ("start with peer"),
1339           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_start },
1340       { 'e', "end", NULL,
1341           gettext_noop ("end with peer"),
1342           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_end },
1343       { 'i', "iterations", NULL,
1344           gettext_noop ("number of iterations used for averaging (default: 1)"),
1345           1, &GNUNET_GETOPT_set_uint, &ph.total_iterations },
1346       { 'p', "percentage", NULL,
1347           gettext_noop ("update a fix percentage of addresses"),
1348           1, &GNUNET_GETOPT_set_uint, &ph.opt_update_percent },
1349       { 'd', "data", NULL,
1350           gettext_noop ("create data file"),
1351           0, &GNUNET_GETOPT_set_one, &ph.create_datafile},
1352       { 'u', "update", NULL,
1353           gettext_noop ("measure updates"),
1354           0, &GNUNET_GETOPT_set_one, &ph.measure_updates},
1355       GNUNET_GETOPT_OPTION_END
1356   };
1357
1358   GNUNET_PROGRAM_run (argc, argv, argv[0], NULL, options, &run, argv[0]);
1359   return ret;
1360 }
1361
1362 /* end of file perf_ats_solver.c */