-add multi-peer testcase for stream-based transfers (expected to fail right now)...
[oweals/gnunet.git] / src / fs / perf_gnunet_service_fs_p2p.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010, 2012 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_testbed_service.h"
29
30 #define VERBOSE GNUNET_NO
31
32 /**
33  * File-size we use for testing.
34  */
35 #define FILESIZE (1024 * 1024 * 10)
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_TESTBED_Peer *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
55 /**
56  * Master context for 'stat_run'.
57  */
58 struct StatMaster
59 {
60   struct GNUNET_STATISTICS_Handle *stat;
61   struct GNUNET_TESTBED_Operation *op;
62   unsigned int daemon;
63   unsigned int value;
64 };
65
66 struct StatValues
67 {
68   const char *subsystem;
69   const char *name;
70 };
71
72 /**
73  * Statistics we print out.
74  */
75 static struct StatValues stats[] = {
76   {"fs", "# queries forwarded"},
77   {"fs", "# replies received and matched"},
78   {"fs", "# results found locally"},
79   {"fs", "# requests forwarded due to high load"},
80   {"fs", "# requests done for free (low load)"},
81   {"fs", "# requests dropped, priority insufficient"},
82   {"fs", "# requests done for a price (normal load)"},
83   {"fs", "# requests dropped by datastore (queue length limit)"},
84   {"fs", "# P2P searches received"},
85   {"fs", "# P2P searches discarded (queue length bound)"},
86   {"fs", "# replies received for local clients"},
87   {"fs", "# queries retransmitted to same target"},
88   {"core", "# bytes decrypted"},
89   {"core", "# bytes encrypted"},
90   {"core", "# discarded CORE_SEND requests"},
91   {"core", "# discarded CORE_SEND request bytes"},
92   {"core", "# discarded lower priority CORE_SEND requests"},
93   {"core", "# discarded lower priority CORE_SEND request bytes"},
94   {"transport", "# bytes received via TCP"},
95   {"transport", "# bytes transmitted via TCP"},
96   {"datacache", "# bytes stored"},
97   {NULL, NULL}
98 };
99
100
101 /**
102  * Callback function to process statistic values.
103  *
104  * @param cls closure
105  * @param subsystem name of subsystem that created the statistic
106  * @param name the name of the datum
107  * @param value the current value
108  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
109  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
110  */
111 static int
112 print_stat (void *cls, const char *subsystem, const char *name, uint64_t value,
113             int is_persistent)
114 {
115   struct StatMaster *sm = cls;
116
117   FPRINTF (stderr, "Peer %2u: %12s/%50s = %12llu\n", sm->daemon, subsystem,
118            name, (unsigned long long) value);
119   return GNUNET_OK;
120 }
121
122
123 /**
124  * Function that gathers stats from all daemons.
125  */
126 static void
127 stat_run (void *cls, 
128           struct GNUNET_TESTBED_Operation *op,
129           void *ca_result,
130           const char *emsg);
131
132
133 /**
134  * Function called when GET operation on stats is done.
135  */
136 static void
137 get_done (void *cls, int success)
138 {
139   struct StatMaster *sm = cls;
140
141   GNUNET_break (GNUNET_OK == success);
142   sm->value++;
143   stat_run (sm, sm->op, sm->stat, NULL);
144 }
145
146
147 /**
148  * Adapter function called to establish a connection to
149  * statistics service.
150  * 
151  * @param cls closure
152  * @param cfg configuration of the peer to connect to; will be available until
153  *          GNUNET_TESTBED_operation_done() is called on the operation returned
154  *          from GNUNET_TESTBED_service_connect()
155  * @return service handle to return in 'op_result', NULL on error
156  */
157 static void *
158 statistics_connect_adapter (void *cls,
159                             const struct GNUNET_CONFIGURATION_Handle *cfg)
160 {
161   return GNUNET_STATISTICS_create ("<driver>",
162                                    cfg);
163 }
164
165
166 /**
167  * Adapter function called to destroy a connection to
168  * statistics service.
169  * 
170  * @param cls closure
171  * @param op_result service handle returned from the connect adapter
172  */
173 static void 
174 statistics_disconnect_adapter (void *cls,
175                                void *op_result)
176 {
177   GNUNET_STATISTICS_destroy (op_result, GNUNET_NO);
178 }
179
180
181 /**
182  * Function that gathers stats from all daemons.
183  */
184 static void
185 stat_run (void *cls, 
186           struct GNUNET_TESTBED_Operation *op,
187           void *ca_result,
188           const char *emsg)
189 {
190   struct StatMaster *sm = cls;
191
192   if (NULL != emsg)
193     {
194       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
195                   "Failed to statistics service: %s\n",
196                   emsg);
197       GNUNET_SCHEDULER_shutdown ();
198       return;
199     }
200   sm->stat = ca_result;
201
202   if (stats[sm->value].name != NULL)
203   {
204     GNUNET_STATISTICS_get (sm->stat,
205 #if 0
206                            NULL, NULL,
207 #else
208                            stats[sm->value].subsystem, stats[sm->value].name,
209 #endif
210                            GNUNET_TIME_UNIT_FOREVER_REL, &get_done, &print_stat,
211                            sm);
212     return;
213   }
214   GNUNET_TESTBED_operation_done (sm->op);
215   sm->value = 0;
216   sm->daemon++;
217   if (NUM_DAEMONS == sm->daemon)
218   {
219     GNUNET_free (sm);
220     GNUNET_SCHEDULER_shutdown ();
221     return;
222   }
223   sm->op =
224     GNUNET_TESTBED_service_connect (NULL,
225                                     daemons[sm->daemon],
226                                     "statistics",
227                                     &stat_run, sm,
228                                     &statistics_connect_adapter,
229                                     &statistics_disconnect_adapter,
230                                     NULL);
231 }
232
233
234 static void
235 do_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
236 {
237   struct GNUNET_TIME_Relative del;
238   char *fancy;
239   struct StatMaster *sm;
240
241   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) 
242   {
243     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
244                 "Timeout during download, shutting down with error\n");
245     ok = 1;
246     GNUNET_SCHEDULER_shutdown ();
247     return;
248   }
249   del = GNUNET_TIME_absolute_get_duration (start_time);
250   if (del.rel_value == 0)
251     del.rel_value = 1;
252   fancy =
253     GNUNET_STRINGS_byte_size_fancy (((unsigned long long) FILESIZE) *
254                                     1000LL / del.rel_value);
255   FPRINTF (stdout, "Download speed was %s/s\n", fancy);
256   GNUNET_free (fancy);
257   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished download, shutting down\n",
258               (unsigned long long) FILESIZE);
259   sm = GNUNET_malloc (sizeof (struct StatMaster));
260   sm->op =
261     GNUNET_TESTBED_service_connect (NULL,
262                                     daemons[sm->daemon],
263                                     "statistics",
264                                     &stat_run, sm,
265                                     &statistics_connect_adapter,
266                                     &statistics_disconnect_adapter,
267                                     NULL);
268 }
269
270
271 static void
272 do_download (void *cls, const struct GNUNET_FS_Uri *uri)
273 {
274   int anonymity;
275
276   if (NULL == uri)
277     {
278     GNUNET_SCHEDULER_shutdown ();
279     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
280                 "Timeout during upload attempt, shutting down with error\n");
281     ok = 1;
282     return;
283   }
284   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Downloading %llu bytes\n",
285               (unsigned long long) FILESIZE);
286   start_time = GNUNET_TIME_absolute_get ();
287   if (NULL != strstr (progname, "dht"))
288     anonymity = 0;
289   else
290     anonymity = 1;
291   GNUNET_FS_TEST_download (daemons[0], TIMEOUT, anonymity, SEED, uri, VERBOSE,
292                            &do_report, NULL);
293 }
294
295
296 static void
297 do_publish (void *cls, 
298             unsigned int num_peers,
299             struct GNUNET_TESTBED_Peer **peers)
300 {
301   unsigned int i;
302   int do_index;
303   int anonymity;
304  
305   GNUNET_assert (NUM_DAEMONS == num_peers);
306   for (i=0;i<num_peers;i++)
307     daemons[i] = peers[i];
308   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n",
309               (unsigned long long) FILESIZE);
310   if (NULL != strstr (progname, "index"))
311     do_index = GNUNET_YES;
312   else
313     do_index = GNUNET_NO;
314   if (NULL != strstr (progname, "dht"))
315     anonymity = 0;
316   else
317     anonymity = 1;
318   GNUNET_FS_TEST_publish (daemons[NUM_DAEMONS - 1], TIMEOUT, anonymity,
319                           do_index, FILESIZE, SEED, VERBOSE, &do_download,
320                           NULL);
321 }
322
323
324 int
325 main (int argc, char *argv[])
326 {
327   progname = argv[0];
328   GNUNET_TESTBED_test_run ("perf-gnunet-service-fs-p2p",
329                            "perf_gnunet_service_fs_p2p.conf",
330                            NUM_DAEMONS,
331                            0, NULL, NULL,
332                            &do_publish, NULL);
333   GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/");
334   return ok;
335 }
336
337 /* end of perf_gnunet_service_fs_p2p.c */