-try using gauger for memory measurements
[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 * 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_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, const char *subsystem, const char *name, uint64_t value,
119             int is_persistent)
120 {
121   struct StatMaster *sm = cls;
122
123   FPRINTF (stderr, "Peer %2u: %12s/%50s = %12llu\n", sm->daemon, subsystem,
124            name, (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, const struct GNUNET_SCHEDULER_TaskContext *tc);
134
135
136 /**
137  * Function called when GET operation on stats is done.
138  */
139 static void
140 get_done (void *cls, int success)
141 {
142   struct StatMaster *sm = cls;
143
144   GNUNET_break (GNUNET_OK == success);
145   sm->value++;
146   GNUNET_SCHEDULER_add_now (&stat_run, sm);
147 }
148
149
150 /**
151  * Function that gathers stats from all daemons.
152  */
153 static void
154 stat_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
155 {
156   struct StatMaster *sm = cls;
157
158   if (stats[sm->value].name != NULL)
159   {
160     GNUNET_STATISTICS_get (sm->stat,
161 #if 0
162                            NULL, NULL,
163 #else
164                            stats[sm->value].subsystem, stats[sm->value].name,
165 #endif
166                            GNUNET_TIME_UNIT_FOREVER_REL, &get_done, &print_stat,
167                            sm);
168     return;
169   }
170   GNUNET_STATISTICS_destroy (sm->stat, GNUNET_NO);
171   sm->value = 0;
172   sm->daemon++;
173   if (sm->daemon == NUM_DAEMONS)
174   {
175     GNUNET_free (sm);
176     GNUNET_SCHEDULER_add_now (&do_stop, NULL);
177     return;
178   }
179   sm->stat =
180       GNUNET_STATISTICS_create ("<driver>",
181                                 GNUNET_FS_TEST_get_configuration (daemons,
182                                                                   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_TIMEOUT))
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, "Finished download, shutting down\n",
205                 (unsigned long long) FILESIZE);
206     sm = GNUNET_malloc (sizeof (struct StatMaster));
207     sm->stat =
208         GNUNET_STATISTICS_create ("<driver>",
209                                   GNUNET_FS_TEST_get_configuration (daemons,
210                                                                     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, "Downloading %llu bytes\n",
237               (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], TIMEOUT, anonymity, SEED, uri, VERBOSE,
244                            &do_report, NULL);
245 }
246
247
248 static void
249 do_publish (void *cls, const char *emsg)
250 {
251   int do_index;
252   int anonymity;
253
254   if (NULL != emsg)
255   {
256     GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons);
257     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error trying to connect: %s\n", emsg);
258     ok = 1;
259     return;
260   }
261   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n",
262               (unsigned long long) FILESIZE);
263   if (NULL != strstr (progname, "index"))
264     do_index = GNUNET_YES;
265   else
266     do_index = GNUNET_NO;
267   if (NULL != strstr (progname, "dht"))
268     anonymity = 0;
269   else
270     anonymity = 1;
271
272   GNUNET_FS_TEST_publish (daemons[NUM_DAEMONS - 1], TIMEOUT, anonymity,
273                           do_index, FILESIZE, SEED, VERBOSE, &do_download,
274                           NULL);
275 }
276
277
278 static void
279 do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
280 {
281   struct GNUNET_TESTING_PeerGroup *pg;
282
283   GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE));
284   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
285               "Daemons started, will now try to connect them\n");
286   pg = GNUNET_FS_TEST_get_group (daemons);
287   GNUNET_break ((NUM_DAEMONS - 1) * 2 ==
288                 (GNUNET_TESTING_create_topology
289                  (pg, GNUNET_TESTING_TOPOLOGY_LINE,
290                   GNUNET_TESTING_TOPOLOGY_NONE, NULL)));
291   GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_LINE,
292                                    GNUNET_TESTING_TOPOLOGY_OPTION_NONE, 0.0,
293                                    TIMEOUT, NUM_DAEMONS, &do_publish, NULL);
294 }
295
296
297 static void
298 run (void *cls, char *const *args, const char *cfgfile,
299      const struct GNUNET_CONFIGURATION_Handle *cfg)
300 {
301   GNUNET_FS_TEST_daemons_start ("perf_gnunet_service_fs_p2p.conf", TIMEOUT, NUM_DAEMONS,
302                                 daemons, &do_connect, NULL);
303 }
304
305
306 int
307 main (int argc, char *argv[])
308 {
309   char *const argvx[] = {
310     "perf-gnunet-service-fs-p2p",
311     "-c",
312     "perf_gnunet_service_fs_p2p.conf",
313     NULL
314   };
315   struct GNUNET_GETOPT_CommandLineOption options[] = {
316     GNUNET_GETOPT_OPTION_END
317   };
318   progname = argv[0];
319   GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/");
320   GNUNET_log_setup ("perf_gnunet_service_fs_p2p_index",
321                     "WARNING",
322                     NULL);
323   GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx,
324                       "perf-gnunet-service-fs-p2p-index", "nohelp", options,
325                       &run, NULL);
326   GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/");
327   return ok;
328 }
329
330 /* end of perf_gnunet_service_fs_p2p.c */