95adea4b3ad622c8fe78d40a3a0c500f6cc25dc0
[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
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     {
795       GNUNET_break (0);
796       fprintf (stderr,
797                "Missing result for %u peers\n", cp);
798     }
799
800
801     if (GNUNET_NO == cur->valid)
802     {
803       fprintf (stderr,
804                "Total time to solve %s for %u peers %u addresses: %s\n",
805                (GNUNET_YES == cur->update) ? "updated" : "full",
806                cur->peers, cur->addresses, "Failed to solve!");
807       continue;
808     }
809
810
811     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_total_full.rel_value_us)
812     {
813       fprintf (stderr,
814          "Total time to solve %s for %u peers %u addresses: %llu us\n",
815          (GNUNET_YES == cur->update) ? "updated" : "full",
816          cur->peers, cur->addresses,
817          (unsigned long long) cur->d_total_full.rel_value_us);
818     }
819
820
821     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_setup_full.rel_value_us)
822     {
823       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
824           "Total time to setup %s %u peers %u addresses: %llu us\n",
825           (GNUNET_YES == cur->update) ? "updated" : "full",
826           cur->peers, cur->addresses,
827           (unsigned long long) cur->d_setup_full.rel_value_us);
828     }
829
830     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_lp_full.rel_value_us)
831     {
832       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
833          "Total time to solve %s LP for %u peers %u addresses: %llu us\n",
834          (GNUNET_YES == cur->update) ? "updated" : "full",
835          cur->peers,
836          cur->addresses,
837          (unsigned long long )cur->d_lp_full.rel_value_us);
838     }
839
840     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_mlp_full.rel_value_us)
841     {
842       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
843           "Total time to solve %s MLP for %u peers %u addresses: %llu us\n",
844           (GNUNET_YES == cur->update) ? "updated" : "full",
845           cur->peers, cur->addresses,
846           (unsigned long long )cur->d_mlp_full.rel_value_us);
847     }
848   }
849
850 }
851
852 /**
853  * Evaluate average results for all iterations
854  */
855 static void
856 write_all_iterations (void)
857 {
858   int c_iteration;
859   int c_peer;
860
861   struct GNUNET_DISK_FileHandle *f_full;
862   struct GNUNET_DISK_FileHandle *f_update;
863   char * data_fn_full;
864   char * data_fn_update;
865   char * data;
866
867   f_full = NULL;
868   f_update = NULL;
869
870   data_fn_full = NULL;
871
872   if (GNUNET_NO == ph.create_datafile)
873     return;
874
875   GNUNET_asprintf (&data_fn_full,
876                    "perf_%s_full_%u-%u_%u_%u.data",
877                    ph.ats_string,
878                    ph.total_iterations,
879                    ph.N_peers_start,
880                    ph.N_peers_end,
881                    ph.N_address);
882   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
883               "Using data file `%s'\n",
884               data_fn_full);
885
886   f_full = GNUNET_DISK_file_open (data_fn_full,
887       GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
888       GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
889   if (NULL == f_full)
890   {
891     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
892                 "Cannot open data file `%s'\n",
893                 data_fn_full);
894     GNUNET_free (data_fn_full);
895     return;
896   }
897
898   data = "#peers;addresses;time total in us;#time setup in us;#time lp in us;#time mlp in us;\n";
899   if (GNUNET_SYSERR == GNUNET_DISK_file_write(f_full, data, strlen(data)))
900     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
901                 "Cannot write data to log file `%s'\n",
902                 data_fn_full);
903
904   data_fn_update = NULL;
905   if (GNUNET_YES == ph.measure_updates)
906   {
907     GNUNET_asprintf (&data_fn_update, "perf_%s_update_%u-%u_%u_%u.data",
908         ph.ats_string,
909         ph.total_iterations,
910         ph.N_peers_start,
911         ph.N_peers_end,
912         ph.N_address);
913     f_update = GNUNET_DISK_file_open (data_fn_update,
914         GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
915         GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
916     if (NULL == f_update)
917     {
918       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
919                   "Cannot open gnuplot file `%s'\n", data_fn_update);
920       GNUNET_free (data_fn_update);
921       if (NULL != f_full)
922         GNUNET_DISK_file_close (f_full);
923       GNUNET_free (data_fn_full);
924       return;
925     }
926
927     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
928                 "Using update data file `%s'\n",
929                 data_fn_update);
930
931     data = "#peers;addresses;time total in us;#time setup in us;#time lp in us;#time mlp in us;\n";
932     if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_update, data, strlen(data)))
933       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
934                   "Cannot write data to log file `%s'\n",
935                   data_fn_update);
936   }
937
938   for (c_peer = ph.N_peers_start; c_peer <= ph.N_peers_end; c_peer ++)
939   {
940     char * data_str;
941     char * data_tmp;
942     char * data_upd_str;
943     char * data_upd_tmp;
944     GNUNET_asprintf(&data_str, "%u;%u",c_peer, ph.N_address);
945     if (ph.measure_updates)
946       GNUNET_asprintf(&data_upd_str, "%u;%u",c_peer, ph.N_address);
947     for (c_iteration = 0; c_iteration < ph.total_iterations; c_iteration ++)
948     {
949       struct Result *cur_full_res;
950       struct Result *cur_upd_res;
951
952
953
954       //fprintf (stderr, "P: %u I: %u  == %p \n", c_peer, c_iteration, cur_res);
955       cur_full_res = ph.iterations_results[c_iteration].results_array[c_peer];
956       if (c_peer == 0)
957         continue;
958       if (NULL == cur_full_res)
959         continue;
960
961       if (ph.measure_updates)
962       {
963         cur_upd_res = ph.iterations_results[c_iteration].update_results_array[c_peer];
964         data_upd_tmp = GNUNET_strdup (data_upd_str);
965         GNUNET_free (data_upd_str);
966         if (GNUNET_YES == cur_full_res->valid)
967         {
968           GNUNET_asprintf (&data_upd_str, "%s;%llu", data_upd_tmp,
969             (NULL == cur_upd_res) ? 0 : cur_upd_res->d_total_full.rel_value_us);
970         }
971         else
972         {
973             GNUNET_asprintf (&data_str, "%s;", data_tmp);
974         }
975         GNUNET_free (data_upd_tmp);
976
977       }
978
979       //fprintf (stderr, "P: %u I: %u: P %i  A %i\n", c_peer, c_iteration, cur_res->peers, cur_res->addresses);
980       //fprintf (stderr, "D total: %llu\n", (long long unsigned int) cur_res->d_total.rel_value_us);
981
982       data_tmp = GNUNET_strdup (data_str);
983       GNUNET_free (data_str);
984       if (GNUNET_YES == cur_full_res->valid)
985       {
986           GNUNET_asprintf (&data_str, "%s;%llu", data_tmp,
987               cur_full_res->d_total_full.rel_value_us);
988       }
989       else
990       {
991           GNUNET_asprintf (&data_str, "%s;", data_tmp);
992       }
993
994       GNUNET_free (data_tmp);
995     }
996     data_tmp = GNUNET_strdup (data_str);
997     GNUNET_free (data_str);
998     GNUNET_asprintf (&data_str, "%s\n", data_tmp);
999     GNUNET_free (data_tmp);
1000
1001     fprintf (stderr, "Result full solution: %s\n", data_str);
1002     if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_full, data_str, strlen(data_str)))
1003       GNUNET_break (0);
1004     GNUNET_free (data_str);
1005
1006     if (ph.measure_updates)
1007     {
1008       data_upd_tmp = GNUNET_strdup (data_upd_str);
1009       GNUNET_free (data_upd_str);
1010       GNUNET_asprintf (&data_upd_str, "%s\n", data_upd_tmp);
1011       GNUNET_free (data_upd_tmp);
1012
1013       fprintf (stderr, "Result updated solution: %s\n", data_upd_str);
1014       if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_update, data_upd_str, strlen(data_upd_str)))
1015         GNUNET_break (0);
1016       GNUNET_free (data_upd_str);
1017     }
1018   }
1019
1020   if ((NULL != f_full) && (GNUNET_SYSERR == GNUNET_DISK_file_close (f_full)))
1021     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n",
1022         data_fn_full);
1023   GNUNET_free_non_null (data_fn_full);
1024
1025   if ((NULL != f_update) && (GNUNET_SYSERR == GNUNET_DISK_file_close (f_update)))
1026     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n",
1027         data_fn_update);
1028   GNUNET_free_non_null (data_fn_update);
1029 }
1030
1031 /**
1032  * Run a performance iteration
1033  */
1034
1035 static void
1036 perf_run_iteration (void)
1037 {
1038   struct ATS_Address *cur;
1039   struct ATS_Address *next;
1040   int cp;
1041   int ca;
1042   int count_p = ph.N_peers_end;
1043   int count_a = ph.N_address;
1044   struct ATS_Address * cur_addr;
1045   uint32_t net;
1046
1047   ph.iterations_results[ph.current_iteration-1].results_array = GNUNET_malloc ((count_p + 1) * sizeof (struct Result *));
1048   if (ph.measure_updates)
1049     ph.iterations_results[ph.current_iteration-1].update_results_array = GNUNET_malloc ((count_p + 1) * sizeof (struct Result *));
1050   ph.peers = GNUNET_malloc ((count_p) * sizeof (struct PerfPeer));
1051   for (cp = 0; cp < count_p; cp++)
1052     perf_create_peer (cp);
1053   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1054       "Iteration %u of %u, added %u peers\n", ph.current_iteration, ph.total_iterations, cp);
1055
1056   for (cp = 0; cp < count_p; cp++)
1057   {
1058     fprintf (stderr,"%u..", cp);
1059     if (GNUNET_NO == ph.bulk_running)
1060     {
1061       ph.bulk_running = GNUNET_YES;
1062       ph.env.sf.s_bulk_start (ph.solver);
1063     }
1064     ph.current_p = cp + 1;
1065     for (ca = 0; ca < count_a; ca++)
1066     {
1067       cur_addr = perf_create_address (cp, ca);
1068       /* Add address */
1069
1070       /* Random network selection */
1071       //net = 1 + GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_ATS_NetworkTypeCount - 1);
1072       /* Random equally distributed network selection */
1073       net = 1 + (ca %  (GNUNET_ATS_NetworkTypeCount - 1));
1074       /* fprintf (stderr, "Network: %u `%s'\n",
1075        * mod_net , GNUNET_ATS_print_network_type(mod_net)); */
1076
1077       cur_addr->atsi = GNUNET_new (struct GNUNET_ATS_Information);
1078       cur_addr->atsi_count = 1;
1079       cur_addr->atsi[0].type = htonl (GNUNET_ATS_NETWORK_TYPE);
1080       cur_addr->atsi[0].value = htonl (net);
1081       ph.env.sf.s_add (ph.solver, cur_addr, net);
1082
1083       ph.current_a = ca + 1;
1084       perf_address_initial_update (ph.solver, ph.addresses, cur_addr);
1085       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1086           "Adding address for peer %u address %u in network %s\n", cp, ca,
1087           GNUNET_ATS_print_network_type(net));
1088     }
1089     /* Notify solver about request */
1090     ph.env.sf.s_get (ph.solver, &ph.peers[cp].id);
1091
1092     if (cp + 1 >= ph.N_peers_start)
1093     {
1094       /* Disable bulk to solve the problem */
1095       if (GNUNET_YES == ph.bulk_running)
1096       {
1097         ph.expecting_solution = GNUNET_YES;
1098         ph.bulk_running = GNUNET_NO;
1099         ph.env.sf.s_bulk_stop (ph.solver);
1100       }
1101       else
1102         GNUNET_break (0);
1103
1104       /* Problem is solved by the solver here due to unlocking */
1105       ph.expecting_solution = GNUNET_NO;
1106
1107       /* Update the problem */
1108       if ((0 < ph.opt_update_percent) && (GNUNET_YES == ph.measure_updates))
1109       {
1110         /* Update */
1111         GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1112             "Updating problem with %u peers and %u addresses\n", cp + 1, ca);
1113
1114         ph.expecting_solution = GNUNET_YES;
1115         ph.performed_update = GNUNET_YES;
1116         if (GNUNET_NO == ph.bulk_running)
1117         {
1118           ph.bulk_running = GNUNET_YES;
1119           ph.env.sf.s_bulk_start (ph.solver);
1120         }
1121         perf_update_all_addresses (cp + 1, ca, ph.opt_update_percent);
1122         ph.bulk_running = GNUNET_NO;
1123         ph.env.sf.s_bulk_stop (ph.solver);
1124         /* Problem is solved by the solver here due to unlocking */
1125         ph.performed_update = GNUNET_NO;
1126         ph.expecting_solution = GNUNET_NO;
1127       }
1128       GNUNET_assert (GNUNET_NO == ph.bulk_running);
1129     }
1130   }
1131   fprintf (stderr,"\n");
1132   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1133       "Done, cleaning up addresses\n");
1134   if (GNUNET_NO == ph.bulk_running)
1135   {
1136     ph.env.sf.s_bulk_start (ph.solver);
1137     ph.bulk_running = GNUNET_YES;
1138   }
1139
1140   for (cp = 0; cp < count_p; cp++)
1141   {
1142     for (cur = ph.peers[cp].head; cur != NULL ; cur = next)
1143     {
1144       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1145           "Deleting addresses for peer %u\n", cp);
1146       GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove (ph.addresses,
1147           &ph.peers[cp].id, cur));
1148       ph.env.sf.s_del (ph.solver, cur, GNUNET_NO);
1149       next = cur->next;
1150       GNUNET_CONTAINER_DLL_remove(ph.peers[cp].head, ph.peers[cp].tail, cur);
1151       GNUNET_free_non_null (cur->atsi);
1152       GNUNET_free (cur);
1153     }
1154   }
1155
1156   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1157       "Iteration done\n");
1158   GNUNET_free(ph.peers);
1159 }
1160
1161
1162 static void
1163 run (void *cls, char * const *args, const char *cfgfile,
1164     const struct GNUNET_CONFIGURATION_Handle *cfg)
1165 {
1166   GNUNET_log_setup ("perf-ats-solver", "WARNING", NULL);
1167   char *sep;
1168   char *src_filename = GNUNET_strdup (__FILE__);
1169   char *test_filename = cls;
1170   char *solver;
1171   char *plugin;
1172   struct GNUNET_CONFIGURATION_Handle *solver_cfg;
1173   unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
1174   unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
1175   int c;
1176   int c2;
1177
1178   /* Extract test name */
1179   if (NULL == (sep  = (strstr (src_filename,".c"))))
1180   {
1181     GNUNET_free (src_filename);
1182     GNUNET_break (0);
1183     ret = 1;
1184     return ;
1185   }
1186   sep[0] = '\0';
1187
1188   if (NULL != (sep = strstr (test_filename, ".exe")))
1189     sep[0] = '\0';
1190
1191   if (NULL == (solver = strstr (test_filename, src_filename)))
1192   {
1193     GNUNET_free (src_filename);
1194     GNUNET_break (0);
1195     ret = 1;
1196     return ;
1197   }
1198   solver += strlen (src_filename) +1;
1199
1200   if (0 == strcmp(solver, "proportional"))
1201   {
1202     ph.ats_mode = MODE_PROPORTIONAL;
1203     ph.ats_string = "proportional";
1204   }
1205   else if (0 == strcmp(solver, "mlp"))
1206   {
1207     ph.ats_mode = MODE_MLP;
1208     ph.ats_string = "mlp";
1209   }
1210   else if ((0 == strcmp(solver, "ril")))
1211   {
1212     ph.ats_mode = MODE_RIL;
1213     ph.ats_string = "ril";
1214   }
1215   else
1216   {
1217     GNUNET_free (src_filename);
1218     GNUNET_break (0);
1219     ret = 1;
1220     return ;
1221   }
1222   GNUNET_free (src_filename);
1223
1224   /* Calculcate peers */
1225   if ((0 == ph.N_peers_start) && (0 == ph.N_peers_end))
1226   {
1227     ph.N_peers_start = DEFAULT_PEERS_START;
1228     ph.N_peers_end = DEFAULT_PEERS_END;
1229   }
1230   if (0 == ph.N_address)
1231     ph.N_address = DEFAULT_ADDRESSES;
1232
1233
1234   if (ph.N_peers_start != ph.N_peers_end)
1235     fprintf (stderr, "Benchmarking solver `%s' with %u to %u peers and %u addresses in %u iterations\n",
1236         ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address, ph.total_iterations);
1237   else
1238     fprintf (stderr, "Benchmarking solver `%s' with %u peers and %u addresses in %u iterations\n",
1239         ph.ats_string, ph.N_peers_end, ph.N_address, ph.total_iterations);
1240
1241   if (0 == ph.opt_update_percent)
1242     ph.opt_update_percent = DEFAULT_UPDATE_PERCENTAGE;
1243
1244   /* Load quotas */
1245   solver_cfg = GNUNET_CONFIGURATION_create();
1246   if ((NULL == solver_cfg) || (GNUNET_SYSERR == (GNUNET_CONFIGURATION_load ( solver_cfg, "perf_ats_solver.conf"))))
1247   {
1248     GNUNET_break(0);
1249     end_now (1);
1250     return;
1251   }
1252   if (GNUNET_ATS_NetworkTypeCount != load_quotas (solver_cfg,
1253       quotas_out, quotas_in, GNUNET_ATS_NetworkTypeCount))
1254   {
1255     GNUNET_break(0);
1256     end_now (1);
1257     return;
1258   }
1259
1260   /* Create array of DLL to store results for iterations */
1261   ph.iterations_results = GNUNET_malloc (sizeof (struct Iteration) * ph.total_iterations);
1262
1263   /* Load solver */
1264   ph.env.cfg = solver_cfg;
1265   ph.stat = GNUNET_STATISTICS_create ("ats", cfg);
1266   ph.env.stats = ph.stat;
1267   ph.addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
1268   ph.env.addresses = ph.addresses;
1269   ph.env.bandwidth_changed_cb = bandwidth_changed_cb;
1270   ph.env.get_preferences = &get_preferences_cb;
1271   ph.env.get_property = &get_property_cb;
1272   ph.env.network_count = GNUNET_ATS_NetworkTypeCount;
1273   ph.env.info_cb = &solver_info_cb;
1274   ph.env.info_cb_cls = NULL;
1275
1276   int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
1277   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
1278   {
1279     ph.env.networks[c] = networks[c];
1280     ph.env.out_quota[c] = quotas_out[c];
1281     ph.env.in_quota[c] = quotas_in[c];
1282     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loading network quotas: `%s' %llu %llu \n",
1283         GNUNET_ATS_print_network_type(ph.env.networks[c]),
1284         ph.env.out_quota[c],
1285         ph.env.in_quota[c]);
1286   }
1287   GAS_normalization_start (NULL, NULL, &normalized_property_changed_cb, NULL );
1288
1289   GNUNET_asprintf (&plugin, "libgnunet_plugin_ats_%s", ph.ats_string);
1290   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initializing solver `%s'\n"), ph.ats_string);
1291   if  (NULL == (ph.solver = GNUNET_PLUGIN_load (plugin, &ph.env)))
1292   {
1293     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver `%s'!\n"), plugin);
1294     ret = 1;
1295     return;
1296   }
1297
1298   /* Do the benchmark */
1299   for (ph.current_iteration = 1; ph.current_iteration <= ph.total_iterations; ph.current_iteration++)
1300   {
1301     fprintf (stderr, "Iteration %u of %u starting\n", ph.current_iteration, ph.total_iterations);
1302     perf_run_iteration ();
1303     evaluate (ph.current_iteration);
1304     fprintf (stderr, "Iteration %u of %u done\n", ph.current_iteration, ph.total_iterations);
1305   }
1306   if (ph.create_datafile)
1307     write_all_iterations ();
1308
1309   /* Unload solver*/
1310   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Unloading solver `%s'\n"), ph.ats_string);
1311   GNUNET_PLUGIN_unload (plugin, ph.solver);
1312   GNUNET_free (plugin);
1313   for (c = 0; c < ph.total_iterations; c++ )
1314   {
1315     for (c2 = ph.N_peers_start; c2 < ph.N_peers_end; c2++ )
1316     {
1317       if (0 == c2)
1318         continue;
1319       if (ph.measure_updates)
1320         GNUNET_free_non_null (ph.iterations_results[c].update_results_array[c2]);
1321       GNUNET_free (ph.iterations_results[c].results_array[c2]);
1322     }
1323     if (ph.measure_updates)
1324       GNUNET_free (ph.iterations_results[c].update_results_array);
1325     GNUNET_free(ph.iterations_results[c].results_array);
1326   }
1327   GNUNET_free (ph.iterations_results);
1328
1329   GNUNET_CONFIGURATION_destroy (solver_cfg);
1330   GNUNET_STATISTICS_destroy (ph.stat, GNUNET_NO);
1331   ph.solver = NULL;
1332 }
1333
1334 /**
1335  * Main function of the benchmark
1336  *
1337  * @param argc argument count
1338  * @param argv argument values
1339  */
1340 int
1341 main (int argc, char *argv[])
1342 {
1343   /* extract command line arguments */
1344   ph.opt_update_percent = 0;
1345   ph.N_peers_start = 0;
1346   ph.N_peers_end = 0;
1347   ph.N_address = 0;
1348   ph.ats_string = NULL;
1349   ph.create_datafile = GNUNET_NO;
1350   ph.measure_updates = GNUNET_NO;
1351   ph.total_iterations = 1;
1352
1353   static struct GNUNET_GETOPT_CommandLineOption options[] = {
1354       { 'a', "addresses", NULL,
1355           gettext_noop ("addresses to use"),
1356           1, &GNUNET_GETOPT_set_uint, &ph.N_address },
1357       { 's', "start", NULL,
1358           gettext_noop ("start with peer"),
1359           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_start },
1360       { 'e', "end", NULL,
1361           gettext_noop ("end with peer"),
1362           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_end },
1363       { 'i', "iterations", NULL,
1364           gettext_noop ("number of iterations used for averaging (default: 1)"),
1365           1, &GNUNET_GETOPT_set_uint, &ph.total_iterations },
1366       { 'p', "percentage", NULL,
1367           gettext_noop ("update a fix percentage of addresses"),
1368           1, &GNUNET_GETOPT_set_uint, &ph.opt_update_percent },
1369       { 'd', "data", NULL,
1370           gettext_noop ("create data file"),
1371           0, &GNUNET_GETOPT_set_one, &ph.create_datafile},
1372       { 'u', "update", NULL,
1373           gettext_noop ("measure updates"),
1374           0, &GNUNET_GETOPT_set_one, &ph.measure_updates},
1375       GNUNET_GETOPT_OPTION_END
1376   };
1377
1378   GNUNET_PROGRAM_run (argc, argv, argv[0], NULL, options, &run, argv[0]);
1379   return ret;
1380 }
1381
1382 /* end of file perf_ats_solver.c */