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