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