4ad93e0baa40b8d6a5939cc1e77ccbe0d86cf819
[oweals/gnunet.git] / src / ats / perf_ats_solver.c
1 /*
2  This file is part of GNUnet.
3  (C) 2010,2011 Christian Grothoff (and other contributing authors)
4
5  GNUnet is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published
7  by the Free Software Foundation; either version 3, or (at your
8  option) any later version.
9
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  General Public License for more details.
14
15  You should have received a copy of the GNU General Public License
16  along with GNUnet; see the file COPYING.  If not, write to the
17  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  Boston, MA 02111-1307, USA.
19  */
20 /**
21  * @file ats/perf_ats_solver.c
22  * @brief generic performance test for ATS solvers
23  * @author Christian Grothoff
24  * @author Matthias Wachs
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_statistics_service.h"
29 #include "gnunet-service-ats_addresses.h"
30 #include "gnunet-service-ats_normalization.h"
31 #include "gnunet_ats_service.h"
32 #include "gnunet_ats_plugin.h"
33 #include "test_ats_api_common.h"
34
35 #define DEFAULT_UPDATE_PERCENTAGE       20
36 #define DEFAULT_PEERS_START     10
37 #define DEFAULT_PEERS_END       10
38 #define DEFAULT_ADDRESSES       10
39 #define DEFAULT_ATS_COUNT       2
40
41 #define GNUPLOT_PROP_TEMPLATE "#!/usr/bin/gnuplot \n" \
42 "set datafile separator ';' \n" \
43 "set title \"Execution time Proportional solver  \" \n" \
44 "set xlabel \"Number of peers\" \n" \
45 "set ylabel \"Execution time in us\" \n" \
46 "set grid \n"
47
48 #define GNUPLOT_PROP_UPDATE_TEMPLATE "#!/usr/bin/gnuplot \n" \
49 "set datafile separator ';' \n" \
50 "set title \"Execution time Proportional solver with updated problem\" \n" \
51 "set xlabel \"Number of peers\" \n" \
52 "set ylabel \"Execution time in us\" \n" \
53 "set grid \n"
54
55 #define GNUPLOT_MLP_TEMPLATE "#!/usr/bin/gnuplot \n" \
56 "set datafile separator ';' \n" \
57 "set title \"Execution time MLP solver \" \n" \
58 "set xlabel \"Number of peers\" \n" \
59 "set ylabel \"Execution time in us\" \n" \
60 "set grid \n"
61
62 #define GNUPLOT_MLP_UPDATE_TEMPLATE "#!/usr/bin/gnuplot \n" \
63 "set datafile separator ';' \n" \
64 "set title \"Execution time MLP solver with updated problem\" \n" \
65 "set xlabel \"Number of peers\" \n" \
66 "set ylabel \"Execution time in us\" \n" \
67 "set grid \n"
68
69 #define GNUPLOT_RIL_TEMPLATE "#!/usr/bin/gnuplot \n" \
70 "set datafile separator ';' \n" \
71 "set title \"Execution time RIL solver \" \n" \
72 "set xlabel \"Number of peers\" \n" \
73 "set ylabel \"Execution time in us\" \n" \
74 "set grid \n"
75
76 #define GNUPLOT_RIL_UPDATE_TEMPLATE "#!/usr/bin/gnuplot \n" \
77 "set datafile separator ';' \n" \
78 "set title \"Execution time RIL solver with updated problem\" \n" \
79 "set xlabel \"Number of peers\" \n" \
80 "set ylabel \"Execution time in us\" \n" \
81 "set grid \n"
82
83 /**
84  * Handle for ATS address component
85  */
86 struct PerfHandle
87 {
88   /**
89    * Performance peers
90    */
91   struct PerfPeer *peers;
92
93   /**
94    *  Solver handle
95    */
96   void *solver;
97
98   /**
99    * Statistics stat;
100    */
101   struct GNUNET_STATISTICS_Handle *stat;
102
103   /**
104    * A multihashmap to store all addresses
105    */
106   struct GNUNET_CONTAINER_MultiPeerMap *addresses;
107
108   /**
109    * Solver functions
110    * */
111   struct GNUNET_ATS_PluginEnvironment env;
112
113   /**
114    * Array for results for each iteration with length iterations
115    */
116   struct Iteration *iterations_results;
117
118   /**
119    * Array to store averaged result with length #peers
120    */
121   struct Result *averaged_full_result;
122
123   struct Result *averaged_update_result;
124
125   /**
126    * The current result
127    */
128   struct Result *current_result;
129
130   int current_p;
131   int current_a;
132
133   /**
134    * Solver description as string
135    */
136   char *ats_string;
137
138   /**
139    * Configured ATS solver
140    */
141   int ats_mode;
142
143   /**
144    * #peers to start benchmarking with
145    */
146   int N_peers_start;
147
148   /**
149    * #peers to end benchmarking with
150    */
151   int N_peers_end;
152
153   /**
154    * #addresses to benchmarking with
155    */
156   int N_address;
157
158   /**
159    * Percentage of peers to update
160    */
161   int opt_update_percent;
162
163   /**
164    * Create gnuplot file
165    */
166   int create_plot;
167
168   /**
169    * Measure updates
170    */
171   int measure_updates;
172
173   /**
174    * Number of iterations
175    */
176   int iterations;
177
178   /**
179    * Current iteration
180    */
181   int current_iteration;
182
183   /**
184    * Is a bulk operation running?
185    */
186   int bulk_running;
187
188   /**
189    * Is a bulk operation running?
190    */
191   int expecting_solution;
192 };
193
194 /**
195  * Data structure to store results for a single iteration
196  */
197 struct Iteration
198 {
199   /**
200    * Head of the linked list
201    */
202   struct Result *result_head;
203
204   /**
205    * Tail of the linked list
206    */
207   struct Result *result_tail;
208 };
209
210
211 /**
212  * Result for a solver calculcation
213  */
214 struct Result
215 {
216   /**
217    * Previous element in the linked list
218    */
219   struct Result *prev;
220
221   /**
222    * Next element in the linked list
223    */
224   struct Result *next;
225
226   /**
227    * Number of peers this solution included
228    */
229   int peers;
230
231   /**
232    * Number of addresses per peer this solution included
233    */
234   int addresses;
235
236   /**
237    * Is this an update or a full solution
238    */
239   int update;
240
241   /**
242    * Was the solution valid or did the solver fail
243    */
244   int valid;
245
246   /**
247    * Result of the solver
248    */
249   enum GAS_Solver_Additional_Information info;
250
251   /**
252    * Duration of setting up the problem in the solver
253    */
254   struct GNUNET_TIME_Relative d_setup;
255
256   /**
257    * Duration of solving the LP problem in the solver
258    * MLP solver only
259    */
260   struct GNUNET_TIME_Relative d_lp;
261
262   /**
263    * Duration of solving the MLP problem in the solver
264    * MLP solver only
265    */
266   struct GNUNET_TIME_Relative d_mlp;
267
268   /**
269    * Duration of solving whole problem in the solver
270    */
271   struct GNUNET_TIME_Relative d_total;
272
273   /**
274    * Start time of setting up the problem in the solver
275    */
276   struct GNUNET_TIME_Absolute s_setup;
277
278   /**
279    * Start time of solving the LP problem in the solver
280    * MLP solver only
281    */
282   struct GNUNET_TIME_Absolute s_lp;
283
284   /**
285    * Start time of solving the MLP problem in the solver
286    * MLP solver only
287    */
288   struct GNUNET_TIME_Absolute s_mlp;
289
290   /**
291    * Start time of solving whole problem in the solver
292    */
293   struct GNUNET_TIME_Absolute s_total;
294
295   /**
296    * End time of setting up the problem in the solver
297    */
298   struct GNUNET_TIME_Absolute e_setup;
299
300   /**
301    * End time of solving the LP problem in the solver
302    * MLP solver only
303    */
304   struct GNUNET_TIME_Absolute e_lp;
305
306   /**
307    * End time of solving the MLP problem in the solver
308    * MLP solver only
309    */
310   struct GNUNET_TIME_Absolute e_mlp;
311
312   /**
313    * End time of solving whole problem in the solver
314    */
315   struct GNUNET_TIME_Absolute e_total;
316 };
317
318 /**
319  * Peer used for the benchmarking
320  */
321 struct PerfPeer
322 {
323   /**
324    * Peer identitity
325    */
326   struct GNUNET_PeerIdentity id;
327
328   /**
329    * Head of linked list of addresses used with this peer
330    */
331   struct ATS_Address *head;
332
333   /**
334    * Head of linked list of addresses used with this peer
335    */
336   struct ATS_Address *tail;
337 };
338
339
340 /**
341  * ATS performance handle
342  */
343 static struct PerfHandle ph;
344
345 /**
346  * Return value
347  */
348 static int ret;
349
350 static void
351 end_now (int res)
352 {
353   if (NULL != ph.stat)
354   {
355     GNUNET_STATISTICS_destroy (ph.stat, GNUNET_NO);
356     ph.stat = NULL;
357   }
358   /*
359    if (NULL != addresses)
360    {
361    GNUNET_CONTAINER_multihashmap_iterate (addresses, &addr_it, NULL);
362    GNUNET_CONTAINER_multihashmap_destroy (addresses);
363    addresses = NULL ;
364    }*/
365   if (NULL != ph.peers)
366   {
367     GNUNET_free(ph.peers);
368   }
369
370   GAS_normalization_stop ();
371   ret = res;
372 }
373
374
375 static void
376 perf_create_peer (int cp)
377 {
378
379   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
380       &ph.peers[cp].id, sizeof (struct GNUNET_PeerIdentity));
381   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Creating peer #%u: %s \n", cp,
382       GNUNET_i2s (&ph.peers[cp].id));
383 }
384
385
386
387 static void
388 perf_update_address (struct ATS_Address *cur)
389 {
390   int r_type;
391   int r_val;
392
393   r_type = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2);
394   switch (r_type)
395   {
396   case 0:
397     r_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
398     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
399         "Updating peer `%s' address %p type %s val %u\n",
400         GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DELAY", r_val);
401     ph.env.sf.s_address_update_property (ph.solver, cur,
402         GNUNET_ATS_QUALITY_NET_DELAY,
403         r_val, (double) (100 + r_val / 100));
404     break;
405   case 1:
406     r_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 10);
407
408     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
409         "Updating peer `%s' address %p type %s val %u\n",
410         GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DISTANCE", r_val);
411     ph.env.sf.s_address_update_property (ph.solver, cur,
412         GNUNET_ATS_QUALITY_NET_DISTANCE,
413         r_val, (double) (100 + r_val) / 100);
414     break;
415   default:
416     break;
417   }
418   ph.env.sf.s_address_update_inuse (ph.solver, cur, GNUNET_YES);
419 }
420
421
422 static void
423 bandwidth_changed_cb (void *cls,
424                       struct ATS_Address *address)
425 {
426   if ( (0 == ntohl (address->assigned_bw_out.value__)) &&
427        (0 == ntohl (address->assigned_bw_in.value__)) )
428     return;
429
430   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
431               "Bandwidth changed addresses %s %p to %u Bps out / %u Bps in\n",
432               GNUNET_i2s (&address->peer),
433               address,
434               (unsigned int) ntohl (address->assigned_bw_out.value__),
435               (unsigned int) ntohl (address->assigned_bw_in.value__));
436   if (GNUNET_YES == ph.bulk_running)
437     GNUNET_break (0);
438   return;
439 }
440
441
442 const double *
443 get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
444 {
445   return GAS_normalization_get_preferences_by_peer (id);
446 }
447
448
449 const double *
450 get_property_cb (void *cls, const struct ATS_Address *address)
451 {
452   return GAS_normalization_get_properties ((struct ATS_Address *) address);
453 }
454
455 static void
456 normalized_property_changed_cb (void *cls, struct ATS_Address *peer,
457     uint32_t type, double prop_rel)
458 {
459   /* TODO */
460 }
461
462 static void
463 perf_address_initial_update (void *solver,
464     struct GNUNET_CONTAINER_MultiPeerMap * addresses,
465     struct ATS_Address *address)
466 {
467   ph.env.sf.s_address_update_property (solver, address, GNUNET_ATS_QUALITY_NET_DELAY,
468       100,
469       (double) (100 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100))
470           / 100);
471
472   ph.env.sf.s_address_update_property (solver, address,
473       GNUNET_ATS_QUALITY_NET_DISTANCE, 10,
474       (double) (100 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100))
475           / 100);
476 }
477
478 static void
479 perf_update_all_addresses (unsigned int cp, unsigned int ca, unsigned int percentage_peers)
480 {
481   struct ATS_Address *cur_address;
482   int c_peer;
483   int c_select;
484   int c_cur_p;
485   int c_cur_a;
486   int r;
487   int count;
488   unsigned int m[cp];
489
490   count = cp * ((double) percentage_peers / 100);
491   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
492       "Updating %u of %u peers \n", count, cp);
493
494   for (c_peer = 0; c_peer < cp; c_peer++)
495     m[c_peer] = 0;
496
497   c_select = 0;
498
499   while (c_select < count)
500   {
501     r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, cp);
502     if (0 == m[r])
503     {
504       m[r] = 1;
505       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
506           "Updating peer [%u] \n", r);
507       c_select++;
508     }
509   }
510   for (c_cur_p = 0; c_cur_p < cp; c_cur_p++)
511   {
512     if (1 == m[c_cur_p])
513     {
514       r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, ca);
515       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
516           "Updating peer [%u] address [%u]\n", c_cur_p, r);
517
518       c_cur_a = 0;
519       for (cur_address = ph.peers[c_cur_p].head; NULL != cur_address; cur_address = cur_address->next)
520       {
521         if (c_cur_a == r)
522           perf_update_address (cur_address);
523
524         c_cur_a ++;
525       }
526     }
527   }
528 }
529
530
531 static struct ATS_Address *
532 perf_create_address (int cp, int ca)
533 {
534   struct ATS_Address *a;
535   a = create_address (&ph.peers[cp].id,
536       "Test 1", "test 1", strlen ("test 1") + 1, 0);
537   GNUNET_CONTAINER_DLL_insert (ph.peers[cp].head, ph.peers[cp].tail, a);
538   GNUNET_CONTAINER_multipeermap_put (ph.addresses, &ph.peers[cp].id, a,
539       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
540   return a;
541 }
542
543 static void
544 solver_info_cb (void *cls,
545     enum GAS_Solver_Operation op,
546     enum GAS_Solver_Status stat,
547     enum GAS_Solver_Additional_Information add)
548 {
549   char *add_info;
550   switch (add) {
551     case GAS_INFO_NONE:
552       add_info = "GAS_INFO_NONE";
553       break;
554     case GAS_INFO_FULL:
555       add_info = "GAS_INFO_MLP_FULL";
556       break;
557     case GAS_INFO_UPDATED:
558       add_info = "GAS_INFO_MLP_UPDATED";
559       break;
560     case GAS_INFO_PROP_ALL:
561       add_info = "GAS_INFO_PROP_ALL";
562       break;
563     case GAS_INFO_PROP_SINGLE:
564       add_info = "GAS_INFO_PROP_SINGLE";
565       break;
566     default:
567       add_info = "INVALID";
568       break;
569   }
570
571   struct Result *tmp;
572   switch (op)
573   {
574     case GAS_OP_SOLVE_START:
575       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
576           "Solver notifies `%s' with result `%s' `%s'\n", "GAS_OP_SOLVE_START",
577           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
578       if (GNUNET_NO == ph.expecting_solution)
579       {
580         /* We do not expect a solution at the moment */
581         GNUNET_break (0);
582         return;
583       }
584
585       if ((GAS_STAT_SUCCESS == stat) && (NULL == ph.current_result))
586       {
587         /* Create new result */
588         tmp = GNUNET_new (struct Result);
589         ph.current_result = tmp;
590         GNUNET_CONTAINER_DLL_insert_tail(ph.iterations_results[ph.current_iteration-1].result_head,
591             ph.iterations_results[ph.current_iteration-1].result_tail, tmp);
592         ph.current_result->addresses = ph.current_a;
593         ph.current_result->peers = ph.current_p;
594         ph.current_result->s_total = GNUNET_TIME_absolute_get();
595         ph.current_result->d_total = GNUNET_TIME_UNIT_FOREVER_REL;
596         ph.current_result->d_setup = GNUNET_TIME_UNIT_FOREVER_REL;
597         ph.current_result->d_lp = GNUNET_TIME_UNIT_FOREVER_REL;
598         ph.current_result->d_mlp = GNUNET_TIME_UNIT_FOREVER_REL;
599         ph.current_result->info = add;
600         if (add == GAS_INFO_UPDATED)
601           ph.current_result->update = GNUNET_YES;
602         else
603           ph.current_result->update = GNUNET_NO;
604       }
605       return;
606     case GAS_OP_SOLVE_STOP:
607       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
608           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_STOP",
609           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
610       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
611       {
612         /* We do not expect a solution at the moment */
613         GNUNET_break (0);
614         return;
615       }
616
617       if (GAS_STAT_SUCCESS == stat)
618         ph.current_result->valid = GNUNET_YES;
619       else
620         ph.current_result->valid = GNUNET_NO;
621
622       if (NULL != ph.current_result)
623       {
624         /* Finalize result */
625         ph.current_result->e_total = GNUNET_TIME_absolute_get ();
626         ph.current_result->d_total = GNUNET_TIME_absolute_get_difference (
627             ph.current_result->s_total, ph.current_result->e_total);
628       }
629       ph.current_result = NULL;
630       return;
631
632     case GAS_OP_SOLVE_SETUP_START:
633       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
634           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_START",
635           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
636       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
637       {
638         GNUNET_break(0);
639         return;
640       }
641
642       if (GAS_STAT_SUCCESS == stat)
643         ph.current_result->valid = GNUNET_YES;
644       else
645         ph.current_result->valid = GNUNET_NO;
646
647       ph.current_result->s_setup = GNUNET_TIME_absolute_get ();
648       return;
649
650     case GAS_OP_SOLVE_SETUP_STOP:
651       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
652           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_STOP",
653           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
654       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
655       {
656         GNUNET_break(0);
657         return;
658       }
659
660       if (GAS_STAT_SUCCESS == stat)
661         ph.current_result->valid = GNUNET_YES;
662       else
663         ph.current_result->valid = GNUNET_NO;
664
665       ph.current_result->e_setup = GNUNET_TIME_absolute_get ();
666       ph.current_result->d_setup = GNUNET_TIME_absolute_get_difference (
667           ph.current_result->s_setup, ph.current_result->e_setup);
668       return;
669
670     case GAS_OP_SOLVE_MLP_LP_START:
671       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
672           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_START",
673           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
674       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
675       {
676         GNUNET_break(0);
677         return;
678       }
679
680       if (GAS_STAT_SUCCESS == stat)
681         ph.current_result->valid = GNUNET_YES;
682       else
683         ph.current_result->valid = GNUNET_NO;
684
685       ph.current_result->s_lp = GNUNET_TIME_absolute_get ();
686       return;
687     case GAS_OP_SOLVE_MLP_LP_STOP:
688       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
689           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_STOP",
690           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
691       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
692       {
693         GNUNET_break(0);
694         return;
695       }
696
697       if (GAS_STAT_SUCCESS == stat)
698         ph.current_result->valid = GNUNET_YES;
699       else
700         ph.current_result->valid = GNUNET_NO;
701
702       ph.current_result->e_lp = GNUNET_TIME_absolute_get ();
703       ph.current_result->d_lp = GNUNET_TIME_absolute_get_difference (
704           ph.current_result->s_lp, ph.current_result->e_lp);
705       return;
706
707     case GAS_OP_SOLVE_MLP_MLP_START:
708       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
709           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_START",
710           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
711       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
712       {
713         GNUNET_break(0);
714         return;
715       }
716
717       if (GAS_STAT_SUCCESS == stat)
718         ph.current_result->valid = GNUNET_YES;
719       else
720         ph.current_result->valid = GNUNET_NO;
721
722       ph.current_result->s_mlp = GNUNET_TIME_absolute_get ();
723       return;
724     case GAS_OP_SOLVE_MLP_MLP_STOP:
725       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
726           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_STOP",
727           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
728       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
729       {
730         GNUNET_break(0);
731         return;
732       }
733
734       if (GAS_STAT_SUCCESS == stat)
735         ph.current_result->valid = GNUNET_YES;
736       else
737         ph.current_result->valid = GNUNET_NO;
738
739       ph.current_result->e_mlp = GNUNET_TIME_absolute_get ();
740       ph.current_result->d_mlp = GNUNET_TIME_absolute_get_difference (
741       ph.current_result->s_mlp, ph.current_result->e_mlp);
742       return;
743     case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
744       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
745           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
746           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
747       return;
748     case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
749       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
750           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
751           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
752       if (GAS_STAT_SUCCESS != stat)
753       {
754         GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
755             "Solver `%s' failed to update problem with %u peers and %u address!\n",
756             ph.ats_string, ph.current_p, ph.current_a);
757       }
758
759       return;
760     default:
761       break;
762     }
763 }
764
765 static void
766 write_gnuplot_script (char * data_fn, int iteration, int full)
767 {
768   struct GNUNET_DISK_FileHandle *f;
769   char * gfn;
770   char *data;
771   char *iter_text;
772   char *template;
773
774   /* Write header */
775   switch (ph.ats_mode) {
776     case MODE_PROPORTIONAL:
777       if (GNUNET_YES == full)
778         template = GNUPLOT_PROP_TEMPLATE;
779       else
780         template = GNUPLOT_PROP_UPDATE_TEMPLATE;
781       break;
782     case MODE_MLP:
783       if (GNUNET_YES == full)
784         template = GNUPLOT_MLP_TEMPLATE;
785       else
786         template = GNUPLOT_MLP_UPDATE_TEMPLATE;
787       break;
788     case MODE_RIL:
789       if (GNUNET_YES == full)
790         template = GNUPLOT_RIL_TEMPLATE;
791       else
792         template = GNUPLOT_RIL_UPDATE_TEMPLATE;
793       break;
794     default:
795       GNUNET_break (0);
796       return;
797   }
798   if (-1 == iteration)
799     GNUNET_asprintf (&iter_text, "%s_%u", "avg",ph.iterations);
800   else
801     GNUNET_asprintf (&iter_text, "%u", iteration);
802   if (GNUNET_YES == full)
803   {
804     GNUNET_asprintf (&gfn, "perf_%s_full_%s-%u_%u_%u.gnuplot",
805         ph.ats_string,
806         iter_text,
807         ph.N_peers_start,
808         ph.N_peers_end,
809         ph.N_address);
810   }
811   else
812   {
813     GNUNET_asprintf (&gfn, "perf_%s_updat_%s-%u_%u_%u.gnuplot",
814         ph.ats_string,
815         iter_text,
816         ph.N_peers_start,
817         ph.N_peers_end,
818         ph.N_address);
819   }
820   GNUNET_free (iter_text);
821
822   f = GNUNET_DISK_file_open (gfn,
823       GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
824       GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
825   if (NULL == f)
826   {
827     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot open gnuplot file `%s'\n", gfn);
828     GNUNET_free (gfn);
829     return;
830   }
831
832   if (GNUNET_SYSERR == GNUNET_DISK_file_write(f, template, strlen(template)))
833     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot write data to plot file `%s'\n", gfn);
834
835   data = NULL;
836   if (MODE_PROPORTIONAL == ph.ats_mode)
837   {
838     GNUNET_asprintf (&data, "plot '%s' using 1:%u with lines title 'Total time to solve'\n" \
839                            "pause -1",
840                            data_fn, 3);
841   }
842   else if (MODE_MLP == ph.ats_mode)
843   {
844     GNUNET_asprintf (&data, "plot '%s' using 1:%u with lines title 'Total time to solve',\\\n" \
845                             "'%s' using 1:%u with lines title 'Time to setup',\\\n"
846                             "'%s' using 1:%u with lines title 'Time to solve LP',\\\n"
847                             "'%s' using 1:%u with lines title 'Total time to solve MLP'\n" \
848                             "pause -1",
849                            data_fn, 3,
850                            data_fn, 4,
851                            data_fn, 5,
852                            data_fn, 6);
853   }
854   else if (MODE_RIL == ph.ats_mode)
855   {
856     GNUNET_asprintf (&data,
857                      "plot '%s' using 1:%u with lines title 'Total time to solve'\n" \
858                      "pause -1",
859                      data_fn, 3);
860   }
861
862   if ((NULL != data) &&
863       (GNUNET_SYSERR == GNUNET_DISK_file_write (f, data, strlen(data))))
864     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
865                 "Cannot write data to plot file `%s'\n",
866                 gfn);
867   GNUNET_free_non_null (data);
868
869   if (GNUNET_SYSERR == GNUNET_DISK_file_close(f))
870     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
871                 "Cannot close gnuplot file `%s'\n",
872                 gfn);
873   else
874     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
875                 "Data successfully written to plot file `%s'\n",
876                 gfn);
877   GNUNET_free (gfn);
878
879 }
880
881 /**
882  * Evaluate results for a specific iteration
883  *
884  * @param iteration the iteration to evaluate
885  */
886
887 static void
888 evaluate (int iteration)
889 {
890   struct GNUNET_DISK_FileHandle *f_full;
891   struct GNUNET_DISK_FileHandle *f_update;
892   char * data_fn_full;
893   char * data_fn_update;
894   char * data;
895   struct Result *cur;
896   struct Result *next;
897   struct Result *cur_res;
898   char * str_d_total;
899   char * str_d_setup;
900   char * str_d_lp;
901   char * str_d_mlp;
902   char * iter_text;
903
904   f_full = NULL;
905   f_update = NULL;
906
907   data_fn_full = NULL;
908
909   if (ph.create_plot)
910   {
911     if (-1 == iteration)
912       GNUNET_asprintf (&iter_text, "%s", "avg");
913     else
914       GNUNET_asprintf (&iter_text, "%u", iteration);
915     GNUNET_asprintf (&data_fn_full,
916                      "perf_%s_full_%s_%u_%u_%u.data",
917                      ph.ats_string,
918                      iter_text,
919                      ph.N_peers_start,
920                      ph.N_peers_end,
921                      ph.N_address);
922     GNUNET_free (iter_text);
923     f_full = GNUNET_DISK_file_open (data_fn_full,
924         GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
925         GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
926     if (NULL == f_full)
927     {
928       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
929                   "Cannot open gnuplot file `%s'\n",
930                   data_fn_full);
931       GNUNET_free (data_fn_full);
932       return;
933     }
934     data = "#peers;addresses;time total in us;#time setup in us;#time lp in us;#time mlp in us;\n";
935     if (GNUNET_SYSERR == GNUNET_DISK_file_write(f_full, data, strlen(data)))
936       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
937                   "Cannot write data to log file `%s'\n",
938                   data_fn_full);
939     write_gnuplot_script (data_fn_full, iteration, GNUNET_YES);
940   }
941
942   data_fn_update = NULL;
943   if ((ph.create_plot) && (GNUNET_YES == ph.measure_updates))
944   {
945     if (-1 == iteration)
946       GNUNET_asprintf (&iter_text, "%s", "avg");
947     else
948       GNUNET_asprintf (&iter_text, "%u", iteration);
949     GNUNET_asprintf (&data_fn_update, "perf_%s_update_i%u_%u_%u_%u.data",
950         ph.ats_string,
951         iter_text,
952         ph.N_peers_start,
953         ph.N_peers_end,
954         ph.N_address);
955     GNUNET_free (iter_text);
956     f_update = GNUNET_DISK_file_open (data_fn_update,
957         GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
958         GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
959     if (NULL == f_update)
960     {
961       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
962                   "Cannot open gnuplot file `%s'\n", data_fn_update);
963       GNUNET_free (data_fn_update);
964       if (NULL != f_full)
965         GNUNET_DISK_file_close (f_full);
966       GNUNET_free (data_fn_full);
967       return;
968     }
969     data = "#peers;addresses;time total in us;#time setup in us;#time lp in us;#time mlp in us;\n";
970     if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_update, data, strlen(data)))
971       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
972                   "Cannot write data to log file `%s'\n",
973                   data_fn_update);
974     write_gnuplot_script (data_fn_update, iteration, GNUNET_NO);
975   }
976
977   next = ph.iterations_results[ph.current_iteration -1].result_head;
978   while (NULL != (cur = next))
979   {
980     next = cur->next;
981     str_d_total = NULL;
982     str_d_setup = NULL;
983     str_d_lp = NULL;
984     str_d_mlp = NULL;
985
986     /* Print log */
987     if (GNUNET_NO == cur->update)
988       cur_res = &ph.averaged_full_result[cur->peers - ph.N_peers_start];
989     else
990       cur_res = &ph.averaged_update_result[cur->peers - ph.N_peers_start];
991
992     cur_res->peers = cur->peers;
993     cur_res->addresses = cur->addresses;
994     cur_res->update = cur->update;
995
996     if (GNUNET_NO == cur->valid)
997     {
998       fprintf (stderr,
999                "Total time to solve %s for %u peers %u addresses: %s\n",
1000                (GNUNET_YES == cur->update) ? "updated" : "full",
1001                cur->peers, cur->addresses, "Failed to solve!");
1002       continue;
1003     }
1004     else
1005       cur_res->valid ++;
1006
1007     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_total.rel_value_us)
1008     {
1009       if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == cur_res->d_total.rel_value_us)
1010         cur_res->d_total.rel_value_us = 0;
1011       if (GNUNET_YES == cur->valid)
1012         cur_res->d_total.rel_value_us += cur->d_total.rel_value_us;
1013       fprintf (stderr,
1014                "Total time to solve %s for %u peers %u addresses: %llu us\n",
1015                (GNUNET_YES == cur->update) ? "updated" : "full",
1016                cur->peers, cur->addresses, (unsigned long long) cur->d_total.rel_value_us);
1017       GNUNET_asprintf(&str_d_total,
1018                       "%llu",
1019                       (unsigned long long) cur->d_total.rel_value_us);
1020     }
1021     else
1022       GNUNET_asprintf(&str_d_total, "-1");
1023     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_setup.rel_value_us)
1024     {
1025       if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == cur_res->d_setup.rel_value_us)
1026         cur_res->d_setup.rel_value_us = 0;
1027       if (GNUNET_YES == cur->valid)
1028         cur_res->d_setup.rel_value_us += cur->d_setup.rel_value_us;
1029       fprintf (stderr, "Total time to setup %s %u peers %u addresses: %llu us\n",
1030           (GNUNET_YES == cur->update) ? "updated" : "full",
1031           cur->peers, cur->addresses, (unsigned long long )cur->d_setup.rel_value_us);
1032       GNUNET_asprintf(&str_d_setup, "%llu", (unsigned long long )cur->d_setup.rel_value_us);
1033     }
1034     else
1035       GNUNET_asprintf(&str_d_setup, "-1");
1036     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_lp.rel_value_us)
1037     {
1038       if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == cur_res->d_lp.rel_value_us)
1039         cur_res->d_lp.rel_value_us = 0;
1040       if (GNUNET_YES == cur->valid)
1041         cur_res->d_lp.rel_value_us += cur->d_lp.rel_value_us;
1042       fprintf (stderr,
1043                "Total time to solve %s LP for %u peers %u addresses: %llu us\n",
1044                (GNUNET_YES == cur->update) ? "updated" : "full",
1045                cur->peers,
1046                cur->addresses,
1047                (unsigned long long )cur->d_lp.rel_value_us);
1048       GNUNET_asprintf (&str_d_lp,
1049                        "%llu",
1050                        (unsigned long long )cur->d_lp.rel_value_us);
1051     }
1052     else
1053       GNUNET_asprintf (&str_d_lp, "-1");
1054     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_mlp.rel_value_us)
1055     {
1056       if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == cur_res->d_mlp.rel_value_us)
1057         cur_res->d_mlp.rel_value_us = 0;
1058       if (GNUNET_YES == cur->valid)
1059         cur_res->d_mlp.rel_value_us += cur->d_mlp.rel_value_us;
1060
1061       fprintf (stderr, "Total time to solve %s MLP for %u peers %u addresses: %llu us\n",
1062           (GNUNET_YES == cur->update) ? "updated" : "full",
1063           cur->peers, cur->addresses, (unsigned long long )cur->d_mlp.rel_value_us);
1064       GNUNET_asprintf (&str_d_mlp,
1065                        "%llu",
1066                        (unsigned long long )cur->d_mlp.rel_value_us);
1067     }
1068     else
1069       GNUNET_asprintf (&str_d_mlp, "-1");
1070
1071     data = NULL;
1072     if (GNUNET_YES == ph.create_plot)
1073     {
1074
1075       GNUNET_asprintf (&data,
1076                        "%u;%u;%s;%s;%s;%s\n",
1077                        cur->peers, cur->addresses,
1078                        str_d_total,
1079                        str_d_setup,
1080                        str_d_lp,
1081                        str_d_mlp);
1082       if (cur->update == GNUNET_NO)
1083       {
1084         if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_full, data, strlen(data)))
1085           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1086                       "Cannot write data to log file `%s'\n",
1087                       data_fn_full);
1088       }
1089       if ((cur->update == GNUNET_YES) && (NULL != f_update))
1090       {
1091         if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_update, data, strlen(data)))
1092           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1093                       "Cannot write data to log file `%s'\n",
1094                       data_fn_update);
1095       }
1096       GNUNET_free (data);
1097     }
1098     GNUNET_free_non_null (str_d_total);
1099     GNUNET_free_non_null (str_d_setup);
1100     GNUNET_free_non_null (str_d_lp);
1101     GNUNET_free_non_null (str_d_mlp);
1102
1103     GNUNET_CONTAINER_DLL_remove (ph.iterations_results[ph.current_iteration-1].result_head,
1104         ph.iterations_results[ph.current_iteration-1].result_tail, cur);
1105     GNUNET_free (cur);
1106   }
1107
1108   if ((NULL != f_full) && (GNUNET_SYSERR == GNUNET_DISK_file_close (f_full)))
1109     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n",
1110         data_fn_full);
1111   GNUNET_free_non_null (data_fn_full);
1112
1113   if ((NULL != f_update) && (GNUNET_SYSERR == GNUNET_DISK_file_close (f_update)))
1114     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n",
1115         data_fn_update);
1116   GNUNET_free_non_null (data_fn_update);
1117 }
1118
1119
1120 static void
1121 evaluate_average (void)
1122 {
1123   int c;
1124
1125   struct GNUNET_DISK_FileHandle *f_full;
1126   struct GNUNET_DISK_FileHandle *f_update;
1127   char * data_fn_full;
1128   char * data_fn_update;
1129   char * data;
1130   char * str_d_total;
1131   char * str_d_setup;
1132   char * str_d_lp;
1133   char * str_d_mlp;
1134
1135   f_full = NULL;
1136   f_update = NULL;
1137
1138   data_fn_full = NULL;
1139
1140   if (ph.create_plot)
1141   {
1142     GNUNET_asprintf (&data_fn_full,
1143                      "perf_%s_full_avg_%u-%u_%u_%u.data",
1144                      ph.ats_string,
1145                      ph.iterations,
1146                      ph.N_peers_start,
1147                      ph.N_peers_end,
1148                      ph.N_address);
1149     f_full = GNUNET_DISK_file_open (data_fn_full,
1150         GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
1151         GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
1152     if (NULL == f_full)
1153     {
1154       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1155                   "Cannot open gnuplot file `%s'\n",
1156                   data_fn_full);
1157       GNUNET_free (data_fn_full);
1158       return;
1159     }
1160     data = "#peers;addresses;time total in us;#time setup in us;#time lp in us;#time mlp in us;\n";
1161     if (GNUNET_SYSERR == GNUNET_DISK_file_write(f_full, data, strlen(data)))
1162       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1163                   "Cannot write data to log file `%s'\n",
1164                   data_fn_full);
1165     write_gnuplot_script (data_fn_full, -1, GNUNET_YES);
1166   }
1167
1168   data_fn_update = NULL;
1169   if ((ph.create_plot) && (GNUNET_YES == ph.measure_updates))
1170   {
1171     GNUNET_asprintf (&data_fn_update, "perf_%s_update_avg_%u-%u_%u_%u.data",
1172         ph.ats_string,
1173         ph.iterations,
1174         ph.N_peers_start,
1175         ph.N_peers_end,
1176         ph.N_address);
1177     f_update = GNUNET_DISK_file_open (data_fn_update,
1178         GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
1179         GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
1180     if (NULL == f_update)
1181     {
1182       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1183                   "Cannot open gnuplot file `%s'\n", data_fn_update);
1184       GNUNET_free (data_fn_update);
1185       if (NULL != f_full)
1186         GNUNET_DISK_file_close (f_full);
1187       GNUNET_free (data_fn_full);
1188       return;
1189     }
1190     data = "#peers;addresses;time total in us;#time setup in us;#time lp in us;#time mlp in us;\n";
1191     if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_update, data, strlen(data)))
1192       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1193                   "Cannot write data to log file `%s'\n",
1194                   data_fn_update);
1195     write_gnuplot_script (data_fn_update, -1, GNUNET_NO);
1196   }
1197
1198   for (c = 0; c <= ph.N_peers_end - ph.N_peers_start; c++)
1199   {
1200     struct Result *cur = &ph.averaged_full_result[c];
1201
1202     str_d_total = NULL;
1203     str_d_setup = NULL;
1204     str_d_lp = NULL;
1205     str_d_mlp = NULL;
1206
1207     if (0 >= cur->valid)
1208     {
1209       fprintf (stderr,
1210          "No valid results for %s for %u peers %u addresses!\n",
1211          (GNUNET_YES == cur->update) ? "updated" : "full",
1212              cur->peers, cur->addresses);
1213
1214       continue;
1215     }
1216
1217
1218     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_total.rel_value_us)
1219     {
1220       fprintf (stderr,
1221          "Average total time from %u iterations to solve %s for %u peers %u addresses: %llu us\n",
1222          cur->valid,
1223          (GNUNET_YES == cur->update) ? "updated" : "full",
1224              cur->peers, cur->addresses,
1225          (unsigned long long) cur->d_total.rel_value_us / cur->valid);
1226       GNUNET_asprintf(&str_d_total, "%llu",
1227          (unsigned long long) cur->d_total.rel_value_us / cur->valid);
1228     }
1229     else
1230       GNUNET_asprintf (&str_d_total, "-1");
1231
1232     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_setup.rel_value_us)
1233     {
1234       fprintf (stderr,
1235          "Average total time from %u iterations to setup for %u peers %u addresses: %llu us\n",
1236          cur->valid, cur->peers, cur->addresses,
1237          (unsigned long long) cur->d_setup.rel_value_us / cur->valid);
1238       GNUNET_asprintf(&str_d_setup, "%llu",
1239          (unsigned long long) cur->d_setup.rel_value_us / cur->valid);
1240
1241     }
1242     else
1243       GNUNET_asprintf (&str_d_setup, "-1");
1244
1245     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_lp.rel_value_us)
1246     {
1247       fprintf (stderr,
1248          "Average total time from %u iterations to solve lp %s for %u peers %u addresses: %llu us\n",
1249          cur->valid,
1250          (GNUNET_YES == cur->update) ? "updated" : "full",
1251          cur->peers, cur->addresses,
1252          (unsigned long long) cur->d_lp.rel_value_us / cur->valid);
1253       GNUNET_asprintf(&str_d_lp, "%llu",
1254          (unsigned long long) cur->d_lp.rel_value_us / ph.iterations);
1255     }
1256     else
1257       GNUNET_asprintf (&str_d_lp, "-1");
1258
1259     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_mlp.rel_value_us)
1260     {
1261       fprintf (stderr,
1262          "Average total time from %u iterations to solve mlp %s for %u peers %u addresses: %llu us\n",
1263          cur->valid,
1264          (GNUNET_YES == cur->update) ? "updated" : "full",
1265              cur->peers, cur->addresses,
1266          (unsigned long long) cur->d_mlp.rel_value_us / cur->valid);
1267       GNUNET_asprintf(&str_d_mlp, "%llu",
1268          (unsigned long long) cur->d_mlp.rel_value_us / cur->valid);
1269     }
1270     else
1271       GNUNET_asprintf (&str_d_mlp, "-1");
1272
1273     data = NULL;
1274     if (GNUNET_YES == ph.create_plot)
1275     {
1276       GNUNET_asprintf (&data,
1277                        "%u;%u;%s;%s;%s;%s\n",
1278                        cur->peers, cur->addresses,
1279                        str_d_total,
1280                        str_d_setup,
1281                        str_d_lp,
1282                        str_d_mlp);
1283       if (cur->update == GNUNET_NO)
1284       {
1285         if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_full, data, strlen(data)))
1286           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1287                       "Cannot write data to log file `%s'\n",
1288                       data_fn_full);
1289       }
1290       if ((cur->update == GNUNET_YES) && (NULL != f_update))
1291       {
1292         if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_update, data, strlen(data)))
1293           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1294                       "Cannot write data to log file `%s'\n",
1295                       data_fn_update);
1296       }
1297       GNUNET_free (data);
1298     }
1299
1300     GNUNET_free_non_null (str_d_total);
1301     GNUNET_free_non_null (str_d_setup);
1302     GNUNET_free_non_null (str_d_lp);
1303     GNUNET_free_non_null (str_d_mlp);
1304   }
1305
1306   if ((NULL != f_full) && (GNUNET_SYSERR == GNUNET_DISK_file_close (f_full)))
1307     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n",
1308         data_fn_full);
1309   GNUNET_free_non_null (data_fn_full);
1310
1311   if ((NULL != f_update) && (GNUNET_SYSERR == GNUNET_DISK_file_close (f_update)))
1312     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n",
1313         data_fn_update);
1314   GNUNET_free_non_null (data_fn_update);
1315 }
1316
1317 static void
1318 perf_run (void)
1319 {
1320   struct ATS_Address *cur;
1321   struct ATS_Address *next;
1322   int cp;
1323   int ca;
1324   int count_p = ph.N_peers_end;
1325   int count_a = ph.N_address;
1326   struct ATS_Address * cur_addr;
1327
1328
1329   ph.peers = GNUNET_malloc ((count_p) * sizeof (struct PerfPeer));
1330   for (cp = 0; cp < count_p; cp++)
1331     perf_create_peer (cp);
1332   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1333       "Iteration %u of %u, added %u peers\n", ph.current_iteration, ph.iterations, cp);
1334
1335   for (cp = 0; cp < count_p; cp++)
1336   {
1337     if (GNUNET_NO == ph.bulk_running)
1338     {
1339       ph.bulk_running = GNUNET_YES;
1340       ph.env.sf.s_bulk_start (ph.solver);
1341     }
1342     ph.current_p = cp + 1;
1343     for (ca = 0; ca < count_a; ca++)
1344     {
1345       cur_addr = perf_create_address (cp, ca);
1346       /* Add address */
1347       ph.env.sf.s_add (ph.solver, cur_addr, GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_ATS_NetworkTypeCount));
1348       ph.current_a = ca + 1;
1349       perf_address_initial_update (ph.solver, ph.addresses, cur_addr);
1350       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1351           "Adding address for peer %u address %u\n", cp, ca);
1352     }
1353     /* Notify solver about request */
1354     ph.env.sf.s_get (ph.solver, &ph.peers[cp].id);
1355
1356     if (cp + 1 >= ph.N_peers_start)
1357     {
1358       /* Disable bulk to solve the problem */
1359       if (GNUNET_YES == ph.bulk_running)
1360       {
1361         ph.expecting_solution = GNUNET_YES;
1362         ph.bulk_running = GNUNET_NO;
1363         ph.env.sf.s_bulk_stop (ph.solver);
1364       }
1365       else
1366       {
1367         GNUNET_break (0);
1368       }
1369
1370       /* Problem is solved by the solver here due to unlocking */
1371       ph.expecting_solution = GNUNET_NO;
1372
1373       /* Update the problem */
1374       if ((0 < ph.opt_update_percent) && (GNUNET_YES == ph.measure_updates))
1375       {
1376         /* Update */
1377         GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1378             "Updating problem with %u peers and %u addresses\n", cp + 1, ca);
1379
1380         ph.expecting_solution = GNUNET_YES;
1381         if (GNUNET_NO == ph.bulk_running)
1382         {
1383           ph.bulk_running = GNUNET_YES;
1384           ph.env.sf.s_bulk_start (ph.solver);
1385         }
1386         perf_update_all_addresses (cp + 1, ca, ph.opt_update_percent);
1387         ph.bulk_running = GNUNET_NO;
1388         ph.env.sf.s_bulk_stop (ph.solver);
1389         /* Problem is solved by the solver here due to unlocking */
1390         ph.expecting_solution = GNUNET_NO;
1391       }
1392       GNUNET_assert (GNUNET_NO == ph.bulk_running);
1393     }
1394   }
1395
1396   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1397       "Done, cleaning up addresses\n");
1398   if (GNUNET_NO == ph.bulk_running)
1399   {
1400     ph.env.sf.s_bulk_start (ph.solver);
1401     ph.bulk_running = GNUNET_YES;
1402   }
1403
1404   for (cp = 0; cp < count_p; cp++)
1405   {
1406     for (cur = ph.peers[cp].head; cur != NULL ; cur = next)
1407     {
1408       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1409           "Deleting addresses for peer %u\n", cp);
1410       GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove (ph.addresses,
1411           &ph.peers[cp].id, cur));
1412       ph.env.sf.s_del (ph.solver, cur, GNUNET_NO);
1413       next = cur->next;
1414       GNUNET_CONTAINER_DLL_remove(ph.peers[cp].head, ph.peers[cp].tail, cur);
1415       GNUNET_free(cur);
1416     }
1417   }
1418
1419   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1420       "Iteration done\n");
1421   GNUNET_free(ph.peers);
1422 }
1423
1424
1425 static void
1426 run (void *cls, char * const *args, const char *cfgfile,
1427     const struct GNUNET_CONFIGURATION_Handle *cfg)
1428 {
1429   GNUNET_log_setup ("perf-ats-solver", "WARNING", NULL);
1430   char *sep;
1431   char *src_filename = GNUNET_strdup (__FILE__);
1432   char *test_filename = cls;
1433   char *solver;
1434   char *plugin;
1435   struct GNUNET_CONFIGURATION_Handle *solver_cfg;
1436   unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
1437   unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
1438   int c;
1439
1440   /* Extract test name */
1441   if (NULL == (sep  = (strstr (src_filename,".c"))))
1442   {
1443     GNUNET_free (src_filename);
1444     GNUNET_break (0);
1445     ret = 1;
1446     return ;
1447   }
1448   sep[0] = '\0';
1449
1450   if (NULL != (sep = strstr (test_filename, ".exe")))
1451     sep[0] = '\0';
1452
1453   if (NULL == (solver = strstr (test_filename, src_filename)))
1454   {
1455     GNUNET_free (src_filename);
1456     GNUNET_break (0);
1457     ret = 1;
1458     return ;
1459   }
1460   solver += strlen (src_filename) +1;
1461
1462   if (0 == strcmp(solver, "proportional"))
1463   {
1464     ph.ats_mode = MODE_PROPORTIONAL;
1465     ph.ats_string = "proportional";
1466   }
1467   else if (0 == strcmp(solver, "mlp"))
1468   {
1469     ph.ats_mode = MODE_MLP;
1470     ph.ats_string = "mlp";
1471   }
1472   else if ((0 == strcmp(solver, "ril")))
1473   {
1474     ph.ats_mode = MODE_RIL;
1475     ph.ats_string = "ril";
1476   }
1477   else
1478   {
1479     GNUNET_free (src_filename);
1480     GNUNET_break (0);
1481     ret = 1;
1482     return ;
1483   }
1484   GNUNET_free (src_filename);
1485
1486   /* Calculcate peers */
1487   if ((0 == ph.N_peers_start) && (0 == ph.N_peers_end))
1488   {
1489     ph.N_peers_start = DEFAULT_PEERS_START;
1490     ph.N_peers_end = DEFAULT_PEERS_END;
1491   }
1492   if (0 == ph.N_address)
1493     ph.N_address = DEFAULT_ADDRESSES;
1494
1495   if (ph.N_peers_start != ph.N_peers_end)
1496     fprintf (stderr, "Benchmarking solver `%s' with %u to %u peers and %u addresses in %u iterations\n",
1497         ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address, ph.iterations);
1498   else
1499     fprintf (stderr, "Benchmarking solver `%s' with %u peers and %u addresses in %u iterations\n",
1500         ph.ats_string, ph.N_peers_end, ph.N_address, ph.iterations);
1501
1502   if (0 == ph.opt_update_percent)
1503     ph.opt_update_percent = DEFAULT_UPDATE_PERCENTAGE;
1504
1505   /* Load quotas */
1506   solver_cfg = GNUNET_CONFIGURATION_create();
1507   if ((NULL == solver_cfg) || (GNUNET_SYSERR == (GNUNET_CONFIGURATION_load ( solver_cfg, "perf_ats_solver.conf"))))
1508   {
1509     GNUNET_break(0);
1510     end_now (1);
1511     return;
1512   }
1513   if (GNUNET_ATS_NetworkTypeCount != load_quotas (solver_cfg,
1514       quotas_out, quotas_in, GNUNET_ATS_NetworkTypeCount))
1515   {
1516     GNUNET_break(0);
1517     end_now (1);
1518     return;
1519   }
1520
1521   /* Create array of DLL to store results for iterations */
1522   ph.iterations_results = GNUNET_malloc (sizeof (struct Iteration) * ph.iterations);
1523   ph.averaged_full_result = GNUNET_malloc (sizeof (struct Result) * ((ph.N_peers_end + 1) - ph.N_peers_start));
1524   ph.averaged_update_result = GNUNET_malloc (sizeof (struct Result) * ((ph.N_peers_end + 1) - ph.N_peers_start));
1525   for (c = 0; c <= ph.N_peers_end - ph.N_peers_start; c++)
1526   {
1527     ph.averaged_full_result[c].d_setup = GNUNET_TIME_UNIT_FOREVER_REL;
1528     ph.averaged_full_result[c].d_total = GNUNET_TIME_UNIT_FOREVER_REL;
1529     ph.averaged_full_result[c].d_lp = GNUNET_TIME_UNIT_FOREVER_REL;
1530     ph.averaged_full_result[c].d_mlp = GNUNET_TIME_UNIT_FOREVER_REL;
1531   }
1532
1533   /* Load solver */
1534   ph.env.cfg = solver_cfg;
1535   ph.stat = GNUNET_STATISTICS_create ("ats", cfg);
1536   ph.env.stats = ph.stat;
1537   ph.addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
1538   ph.env.addresses = ph.addresses;
1539   ph.env.bandwidth_changed_cb = bandwidth_changed_cb;
1540   ph.env.get_preferences = &get_preferences_cb;
1541   ph.env.get_property = &get_property_cb;
1542   ph.env.network_count = GNUNET_ATS_NetworkTypeCount;
1543   ph.env.info_cb = &solver_info_cb;
1544   ph.env.info_cb_cls = NULL;
1545
1546   int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
1547   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
1548   {
1549     ph.env.networks[c] = networks[c];
1550     ph.env.out_quota[c] = quotas_out[c];
1551     ph.env.in_quota[c] = quotas_in[c];
1552     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loading network quotas: `%s' %llu %llu \n",
1553         GNUNET_ATS_print_network_type(ph.env.networks[c]),
1554         ph.env.out_quota[c],
1555         ph.env.in_quota[c]);
1556   }
1557   GAS_normalization_start (NULL, NULL, &normalized_property_changed_cb, NULL );
1558
1559   GNUNET_asprintf (&plugin, "libgnunet_plugin_ats_%s", ph.ats_string);
1560   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initializing solver `%s'\n"), ph.ats_string);
1561   if  (NULL == (ph.solver = GNUNET_PLUGIN_load (plugin, &ph.env)))
1562   {
1563     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver `%s'!\n"), plugin);
1564     ret = 1;
1565     return;
1566   }
1567
1568   /* Do the benchmark */
1569   for (ph.current_iteration = 1; ph.current_iteration <= ph.iterations; ph.current_iteration++)
1570   {
1571     perf_run ();
1572     evaluate (ph.current_iteration);
1573   }
1574   evaluate_average ();
1575
1576   /* Unload solver*/
1577   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Unloading solver `%s'\n"), ph.ats_string);
1578   GNUNET_PLUGIN_unload (plugin, ph.solver);
1579   GNUNET_free (plugin);
1580   GNUNET_free (ph.iterations_results);
1581   GNUNET_free (ph.averaged_full_result);
1582   GNUNET_free (ph.averaged_update_result);
1583   GNUNET_CONFIGURATION_destroy (solver_cfg);
1584   GNUNET_STATISTICS_destroy (ph.stat, GNUNET_NO);
1585   ph.solver = NULL;
1586 }
1587
1588 int
1589 main (int argc, char *argv[])
1590 {
1591   /* extract command line arguments */
1592   ph.opt_update_percent = 0;
1593   ph.N_peers_start = 0;
1594   ph.N_peers_end = 0;
1595   ph.N_address = 0;
1596   ph.ats_string = NULL;
1597   ph.create_plot = GNUNET_NO;
1598   ph.measure_updates = GNUNET_NO;
1599   ph.iterations = 1;
1600
1601   static struct GNUNET_GETOPT_CommandLineOption options[] = {
1602       { 'a', "addresses", NULL,
1603           gettext_noop ("addresses to use"),
1604           1, &GNUNET_GETOPT_set_uint, &ph.N_address },
1605       { 's', "start", NULL,
1606           gettext_noop ("start with peer"),
1607           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_start },
1608       { 'e', "end", NULL,
1609           gettext_noop ("end with peer"),
1610           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_end },
1611       { 'i', "iterations", NULL,
1612           gettext_noop ("number of iterations used for averaging (default: 1)"),
1613           1, &GNUNET_GETOPT_set_uint, &ph.iterations },
1614       { 'p', "percentage", NULL,
1615           gettext_noop ("update a fix percentage of addresses"),
1616           1, &GNUNET_GETOPT_set_uint, &ph.opt_update_percent },
1617       { 'g', "gnuplot", NULL,
1618           gettext_noop ("create GNUplot file"),
1619           0, &GNUNET_GETOPT_set_one, &ph.create_plot},
1620       { 'u', "update", NULL,
1621           gettext_noop ("measure updates"),
1622           0, &GNUNET_GETOPT_set_one, &ph.measure_updates},
1623       GNUNET_GETOPT_OPTION_END
1624   };
1625
1626   GNUNET_PROGRAM_run (argc, argv, argv[0], NULL, options, &run, argv[0]);
1627
1628   return ret;
1629 }
1630
1631 /* end of file perf_ats_solver.c */