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