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