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