adding additional INFO
[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_PEERS_START     10
36 #define DEFAULT_PEERS_END       10
37 #define DEFAULT_ADDRESSES       10
38 #define DEFAULT_ATS_COUNT       2
39
40 #define GNUPLOT_PROP_TEMPLATE "#!/usr/bin/gnuplot \n" \
41 "set datafile separator ';' \n" \
42 "set title \"Execution time Proportional solver  \" \n" \
43 "set xlabel \"Number of peers\" \n" \
44 "set ylabel \"Execution time in us\" \n" \
45 "set grid \n"
46
47 #define GNUPLOT_MLP_TEMPLATE "#!/usr/bin/gnuplot \n" \
48 "set datafile separator ';' \n" \
49 "set title \"Execution time MLP solver \" \n" \
50 "set xlabel \"Number of peers\" \n" \
51 "set ylabel \"Execution time in us\" \n" \
52 "set grid \n"
53
54 #define GNUPLOT_RIL_TEMPLATE "#!/usr/bin/gnuplot \n" \
55 "set datafile separator ';' \n" \
56 "set title \"Execution time RIL solver \" \n" \
57 "set xlabel \"Number of peers\" \n" \
58 "set ylabel \"Execution time in us\" \n" \
59 "set grid \n"
60
61 /**
62  * Handle for ATS address component
63  */
64 struct PerfHandle
65 {
66   /**
67    * Performance peers
68    */
69   struct PerfPeer *peers;
70
71   /**
72    *  Solver handle
73    */
74   void *solver;
75
76   /**
77    * Statistics stat;
78    */
79   struct GNUNET_STATISTICS_Handle *stat;
80
81   /**
82    * A multihashmap to store all addresses
83    */
84   struct GNUNET_CONTAINER_MultiPeerMap *addresses;
85
86   /**
87    * Solver functions
88    * */
89   struct GNUNET_ATS_PluginEnvironment env;
90
91   struct Result *head;
92
93   struct Result *tail;
94
95   struct Result *current_result;
96
97   int current_p;
98   int current_a;
99
100   /**
101    * Solver description as string
102    */
103   char *ats_string;
104
105   /**
106    * Configured ATS solver
107    */
108   int ats_mode;
109
110   /**
111    * #peers to start benchmarking with
112    */
113   int N_peers_start;
114
115   /**
116    * #peers to end benchmarking with
117    */
118   int N_peers_end;
119
120   /**
121    * #addresses to benchmarking with
122    */
123   int N_address;
124
125   /**
126    * Percentage of peers to update
127    */
128   int opt_update_percent;
129
130   /**
131    * Number of peers to update
132    */
133   int opt_update_quantity;
134
135   /**
136    * Create gnuplot file
137    */
138   int create_plot;
139
140   /**
141    * Is a bulk operation running?
142    */
143   int bulk_running;
144
145   /**
146    * Is a bulk operation running?
147    */
148   int expecting_solution;
149 };
150
151 struct Result
152 {
153   struct Result *prev;
154   struct Result *next;
155
156   int peers;
157   int addresses;
158
159   struct GNUNET_TIME_Relative d_setup;
160   struct GNUNET_TIME_Relative d_lp;
161   struct GNUNET_TIME_Relative d_mlp;
162   struct GNUNET_TIME_Relative d_total;
163
164   struct GNUNET_TIME_Absolute s_setup;
165   struct GNUNET_TIME_Absolute s_lp;
166   struct GNUNET_TIME_Absolute s_mlp;
167   struct GNUNET_TIME_Absolute s_total;
168
169   struct GNUNET_TIME_Absolute e_setup;
170   struct GNUNET_TIME_Absolute e_lp;
171   struct GNUNET_TIME_Absolute e_mlp;
172   struct GNUNET_TIME_Absolute e_total;
173 };
174
175 struct PerfPeer
176 {
177   struct GNUNET_PeerIdentity id;
178
179   struct ATS_Address *head;
180   struct ATS_Address *tail;
181 };
182
183 static struct PerfHandle ph;
184
185 /**
186  * Return value
187  */
188 static int ret;
189
190
191 /**
192  * ATS information
193  */
194 //static struct GNUNET_ATS_Information ats[2];
195
196
197 static void
198 end_now (int res)
199 {
200   if (NULL != ph.stat)
201   {
202     GNUNET_STATISTICS_destroy (ph.stat, GNUNET_NO);
203     ph.stat = NULL;
204   }
205   /*
206    if (NULL != addresses)
207    {
208    GNUNET_CONTAINER_multihashmap_iterate (addresses, &addr_it, NULL);
209    GNUNET_CONTAINER_multihashmap_destroy (addresses);
210    addresses = NULL ;
211    }*/
212   if (NULL != ph.peers)
213   {
214     GNUNET_free(ph.peers);
215   }
216
217   GAS_normalization_stop ();
218   ret = res;
219 }
220
221
222 static void
223 perf_create_peer (int cp)
224 {
225
226   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
227       &ph.peers[cp].id, sizeof (struct GNUNET_PeerIdentity));
228   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Creating peer #%u: %s \n", cp,
229       GNUNET_i2s (&ph.peers[cp].id));
230 }
231
232
233
234 static void
235 perf_update_address (struct ATS_Address *cur)
236 {
237   int r_type;
238   int r_val;
239
240   r_type = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2);
241   switch (r_type)
242   {
243   case 0:
244     r_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
245     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
246         "Updating peer `%s' address %p type %s val %u\n",
247         GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DELAY", r_val);
248     ph.env.sf.s_address_update_property (ph.solver, cur,
249         GNUNET_ATS_QUALITY_NET_DELAY,
250         r_val, (double) (100 + r_val / 100));
251     break;
252   case 1:
253     r_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 10);
254
255     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
256         "Updating peer `%s' address %p type %s val %u\n",
257         GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DISTANCE", r_val);
258     ph.env.sf.s_address_update_property (ph.solver, cur,
259         GNUNET_ATS_QUALITY_NET_DISTANCE,
260         r_val, (double) (100 + r_val) / 100);
261     break;
262   default:
263     break;
264   }
265   ph.env.sf.s_address_update_inuse (ph.solver, cur, GNUNET_YES);
266 }
267
268
269
270 static void
271 bandwidth_changed_cb (void *cls, struct ATS_Address *address)
272 {
273   if (0 == ntohl(address->assigned_bw_out.value__) &&
274       0 == ntohl(address->assigned_bw_in.value__))
275     return;
276
277   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
278       "Bandwidth changed addresses %s %p to %llu Bps out / %llu Bps in\n",
279       GNUNET_i2s (&address->peer),
280       address,
281       ntohl(address->assigned_bw_out.value__),
282       ntohl(address->assigned_bw_in.value__));
283   if (GNUNET_YES == ph.bulk_running)
284     GNUNET_break (0);
285   return;
286 }
287
288 const double *
289 get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
290 {
291   return GAS_normalization_get_preferences (id);
292 }
293
294
295 const double *
296 get_property_cb (void *cls, const struct ATS_Address *address)
297 {
298   return GAS_normalization_get_properties ((struct ATS_Address *) address);
299 }
300
301 static void
302 normalized_property_changed_cb (void *cls, struct ATS_Address *peer,
303     uint32_t type, double prop_rel)
304 {
305   /* TODO */
306 }
307
308 static void
309 perf_address_initial_update (void *solver,
310     struct GNUNET_CONTAINER_MultiPeerMap * addresses,
311     struct ATS_Address *address)
312 {
313   ph.env.sf.s_address_update_property (solver, address, GNUNET_ATS_QUALITY_NET_DELAY,
314       100,
315       (double) (100 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100))
316           / 100);
317
318   ph.env.sf.s_address_update_property (solver, address,
319       GNUNET_ATS_QUALITY_NET_DISTANCE, 10,
320       (double) (100 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100))
321           / 100);
322 }
323
324 static void
325 perf_update_all_addresses (unsigned int cp, unsigned int ca, unsigned int up_q)
326 {
327   struct ATS_Address *cur;
328   int c_peer;
329   int c_select;
330   int c_addr;
331   int r;
332
333   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
334       "Updating addresses %u addresses per peer \n", up_q);
335   unsigned int m[ca];
336
337   for (c_peer = 0; c_peer < cp; c_peer++)
338   {
339     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Updating peer `%s'\n",
340         GNUNET_i2s (&ph.peers[c_peer].id));
341     for (c_select = 0; c_select < ca; c_select++)
342       m[c_select] = 0;
343     c_select = 0;
344     while (c_select < ph.opt_update_quantity)
345     {
346       r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, ca);
347       if (0 == m[r])
348       {
349         m[r] = 1;
350         c_select++;
351       }
352     }
353
354     c_addr = 0;
355     for (cur = ph.peers[c_peer].head; NULL != cur; cur = cur->next)
356     {
357       if (1 == m[c_addr])
358         perf_update_address (cur);
359       c_addr++;
360     }
361   }
362 }
363
364
365 static struct ATS_Address *
366 perf_create_address (int cp, int ca)
367 {
368   struct ATS_Address *a;
369   a = create_address (&ph.peers[cp].id,
370       "Test 1", "test 1", strlen ("test 1") + 1, 0);
371   GNUNET_CONTAINER_DLL_insert (ph.peers[cp].head, ph.peers[cp].tail, a);
372   GNUNET_CONTAINER_multipeermap_put (ph.addresses, &ph.peers[cp].id, a,
373       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
374   return a;
375 }
376
377 static void
378 solver_info_cb (void *cls,
379     enum GAS_Solver_Operation op,
380     enum GAS_Solver_Status stat,
381     enum GAS_Solver_Additional_Information add)
382 {
383
384   struct Result *tmp;
385   switch (op)
386   {
387     case GAS_OP_SOLVE_START:
388       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
389           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_START",
390           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
391       if (GNUNET_NO == ph.expecting_solution)
392       {
393         /* We do not expect a solution at the moment */
394         GNUNET_break (0);
395         return;
396       }
397       if ((GAS_STAT_SUCCESS == stat) && (NULL == ph.current_result))
398       {
399         /* Create new result */
400         tmp = GNUNET_malloc (sizeof (struct Result));
401         ph.current_result = tmp;
402         GNUNET_CONTAINER_DLL_insert_tail(ph.head, ph.tail, tmp);
403         ph.current_result->addresses = ph.current_a;
404         ph.current_result->peers = ph.current_p;
405         ph.current_result->s_total = GNUNET_TIME_absolute_get ();
406         ph.current_result->d_total = GNUNET_TIME_relative_get_forever_ ();
407         ph.current_result->d_setup = GNUNET_TIME_relative_get_forever_ ();
408         ph.current_result->d_lp = GNUNET_TIME_relative_get_forever_ ();
409         ph.current_result->d_mlp = GNUNET_TIME_relative_get_forever_ ();
410       }
411       return;
412     case GAS_OP_SOLVE_STOP:
413       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
414           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_STOP",
415           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
416       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
417       {
418         /* We do not expect a solution at the moment */
419         GNUNET_break (0);
420         return;
421       }
422       if (NULL != ph.current_result)
423       {
424         /* Finalize result */
425         ph.current_result->e_total = GNUNET_TIME_absolute_get ();
426         ph.current_result->d_total = GNUNET_TIME_absolute_get_difference (
427             ph.current_result->s_total, ph.current_result->e_total);
428       }
429       ph.current_result = NULL;
430       return;
431
432     case GAS_OP_SOLVE_SETUP_START:
433       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
434           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_START",
435           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
436       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
437       {
438         GNUNET_break(0);
439         return;
440       }
441       ph.current_result->s_setup = GNUNET_TIME_absolute_get ();
442       return;
443
444     case GAS_OP_SOLVE_SETUP_STOP:
445       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
446           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_STOP",
447           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
448       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
449       {
450         GNUNET_break(0);
451         return;
452       }
453       ph.current_result->e_setup = GNUNET_TIME_absolute_get ();
454       ph.current_result->d_setup = GNUNET_TIME_absolute_get_difference (
455           ph.current_result->s_setup, ph.current_result->e_setup);
456       return;
457
458     case GAS_OP_SOLVE_LP_START:
459       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
460           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_START",
461           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
462       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
463       {
464         GNUNET_break(0);
465         return;
466       }
467       ph.current_result->s_lp = GNUNET_TIME_absolute_get ();
468       return;
469     case GAS_OP_SOLVE_LP_STOP:
470       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
471           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_STOP",
472           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
473       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
474       {
475         GNUNET_break(0);
476         return;
477       }
478       ph.current_result->e_lp = GNUNET_TIME_absolute_get ();
479       ph.current_result->d_lp = GNUNET_TIME_absolute_get_difference (
480           ph.current_result->s_lp, ph.current_result->e_lp);
481       return;
482
483     case GAS_OP_SOLVE_MLP_START:
484       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
485           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_START",
486           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
487       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
488       {
489         GNUNET_break(0);
490         return;
491       }
492       ph.current_result->s_mlp = GNUNET_TIME_absolute_get ();
493       return;
494     case GAS_OP_SOLVE_MLP_STOP:
495       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
496           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_STOP",
497           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
498       if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
499       {
500         GNUNET_break(0);
501         return;
502       }
503       ph.current_result->e_mlp = GNUNET_TIME_absolute_get ();
504       ph.current_result->d_mlp = GNUNET_TIME_absolute_get_difference (
505           ph.current_result->s_mlp, ph.current_result->e_mlp);
506       return;
507
508     default:
509       break;
510     }
511 }
512
513 static void
514 write_gnuplot_script (char * data_fn)
515 {
516   struct GNUNET_DISK_FileHandle *f;
517   char * gfn;
518   char *data;
519   char *template;
520
521   GNUNET_asprintf (&gfn, "perf_%s_%u_%u_%u.gnuplot", ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address);
522   f = GNUNET_DISK_file_open (gfn,
523       GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
524       GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
525   if (NULL == f)
526   {
527     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot open gnuplot file `%s'\n", gfn);
528     GNUNET_free (gfn);
529     return;
530   }
531
532   /* Write header */
533   switch (ph.ats_mode) {
534     case MODE_PROPORTIONAL:
535       template = GNUPLOT_PROP_TEMPLATE;
536       break;
537     case MODE_MLP:
538       template = GNUPLOT_MLP_TEMPLATE;
539       break;
540     case MODE_RIL:
541       template = GNUPLOT_RIL_TEMPLATE;
542       break;
543     default:
544       break;
545   }
546   if (GNUNET_SYSERR == GNUNET_DISK_file_write(f, template, strlen(template)))
547     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot write data to plot file `%s'\n", gfn);
548
549   if (MODE_PROPORTIONAL == ph.ats_mode)
550   {
551     GNUNET_asprintf (&data, "plot '%s' using 1:%u with lines title 'Total time to solve'\n" \
552                            "pause -1",
553                            data_fn, 3);
554   }
555   if (MODE_MLP == ph.ats_mode)
556   {
557     GNUNET_asprintf (&data, "plot '%s' using 1:%u with lines title 'Total time to solve',\\\n" \
558                             "'%s' using 1:%u with lines title 'Time to setup',\\\n"
559                             "'%s' using 1:%u with lines title 'Time to solve LP',\\\n"
560                             "'%s' using 1:%u with lines title 'Total time to solve MLP'\n" \
561                             "pause -1",
562                            data_fn, 3,
563                            data_fn, 4,
564                            data_fn, 5,
565                            data_fn, 6);
566   }
567   if (MODE_RIL == ph.ats_mode)
568   {
569     GNUNET_asprintf (&data, "plot '%s' using 1:%u with lines title 'Total time to solve'\n" \
570                            "pause -1",
571                            data_fn, 3);
572   }
573
574   if (GNUNET_SYSERR == GNUNET_DISK_file_write(f, data, strlen(data)))
575     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot write data to plot file `%s'\n", gfn);
576   GNUNET_free (data);
577
578   if (GNUNET_SYSERR == GNUNET_DISK_file_close(f))
579     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot close gnuplot file `%s'\n", gfn);
580   else
581     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Data successfully written to plot file `%s'\n", gfn);
582   GNUNET_free (gfn);
583
584 }
585
586
587 static void
588 evaluate ()
589 {
590   struct GNUNET_DISK_FileHandle *f;
591   char * data_fn;
592   char * data;
593   struct Result *cur;
594   struct Result *next;
595   char * str_d_total;
596   char * str_d_setup;
597   char * str_d_lp;
598   char * str_d_mlp;
599
600   if (ph.create_plot)
601   {
602     GNUNET_asprintf (&data_fn, "perf_%s_%u_%u_%u.data", ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address);
603     f = GNUNET_DISK_file_open (data_fn,
604         GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
605         GNUNET_DISK_PERM_USER_EXEC | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
606     if (NULL == f)
607     {
608       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot open gnuplot file `%s'\n", data_fn);
609       return;
610     }
611     data = "#peers;addresses;time total in us;#time setup in us;#time lp in us;#time mlp in us;\n";
612     if (GNUNET_SYSERR == GNUNET_DISK_file_write(f, data, strlen(data)))
613             GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot write data to log file `%s'\n", data_fn);
614     write_gnuplot_script (data_fn);
615   }
616
617   next = ph.head;
618   while (NULL != (cur = next))
619   {
620     next = cur->next;
621
622     /* Print log */
623     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_total.rel_value_us)
624     {
625       fprintf (stderr, "Total time to solve for %u peers %u addresses: %llu us\n",
626           cur->peers, cur->addresses, (unsigned long long )cur->d_total.rel_value_us);
627       GNUNET_asprintf(&str_d_total, "%llu", (unsigned long long )cur->d_total.rel_value_us);
628     }
629     else
630       GNUNET_asprintf(&str_d_total, "-1");
631     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_setup.rel_value_us)
632     {
633       fprintf (stderr, "Total time to setup %u peers %u addresses: %llu us\n",
634           cur->peers, cur->addresses, (unsigned long long )cur->d_setup.rel_value_us);
635       GNUNET_asprintf(&str_d_setup, "%llu", (unsigned long long )cur->d_setup.rel_value_us);
636     }
637     else
638       GNUNET_asprintf(&str_d_setup, "-1");
639     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_lp.rel_value_us)
640     {
641       fprintf (stderr, "Total time to solve LP for %u peers %u addresses: %llu us\n",
642           cur->peers, cur->addresses, (unsigned long long )cur->d_lp.rel_value_us);
643       GNUNET_asprintf(&str_d_lp, "%llu", (unsigned long long )cur->d_lp.rel_value_us);
644     }
645     else
646       GNUNET_asprintf(&str_d_lp, "-1");
647     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != cur->d_mlp.rel_value_us)
648     {
649       fprintf (stderr, "Total time to solve MLP for %u peers %u addresses: %llu us\n",
650           cur->peers, cur->addresses, (unsigned long long )cur->d_mlp.rel_value_us);
651       GNUNET_asprintf(&str_d_mlp, "%llu", (unsigned long long )cur->d_mlp.rel_value_us);
652     }
653     else
654       GNUNET_asprintf(&str_d_mlp, "-1");
655
656     if (GNUNET_YES == ph.create_plot)
657     {
658
659       GNUNET_asprintf(&data,"%u;%u;%s;%s;%s;%s\n",
660           cur->peers, cur->addresses,
661           str_d_total,
662           str_d_setup,
663           str_d_lp,
664           str_d_mlp);
665
666       if (GNUNET_SYSERR == GNUNET_DISK_file_write(f, data, strlen(data)))
667         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot write data to log file `%s'\n", data_fn);
668       GNUNET_free (str_d_total);
669       GNUNET_free (str_d_setup);
670       GNUNET_free (str_d_lp);
671       GNUNET_free (str_d_mlp);
672       GNUNET_free (data);
673     }
674     GNUNET_CONTAINER_DLL_remove (ph.head, ph.tail, cur);
675     GNUNET_free (cur);
676   }
677
678   if (GNUNET_YES == ph.create_plot)
679   {
680     if (GNUNET_SYSERR == GNUNET_DISK_file_close(f))
681       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n", data_fn);
682     GNUNET_free (data_fn);
683   }
684 }
685
686 static void
687 perf_run ()
688 {
689   struct ATS_Address *cur;
690   struct ATS_Address *next;
691   int cp;
692   int ca;
693   int count_p = ph.N_peers_end;
694   int count_a = ph.N_address;
695   struct ATS_Address * cur_addr;
696
697
698   ph.peers = GNUNET_malloc ((count_p) * sizeof (struct PerfPeer));
699
700   for (cp = 0; cp < count_p; cp++)
701     perf_create_peer (cp);
702   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
703       "Added %u peers\n", cp);
704
705   /* Set initial bulk start to not solve */
706   ph.env.sf.s_bulk_start (ph.solver);
707   ph.bulk_running = GNUNET_YES;
708
709   for (cp = 0; cp < count_p; cp++)
710   {
711     ph.current_p = cp + 1;
712     for (ca = 0; ca < count_a; ca++)
713     {
714       cur_addr = perf_create_address (cp, ca);
715       /* Add address */
716       ph.env.sf.s_add (ph.solver, cur_addr, GNUNET_ATS_NET_LAN);
717       ph.current_a = ca + 1;
718       perf_address_initial_update (ph.solver, ph.addresses, cur_addr);
719       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
720           "Adding address for peer %u address %u\n", cp, ca);
721     }
722     /* Notify solver about request */
723     ph.env.sf.s_get (ph.solver, &ph.peers[cp].id);
724
725     if (cp + 1 >= ph.N_peers_start)
726     {
727       /* Disable bulk to solve the problem */
728       if (GNUNET_YES == ph.bulk_running)
729       {
730         ph.bulk_running = GNUNET_NO;
731         ph.expecting_solution = GNUNET_YES;
732         ph.env.sf.s_bulk_stop (ph.solver);
733       }
734       else
735       {
736         GNUNET_break (0);
737       }
738
739       /* Problem is solved by the solver here due to unlocking */
740
741       ph.expecting_solution = GNUNET_NO;
742       /* Disable bulk to solve the problem */
743       if (GNUNET_NO == ph.bulk_running)
744       {
745         ph.env.sf.s_bulk_start (ph.solver);
746         ph.bulk_running = GNUNET_YES;
747       }
748 #if 0
749       if ((0 < ph.opt_update_quantity) || (0 < ph.opt_update_percent))
750       {
751         /* Update */
752         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
753             "Updating problem with %u peers and %u addresses\n", cp + 1, ca);
754         //ph.env.sf.s_bulk_start (ph.solver);
755         //update_addresses (cp + 1, ca, ph.opt_update_quantity);
756         //ph.env.sf.s_bulk_stop (ph.solver);
757       }
758 #endif
759     }
760   }
761   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
762       "Done, cleaning up addresses\n");
763   if (GNUNET_NO == ph.bulk_running)
764   {
765     ph.env.sf.s_bulk_start (ph.solver);
766     ph.bulk_running = GNUNET_YES;
767   }
768
769   for (cp = 0; cp < count_p; cp++)
770   {
771     for (cur = ph.peers[cp].head; cur != NULL ; cur = next)
772     {
773       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
774           "Deleting addresses for peer %u\n", cp);
775       GNUNET_CONTAINER_multipeermap_remove (ph.addresses, &ph.peers[cp].id, cur);
776       ph.env.sf.s_del (ph.solver, cur, GNUNET_NO);
777       next = cur->next;
778       GNUNET_CONTAINER_DLL_remove(ph.peers[cp].head, ph.peers[cp].tail, cur);
779       GNUNET_free(cur);
780     }
781
782   }
783   GNUNET_free(ph.peers);
784
785   evaluate ();
786 }
787
788
789 static void
790 run (void *cls, char * const *args, const char *cfgfile,
791     const struct GNUNET_CONFIGURATION_Handle *cfg)
792 {
793   GNUNET_log_setup ("perf-ats-solver", "WARNING", NULL);
794   char *sep;
795   char *src_filename = GNUNET_strdup (__FILE__);
796   char *test_filename = cls;
797   char *solver;
798   char *plugin;
799   unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
800   unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
801   int c;
802
803   /* Extract test name */
804   if (NULL == (sep  = (strstr (src_filename,".c"))))
805   {
806     GNUNET_break (0);
807     ret = 1;
808     return;
809   }
810   sep[0] = '\0';
811
812   if (NULL != (sep = strstr (test_filename, ".exe")))
813     sep[0] = '\0';
814
815   if (NULL == (solver = strstr (test_filename, src_filename)))
816   {
817     GNUNET_break (0);
818     ret = 1;
819     return ;
820   }
821   solver += strlen (src_filename) +1;
822
823   if (0 == strcmp(solver, "proportional"))
824   {
825     ph.ats_mode = MODE_PROPORTIONAL;
826     ph.ats_string = "proportional";
827   }
828   else if (0 == strcmp(solver, "mlp"))
829   {
830     ph.ats_mode = MODE_MLP;
831     ph.ats_string = "mlp";
832   }
833   else if ((0 == strcmp(solver, "ril")))
834   {
835     ph.ats_mode = MODE_RIL;
836     ph.ats_string = "ril";
837   }
838   else
839   {
840     GNUNET_free (src_filename);
841     GNUNET_break (0);
842     ret = 1;
843     return ;
844   }
845   GNUNET_free (src_filename);
846
847   /* Calculcate peers */
848   if ((0 == ph.N_peers_start) && (0 == ph.N_peers_end))
849   {
850     ph.N_peers_start = DEFAULT_PEERS_START;
851     ph.N_peers_end = DEFAULT_PEERS_END;
852   }
853   if (0 == ph.N_address)
854     ph.N_address = DEFAULT_ADDRESSES;
855
856   if (ph.opt_update_quantity > ph.N_address)
857   {
858     fprintf (stderr,
859         _("Trying to update more addresses than we have per peer! (%u vs %u)"),
860         ph.opt_update_quantity, ph.N_address);
861     exit (1);
862   }
863
864   if (ph.N_peers_start != ph.N_peers_end)
865     fprintf (stderr, "Benchmarking solver `%s' with %u to %u peers and %u addresses\n",
866         ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address);
867   else
868     fprintf (stderr, "Benchmarking solver `%s' with %u peers and %u addresses\n",
869         ph.ats_string, ph.N_peers_end, ph.N_address);
870
871   /* Load quotas */
872   if (GNUNET_ATS_NetworkTypeCount != load_quotas (cfg,
873       quotas_out, quotas_in, GNUNET_ATS_NetworkTypeCount))
874   {
875     GNUNET_break(0);
876     end_now (1);
877     return;
878   }
879
880   /* Load solver */
881   ph.env.cfg = cfg;
882   ph.stat = GNUNET_STATISTICS_create ("ats", cfg);
883   ph.env.stats = ph.stat;
884   ph.addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
885   ph.env.addresses = ph.addresses;
886   ph.env.bandwidth_changed_cb = bandwidth_changed_cb;
887   ph.env.get_preferences = &get_preferences_cb;
888   ph.env.get_property = &get_property_cb;
889   ph.env.network_count = GNUNET_ATS_NetworkTypeCount;
890   ph.env.info_cb = &solver_info_cb;
891   ph.env.info_cb_cls = NULL;
892
893   int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
894   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
895   {
896     ph.env.networks[c] = networks[c];
897     ph.env.out_quota[c] = quotas_out[c];
898     ph.env.in_quota[c] = quotas_in[c];
899     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loading network quotas: `%s' %llu %llu \n",
900         GNUNET_ATS_print_network_type(ph.env.networks[c]),
901         ph.env.out_quota[c],
902         ph.env.in_quota[c]);
903   }
904   GAS_normalization_start (NULL, NULL, &normalized_property_changed_cb, NULL );
905
906   GNUNET_asprintf (&plugin, "libgnunet_plugin_ats_%s", ph.ats_string);
907   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initializing solver `%s'\n"), ph.ats_string);
908   if  (NULL == (ph.solver = GNUNET_PLUGIN_load (plugin, &ph.env)))
909   {
910     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver `%s'!\n"), plugin);
911     ret = 1;
912     return;
913   }
914
915   /* Do work */
916   perf_run ();
917
918   /* Unload solver*/
919   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Unloading solver `%s'\n"), ph.ats_string);
920   GNUNET_PLUGIN_unload (plugin, ph.solver);
921   GNUNET_free (plugin);
922   ph.solver = NULL;
923 }
924
925 int
926 main (int argc, char *argv[])
927 {
928   /* extract command line arguments */
929   ph.opt_update_quantity = 0;
930   ph.opt_update_percent = 0;
931   ph.N_peers_start = 0;
932   ph.N_peers_end = 0;
933   ph.N_address = 0;
934   ph.ats_string = NULL;
935   ph.create_plot = GNUNET_NO;
936
937   static struct GNUNET_GETOPT_CommandLineOption options[] = {
938       { 'a', "addresses", NULL,
939           gettext_noop ("addresses to use"),
940           1, &GNUNET_GETOPT_set_uint, &ph.N_address },
941       { 's', "start", NULL,
942           gettext_noop ("start with peer"),
943           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_start },
944       { 'e', "end", NULL,
945           gettext_noop ("end with peer"),
946           1, &GNUNET_GETOPT_set_uint, &ph.N_peers_end },
947       { 'p', "percentage", NULL,
948           gettext_noop ("update a fix percentage of addresses"),
949           1, &GNUNET_GETOPT_set_uint, &ph.opt_update_percent },
950       { 'q', "quantity", NULL,
951           gettext_noop ("update a fix quantity of addresses"),
952           1, &GNUNET_GETOPT_set_uint, &ph.opt_update_quantity },
953       { 'g', "gnuplot", NULL,
954           gettext_noop ("create GNUplot file"),
955           0, &GNUNET_GETOPT_set_one, &ph.create_plot},
956       GNUNET_GETOPT_OPTION_END
957   };
958
959   GNUNET_PROGRAM_run (argc, argv, argv[0], NULL, options, &run, argv[0]);
960
961   return ret;
962 }
963
964 /* end of file perf_ats_solver.c */