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