-add info about traffic
[oweals/gnunet.git] / src / mesh / mesh_profiler.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011 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  * @file mesh/mesh_profiler.c
22  *
23  * @brief Profiler for mesh experiments.
24  */
25 #include <stdio.h>
26 #include "platform.h"
27 #include "mesh_test_lib.h"
28 #include "gnunet_mesh_service.h"
29 #include "gnunet_statistics_service.h"
30
31
32 /**
33  * How namy messages to send
34  */
35 #define TOTAL_PACKETS 1000
36
37 /**
38  * How namy peers to run
39  */
40 #define TOTAL_PEERS 1000
41
42 /**
43  * How long until we give up on connecting the peers?
44  */
45 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
46
47 /**
48  * Time to wait for stuff that should be rather fast
49  */
50 #define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
51
52
53 struct MeshPeer
54 {
55   /**
56    * Testbed Operation (to get peer id, etc).
57    */
58   struct GNUNET_TESTBED_Operation *op;
59
60   /**
61    * Peer ID.
62    */
63   struct GNUNET_PeerIdentity id;
64
65   /**
66    * Mesh handle for the root peer
67    */
68   struct GNUNET_MESH_Handle *mesh;
69
70   /**
71    * Channel handle for the root peer
72    */
73   struct GNUNET_MESH_Channel *ch;
74
75   /**
76    * Channel handle for the dest peer
77    */
78   struct GNUNET_MESH_Channel *incoming_ch;
79
80   /**
81    * Number of payload packes sent
82    */
83   int data_sent;
84
85   /**
86    * Number of payload packets received
87    */
88   int data_received;
89
90   unsigned int dest;
91   GNUNET_SCHEDULER_TaskIdentifier ping_task;
92 };
93
94 /**
95  * Testbed peer handles.
96  */
97 struct GNUNET_TESTBED_Peer **testbed_handles;
98
99 /**
100  * Testbed Operation (to get stats).
101  */
102 struct GNUNET_TESTBED_Operation *stats_op;
103
104 /**
105  * How many events have happened
106  */
107 static int ok;
108
109 /**
110  * Number of events expected to conclude the test successfully.
111  */
112 int ok_goal;
113
114 /**
115  * Size of each test packet
116  */
117 size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t);
118
119 /**
120  * Operation to get peer ids.
121  */
122 struct MeshPeer peers[TOTAL_PEERS];
123
124 /**
125  * Peer ids counter.
126  */
127 unsigned int p_ids;
128
129 /**
130  * Is the setup initialized?
131  */
132 static int initialized;
133
134 /**
135  * Total number of currently running peers.
136  */
137 static unsigned long long peers_running;
138
139 /**
140  * Test context (to shut down).
141  */
142 struct GNUNET_MESH_TEST_Context *test_ctx;
143
144 /**
145  * Task called to shutdown test.
146  */
147 static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle;
148
149 /**
150  * Task called to disconnect peers, before shutdown.
151  */
152 static GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
153
154 /**
155  * Task to perform tests
156  */
157 static GNUNET_SCHEDULER_TaskIdentifier test_task;
158
159 /**
160  * Time we started the data transmission (after channel has been established
161  * and initilized).
162  */
163 static struct GNUNET_TIME_Absolute start_time;
164
165 /**
166  *
167  */
168 static unsigned int ka_sent;
169 static unsigned int ka_received;
170
171 /**
172  * Calculate a random delay.
173  *
174  * @param max Exclusive maximum, in ms.
175  *
176  * @return A time between 0 a max-1 ms.
177  */
178 static struct GNUNET_TIME_Relative
179 delay_ms_rnd (unsigned int max)
180 {
181   unsigned int rnd;
182
183   rnd = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, max);
184   return GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, rnd);
185 }
186
187
188 /**
189  * Get the index of a peer in the peers array.
190  *
191  * @param peer Peer whose index to get.
192  *
193  * @return Index of peer in peers.
194  */
195 static unsigned int
196 get_index (struct MeshPeer *peer)
197 {
198   return peer - peers;
199 }
200
201
202 /**
203  * Show the results of the test (banwidth acheived) and log them to GAUGER
204  */
205 static void
206 show_end_data (void)
207 {
208   static struct GNUNET_TIME_Absolute end_time;
209   static struct GNUNET_TIME_Relative total_time;
210
211   end_time = GNUNET_TIME_absolute_get();
212   total_time = GNUNET_TIME_absolute_get_difference(start_time, end_time);
213   FPRINTF (stderr, "Test time %s\n",
214            GNUNET_STRINGS_relative_time_to_string (total_time,
215                                                    GNUNET_YES));
216   FPRINTF (stderr, "Test bandwidth: %f kb/s\n",
217            4 * TOTAL_PACKETS * 1.0 / (total_time.rel_value_us / 1000)); // 4bytes * ms
218   FPRINTF (stderr, "Test throughput: %f packets/s\n\n",
219            TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000)); // packets * ms
220 }
221
222
223 /**
224  * Shut down peergroup, clean up.
225  *
226  * @param cls Closure (unused).
227  * @param tc Task Context.
228  */
229 static void
230 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
231 {
232   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
233   shutdown_handle = GNUNET_SCHEDULER_NO_TASK;
234 }
235
236
237 /**
238  * Disconnect from mesh services af all peers, call shutdown.
239  *
240  * @param cls Closure (unused).
241  * @param tc Task Context.
242  */
243 static void
244 disconnect_mesh_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
245 {
246   long line = (long) cls;
247   unsigned int i;
248
249   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
250               "disconnecting mesh service of peers, called from line %ld\n",
251               line);
252   disconnect_task = GNUNET_SCHEDULER_NO_TASK;
253   for (i = 0; i < TOTAL_PEERS; i++)
254   {
255     GNUNET_TESTBED_operation_done (peers[i].op);
256     GNUNET_MESH_channel_destroy (peers[i].ch);
257     GNUNET_MESH_channel_destroy (peers[i].incoming_ch);
258   }
259   GNUNET_MESH_TEST_cleanup (test_ctx);
260   if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle)
261   {
262     GNUNET_SCHEDULER_cancel (shutdown_handle);
263   }
264   shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
265 }
266
267
268 /**
269  * Abort test: schedule disconnect and shutdown immediately
270  *
271  * @param line Line in the code the abort is requested from (__LINE__).
272  */
273 static void
274 abort_test (long line)
275 {
276   if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
277   {
278     GNUNET_SCHEDULER_cancel (disconnect_task);
279     disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_mesh_peers,
280                                                 (void *) line);
281   }
282 }
283
284
285 /**
286  * Stats callback. Finish the stats testbed operation and when all stats have
287  * been iterated, shutdown the test.
288  *
289  * @param cls closure
290  * @param op the operation that has been finished
291  * @param emsg error message in case the operation has failed; will be NULL if
292  *          operation has executed successfully.
293  */
294 static void
295 stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
296 {
297   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "... collecting statistics done.\n");
298   GNUNET_TESTBED_operation_done (stats_op);
299
300   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
301     GNUNET_SCHEDULER_cancel (disconnect_task);
302   disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_mesh_peers,
303                                               (void *) __LINE__);
304
305 }
306
307
308 /**
309  * Process statistic values.
310  *
311  * @param cls closure
312  * @param peer the peer the statistic belong to
313  * @param subsystem name of subsystem that created the statistic
314  * @param name the name of the datum
315  * @param value the current value
316  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
317  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
318  */
319 static int
320 stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer,
321                 const char *subsystem, const char *name,
322                 uint64_t value, int is_persistent)
323 {
324   static const char *s_sent = "# keepalives sent";
325   static const char *s_recv = "# keepalives received";
326   uint32_t i;
327
328   i = GNUNET_TESTBED_get_index (peer);
329   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  %u - %s [%s]: %llu\n",
330               i, subsystem, name, value);
331   if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i)
332     ka_sent = value;
333
334   if (0 == strncmp(s_recv, name, strlen (s_recv)) && 4 == i)
335   {
336     ka_received = value;
337     GNUNET_log (GNUNET_ERROR_TYPE_INFO, " sent: %u, received: %u\n",
338                 ka_sent, ka_received);
339     if (ka_sent < 2 || ka_sent > ka_received + 1)
340       ok--;
341   }
342
343   return GNUNET_OK;
344 }
345
346
347 /**
348  * Task check that keepalives were sent and received.
349  *
350  * @param cls Closure (NULL).
351  * @param tc Task Context.
352  */
353 static void
354 collect_stats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
355 {
356   if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
357     return;
358
359   disconnect_task = GNUNET_SCHEDULER_NO_TASK;
360   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start collecting statistics...\n");
361   stats_op = GNUNET_TESTBED_get_statistics (TOTAL_PEERS, testbed_handles,
362                                             NULL, NULL,
363                                             stats_iterator, stats_cont, NULL);
364 }
365
366
367 /**
368  * Transmit ready callback.
369  *
370  * @param cls Closure (peer).
371  * @param size Size of the tranmist buffer.
372  * @param buf Pointer to the beginning of the buffer.
373  *
374  * @return Number of bytes written to buf.
375  */
376 static size_t
377 tmt_rdy (void *cls, size_t size, void *buf);
378
379
380 /**
381  * Task to schedule a new data transmission.
382  *
383  * @param cls Closure (peer).
384  * @param tc Task Context.
385  */
386 static void
387 data_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
388 {
389   struct MeshPeer *peer = (struct MeshPeer *) cls;
390   struct GNUNET_MESH_TransmitHandle *th;
391   struct GNUNET_MESH_Channel *channel;
392
393   if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
394     return;
395
396   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data task\n");
397
398   channel = peer->ch;
399   th = GNUNET_MESH_notify_transmit_ready (channel, GNUNET_NO,
400                                           GNUNET_TIME_UNIT_FOREVER_REL,
401                                           size_payload, &tmt_rdy, peer);
402   if (NULL == th)
403     GNUNET_abort ();
404 }
405
406
407 /**
408  * Transmit ready callback
409  *
410  * @param cls Closure (peer).
411  * @param size Size of the buffer we have.
412  * @param buf Buffer to copy data to.
413  */
414 size_t
415 tmt_rdy (void *cls, size_t size, void *buf)
416 {
417   struct MeshPeer *peer = (struct MeshPeer *) cls;
418   struct GNUNET_MessageHeader *msg = buf;
419   uint32_t *data;
420
421   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tmt_rdy called, filling buffer\n");
422   if (size < size_payload || NULL == buf)
423   {
424     GNUNET_break (ok >= ok_goal - 2);
425     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
426                 "size %u, buf %p, data_sent %u, data_received %u\n",
427                 size, buf, peer->data_sent, peer->data_received);
428     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ok %u, ok goal %u\n", ok, ok_goal);
429
430     return 0;
431   }
432   msg->size = htons (size);
433   msg->type = htons ((long) cls);
434   data = (uint32_t *) &msg[1];
435   *data = htonl (peer->data_sent);
436   if (GNUNET_NO == initialized)
437   {
438     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
439                 "sending initializer\n");
440   }
441   else
442   {
443     peer->data_sent++;
444     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
445               " Sent packet %d\n", peer->data_sent);
446     if (peer->data_sent < TOTAL_PACKETS)
447     {
448       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
449               " Scheduling packet %d\n", peer->data_sent + 1);
450       GNUNET_SCHEDULER_add_now (&data_task, peer);
451     }
452   }
453
454   return size_payload;
455 }
456
457
458 /**
459  * Function is called whenever a message is received.
460  *
461  * @param cls closure (set from GNUNET_MESH_connect)
462  * @param channel connection to the other end
463  * @param channel_ctx place to store local state associated with the channel
464  * @param message the actual message
465  * @return GNUNET_OK to keep the connection open,
466  *         GNUNET_SYSERR to close it (signal serious error)
467  */
468 int
469 data_callback (void *cls, struct GNUNET_MESH_Channel *channel,
470                void **channel_ctx,
471                const struct GNUNET_MessageHeader *message)
472 {
473 //   long n = (long) cls;
474
475   GNUNET_MESH_receive_done (channel);
476
477
478   if (GNUNET_NO == initialized)
479   {
480     initialized = GNUNET_YES;
481     start_time = GNUNET_TIME_absolute_get ();
482     GNUNET_SCHEDULER_add_now (&data_task, NULL);
483   }
484   GNUNET_MESH_notify_transmit_ready (channel, GNUNET_NO,
485                                      GNUNET_TIME_UNIT_FOREVER_REL,
486                                      size_payload, &tmt_rdy, (void *) 1L);
487
488   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
489   {
490     GNUNET_SCHEDULER_cancel (disconnect_task);
491     disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
492                                                     &disconnect_mesh_peers,
493                                                     (void *) __LINE__);
494   }
495
496   return GNUNET_OK;
497 }
498
499
500 /**
501  * Handlers, for diverse services
502  */
503 static struct GNUNET_MESH_MessageHandler handlers[] = {
504   {&data_callback, 1, sizeof (struct GNUNET_MessageHeader)},
505   {NULL, 0, 0}
506 };
507
508
509 /**
510  * Method called whenever another peer has added us to a channel
511  * the other peer initiated.
512  *
513  * @param cls Closure.
514  * @param channel New handle to the channel.
515  * @param initiator Peer that started the channel.
516  * @param port Port this channel is connected to.
517  * @param options channel option flags
518  * @return Initial channel context for the channel
519  *         (can be NULL -- that's not an error).
520  */
521 static void *
522 incoming_channel (void *cls, struct GNUNET_MESH_Channel *channel,
523                  const struct GNUNET_PeerIdentity *initiator,
524                  uint32_t port, enum GNUNET_MESH_ChannelOption options)
525 {
526   long n = (long) cls;
527
528   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
529               "Incoming channel from %s to peer %ld\n",
530               GNUNET_i2s (initiator), n);
531   ok++;
532   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
533   peers[n].incoming_ch = channel;
534
535   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
536   {
537     GNUNET_SCHEDULER_cancel (disconnect_task);
538     disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
539                                                     &disconnect_mesh_peers,
540                                                     (void *) __LINE__);
541   }
542
543   return NULL;
544 }
545
546 /**
547  * Function called whenever an inbound channel is destroyed.  Should clean up
548  * any associated state.
549  *
550  * @param cls closure (set from GNUNET_MESH_connect)
551  * @param channel connection to the other end (henceforth invalid)
552  * @param channel_ctx place where local state associated
553  *                   with the channel is stored
554  */
555 static void
556 channel_cleaner (void *cls, const struct GNUNET_MESH_Channel *channel,
557                  void *channel_ctx)
558 {
559   long n = (long) cls;
560
561   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
562               "Incoming channel disconnected at peer %ld\n", n);
563   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
564
565   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
566   {
567     GNUNET_SCHEDULER_cancel (disconnect_task);
568     disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_mesh_peers,
569                                                 (void *) __LINE__);
570   }
571 }
572
573
574 /**
575  * @brief Send data to destination
576  *
577  * @param cls Closure (peer).
578  * @param tc Task context.
579  */
580 static void
581 ping (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
582 {
583   struct MeshPeer *peer = (struct MeshPeer *) cls;
584   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u -> %u\n",
585               get_index (peer), peer->dest);
586
587   GNUNET_MESH_notify_transmit_ready (peer->ch, GNUNET_NO,
588                                      GNUNET_TIME_UNIT_FOREVER_REL,
589                                      size_payload, &tmt_rdy, (void *) 1L);
590 }
591
592
593 /**
594  * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE MESH SERVICES.
595  *
596  * Testcase continues when the root receives confirmation of connected peers,
597  * on callback funtion ch.
598  *
599  * @param cls Closure (unsued).
600  * @param tc Task Context.
601  */
602 static void
603 do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
604 {
605   enum GNUNET_MESH_ChannelOption flags;
606   unsigned long i;
607
608   if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
609     return;
610
611   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start profiler\n");
612
613   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
614     GNUNET_SCHEDULER_cancel (disconnect_task);
615   disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
616                                                   &disconnect_mesh_peers,
617                                                   (void *) __LINE__);
618
619   flags = GNUNET_MESH_OPTION_DEFAULT;
620   for (i = 0; i < TOTAL_PEERS; i++)
621   {
622     peers[i].dest = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
623                                               TOTAL_PEERS);
624     peers[i].ch = GNUNET_MESH_channel_create (peers[i].mesh, NULL,
625                                               &peers[peers[i].dest].id,
626                                               1, flags);
627     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u => %u\n", i, peers[i].dest);
628     peers[i].ping_task = GNUNET_SCHEDULER_add_delayed (delay_ms_rnd(2000),
629                                                        &ping, &peers[i]);
630   }
631 }
632
633
634 /**
635  * Callback to be called when the requested peer information is available
636  *
637  * @param cls the closure from GNUNET_TESTBED_peer_get_information()
638  * @param op the operation this callback corresponds to
639  * @param pinfo the result; will be NULL if the operation has failed
640  * @param emsg error message if the operation has failed;
641  *             NULL if the operation is successfull
642  */
643 static void
644 peer_id_cb (void *cls,
645        struct GNUNET_TESTBED_Operation *op,
646        const struct GNUNET_TESTBED_PeerInformation *pinfo,
647        const char *emsg)
648 {
649   long n = (long) cls;
650
651   if (NULL == pinfo || NULL != emsg)
652   {
653     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
654     abort_test (__LINE__);
655     return;
656   }
657   peers[n].id = *(pinfo->result.id);
658   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %u  id: %s\n",
659               n, GNUNET_i2s (&peers[n].id));
660   p_ids++;
661   if (p_ids < TOTAL_PEERS)
662     return;
663   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got all IDs, starting profiler\n");
664   test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
665                                             &do_test, NULL);
666 }
667
668 /**
669  * test main: start test when all peers are connected
670  *
671  * @param cls Closure.
672  * @param ctx Argument to give to GNUNET_MESH_TEST_cleanup on test end.
673  * @param num_peers Number of peers that are running.
674  * @param testbed_peers Array of peers.
675  * @param meshes Handle to each of the MESHs of the peers.
676  */
677 static void
678 tmain (void *cls,
679        struct GNUNET_MESH_TEST_Context *ctx,
680        unsigned int num_peers,
681        struct GNUNET_TESTBED_Peer **testbed_peers,
682        struct GNUNET_MESH_Handle **meshes)
683 {
684   unsigned long i;
685
686   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n");
687   ok = 0;
688   test_ctx = ctx;
689   GNUNET_assert (TOTAL_PEERS == num_peers);
690   peers_running = num_peers;
691   testbed_handles = testbed_handles;
692   disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
693                                                   &disconnect_mesh_peers,
694                                                   (void *) __LINE__);
695   shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
696                                                   &shutdown_task, NULL);
697   for (i = 0; i < TOTAL_PEERS; i++)
698   {
699     peers[i].mesh = meshes[i];
700     peers[i].op =
701       GNUNET_TESTBED_peer_get_information (testbed_handles[i],
702                                            GNUNET_TESTBED_PIT_IDENTITY,
703                                            &peer_id_cb, (void *) i);
704   }
705   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
706   /* Continues from pi_cb -> do_test */
707 }
708
709
710 /**
711  * Main: start profiler.
712  */
713 int
714 main (int argc, char *argv[])
715 {
716   initialized = GNUNET_NO;
717   static uint32_t ports[2];
718   const char *config_file;
719
720   config_file = "test_mesh.conf";
721
722   p_ids = 0;
723   ports[0] = 1;
724   ports[1] = 0;
725   GNUNET_MESH_TEST_run ("mesh_profiler", config_file, TOTAL_PEERS,
726                         &tmain, NULL, /* tmain cls */
727                         &incoming_channel, &channel_cleaner,
728                         handlers, ports);
729
730   if (ok_goal > ok)
731   {
732     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
733                 "FAILED! (%d/%d)\n", ok, ok_goal);
734     return 1;
735   }
736   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n");
737   return 0;
738 }
739
740 /* end of test_mesh_small.c */
741