added multiple iteration support for averaging
[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   struct Iteration *iterations_results;
114
115   struct Result *current_result;
116
117   int current_p;
118   int current_a;
119
120   /**
121    * Solver description as string
122    */
123   char *ats_string;
124
125   /**
126    * Configured ATS solver
127    */
128   int ats_mode;
129
130   /**
131    * #peers to start benchmarking with
132    */
133   int N_peers_start;
134
135   /**
136    * #peers to end benchmarking with
137    */
138   int N_peers_end;
139
140   /**
141    * #addresses to benchmarking with
142    */
143   int N_address;
144
145   /**
146    * Percentage of peers to update
147    */
148   int opt_update_percent;
149
150   /**
151    * Create gnuplot file
152    */
153   int create_plot;
154
155   /**
156    * Measure updates
157    */
158   int measure_updates;
159
160   /**
161    * Number of iterations
162    */
163   int iterations;
164
165   /**
166    * Current iteration
167    */
168   int current_iteration;
169
170   /**
171    * Is a bulk operation running?
172    */
173   int bulk_running;
174
175   /**
176    * Is a bulk operation running?
177    */
178   int expecting_solution;
179 };
180
181 struct Iteration
182 {
183   struct Result *result_head;
184
185   struct Result *result_tail;
186 };
187
188 struct Result
189 {
190   struct Result *prev;
191   struct Result *next;
192
193   int peers;
194   int addresses;
195   int update;
196
197   enum GAS_Solver_Additional_Information info;
198
199   struct GNUNET_TIME_Relative d_setup;
200   struct GNUNET_TIME_Relative d_lp;
201   struct GNUNET_TIME_Relative d_mlp;
202   struct GNUNET_TIME_Relative d_total;
203
204   struct GNUNET_TIME_Absolute s_setup;
205   struct GNUNET_TIME_Absolute s_lp;
206   struct GNUNET_TIME_Absolute s_mlp;
207   struct GNUNET_TIME_Absolute s_total;
208
209   struct GNUNET_TIME_Absolute e_setup;
210   struct GNUNET_TIME_Absolute e_lp;
211   struct GNUNET_TIME_Absolute e_mlp;
212   struct GNUNET_TIME_Absolute e_total;
213 };
214
215 struct PerfPeer
216 {
217   struct GNUNET_PeerIdentity id;
218
219   struct ATS_Address *head;
220   struct ATS_Address *tail;
221 };
222
223 static struct PerfHandle ph;
224
225 /**
226  * Return value
227  */
228 static int ret;
229
230
231 /**
232  * ATS information
233  */
234 //static struct GNUNET_ATS_Information ats[2];
235
236
237 static void
238 end_now (int res)
239 {
240   if (NULL != ph.stat)
241   {
242     GNUNET_STATISTICS_destroy (ph.stat, GNUNET_NO);
243     ph.stat = NULL;
244   }
245   /*
246    if (NULL != addresses)
247    {
248    GNUNET_CONTAINER_multihashmap_iterate (addresses, &addr_it, NULL);
249    GNUNET_CONTAINER_multihashmap_destroy (addresses);
250    addresses = NULL ;
251    }*/
252   if (NULL != ph.peers)
253   {
254     GNUNET_free(ph.peers);
255   }
256
257   GAS_normalization_stop ();
258   ret = res;
259 }
260
261
262 static void
263 perf_create_peer (int cp)
264 {
265
266   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
267       &ph.peers[cp].id, sizeof (struct GNUNET_PeerIdentity));
268   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Creating peer #%u: %s \n", cp,
269       GNUNET_i2s (&ph.peers[cp].id));
270 }
271
272
273
274 static void
275 perf_update_address (struct ATS_Address *cur)
276 {
277   int r_type;
278   int r_val;
279
280   r_type = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2);
281   switch (r_type)
282   {
283   case 0:
284     r_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
285     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
286         "Updating peer `%s' address %p type %s val %u\n",
287         GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DELAY", r_val);
288     ph.env.sf.s_address_update_property (ph.solver, cur,
289         GNUNET_ATS_QUALITY_NET_DELAY,
290         r_val, (double) (100 + r_val / 100));
291     break;
292   case 1:
293     r_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 10);
294
295     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
296         "Updating peer `%s' address %p type %s val %u\n",
297         GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DISTANCE", r_val);
298     ph.env.sf.s_address_update_property (ph.solver, cur,
299         GNUNET_ATS_QUALITY_NET_DISTANCE,
300         r_val, (double) (100 + r_val) / 100);
301     break;
302   default:
303     break;
304   }
305   ph.env.sf.s_address_update_inuse (ph.solver, cur, GNUNET_YES);
306 }
307
308
309 static void
310 bandwidth_changed_cb (void *cls,
311                       struct ATS_Address *address)
312 {
313   if ( (0 == ntohl (address->assigned_bw_out.value__)) &&
314        (0 == ntohl (address->assigned_bw_in.value__)) )
315     return;
316
317   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
318               "Bandwidth changed addresses %s %p to %u Bps out / %u Bps in\n",
319               GNUNET_i2s (&address->peer),
320               address,
321               (unsigned int) ntohl (address->assigned_bw_out.value__),
322               (unsigned int) ntohl (address->assigned_bw_in.value__));
323   if (GNUNET_YES == ph.bulk_running)
324     GNUNET_break (0);
325   return;
326 }
327
328
329 const double *
330 get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
331 {
332   return GAS_normalization_get_preferences_by_peer (id);
333 }
334
335
336 const double *
337 get_property_cb (void *cls, const struct ATS_Address *address)
338 {
339   return GAS_normalization_get_properties ((struct ATS_Address *) address);
340 }
341
342 static void
343 normalized_property_changed_cb (void *cls, struct ATS_Address *peer,
344     uint32_t type, double prop_rel)
345 {
346   /* TODO */
347 }
348
349 static void
350 perf_address_initial_update (void *solver,
351     struct GNUNET_CONTAINER_MultiPeerMap * addresses,
352     struct ATS_Address *address)
353 {
354   ph.env.sf.s_address_update_property (solver, address, GNUNET_ATS_QUALITY_NET_DELAY,
355       100,
356       (double) (100 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100))
357           / 100);
358
359   ph.env.sf.s_address_update_property (solver, address,
360       GNUNET_ATS_QUALITY_NET_DISTANCE, 10,
361       (double) (100 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100))
362           / 100);
363 }
364
365 static void
366 perf_update_all_addresses (unsigned int cp, unsigned int ca, unsigned int percentage_peers)
367 {
368   struct ATS_Address *cur_address;
369   int c_peer;
370   int c_select;
371   int c_cur_p;
372   int c_cur_a;
373   int r;
374   int count;
375   unsigned int m[cp];
376
377   count = cp * ((double) percentage_peers / 100);
378   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
379       "Updating %u of %u peers \n", count, cp);
380
381   for (c_peer = 0; c_peer < cp; c_peer++)
382     m[c_peer] = 0;
383
384   c_select = 0;
385
386   while (c_select < count)
387   {
388     r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, cp);
389     if (0 == m[r])
390     {
391       m[r] = 1;
392       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
393           "Updating peer [%u] \n", r);
394       c_select++;
395     }
396   }
397   for (c_cur_p = 0; c_cur_p < cp; c_cur_p++)
398   {
399     if (1 == m[c_cur_p])
400     {
401       r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, ca);
402       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
403           "Updating peer [%u] address [%u]\n", c_cur_p, r);
404
405       c_cur_a = 0;
406       for (cur_address = ph.peers[c_cur_p].head; NULL != cur_address; cur_address = cur_address->next)
407       {
408         if (c_cur_a == r)
409           perf_update_address (cur_address);
410
411         c_cur_a ++;
412       }
413     }
414   }
415 }
416
417
418 static struct ATS_Address *
419 perf_create_address (int cp, int ca)
420 {
421   struct ATS_Address *a;
422   a = create_address (&ph.peers[cp].id,
423       "Test 1", "test 1", strlen ("test 1") + 1, 0);
424   GNUNET_CONTAINER_DLL_insert (ph.peers[cp].head, ph.peers[cp].tail, a);
425   GNUNET_CONTAINER_multipeermap_put (ph.addresses, &ph.peers[cp].id, a,
426       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
427   return a;
428 }
429
430 static void
431 solver_info_cb (void *cls,
432     enum GAS_Solver_Operation op,
433     enum GAS_Solver_Status stat,
434     enum GAS_Solver_Additional_Information add)
435 {
436   char *add_info;
437   switch (add) {
438     case GAS_INFO_NONE:
439       add_info = "GAS_INFO_NONE";
440       break;
441     case GAS_INFO_FULL:
442       add_info = "GAS_INFO_MLP_FULL";
443       break;
444     case GAS_INFO_UPDATED:
445       add_info = "GAS_INFO_MLP_UPDATED";
446       break;
447     case GAS_INFO_PROP_ALL:
448       add_info = "GAS_INFO_PROP_ALL";
449       break;
450     case GAS_INFO_PROP_SINGLE:
451       add_info = "GAS_INFO_PROP_SINGLE";
452       break;
453     default:
454       add_info = "INVALID";
455       break;
456   }
457
458   struct Result *tmp;
459   switch (op)
460   {
461     case GAS_OP_SOLVE_START:
462       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
463           "Solver notifies `%s' with result `%s' `%s' in iteration %u \n", "GAS_OP_SOLVE_START",
464           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info, ph.current_iteration);
465       if (GNUNET_NO == ph.expecting_solution)
466       {
467         /* We do not expect a solution at the moment */
468         GNUNET_break (0);
469         return;
470       }
471
472       if ((GAS_STAT_SUCCESS == stat) && (NULL == ph.current_result))
473       {
474         /* Create new result */
475         tmp = GNUNET_new (struct Result);
476         ph.current_result = tmp;
477         GNUNET_CONTAINER_DLL_insert_tail(ph.iterations_results[ph.current_iteration-1].result_head,
478             ph.iterations_results[ph.current_iteration-1].result_tail, tmp);
479         ph.current_result->addresses = ph.current_a;
480         ph.current_result->peers = ph.current_p;
481         ph.current_result->s_total = GNUNET_TIME_absolute_get();
482         ph.current_result->d_total = GNUNET_TIME_UNIT_FOREVER_REL;
483         ph.current_result->d_setup = GNUNET_TIME_UNIT_FOREVER_REL;
484         ph.current_result->d_lp = GNUNET_TIME_UNIT_FOREVER_REL;
485         ph.current_result->d_mlp = GNUNET_TIME_UNIT_FOREVER_REL;
486         ph.current_result->info = add;
487         if (add == GAS_INFO_UPDATED)
488           ph.current_result->update = GNUNET_YES;
489         else
490           ph.current_result->update = GNUNET_NO;
491       }
492       return;
493     case GAS_OP_SOLVE_STOP:
494       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
495           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_STOP",
496           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
497       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
498       {
499         /* We do not expect a solution at the moment */
500         GNUNET_break (0);
501         return;
502       }
503       if (NULL != ph.current_result)
504       {
505         /* Finalize result */
506         ph.current_result->e_total = GNUNET_TIME_absolute_get ();
507         ph.current_result->d_total = GNUNET_TIME_absolute_get_difference (
508             ph.current_result->s_total, ph.current_result->e_total);
509       }
510       ph.current_result = NULL;
511       return;
512
513     case GAS_OP_SOLVE_SETUP_START:
514       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
515           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_START",
516           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
517       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
518       {
519         GNUNET_break(0);
520         return;
521       }
522       ph.current_result->s_setup = GNUNET_TIME_absolute_get ();
523       return;
524
525     case GAS_OP_SOLVE_SETUP_STOP:
526       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
527           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_STOP",
528           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
529       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
530       {
531         GNUNET_break(0);
532         return;
533       }
534       ph.current_result->e_setup = GNUNET_TIME_absolute_get ();
535       ph.current_result->d_setup = GNUNET_TIME_absolute_get_difference (
536           ph.current_result->s_setup, ph.current_result->e_setup);
537       return;
538
539     case GAS_OP_SOLVE_MLP_LP_START:
540       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
541           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_START",
542           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
543       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
544       {
545         GNUNET_break(0);
546         return;
547       }
548       ph.current_result->s_lp = GNUNET_TIME_absolute_get ();
549       return;
550     case GAS_OP_SOLVE_MLP_LP_STOP:
551       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
552           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_STOP",
553           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
554       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
555       {
556         GNUNET_break(0);
557         return;
558       }
559       ph.current_result->e_lp = GNUNET_TIME_absolute_get ();
560       ph.current_result->d_lp = GNUNET_TIME_absolute_get_difference (
561           ph.current_result->s_lp, ph.current_result->e_lp);
562       return;
563
564     case GAS_OP_SOLVE_MLP_MLP_START:
565       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
566           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_START",
567           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
568       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
569       {
570         GNUNET_break(0);
571         return;
572       }
573       ph.current_result->s_mlp = GNUNET_TIME_absolute_get ();
574       return;
575     case GAS_OP_SOLVE_MLP_MLP_STOP:
576       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
577           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_STOP",
578           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
579       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
580       {
581         GNUNET_break(0);
582         return;
583       }
584       ph.current_result->e_mlp = GNUNET_TIME_absolute_get ();
585       ph.current_result->d_mlp = GNUNET_TIME_absolute_get_difference (
586       ph.current_result->s_mlp, ph.current_result->e_mlp);
587       return;
588     case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
589       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
590           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
591           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
592       return;
593     case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
594       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
595           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
596           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
597       return;
598     default:
599       break;
600     }
601 }
602
603 static void
604 write_gnuplot_script (char * data_fn, int full)
605 {
606   struct GNUNET_DISK_FileHandle *f;
607   char * gfn;
608   char *data;
609   char *template;
610
611   /* Write header */
612   switch (ph.ats_mode) {
613     case MODE_PROPORTIONAL:
614       if (GNUNET_YES == full)
615         template = GNUPLOT_PROP_TEMPLATE;
616       else
617         template = GNUPLOT_PROP_UPDATE_TEMPLATE;
618       break;
619     case MODE_MLP:
620       if (GNUNET_YES == full)
621         template = GNUPLOT_MLP_TEMPLATE;
622       else
623         template = GNUPLOT_MLP_UPDATE_TEMPLATE;
624       break;
625     case MODE_RIL:
626       if (GNUNET_YES == full)
627         template = GNUPLOT_RIL_TEMPLATE;
628       else
629         template = GNUPLOT_RIL_UPDATE_TEMPLATE;
630       break;
631     default:
632       GNUNET_break (0);
633       return;
634   }
635
636   if (GNUNET_YES == full)
637     GNUNET_asprintf (&gfn, "perf_%s_full_%u_%u_%u.gnuplot", ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address);
638   else
639     GNUNET_asprintf (&gfn, "perf_%s_update_%u_%u_%u.gnuplot", ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address);
640
641   f = GNUNET_DISK_file_open (gfn,
642       GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
643       GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
644   if (NULL == f)
645   {
646     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot open gnuplot file `%s'\n", gfn);
647     GNUNET_free (gfn);
648     return;
649   }
650
651   if (GNUNET_SYSERR == GNUNET_DISK_file_write(f, template, strlen(template)))
652     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot write data to plot file `%s'\n", gfn);
653
654   data = NULL;
655   if (MODE_PROPORTIONAL == ph.ats_mode)
656   {
657     GNUNET_asprintf (&data, "plot '%s' using 1:%u with lines title 'Total time to solve'\n" \
658                            "pause -1",
659                            data_fn, 3);
660   }
661   else if (MODE_MLP == ph.ats_mode)
662   {
663     GNUNET_asprintf (&data, "plot '%s' using 1:%u with lines title 'Total time to solve',\\\n" \
664                             "'%s' using 1:%u with lines title 'Time to setup',\\\n"
665                             "'%s' using 1:%u with lines title 'Time to solve LP',\\\n"
666                             "'%s' using 1:%u with lines title 'Total time to solve MLP'\n" \
667                             "pause -1",
668                            data_fn, 3,
669                            data_fn, 4,
670                            data_fn, 5,
671                            data_fn, 6);
672   }
673   else if (MODE_RIL == ph.ats_mode)
674   {
675     GNUNET_asprintf (&data,
676                      "plot '%s' using 1:%u with lines title 'Total time to solve'\n" \
677                      "pause -1",
678                      data_fn, 3);
679   }
680
681   if ((NULL != data) &&
682       (GNUNET_SYSERR == GNUNET_DISK_file_write (f, data, strlen(data))))
683     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
684                 "Cannot write data to plot file `%s'\n",
685                 gfn);
686   GNUNET_free_non_null (data);
687
688   if (GNUNET_SYSERR == GNUNET_DISK_file_close(f))
689     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
690                 "Cannot close gnuplot file `%s'\n",
691                 gfn);
692   else
693     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
694                 "Data successfully written to plot file `%s'\n",
695                 gfn);
696   GNUNET_free (gfn);
697
698 }
699
700 /**
701  * Evaluate results for a specific iteration
702  *
703  * @oaram iteration the iteration to evaluate
704  */
705
706 static void
707 evaluate (int iteration)
708 {
709   struct GNUNET_DISK_FileHandle *f_full;
710   struct GNUNET_DISK_FileHandle *f_update;
711   char * data_fn_full;
712   char * data_fn_update;
713   char * data;
714   struct Result *cur;
715   struct Result *next;
716   char * str_d_total;
717   char * str_d_setup;
718   char * str_d_lp;
719   char * str_d_mlp;
720
721   f_full = NULL;
722   f_update = NULL;
723
724   data_fn_full = NULL;
725
726   if (ph.create_plot)
727   {
728     GNUNET_asprintf (&data_fn_full,
729                      "perf_%s_full_%u_%u_%u.data",
730                      ph.ats_string,
731                      ph.N_peers_start,
732                      ph.N_peers_end,
733                      ph.N_address);
734     f_full = GNUNET_DISK_file_open (data_fn_full,
735         GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
736         GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
737     if (NULL == f_full)
738     {
739       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
740                   "Cannot open gnuplot file `%s'\n",
741                   data_fn_full);
742       GNUNET_free (data_fn_full);
743       return;
744     }
745     data = "#peers;addresses;time total in us;#time setup in us;#time lp in us;#time mlp in us;\n";
746     if (GNUNET_SYSERR == GNUNET_DISK_file_write(f_full, data, strlen(data)))
747       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
748                   "Cannot write data to log file `%s'\n",
749                   data_fn_full);
750     write_gnuplot_script (data_fn_full, GNUNET_YES);
751   }
752
753   data_fn_update = NULL;
754   if ((ph.create_plot) && (GNUNET_YES == ph.measure_updates))
755   {
756     GNUNET_asprintf (&data_fn_update, "perf_%s_update_%u_%u_%u.data", ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address);
757     f_update = GNUNET_DISK_file_open (data_fn_update,
758         GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
759         GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
760     if (NULL == f_update)
761     {
762       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
763                   "Cannot open gnuplot file `%s'\n", data_fn_update);
764       GNUNET_free (data_fn_update);
765       if (NULL != f_full)
766         GNUNET_DISK_file_close (f_full);
767       GNUNET_free (data_fn_full);
768       return;
769     }
770     data = "#peers;addresses;time total in us;#time setup in us;#time lp in us;#time mlp in us;\n";
771     if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_update, data, strlen(data)))
772       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
773                   "Cannot write data to log file `%s'\n",
774                   data_fn_update);
775     write_gnuplot_script (data_fn_update, GNUNET_NO);
776   }
777
778
779   next = ph.iterations_results[ph.current_iteration -1].result_head;
780   while (NULL != (cur = next))
781   {
782     next = cur->next;
783     str_d_total = NULL;
784     str_d_setup = NULL;
785     str_d_lp = NULL;
786     str_d_mlp = NULL;
787
788     /* Print log */
789     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_total.rel_value_us)
790     {
791       fprintf (stderr,
792                "Total time to solve %s for %u peers %u addresses: %llu us\n",
793                (GNUNET_YES == cur->update) ? "updated" : "full",
794                cur->peers, cur->addresses, (unsigned long long) cur->d_total.rel_value_us);
795       GNUNET_asprintf(&str_d_total,
796                       "%llu",
797                       (unsigned long long) cur->d_total.rel_value_us);
798     }
799     else
800       GNUNET_asprintf(&str_d_total, "-1");
801     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_setup.rel_value_us)
802     {
803       fprintf (stderr, "Total time to setup %s %u peers %u addresses: %llu us\n",
804           (GNUNET_YES == cur->update) ? "updated" : "full",
805           cur->peers, cur->addresses, (unsigned long long )cur->d_setup.rel_value_us);
806       GNUNET_asprintf(&str_d_setup, "%llu", (unsigned long long )cur->d_setup.rel_value_us);
807     }
808     else
809       GNUNET_asprintf(&str_d_setup, "-1");
810     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_lp.rel_value_us)
811     {
812       fprintf (stderr,
813                "Total time to solve %s LP for %u peers %u addresses: %llu us\n",
814                (GNUNET_YES == cur->update) ? "updated" : "full",
815                cur->peers,
816                cur->addresses,
817                (unsigned long long )cur->d_lp.rel_value_us);
818       GNUNET_asprintf (&str_d_lp,
819                        "%llu",
820                        (unsigned long long )cur->d_lp.rel_value_us);
821     }
822     else
823       GNUNET_asprintf (&str_d_lp, "-1");
824     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_mlp.rel_value_us)
825     {
826       fprintf (stderr, "Total time to solve %s MLP for %u peers %u addresses: %llu us\n",
827           (GNUNET_YES == cur->update) ? "updated" : "full",
828           cur->peers, cur->addresses, (unsigned long long )cur->d_mlp.rel_value_us);
829       GNUNET_asprintf (&str_d_mlp,
830                        "%llu",
831                        (unsigned long long )cur->d_mlp.rel_value_us);
832     }
833     else
834       GNUNET_asprintf (&str_d_mlp, "-1");
835
836     data = NULL;
837     if (GNUNET_YES == ph.create_plot)
838     {
839
840       GNUNET_asprintf (&data,
841                        "%u;%u;%s;%s;%s;%s\n",
842                        cur->peers, cur->addresses,
843                        str_d_total,
844                        str_d_setup,
845                        str_d_lp,
846                        str_d_mlp);
847       if (cur->update == GNUNET_NO)
848       {
849         if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_full, data, strlen(data)))
850           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
851                       "Cannot write data to log file `%s'\n",
852                       data_fn_full);
853       }
854       if ((cur->update == GNUNET_YES) && (NULL != f_update))
855       {
856         if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_update, data, strlen(data)))
857           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
858                       "Cannot write data to log file `%s'\n",
859                       data_fn_update);
860       }
861       GNUNET_free (data);
862     }
863     GNUNET_free_non_null (str_d_total);
864     GNUNET_free_non_null (str_d_setup);
865     GNUNET_free_non_null (str_d_lp);
866     GNUNET_free_non_null (str_d_mlp);
867
868     GNUNET_CONTAINER_DLL_remove (ph.iterations_results[ph.current_iteration-1].result_head,
869         ph.iterations_results[ph.current_iteration-1].result_tail, cur);
870     GNUNET_free (cur);
871   }
872
873   if ((NULL != f_full) && (GNUNET_SYSERR == GNUNET_DISK_file_close (f_full)))
874     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n",
875         data_fn_full);
876   GNUNET_free_non_null (data_fn_full);
877
878   if ((NULL != f_update) && (GNUNET_SYSERR == GNUNET_DISK_file_close (f_update)))
879     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n",
880         data_fn_update);
881   GNUNET_free_non_null (data_fn_update);
882 }
883
884
885 static void
886 perf_run (void)
887 {
888   struct ATS_Address *cur;
889   struct ATS_Address *next;
890   int cp;
891   int ca;
892   int count_p = ph.N_peers_end;
893   int count_a = ph.N_address;
894   struct ATS_Address * cur_addr;
895
896
897   ph.peers = GNUNET_malloc ((count_p) * sizeof (struct PerfPeer));
898   for (cp = 0; cp < count_p; cp++)
899     perf_create_peer (cp);
900   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
901       "Iteration %u of %u, added %u peers\n", ph.current_iteration, ph.iterations, cp);
902
903   for (cp = 0; cp < count_p; cp++)
904   {
905     if (GNUNET_NO == ph.bulk_running)
906     {
907       ph.bulk_running = GNUNET_YES;
908       ph.env.sf.s_bulk_start (ph.solver);
909     }
910     ph.current_p = cp + 1;
911     for (ca = 0; ca < count_a; ca++)
912     {
913       cur_addr = perf_create_address (cp, ca);
914       /* Add address */
915       ph.env.sf.s_add (ph.solver, cur_addr, GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_ATS_NetworkTypeCount));
916       ph.current_a = ca + 1;
917       perf_address_initial_update (ph.solver, ph.addresses, cur_addr);
918       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
919           "Adding address for peer %u address %u\n", cp, ca);
920     }
921     /* Notify solver about request */
922     ph.env.sf.s_get (ph.solver, &ph.peers[cp].id);
923
924     if (cp + 1 >= ph.N_peers_start)
925     {
926       /* Disable bulk to solve the problem */
927       if (GNUNET_YES == ph.bulk_running)
928       {
929         ph.expecting_solution = GNUNET_YES;
930         ph.bulk_running = GNUNET_NO;
931         ph.env.sf.s_bulk_stop (ph.solver);
932       }
933       else
934       {
935         GNUNET_break (0);
936       }
937
938       /* Problem is solved by the solver here due to unlocking */
939       ph.expecting_solution = GNUNET_NO;
940
941       /* Update the problem */
942       if ((0 < ph.opt_update_percent) && (GNUNET_YES == ph.measure_updates))
943       {
944         /* Update */
945         GNUNET_log(GNUNET_ERROR_TYPE_INFO,
946             "Updating problem with %u peers and %u addresses\n", cp + 1, ca);
947
948         ph.expecting_solution = GNUNET_YES;
949         if (GNUNET_NO == ph.bulk_running)
950         {
951           ph.bulk_running = GNUNET_YES;
952           ph.env.sf.s_bulk_start (ph.solver);
953         }
954         perf_update_all_addresses (cp + 1, ca, ph.opt_update_percent);
955         ph.bulk_running = GNUNET_NO;
956         ph.env.sf.s_bulk_stop (ph.solver);
957         /* Problem is solved by the solver here due to unlocking */
958         ph.expecting_solution = GNUNET_NO;
959       }
960       GNUNET_assert (GNUNET_NO == ph.bulk_running);
961     }
962   }
963
964   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
965       "Done, cleaning up addresses\n");
966   if (GNUNET_NO == ph.bulk_running)
967   {
968     ph.env.sf.s_bulk_start (ph.solver);
969     ph.bulk_running = GNUNET_YES;
970   }
971
972   for (cp = 0; cp < count_p; cp++)
973   {
974     for (cur = ph.peers[cp].head; cur != NULL ; cur = next)
975     {
976       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
977           "Deleting addresses for peer %u\n", cp);
978       GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove (ph.addresses,
979           &ph.peers[cp].id, cur));
980       ph.env.sf.s_del (ph.solver, cur, GNUNET_NO);
981       next = cur->next;
982       GNUNET_CONTAINER_DLL_remove(ph.peers[cp].head, ph.peers[cp].tail, cur);
983       GNUNET_free(cur);
984     }
985
986   }
987   GNUNET_free(ph.peers);
988 }
989
990
991 static void
992 run (void *cls, char * const *args, const char *cfgfile,
993     const struct GNUNET_CONFIGURATION_Handle *cfg)
994 {
995   GNUNET_log_setup ("perf-ats-solver", "WARNING", NULL);
996   char *sep;
997   char *src_filename = GNUNET_strdup (__FILE__);
998   char *test_filename = cls;
999   char *solver;
1000   char *plugin;
1001   struct GNUNET_CONFIGURATION_Handle *solver_cfg;
1002   unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
1003   unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
1004   int c;
1005
1006   /* Extract test name */
1007   if (NULL == (sep  = (strstr (src_filename,".c"))))
1008   {
1009     GNUNET_free (src_filename);
1010     GNUNET_break (0);
1011     ret = 1;
1012     return ;
1013   }
1014   sep[0] = '\0';
1015
1016   if (NULL != (sep = strstr (test_filename, ".exe")))
1017     sep[0] = '\0';
1018
1019   if (NULL == (solver = strstr (test_filename, src_filename)))
1020   {
1021     GNUNET_free (src_filename);
1022     GNUNET_break (0);
1023     ret = 1;
1024     return ;
1025   }
1026   solver += strlen (src_filename) +1;
1027
1028   if (0 == strcmp(solver, "proportional"))
1029   {
1030     ph.ats_mode = MODE_PROPORTIONAL;
1031     ph.ats_string = "proportional";
1032   }
1033   else if (0 == strcmp(solver, "mlp"))
1034   {
1035     ph.ats_mode = MODE_MLP;
1036     ph.ats_string = "mlp";
1037   }
1038   else if ((0 == strcmp(solver, "ril")))
1039   {
1040     ph.ats_mode = MODE_RIL;
1041     ph.ats_string = "ril";
1042   }
1043   else
1044   {
1045     GNUNET_free (src_filename);
1046     GNUNET_break (0);
1047     ret = 1;
1048     return ;
1049   }
1050   GNUNET_free (src_filename);
1051
1052   /* Calculcate peers */
1053   if ((0 == ph.N_peers_start) && (0 == ph.N_peers_end))
1054   {
1055     ph.N_peers_start = DEFAULT_PEERS_START;
1056     ph.N_peers_end = DEFAULT_PEERS_END;
1057   }
1058   if (0 == ph.N_address)
1059     ph.N_address = DEFAULT_ADDRESSES;
1060
1061   if (ph.N_peers_start != ph.N_peers_end)
1062     fprintf (stderr, "Benchmarking solver `%s' with %u to %u peers and %u addresses in %u iterations\n",
1063         ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address, ph.iterations);
1064   else
1065     fprintf (stderr, "Benchmarking solver `%s' with %u peers and %u addresses in %u iterations\n",
1066         ph.ats_string, ph.N_peers_end, ph.N_address, ph.iterations);
1067
1068   if (0 == ph.opt_update_percent)
1069     ph.opt_update_percent = DEFAULT_UPDATE_PERCENTAGE;
1070
1071   /* Load quotas */
1072   solver_cfg = GNUNET_CONFIGURATION_create();
1073   if ((NULL == solver_cfg) || (GNUNET_SYSERR == (GNUNET_CONFIGURATION_load ( solver_cfg, "perf_ats_solver.conf"))))
1074   {
1075     GNUNET_break(0);
1076     end_now (1);
1077     return;
1078   }
1079   if (GNUNET_ATS_NetworkTypeCount != load_quotas (solver_cfg,
1080       quotas_out, quotas_in, GNUNET_ATS_NetworkTypeCount))
1081   {
1082     GNUNET_break(0);
1083     end_now (1);
1084     return;
1085   }
1086
1087   /* Create array of DLL to store results for iterations */
1088   ph.iterations_results = GNUNET_malloc (sizeof (struct Iteration) * ph.iterations);
1089
1090   /* Load solver */
1091   ph.env.cfg = solver_cfg;
1092   ph.stat = GNUNET_STATISTICS_create ("ats", cfg);
1093   ph.env.stats = ph.stat;
1094   ph.addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
1095   ph.env.addresses = ph.addresses;
1096   ph.env.bandwidth_changed_cb = bandwidth_changed_cb;
1097   ph.env.get_preferences = &get_preferences_cb;
1098   ph.env.get_property = &get_property_cb;
1099   ph.env.network_count = GNUNET_ATS_NetworkTypeCount;
1100   ph.env.info_cb = &solver_info_cb;
1101   ph.env.info_cb_cls = NULL;
1102
1103   int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
1104   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
1105   {
1106     ph.env.networks[c] = networks[c];
1107     ph.env.out_quota[c] = quotas_out[c];
1108     ph.env.in_quota[c] = quotas_in[c];
1109     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loading network quotas: `%s' %llu %llu \n",
1110         GNUNET_ATS_print_network_type(ph.env.networks[c]),
1111         ph.env.out_quota[c],
1112         ph.env.in_quota[c]);
1113   }
1114   GAS_normalization_start (NULL, NULL, &normalized_property_changed_cb, NULL );
1115
1116   GNUNET_asprintf (&plugin, "libgnunet_plugin_ats_%s", ph.ats_string);
1117   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initializing solver `%s'\n"), ph.ats_string);
1118   if  (NULL == (ph.solver = GNUNET_PLUGIN_load (plugin, &ph.env)))
1119   {
1120     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver `%s'!\n"), plugin);
1121     ret = 1;
1122     return;
1123   }
1124
1125   /* Do the benchmark */
1126   for (ph.current_iteration = 1; ph.current_iteration <= ph.iterations; ph.current_iteration++)
1127   {
1128     perf_run ();
1129     evaluate (ph.current_iteration);
1130   }
1131
1132   /* Unload solver*/
1133   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Unloading solver `%s'\n"), ph.ats_string);
1134   GNUNET_PLUGIN_unload (plugin, ph.solver);
1135   GNUNET_free (plugin);
1136   GNUNET_CONFIGURATION_destroy (solver_cfg);
1137   GNUNET_STATISTICS_destroy (ph.stat, GNUNET_NO);
1138   ph.solver = NULL;
1139 }
1140
1141 int
1142 main (int argc, char *argv[])
1143 {
1144   /* extract command line arguments */
1145   ph.opt_update_percent = 0;
1146   ph.N_peers_start = 0;
1147   ph.N_peers_end = 0;
1148   ph.N_address = 0;
1149   ph.ats_string = NULL;
1150   ph.create_plot = GNUNET_NO;
1151   ph.measure_updates = GNUNET_NO;
1152   ph.iterations = 1;
1153
1154   static struct GNUNET_GETOPT_CommandLineOption options[] = {
1155       { 'a', "addresses", NULL,
1156           gettext_noop ("addresses to use"),
1157           1, &GNUNET_GETOPT_set_uint, &ph.N_address },
1158       { 's', "start", NULL,
1159           gettext_noop ("start with peer"),
1160           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_start },
1161       { 'e', "end", NULL,
1162           gettext_noop ("end with peer"),
1163           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_end },
1164       { 'i', "iterations", NULL,
1165           gettext_noop ("number of iterations used for averaging (default: 1)"),
1166           1, &GNUNET_GETOPT_set_uint, &ph.iterations },
1167       { 'p', "percentage", NULL,
1168           gettext_noop ("update a fix percentage of addresses"),
1169           1, &GNUNET_GETOPT_set_uint, &ph.opt_update_percent },
1170       { 'g', "gnuplot", NULL,
1171           gettext_noop ("create GNUplot file"),
1172           0, &GNUNET_GETOPT_set_one, &ph.create_plot},
1173       { 'u', "update", NULL,
1174           gettext_noop ("measure updates"),
1175           0, &GNUNET_GETOPT_set_one, &ph.measure_updates},
1176       GNUNET_GETOPT_OPTION_END
1177   };
1178
1179   GNUNET_PROGRAM_run (argc, argv, argv[0], NULL, options, &run, argv[0]);
1180
1181   return ret;
1182 }
1183
1184 /* end of file perf_ats_solver.c */