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