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