(no commit message)
[oweals/gnunet.git] / src / fs / perf_gnunet_service_fs_p2p.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010 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 /**
22  * @file fs/perf_gnunet_service_fs_p2p.c
23  * @brief profile P2P routing using simple publish + download operation
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "fs_test_lib.h"
28 #include "gnunet_testing_lib.h"
29
30 #define VERBOSE GNUNET_NO
31
32 /**
33  * File-size we use for testing.
34  */
35 #define FILESIZE (1024 * 1024 * 1)
36
37 /**
38  * How long until we give up on transmitting the message?
39  */
40 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
41
42 #define NUM_DAEMONS 2
43
44 #define SEED 42
45
46 static struct GNUNET_FS_TestDaemon *daemons[NUM_DAEMONS];
47
48 static int ok;
49
50 static struct GNUNET_TIME_Absolute start_time;
51
52 static const char *progname;
53
54 static void
55 do_stop (void *cls,
56          const struct GNUNET_SCHEDULER_TaskContext *tc)
57 {
58   GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS,
59                                daemons);
60 }
61
62
63 /**
64  * Master context for 'stat_run'.
65  */
66 struct StatMaster
67 {
68   struct GNUNET_STATISTICS_Handle *stat;  
69   unsigned int daemon;
70   unsigned int value;
71 };
72
73 struct StatValues
74 {
75   const char *subsystem;
76   const char *name;
77 };
78
79 /**
80  * Statistics we print out.
81  */
82 static struct StatValues stats[] =
83   {
84     { "fs", "# queries forwarded"},
85     { "fs", "# replies received and matched"},
86     { "fs", "# results found locally"},
87     { "fs", "# requests forwarded due to high load"},
88     { "fs", "# requests done for free (low load)"},
89     { "fs", "# requests dropped, priority insufficient"},
90     { "fs", "# requests done for a price (normal load)"},
91     { "fs", "# requests dropped by datastore (queue length limit)"},
92     { "fs", "# P2P searches received"},
93     { "fs", "# P2P searches discarded (queue length bound)"},
94     { "fs", "# replies received for local clients"},
95     { "fs", "# queries retransmitted to same target"},
96     { "fs", "cummulative artificial delay introduced (ms)"},
97     { "core", "# bytes decrypted"},
98     { "core", "# bytes encrypted"},
99     { "core", "# discarded CORE_SEND requests"},
100     { "core", "# discarded CORE_SEND request bytes"},
101     { "core", "# discarded lower priority CORE_SEND requests"},
102     { "core", "# discarded lower priority CORE_SEND request bytes"},
103     { "transport", "# bytes received via TCP"},
104     { "transport", "# bytes transmitted via TCP"},
105     { "datacache", "# bytes stored"},
106     { NULL, NULL}
107   };
108
109
110 /**
111  * Callback function to process statistic values.
112  *
113  * @param cls closure
114  * @param subsystem name of subsystem that created the statistic
115  * @param name the name of the datum
116  * @param value the current value
117  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
118  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
119  */
120 static int
121 print_stat (void *cls,
122             const char *subsystem,
123             const char *name,
124             uint64_t value,
125             int is_persistent)
126 {
127   struct StatMaster *sm = cls;
128   fprintf (stderr,
129            "Peer %2u: %12s/%50s = %12llu\n",
130            sm->daemon,
131            subsystem,
132            name,
133            (unsigned long long) value);
134   return GNUNET_OK;
135 }
136
137
138 /**
139  * Function that gathers stats from all daemons.
140  */
141 static void
142 stat_run (void *cls,
143           const struct GNUNET_SCHEDULER_TaskContext *tc);
144
145
146 /**
147  * Function called when GET operation on stats is done.
148  */
149 static void
150 get_done (void *cls,
151           int success)
152 {
153   struct StatMaster *sm = cls;
154   GNUNET_break (GNUNET_OK ==  success);
155   sm->value++;
156   GNUNET_SCHEDULER_add_now (&stat_run, sm);
157 }
158
159
160 /**
161  * Function that gathers stats from all daemons.
162  */
163 static void
164 stat_run (void *cls,
165           const struct GNUNET_SCHEDULER_TaskContext *tc)
166 {
167   struct StatMaster *sm = cls;
168  
169   if (stats[sm->value].name != NULL)
170     {
171       GNUNET_STATISTICS_get (sm->stat,
172 #if 0
173                              NULL, NULL, 
174 #else
175                              stats[sm->value].subsystem,
176                              stats[sm->value].name,
177 #endif
178                              GNUNET_TIME_UNIT_FOREVER_REL,
179                              &get_done,
180                              &print_stat, sm);
181       return;
182     }
183   GNUNET_STATISTICS_destroy (sm->stat, GNUNET_NO);
184   sm->value = 0;
185   sm->daemon++;
186   if (sm->daemon == NUM_DAEMONS)
187     {
188       GNUNET_free (sm);
189       GNUNET_SCHEDULER_add_now (&do_stop, NULL);
190       return;
191     }
192   sm->stat = GNUNET_STATISTICS_create ("<driver>",
193                                        GNUNET_FS_TEST_get_configuration (daemons,
194                                                                          sm->daemon));
195   GNUNET_SCHEDULER_add_now (&stat_run, sm);
196 }
197
198
199 static void
200 do_report (void *cls,
201          const struct GNUNET_SCHEDULER_TaskContext *tc)
202 {
203   struct GNUNET_TIME_Relative del;
204   char *fancy; 
205   struct StatMaster *sm;
206   
207   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE))
208     {
209       del = GNUNET_TIME_absolute_get_duration (start_time);
210       if (del.rel_value == 0)
211         del.rel_value = 1;
212       fancy = GNUNET_STRINGS_byte_size_fancy (((unsigned long long)FILESIZE) * 1000LL / del.rel_value);
213       fprintf (stdout,
214                "Download speed was %s/s\n",
215                fancy);
216       GNUNET_free (fancy);
217       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
218                   "Finished download, shutting down\n",
219                   (unsigned long long) FILESIZE);
220       sm = GNUNET_malloc (sizeof (struct StatMaster));
221       sm->stat = GNUNET_STATISTICS_create ("<driver>",
222                                            GNUNET_FS_TEST_get_configuration (daemons,
223                                                                              sm->daemon));
224       GNUNET_SCHEDULER_add_now (&stat_run, sm);
225     }
226   else
227     {
228       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
229                   "Timeout during download, shutting down with error\n");
230       ok = 1;
231       GNUNET_SCHEDULER_add_now (&do_stop, NULL);
232     }
233 }
234
235
236 static void
237 do_download (void *cls,
238              const struct GNUNET_FS_Uri *uri)
239 {
240   int anonymity;
241
242   if (NULL == uri)
243     {
244       GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS,
245                                    daemons);
246       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
247                   "Timeout during upload attempt, shutting down with error\n");
248       ok = 1;
249       return;
250     }
251   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
252               "Downloading %llu bytes\n",
253               (unsigned long long) FILESIZE);
254   start_time = GNUNET_TIME_absolute_get ();
255   if (NULL != strstr (progname, "dht"))
256     anonymity = 0;
257   else
258     anonymity = 1;
259   GNUNET_FS_TEST_download (daemons[0],
260                            TIMEOUT,
261                            anonymity, SEED, uri, 
262                            VERBOSE, 
263                            &do_report, NULL);
264 }
265
266
267 static void
268 do_publish (void *cls,
269             const char *emsg)
270 {
271   int do_index;
272   int anonymity;
273
274   if (NULL != emsg)
275     {
276       GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS,
277                                    daemons);
278       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
279                   "Error trying to connect: %s\n",
280                   emsg);
281       ok = 1;
282       return;
283     }
284   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
285               "Publishing %llu bytes\n",
286               (unsigned long long) FILESIZE);
287   if (NULL != strstr (progname, "index"))
288     do_index = GNUNET_YES;
289   else
290     do_index = GNUNET_NO;
291   if (NULL != strstr (progname, "dht"))
292     anonymity = 0;
293   else
294     anonymity = 1;
295   
296   GNUNET_FS_TEST_publish (daemons[NUM_DAEMONS-1],
297                           TIMEOUT,
298                           anonymity, 
299                           do_index, FILESIZE, SEED, 
300                           VERBOSE, 
301                           &do_download, NULL);
302 }
303
304
305 static void
306 do_connect (void *cls,
307             const struct GNUNET_SCHEDULER_TaskContext *tc)
308 {
309   struct GNUNET_TESTING_PeerGroup *pg;
310
311   GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE));
312   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
313               "Daemons started, will now try to connect them\n");
314   pg = GNUNET_FS_TEST_get_group (daemons);
315   GNUNET_break ( (NUM_DAEMONS - 1) * 2
316                  == (GNUNET_TESTING_create_topology (pg, 
317                                                      GNUNET_TESTING_TOPOLOGY_LINE,
318                                                      GNUNET_TESTING_TOPOLOGY_NONE,
319                                                      NULL)));
320   GNUNET_TESTING_connect_topology (pg,
321                                    GNUNET_TESTING_TOPOLOGY_LINE,                                   
322                                    GNUNET_TESTING_TOPOLOGY_OPTION_NONE,
323                                    0.0,
324                                    &do_publish,
325                                    NULL);
326 }
327
328
329 static void
330 run (void *cls,
331      char *const *args,
332      const char *cfgfile,
333      const struct GNUNET_CONFIGURATION_Handle *cfg)
334 {
335   GNUNET_FS_TEST_daemons_start ("fs_test_lib_data.conf",
336                                 TIMEOUT,
337                                 NUM_DAEMONS,
338                                 daemons,
339                                 &do_connect,
340                                 NULL);
341 }
342
343
344 int
345 main (int argc, char *argv[])
346 {
347   char *const argvx[] = { 
348     "perf-gnunet-service-fs-p2p",
349     "-c",
350     "fs_test_lib_data.conf",
351 #if VERBOSE
352     "-L", "DEBUG",
353 #endif
354     NULL
355   };
356   struct GNUNET_GETOPT_CommandLineOption options[] = {
357     GNUNET_GETOPT_OPTION_END
358   };
359   progname = argv[0];
360   GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/");
361   GNUNET_log_setup ("perf_gnunet_service_fs_p2p_index", 
362 #if VERBOSE
363                     "DEBUG",
364 #else
365                     "WARNING",
366 #endif
367                     NULL);
368   GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1,
369                       argvx, "perf-gnunet-service-fs-p2p-index",
370                       "nohelp", options, &run, NULL);
371   GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/");
372   return ok;
373 }
374
375 /* end of perf_gnunet_service_fs_p2p_index.c */