aboutsummaryrefslogtreecommitdiff
path: root/src/nse/gnunet-nse-profiler.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-09-10 19:01:30 +0000
committerChristian Grothoff <christian@grothoff.org>2012-09-10 19:01:30 +0000
commit655f8e6e4269913c906aface3f26776f936f3be4 (patch)
treeabf57ae59527d9fae445e76ee2b9481ccbba031f /src/nse/gnunet-nse-profiler.c
parentad85dcdd218b4c710793bea68f1a54d0b07e3cf3 (diff)
downloadgnunet-655f8e6e4269913c906aface3f26776f936f3be4.tar.gz
gnunet-655f8e6e4269913c906aface3f26776f936f3be4.zip
nse profiler _compiles_ against new testbed API
Diffstat (limited to 'src/nse/gnunet-nse-profiler.c')
-rw-r--r--src/nse/gnunet-nse-profiler.c1229
1 files changed, 679 insertions, 550 deletions
diff --git a/src/nse/gnunet-nse-profiler.c b/src/nse/gnunet-nse-profiler.c
index 19adb2064..ca9ec85f4 100644
--- a/src/nse/gnunet-nse-profiler.c
+++ b/src/nse/gnunet-nse-profiler.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2011 Christian Grothoff (and other contributing authors) 3 (C) 2011, 2012 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -24,35 +24,65 @@
24 * Generally, the profiler starts a given number of peers, 24 * Generally, the profiler starts a given number of peers,
25 * then churns some off, waits a certain amount of time, then 25 * then churns some off, waits a certain amount of time, then
26 * churns again, and repeats. 26 * churns again, and repeats.
27 *
28 * TODO:
29 * - need to enable user to specify topology options
30 * - need minor fix with "***"-host argument change in TESTBED (TBD there)
31 * - need to check for leaks (especially FD leaks)
32 * - need to TEST
27 */ 33 */
28#include "platform.h" 34#include "platform.h"
29#include "gnunet_testing_lib.h" 35#include "gnunet_testbed_service.h"
30#include "gnunet_nse_service.h" 36#include "gnunet_nse_service.h"
31 37
32#define VERBOSE 3
33 38
39/**
40 * Information we track for a peer in the testbed.
41 */
34struct NSEPeer 42struct NSEPeer
35{ 43{
44 /**
45 * Prev reference in DLL.
46 */
36 struct NSEPeer *prev; 47 struct NSEPeer *prev;
37 48
49 /**
50 * Next reference in DLL.
51 */
38 struct NSEPeer *next; 52 struct NSEPeer *next;
39 53
40 struct GNUNET_TESTING_Daemon *daemon; 54 /**
55 * Handle with testbed.
56 */
57 struct GNUNET_TESTBED_Peer *daemon;
41 58
42 struct GNUNET_NSE_Handle *nse_handle; 59 /**
60 * Testbed operation to connect to NSE service.
61 */
62 struct GNUNET_TESTBED_Operation *nse_op;
43 63
64 /**
65 * Handle to statistics service of the peer.
66 */
44 struct GNUNET_STATISTICS_Handle *stats; 67 struct GNUNET_STATISTICS_Handle *stats;
68
69 /**
70 * Testbed operation to connect to statistics service.
71 */
72 struct GNUNET_TESTBED_Operation *stats_op;
45 73
74 /**
75 * Task scheduled to get statistics from this peer.
76 */
46 GNUNET_SCHEDULER_TaskIdentifier stats_task; 77 GNUNET_SCHEDULER_TaskIdentifier stats_task;
47}; 78};
48 79
49 80
81/**
82 * Context for the stats task?
83 */
50struct StatsContext 84struct StatsContext
51{ 85{
52 /**
53 * Whether or not shoutdown after finishing.
54 */
55 int shutdown;
56 86
57 /** 87 /**
58 * How many messages have peers received during the test. 88 * How many messages have peers received during the test.
@@ -81,51 +111,80 @@ struct StatsContext
81}; 111};
82 112
83 113
114/**
115 * Head of DLL of peers we monitor closely.
116 */
84static struct NSEPeer *peer_head; 117static struct NSEPeer *peer_head;
85 118
119/**
120 * Tail of DLL of peers we monitor closely.
121 */
86static struct NSEPeer *peer_tail; 122static struct NSEPeer *peer_tail;
87 123
88/** 124/**
89 * How long until we give up on connecting the peers? 125 * Return value from 'main' (0 == success)
90 */ 126 */
91#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500)
92
93static int ok; 127static int ok;
94 128
95/** 129/**
96 * Be verbose 130 * Be verbose (configuration option)
97 */ 131 */
98static int verbose; 132static int verbose;
99 133
100/** 134/**
101 * Total number of peers in the test. 135 * Name of the file with the hosts to run the test over (configuration option)
136 */
137static char *hosts_file;
138
139/**
140 * IP address of this system, as seen by the rest of the system (configuration option)
102 */ 141 */
103static unsigned long long num_peers; 142static char *controller_ip;
104 143
105/** 144/**
106 * Global configuration file 145 * Maximum number of peers in the test.
107 */ 146 */
108static struct GNUNET_CONFIGURATION_Handle *testing_cfg; 147static unsigned int num_peers;
109 148
110/** 149/**
111 * Total number of currently running peers. 150 * Total number of rounds to execute.
112 */ 151 */
113static unsigned long long peers_running; 152static unsigned int num_rounds;
114 153
115/** 154/**
116 * Current round we are in. 155 * Current round we are in.
117 */ 156 */
118static unsigned long long current_round; 157static unsigned int current_round;
158
159/**
160 * Array of size 'num_rounds' with the requested number of peers in the given round.
161 */
162static unsigned int *num_peers_in_round;
119 163
120/** 164/**
121 * Peers desired in the next round. 165 * How many peers are running right now?
122 */ 166 */
123static unsigned long long peers_next_round; 167static unsigned int peers_running;
168
169/**
170 * Specification for the numbers of peers to have in each round.
171 */
172static char *num_peer_spec;
173
174/**
175 * Handles to all of the running peers.
176 */
177static struct GNUNET_TESTBED_Peer **daemons;
178
179/**
180 * Global configuration file
181 */
182static struct GNUNET_CONFIGURATION_Handle *testing_cfg;
124 183
125/** 184/**
126 * Maximum number of connections to NSE services. 185 * Maximum number of connections to NSE services.
127 */ 186 */
128static unsigned long long connection_limit; 187static unsigned int connection_limit;
129 188
130/** 189/**
131 * Total number of connections in the whole network. 190 * Total number of connections in the whole network.
@@ -133,14 +192,14 @@ static unsigned long long connection_limit;
133static unsigned int total_connections; 192static unsigned int total_connections;
134 193
135/** 194/**
136 * The currently running peer group. 195 * File to report results to.
137 */ 196 */
138static struct GNUNET_TESTING_PeerGroup *pg; 197static struct GNUNET_DISK_FileHandle *output_file;
139 198
140/** 199/**
141 * File to report results to. 200 * Filename to log results to.
142 */ 201 */
143static struct GNUNET_DISK_FileHandle *output_file; 202static char *output_filename;
144 203
145/** 204/**
146 * File to log connection info, statistics to. 205 * File to log connection info, statistics to.
@@ -148,87 +207,106 @@ static struct GNUNET_DISK_FileHandle *output_file;
148static struct GNUNET_DISK_FileHandle *data_file; 207static struct GNUNET_DISK_FileHandle *data_file;
149 208
150/** 209/**
151 * How many data points to capture before triggering next round? 210 * Filename to log connection info, statistics to.
152 */ 211 */
153static struct GNUNET_TIME_Relative wait_time; 212static char *data_filename;
154 213
155/** 214/**
156 * NSE interval. 215 * How long to wait before triggering next round?
216 * Default: 60 s.
157 */ 217 */
158static struct GNUNET_TIME_Relative interval; 218static struct GNUNET_TIME_Relative wait_time = { 60 * 1000 };
159 219
160/** 220/**
161 * Task called to disconnect peers. 221 * How often do we query for statistics during a round?
222 * Default: 1 s.
162 */ 223 */
163static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; 224static struct GNUNET_TIME_Relative interval = { 1000 };
164 225
165/** 226/**
166 * Task called to shutdown test. 227 * Name of the file where we write the topology for each round; NULL for
228 * none.
167 */ 229 */
168static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; 230static char *topology_file;
169 231
170/** 232/**
171 * Task used to churn the network. 233 * List of hosts we use for the testbed.
172 */ 234 */
173static GNUNET_SCHEDULER_TaskIdentifier churn_task; 235static struct GNUNET_TESTBED_Host **hosts;
174 236
175static char *topology_file; 237/**
238 * Size of the 'hosts' array.
239 */
240static unsigned int num_hosts;
176 241
177/** 242/**
178 * Check whether peers successfully shut down. 243 * Handle to the master controller.
179 */ 244 */
180static void 245static struct GNUNET_TESTBED_Controller *controller;
181shutdown_callback (void *cls, const char *emsg) 246
182{ 247/**
183 if (emsg != NULL) 248 * Controller start handle.
184 { 249 */
185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); 250static struct GNUNET_TESTBED_ControllerProc *copro;
186 if (ok == 0) 251
187 ok = 666; 252/**
188 } 253 * Testbed handle.
189 else 254 */
190 { 255static struct GNUNET_TESTBED_Testbed *testbed;
191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n");
192 ok = 0;
193 }
194}
195 256
196 257
258/**
259 * Clean up all of the monitoring connections to NSE and
260 * STATISTICS that we keep to selected peers.
261 */
197static void 262static void
198shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 263close_monitor_connections ()
199{ 264{
200 struct NSEPeer *pos; 265 struct NSEPeer *pos;
201 266
202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
203 if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
204 {
205 GNUNET_SCHEDULER_cancel (disconnect_task);
206 disconnect_task = GNUNET_SCHEDULER_NO_TASK;
207 }
208 while (NULL != (pos = peer_head)) 267 while (NULL != (pos = peer_head))
209 { 268 {
210 if (pos->nse_handle != NULL) 269 if (NULL != pos->nse_op)
211 GNUNET_NSE_disconnect (pos->nse_handle); 270 GNUNET_TESTBED_operation_done (pos->nse_op);
271 if (NULL != pos->stats_op)
272 GNUNET_TESTBED_operation_done (pos->stats_op);
212 GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos); 273 GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos);
213 if (GNUNET_SCHEDULER_NO_TASK != pos->stats_task) 274 if (GNUNET_SCHEDULER_NO_TASK != pos->stats_task)
214 {
215 GNUNET_SCHEDULER_cancel (pos->stats_task); 275 GNUNET_SCHEDULER_cancel (pos->stats_task);
216 if (NULL != pos->stats)
217 GNUNET_STATISTICS_destroy(pos->stats, GNUNET_NO);
218 }
219 GNUNET_free (pos); 276 GNUNET_free (pos);
220 } 277 }
278}
279
221 280
222 if (data_file != NULL) 281/**
282 * Task run on shutdown; cleans up everything.
283 *
284 * @param cls unused
285 * @param tc unused
286 */
287static void
288shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
289{
290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
291 close_monitor_connections ();
292 if (NULL != testbed)
293 GNUNET_TESTBED_destroy (testbed);
294 if (NULL != controller)
295 GNUNET_TESTBED_controller_disconnect (controller);
296 if (NULL != copro)
297 GNUNET_TESTBED_controller_stop (copro);
298 while (0 > num_hosts)
299 GNUNET_TESTBED_host_destroy (hosts[--num_hosts]);
300 // FIXME: what about closing other files!?
301 if (NULL != data_file)
223 GNUNET_DISK_file_close (data_file); 302 GNUNET_DISK_file_close (data_file);
224 GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
225} 303}
226 304
227 305
228/** 306/**
229 * Callback to call when network size estimate is updated. 307 * Callback to call when network size estimate is updated.
230 * 308 *
231 * @param cls closure 309 * @param cls closure with the 'struct NSEPeer' providing the update
232 * @param timestamp server timestamp 310 * @param timestamp server timestamp
233 * @param estimate the value of the current network size estimate 311 * @param estimate the value of the current network size estimate
234 * @param std_dev standard deviation (rounded down to nearest integer) 312 * @param std_dev standard deviation (rounded down to nearest integer)
@@ -236,32 +314,34 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
236 * 314 *
237 */ 315 */
238static void 316static void
239handle_estimate (void *cls, struct GNUNET_TIME_Absolute timestamp, 317handle_estimate (void *cls,
318 struct GNUNET_TIME_Absolute timestamp,
240 double estimate, double std_dev) 319 double estimate, double std_dev)
241{ 320{
242 struct NSEPeer *peer = cls; 321 struct NSEPeer *peer = cls;
243 char *output_buffer; 322 char output_buffer[512];
244 size_t size; 323 size_t size;
245 324
246 if (output_file != NULL) 325 if (NULL == output_file)
247 { 326 {
248 size = 327 FPRINTF (stderr,
249 GNUNET_asprintf (&output_buffer, "%s %llu %llu %f %f %f\n", 328 "Received network size estimate from peer %p. Size: %f std.dev. %f\n",
250 GNUNET_i2s (&peer->daemon->id), peers_running, 329 peer, estimate, std_dev);
251 timestamp.abs_value, 330 return;
252 GNUNET_NSE_log_estimate_to_n (estimate), estimate, 331 }
253 std_dev); 332 size = GNUNET_snprintf (output_buffer,
254 if (size != GNUNET_DISK_file_write (output_file, output_buffer, size)) 333 sizeof (output_buffer),
255 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n"); 334 "%p %llu %llu %f %f %f\n",
256 GNUNET_free (output_buffer); 335 peer, peers_running,
257 } 336 timestamp.abs_value,
258 else 337 GNUNET_NSE_log_estimate_to_n (estimate), estimate,
259 FPRINTF (stderr, 338 std_dev);
260 "Received network size estimate from peer %s. Size: %f std.dev. %f\n", 339 if (size != GNUNET_DISK_file_write (output_file, output_buffer, size))
261 GNUNET_i2s (&peer->daemon->id), estimate, std_dev); 340 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
262 341 "Unable to write to file!\n");
263} 342}
264 343
344
265/** 345/**
266 * Process core statistic values. 346 * Process core statistic values.
267 * 347 *
@@ -277,29 +357,30 @@ core_stats_iterator (void *cls, const char *subsystem, const char *name,
277 uint64_t value, int is_persistent) 357 uint64_t value, int is_persistent)
278{ 358{
279 struct NSEPeer *peer = cls; 359 struct NSEPeer *peer = cls;
280 char *output_buffer; 360 char output_buffer[512];
281 size_t size; 361 size_t size;
282 362
283 if (output_file != NULL) 363 if (NULL == output_file)
284 { 364 {
285 size = 365 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
286 GNUNET_asprintf (&output_buffer, "%s [%s] %s %llu\n", 366 "%p -> %s [%s]: %llu\n",
287 GNUNET_i2s (&peer->daemon->id), 367 peer, subsystem, name, value);
288 subsystem, name, value); 368 return GNUNET_OK;
289 if (size != GNUNET_DISK_file_write (output_file, output_buffer, size)) 369 }
290 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n"); 370 size =
291 GNUNET_free (output_buffer); 371 GNUNET_snprintf (output_buffer,
292 } 372 sizeof (output_buffer),
293 else 373 "%p [%s] %s %llu\n",
294 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 374 peer,
295 "%s -> %s [%s]: %llu\n", 375 subsystem, name, value);
296 GNUNET_i2s (&peer->daemon->id), subsystem, name, value); 376 if (size != GNUNET_DISK_file_write (output_file, output_buffer, size))
297 377 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n");
298 return GNUNET_OK; 378 return GNUNET_OK;
299} 379}
300 380
381
301/** 382/**
302 * Continuation called by "get_stats" function. 383 * Continuation called by "get_stats" function once we are done.
303 * 384 *
304 * @param cls closure 385 * @param cls closure
305 * @param success GNUNET_OK if statistics were 386 * @param success GNUNET_OK if statistics were
@@ -308,32 +389,43 @@ core_stats_iterator (void *cls, const char *subsystem, const char *name,
308static void 389static void
309core_stats_cont (void *cls, int success); 390core_stats_cont (void *cls, int success);
310 391
392
393/**
394 * Function invoked periodically to get the statistics.
395 *
396 * @param cls 'struct NSEPeer' to get stats from
397 * @param tc scheduler context
398 */
311static void 399static void
312core_get_stats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 400core_get_stats (void *cls,
401 const struct GNUNET_SCHEDULER_TaskContext *tc)
313{ 402{
314 struct NSEPeer *peer = cls; 403 struct NSEPeer *peer = cls;
315 404
316 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) 405 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
317 { 406 {
318 GNUNET_STATISTICS_destroy(peer->stats, GNUNET_NO); 407 GNUNET_TESTBED_operation_done (peer->stats_op);
319 peer->stats = NULL; 408 peer->stats = NULL;
409 peer->stats_op = NULL;
320 return; 410 return;
321 } 411 }
322 else 412 /* FIXME: code duplication! */
323 { 413 GNUNET_STATISTICS_get (peer->stats, "core", NULL,
324 GNUNET_STATISTICS_get(peer->stats, "core", NULL, 414 GNUNET_TIME_UNIT_FOREVER_REL,
325 GNUNET_TIME_UNIT_FOREVER_REL, 415 &core_stats_cont,
326 &core_stats_cont, &core_stats_iterator, peer); 416 &core_stats_iterator, peer);
327 GNUNET_STATISTICS_get(peer->stats, "transport", NULL, 417 GNUNET_STATISTICS_get (peer->stats, "transport", NULL,
328 GNUNET_TIME_UNIT_FOREVER_REL, 418 GNUNET_TIME_UNIT_FOREVER_REL,
329 NULL, &core_stats_iterator, peer); 419 NULL,
330 GNUNET_STATISTICS_get(peer->stats, "nse", NULL, 420 &core_stats_iterator, peer);
331 GNUNET_TIME_UNIT_FOREVER_REL, 421 GNUNET_STATISTICS_get (peer->stats, "nse", NULL,
332 NULL, &core_stats_iterator, peer); 422 GNUNET_TIME_UNIT_FOREVER_REL,
333 } 423 NULL,
424 &core_stats_iterator, peer);
334 peer->stats_task = GNUNET_SCHEDULER_NO_TASK; 425 peer->stats_task = GNUNET_SCHEDULER_NO_TASK;
335} 426}
336 427
428
337/** 429/**
338 * Continuation called by "get_stats" function. 430 * Continuation called by "get_stats" function.
339 * 431 *
@@ -342,19 +434,136 @@ core_get_stats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
342 * successfully obtained, GNUNET_SYSERR if not. 434 * successfully obtained, GNUNET_SYSERR if not.
343 */ 435 */
344static void 436static void
345core_stats_cont (void *cls, int success) 437core_stats_cont (void *cls,
438 int success)
346{ 439{
347 struct NSEPeer *peer = cls; 440 struct NSEPeer *peer = cls;
348 peer->stats_task = GNUNET_SCHEDULER_add_delayed (interval, &core_get_stats, 441
349 peer); 442 if (GNUNET_OK != success)
443 return;
444 peer->stats_task = GNUNET_SCHEDULER_add_delayed (interval,
445 &core_get_stats, peer);
446}
447
448
449/**
450 * Adapter function called to establish a connection to
451 * statistics service.
452 *
453 * @param cls closure
454 * @param cfg configuration of the peer to connect to; will be available until
455 * GNUNET_TESTBED_operation_done() is called on the operation returned
456 * from GNUNET_TESTBED_service_connect()
457 * @return service handle to return in 'op_result', NULL on error
458 */
459static void *
460statistics_connect_adapter (void *cls,
461 const struct GNUNET_CONFIGURATION_Handle *cfg)
462{
463 return GNUNET_STATISTICS_create ("<driver>",
464 cfg);
350} 465}
351 466
352 467
353/** 468/**
469 * Adapter function called to destroy a connection to
470 * statistics service.
471 *
472 * @param cls closure
473 * @param op_result service handle returned from the connect adapter
474 */
475static void
476statistics_disconnect_adapter (void *cls,
477 void *op_result)
478{
479 GNUNET_STATISTICS_destroy (op_result, GNUNET_NO);
480}
481
482
483/**
484 * Function called by testbed once we are connected to stats service.
354 * 485 *
486 * @param cls the 'struct NSEPeer' for which we connected to stats
487 * @param op connect operation handle
488 * @param ca_result handle to stats service
489 * @param emsg error message on failure
355 */ 490 */
356static void 491static void
357connect_nse_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 492stat_run (void *cls,
493 struct GNUNET_TESTBED_Operation *op,
494 void *ca_result,
495 const char *emsg)
496{
497 struct NSEPeer *current_peer = cls;
498
499 if (NULL == ca_result)
500 {
501 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
502 "Failed to connect to statistics service: %s\n",
503 emsg);
504 GNUNET_SCHEDULER_shutdown ();
505 return;
506 }
507 current_peer->stats = ca_result;
508 GNUNET_STATISTICS_get (current_peer->stats, "core", NULL,
509 GNUNET_TIME_UNIT_FOREVER_REL,
510 &core_stats_cont,
511 &core_stats_iterator, current_peer);
512 GNUNET_STATISTICS_get (current_peer->stats, "transport", NULL,
513 GNUNET_TIME_UNIT_FOREVER_REL,
514 NULL,
515 &core_stats_iterator, current_peer);
516 GNUNET_STATISTICS_get (current_peer->stats, "nse", NULL,
517 GNUNET_TIME_UNIT_FOREVER_REL,
518 NULL,
519 &core_stats_iterator, current_peer);
520}
521
522
523/**
524 * Adapter function called to establish a connection to
525 * NSE service.
526 *
527 * @param cls closure (the 'struct NSEPeer')
528 * @param cfg configuration of the peer to connect to; will be available until
529 * GNUNET_TESTBED_operation_done() is called on the operation returned
530 * from GNUNET_TESTBED_service_connect()
531 * @return service handle to return in 'op_result', NULL on error
532 */
533static void *
534nse_connect_adapter (void *cls,
535 const struct GNUNET_CONFIGURATION_Handle *cfg)
536{
537 struct NSEPeer *current_peer = cls;
538
539 return GNUNET_NSE_connect (cfg, &handle_estimate, current_peer);
540}
541
542
543/**
544 * Adapter function called to destroy a connection to
545 * NSE service.
546 *
547 * @param cls closure
548 * @param op_result service handle returned from the connect adapter
549 */
550static void
551nse_disconnect_adapter (void *cls,
552 void *op_result)
553{
554 GNUNET_NSE_disconnect (op_result);
555}
556
557
558/**
559 * Task run to connect to the NSE and statistics services to a subset of
560 * all of the running peers.
561 *
562 * @param cls handle the peer
563 * @param tc ignored
564 */
565static void
566connect_nse_service ()
358{ 567{
359 struct NSEPeer *current_peer; 568 struct NSEPeer *current_peer;
360 unsigned int i; 569 unsigned int i;
@@ -364,123 +573,107 @@ connect_nse_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
364 { 573 {
365 if ((connection_limit > 0) && 574 if ((connection_limit > 0) &&
366 (num_peers > connection_limit) && 575 (num_peers > connection_limit) &&
367 (i % (num_peers / connection_limit) != 0)) 576 (0 != (i % (num_peers / connection_limit))))
368 continue; 577 continue;
369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 578 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
370 "nse-profiler: connecting to nse service of peer %d\n", i); 579 "nse-profiler: connecting to nse service of peer %d\n", i);
371 current_peer = GNUNET_malloc (sizeof (struct NSEPeer)); 580 current_peer = GNUNET_malloc (sizeof (struct NSEPeer));
372 current_peer->daemon = GNUNET_TESTING_daemon_get (pg, i); 581 current_peer->daemon = daemons[i];
373 if (GNUNET_YES == 582 current_peer->nse_op
374 GNUNET_TESTING_test_daemon_running (GNUNET_TESTING_daemon_get (pg, i))) 583 = GNUNET_TESTBED_service_connect (NULL,
375 { 584 current_peer->daemon,
376 current_peer->nse_handle = 585 "nse",
377 GNUNET_NSE_connect (current_peer->daemon->cfg, &handle_estimate, 586 NULL, NULL,
378 current_peer); 587 &nse_connect_adapter,
379 GNUNET_assert (current_peer->nse_handle != NULL); 588 &nse_disconnect_adapter,
380 } 589 current_peer);
381 current_peer->stats = GNUNET_STATISTICS_create("profiler", current_peer->daemon->cfg); 590 current_peer->stats_op
382 GNUNET_STATISTICS_get(current_peer->stats, "core", NULL, 591 = GNUNET_TESTBED_service_connect (NULL,
383 GNUNET_TIME_UNIT_FOREVER_REL, 592 current_peer->daemon,
384 &core_stats_cont, &core_stats_iterator, current_peer); 593 "statistics",
385 GNUNET_STATISTICS_get(current_peer->stats, "transport", NULL, 594 &stat_run, current_peer,
386 GNUNET_TIME_UNIT_FOREVER_REL, 595 &statistics_connect_adapter,
387 NULL, &core_stats_iterator, current_peer); 596 &statistics_disconnect_adapter,
388 GNUNET_STATISTICS_get(current_peer->stats, "nse", NULL, 597 NULL);
389 GNUNET_TIME_UNIT_FOREVER_REL,
390 NULL, &core_stats_iterator, current_peer);
391 GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, current_peer); 598 GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, current_peer);
392 } 599 }
393} 600}
394 601
395 602
603/**
604 * Task that starts/stops peers to move to the next round.
605 *
606 * @param cls NULL, unused
607 * @param tc scheduler context (unused)
608 */
396static void 609static void
397churn_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); 610next_round (void *cls,
611 const struct GNUNET_SCHEDULER_TaskContext *tc);
398 612
399 613
400/** 614/**
401 * Continuation called by the "get_all" and "get" functions. 615 * Continuation called by the "get_all" and "get" functions at the
616 * end of a round. Obtains the final statistics and writes them to
617 * the file, then either starts the next round, or, if this was the
618 * last round, terminates the run.
402 * 619 *
403 * @param cls struct StatsContext 620 * @param cls struct StatsContext
404 * @param success GNUNET_OK if statistics were 621 * @param success GNUNET_OK if statistics were
405 * successfully obtained, GNUNET_SYSERR if not. 622 * successfully obtained, GNUNET_SYSERR if not.
406 */ 623 */
407static void 624static void
408stats_finished_callback (void *cls, int success) 625stats_finished_callback (void *cls,
626 struct GNUNET_TESTBED_Operation *op,
627 const char *emsg)
409{ 628{
410 struct StatsContext *stats_context = cls; 629 struct StatsContext *stats_context = cls;
411 char *buf; 630 char buf[512];
412 int buf_len; 631 size_t buf_len;
413 632
414 if ((GNUNET_OK == success) && (data_file != NULL)) 633 if (NULL != emsg)
415 {
416 /* Stats lookup successful, write out data */
417 buf = NULL;
418 buf_len =
419 GNUNET_asprintf (&buf, "TOTAL_NSE_RECEIVED_MESSAGES_%d: %u \n",
420 stats_context->shutdown,
421 stats_context->total_nse_received_messages);
422 if (buf_len > 0)
423 { 634 {
424 GNUNET_DISK_file_write (data_file, buf, buf_len); 635 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
636 "Failed to get statistics: %s\n",
637 emsg);
638 GNUNET_SCHEDULER_shutdown ();
639 GNUNET_free (stats_context);
640 return;
425 } 641 }
426 GNUNET_free_non_null (buf); 642 if (NULL != data_file)
427
428 buf = NULL;
429 buf_len =
430 GNUNET_asprintf (&buf, "TOTAL_NSE_TRANSMITTED_MESSAGES_%d: %u\n",
431 stats_context->shutdown,
432 stats_context->total_nse_transmitted_messages);
433 if (buf_len > 0)
434 { 643 {
644 /* Stats lookup successful, write out data */
645 buf_len =
646 GNUNET_snprintf (buf, sizeof (buf),
647 "TOTAL_NSE_RECEIVED_MESSAGES_%u: %u \n",
648 current_round,
649 stats_context->total_nse_received_messages);
435 GNUNET_DISK_file_write (data_file, buf, buf_len); 650 GNUNET_DISK_file_write (data_file, buf, buf_len);
436 } 651 buf_len =
437 GNUNET_free_non_null (buf); 652 GNUNET_snprintf (buf, sizeof (buf),
438 653 "TOTAL_NSE_TRANSMITTED_MESSAGES_%u: %u\n",
439 buf = NULL; 654 current_round,
440 buf_len = 655 stats_context->total_nse_transmitted_messages);
441 GNUNET_asprintf (&buf, "TOTAL_NSE_CROSS_%d: %u \n", 656 GNUNET_DISK_file_write (data_file, buf, buf_len);
442 stats_context->shutdown, 657 buf_len =
443 stats_context->total_nse_cross); 658 GNUNET_snprintf (buf, sizeof (buf),
444 if (buf_len > 0) 659 "TOTAL_NSE_CROSS_%u: %u \n",
445 { 660 current_round,
661 stats_context->total_nse_cross);
446 GNUNET_DISK_file_write (data_file, buf, buf_len); 662 GNUNET_DISK_file_write (data_file, buf, buf_len);
447 } 663 buf_len =
448 GNUNET_free_non_null (buf); 664 GNUNET_snprintf (buf, sizeof (buf),
449 665 "TOTAL_NSE_EXTRA_%u: %u \n",
450 buf = NULL; 666 current_round,
451 buf_len = 667 stats_context->total_nse_extra);
452 GNUNET_asprintf (&buf, "TOTAL_NSE_EXTRA_%d: %u \n",
453 stats_context->shutdown,
454 stats_context->total_nse_extra);
455 if (buf_len > 0)
456 {
457 GNUNET_DISK_file_write (data_file, buf, buf_len); 668 GNUNET_DISK_file_write (data_file, buf, buf_len);
458 } 669 buf_len =
459 GNUNET_free_non_null (buf); 670 GNUNET_snprintf (buf, sizeof (buf),
460 671 "TOTAL_NSE_DISCARDED_%u: %u \n",
461 buf = NULL; 672 current_round,
462 buf_len = 673 stats_context->total_discarded);
463 GNUNET_asprintf (&buf, "TOTAL_NSE_DISCARDED_%d: %u \n", 674 GNUNET_DISK_file_write (data_file, buf, buf_len);
464 stats_context->shutdown, 675 }
465 stats_context->total_discarded); 676 GNUNET_SCHEDULER_add_now (&next_round, NULL);
466 if (buf_len > 0)
467 {
468 GNUNET_DISK_file_write (data_file, buf, buf_len);
469 }
470 GNUNET_free_non_null (buf);
471
472 }
473
474 if (GNUNET_YES == stats_context->shutdown)
475 {
476 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == shutdown_handle);
477 shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
478 }
479 else
480 {
481 GNUNET_assert (churn_task == GNUNET_SCHEDULER_NO_TASK);
482 churn_task = GNUNET_SCHEDULER_add_now (&churn_peers, NULL);
483 }
484 GNUNET_free (stats_context); 677 GNUNET_free (stats_context);
485} 678}
486 679
@@ -497,427 +690,363 @@ stats_finished_callback (void *cls, int success)
497 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration 690 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
498 */ 691 */
499static int 692static int
500statistics_iterator (void *cls, const struct GNUNET_PeerIdentity *peer, 693statistics_iterator (void *cls,
694 const struct GNUNET_TESTBED_Peer *peer,
501 const char *subsystem, const char *name, uint64_t value, 695 const char *subsystem, const char *name, uint64_t value,
502 int is_persistent) 696 int is_persistent)
503{ 697{
504 struct StatsContext *stats_context = cls; 698 struct StatsContext *stats_context = cls;
699 char buf[512];
700 size_t buf_len;
505 701
506 if (0 == strcmp (subsystem, "nse")) 702 if (0 != strcmp (subsystem, "nse"))
507 { 703 return GNUNET_OK;
508 if (0 == strcmp (name, "# flood messages received")) 704 if (0 == strcmp (name, "# flood messages received"))
509 { 705 {
510 stats_context->total_nse_received_messages += value; 706 stats_context->total_nse_received_messages += value;
511#if VERBOSE 707 if ( (verbose > 1) &&
512 if (data_file != NULL) 708 (NULL != data_file) )
513 { 709 {
514 char *buf; 710 buf_len =
515 int buf_len; 711 GNUNET_snprintf (buf, sizeof (buf),
516 712 "%p %u RECEIVED\n",
517 buf = NULL; 713 peer, value);
518 buf_len = 714 GNUNET_DISK_file_write (data_file, buf, buf_len);
519 GNUNET_asprintf (&buf, "%s %u RECEIVED\n", GNUNET_i2s(peer), value); 715 }
520 if (buf_len > 0)
521 {
522 GNUNET_DISK_file_write (data_file, buf, buf_len);
523 }
524 GNUNET_free_non_null (buf);
525 }
526#endif
527 } 716 }
528 if (0 == strcmp (name, "# flood messages transmitted")) 717 if (0 == strcmp (name, "# flood messages transmitted"))
529 { 718 {
530 stats_context->total_nse_transmitted_messages += value; 719 stats_context->total_nse_transmitted_messages += value;
531#if VERBOSE 720 if ( (verbose > 1) &&
532 if (data_file != NULL) 721 (NULL != data_file) )
533 { 722 {
534 char *buf; 723 buf_len =
535 int buf_len; 724 GNUNET_snprintf (buf, sizeof (buf),
536 725 "%p %u TRANSMITTED\n",
537 buf = NULL; 726 peer, value);
538 buf_len = 727 GNUNET_DISK_file_write (data_file, buf, buf_len);
539 GNUNET_asprintf (&buf, "%s %u TRANSMITTED\n", 728 }
540 GNUNET_i2s(peer), value);
541 if (buf_len > 0)
542 {
543 GNUNET_DISK_file_write (data_file, buf, buf_len);
544 }
545 GNUNET_free_non_null (buf);
546 }
547#endif
548 }
549 if (0 == strcmp (name, "# cross messages"))
550 {
551 stats_context->total_nse_cross += value;
552 } 729 }
553 if (0 == strcmp (name, "# extra messages")) 730 if (0 == strcmp (name, "# cross messages"))
554 { 731 stats_context->total_nse_cross += value;
555 stats_context->total_nse_extra += value; 732 if (0 == strcmp (name, "# extra messages"))
556 } 733 stats_context->total_nse_extra += value;
557 if (0 == strcmp (name, "# flood messages discarded (clock skew too large)")) 734 if (0 == strcmp (name, "# flood messages discarded (clock skew too large)"))
558 { 735 stats_context->total_discarded += value;
559 stats_context->total_discarded += value;
560 }
561 }
562 return GNUNET_OK; 736 return GNUNET_OK;
563} 737}
564 738
565 739
740/**
741 * Function called upon completion of the node start/stop operations
742 * for the current round. Writes the new topology to disk.
743 */
566static void 744static void
567disconnect_nse_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 745write_topology ()
568{ 746{
569 struct NSEPeer *pos; 747 char temp_output_file[1024];
570 char *buf;
571 struct StatsContext *stats_context;
572 748
573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnecting nse service of peers\n"); 749 if (NULL != topology_file)
574 disconnect_task = GNUNET_SCHEDULER_NO_TASK;
575 while (NULL != (pos = peer_head))
576 {
577 if (pos->nse_handle != NULL)
578 { 750 {
579 GNUNET_NSE_disconnect (pos->nse_handle); 751 GNUNET_snprintf (temp_output_file, sizeof (temp_output_file),
580 pos->nse_handle = NULL; 752 "%s_%llu.dot",
753 topology_file, current_round);
754 GNUNET_TESTBED_overlay_write_topology_to_file (controller,
755 temp_output_file);
581 } 756 }
582 GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos);
583 if (NULL != pos->stats)
584 GNUNET_STATISTICS_destroy(pos->stats, GNUNET_NO);
585 if (GNUNET_SCHEDULER_NO_TASK != pos->stats_task)
586 GNUNET_SCHEDULER_cancel (pos->stats_task);
587 GNUNET_free (pos);
588 }
589
590 GNUNET_asprintf (&buf, "round%llu", current_round);
591 if (GNUNET_OK ==
592 GNUNET_CONFIGURATION_get_value_number (testing_cfg, "nse-profiler", buf,
593 &peers_next_round))
594 {
595 current_round++;
596 if (current_round == 1)
597 {
598 stats_context = GNUNET_malloc (sizeof (struct StatsContext));
599 stats_context->shutdown = GNUNET_NO;
600 GNUNET_TESTING_get_statistics (pg, &stats_finished_callback,
601 &statistics_iterator, stats_context);
602 }
603 else
604 {
605 GNUNET_assert (churn_task == GNUNET_SCHEDULER_NO_TASK);
606 churn_task = GNUNET_SCHEDULER_add_now (&churn_peers, NULL);
607 }
608 }
609 else /* No more rounds, let's shut it down! */
610 {
611 stats_context = GNUNET_malloc (sizeof (struct StatsContext));
612 stats_context->shutdown = GNUNET_YES;
613 GNUNET_SCHEDULER_cancel (shutdown_handle);
614 shutdown_handle = GNUNET_SCHEDULER_NO_TASK;
615 GNUNET_TESTING_get_statistics (pg, &stats_finished_callback,
616 &statistics_iterator, stats_context);
617 }
618 GNUNET_free (buf);
619} 757}
620 758
621 759
622/** 760/**
623 * FIXME. 761 * We're at the end of a round. Stop monitoring, write total
762 * number of connections to log and get full stats. Then trigger
763 * the next round.
624 * 764 *
625 * @param cls unused 765 * @param cls unused, NULL
626 * @param emsg NULL on success 766 * @param tc unused
627 */ 767 */
628static void 768static void
629topology_output_callback (void *cls, const char *emsg) 769finish_round (void *cls,
770 const struct GNUNET_SCHEDULER_TaskContext *tc)
630{ 771{
631 disconnect_task = 772 struct StatsContext *stats_context;
632 GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_nse_peers, NULL); 773 char buf[1024];
633 GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL); 774 size_t buf_len;
775
776 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
777 "Have %u connections\n",
778 total_connections);
779 if (NULL != data_file)
780 {
781 buf_len = GNUNET_snprintf (buf, sizeof (buf),
782 "CONNECTIONS_0: %u\n",
783 total_connections);
784 GNUNET_DISK_file_write (data_file, buf, buf_len);
785 }
786 close_monitor_connections ();
787 stats_context = GNUNET_malloc (sizeof (struct StatsContext));
788 GNUNET_TESTBED_get_statistics (num_peers_in_round[current_round],
789 daemons,
790 &statistics_iterator,
791 &stats_finished_callback,
792 stats_context);
634} 793}
635 794
636 795
637/** 796/**
638 * FIXME. 797 * We have reached the desired number of peers for the current round.
639 * 798 * Run it (by connecting and monitoring a few peers and waiting the
640 * @param cls closure 799 * specified delay before finishing the round).
641 * @param emsg NULL on success
642 */ 800 */
643static void 801static void
644churn_callback (void *cls, const char *emsg) 802run_round ()
645{ 803{
646 char *temp_output_file; 804 write_topology ();
647 805 connect_nse_service ();
648 if (emsg == NULL) /* Everything is okay! */ 806 GNUNET_SCHEDULER_add_delayed (wait_time,
649 { 807 &finish_round,
650 peers_running = peers_next_round; 808 NULL);
651 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
652 "Round %llu, churn finished successfully.\n", current_round);
653 GNUNET_assert (disconnect_task == GNUNET_SCHEDULER_NO_TASK);
654 GNUNET_asprintf (&temp_output_file, "%s_%llu.dot", topology_file,
655 current_round);
656 GNUNET_TESTING_peergroup_topology_to_file (pg, temp_output_file,
657 &topology_output_callback, NULL);
658 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Writing topology to file %s\n",
659 temp_output_file);
660 GNUNET_free (temp_output_file);
661 }
662 else
663 {
664 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Round %llu, churn FAILED!!\n",
665 current_round);
666 GNUNET_SCHEDULER_cancel (shutdown_handle);
667 shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
668 }
669} 809}
670 810
671 811
812/**
813 * Task run at the end of a round. Disconnect from all monitored
814 * peers; then get statistics from *all* peers.
815 *
816 * @param cls NULL, unused
817 * @param tc unused
818 */
672static void 819static void
673churn_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 820next_round (void *cls,
821 const struct GNUNET_SCHEDULER_TaskContext *tc)
674{ 822{
675 /* peers_running = GNUNET_TESTING_daemons_running(pg); */ 823 unsigned int i;
676 churn_task = GNUNET_SCHEDULER_NO_TASK; 824
677 if (peers_next_round == peers_running) 825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnecting nse service of peers\n");
678 { 826 current_round++;
679 /* Nothing to do... */ 827
680 GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL); 828 if (current_round == num_rounds)
681 GNUNET_assert (disconnect_task == GNUNET_SCHEDULER_NO_TASK);
682 disconnect_task =
683 GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_nse_peers, NULL);
684 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Round %lu, doing nothing!\n",
685 current_round);
686 }
687 else
688 {
689 if (peers_next_round > num_peers)
690 { 829 {
691 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 830 /* this was the last round, terminate */
692 "Asked to turn on more peers than we have!!\n"); 831 GNUNET_SCHEDULER_shutdown ();
693 GNUNET_SCHEDULER_cancel (shutdown_handle); 832 return;
694 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
695 } 833 }
696 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 834 if (num_peers_in_round[current_round] == peers_running)
697 "Round %llu, turning off %llu peers, turning on %llu peers!\n", 835 {
698 current_round, 836 /* no need to churn, just run next round */
699 (peers_running > 837 run_round ();
700 peers_next_round) ? peers_running - peers_next_round : 0, 838 return;
701 (peers_next_round > 839 }
702 peers_running) ? peers_next_round - peers_running : 0); 840
703 GNUNET_TESTING_daemons_churn (pg, "nse", 841 /* start peers if we have too few */
704 (peers_running > 842 for (i=peers_running;i<num_peers_in_round[current_round];i++)
705 peers_next_round) ? peers_running - 843 GNUNET_TESTBED_peer_start (daemons[i], NULL, NULL);
706 peers_next_round : 0, 844
707 (peers_next_round > 845 /* stop peers if we have too many */
708 peers_running) ? peers_next_round - 846 for (i=num_peers_in_round[current_round];i<peers_running;i++)
709 peers_running : 0, wait_time, &churn_callback, 847 GNUNET_TESTBED_peer_stop (daemons[i], NULL, NULL);
710 NULL);
711 }
712} 848}
713 849
714 850
851/**
852 * Function that will be called whenever something in the
853 * testbed changes.
854 *
855 * @param cls closure, NULL
856 * @param event information on what is happening
857 */
715static void 858static void
716nse_started_cb (void *cls, const char *emsg) 859master_controller_cb (void *cls,
860 const struct GNUNET_TESTBED_EventInformation *event)
717{ 861{
718 GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL); 862 switch (event->type)
719 disconnect_task = 863 {
720 GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_nse_peers, NULL); 864 case GNUNET_TESTBED_ET_PEER_START:
865 peers_running++;
866 if (num_peers_in_round[current_round] == peers_running)
867 run_round ();
868 break;
869 case GNUNET_TESTBED_ET_PEER_STOP:
870 peers_running--;
871 if (num_peers_in_round[current_round] == peers_running)
872 run_round ();
873 break;
874 case GNUNET_TESTBED_ET_CONNECT:
875 total_connections++;
876 case GNUNET_TESTBED_ET_DISCONNECT:
877 total_connections--;
878 default:
879 break;
880 }
721} 881}
722 882
723 883
724static void 884static void
725my_cb (void *cls, const char *emsg) 885controller_start_cb (void *cls,
886 const struct GNUNET_CONFIGURATION_Handle *cfg,
887 int status)
726{ 888{
727 char *buf; 889 if (GNUNET_OK != status)
728 int buf_len; 890 {
729 891 copro = NULL;
730 if (emsg != NULL) 892 GNUNET_SCHEDULER_shutdown ();
731 { 893 return;
732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 894 }
733 "Peergroup callback called with error, aborting test!\n"); 895 num_hosts = GNUNET_TESTBED_hosts_load_from_file (hosts_file,
734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); 896 /* FIXME: & */ hosts);
735 ok = 1; 897 if (0 == num_hosts)
736 GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); 898 {
737 return; 899 fprintf (stderr,
738 } 900 "Failed to read host information from `%s'\n",
739 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 901 hosts_file);
740 "Peer Group started successfully, connecting to NSE service for each peer!\n"); 902 return;
741 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Have %u connections\n", 903 }
742 total_connections); 904 controller = GNUNET_TESTBED_controller_connect (cfg,
743 if (data_file != NULL) 905 NULL,
744 { 906 0 /* mask */,
745 buf = NULL; 907 &master_controller_cb, NULL);
746 buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections); 908 testbed = GNUNET_TESTBED_create (controller,
747 if (buf_len > 0) 909 num_hosts, hosts,
748 GNUNET_DISK_file_write (data_file, buf, buf_len); 910 num_peers,
749 GNUNET_free (buf); 911 cfg,
750 } 912 0 /* FIXME: topology */,
751 peers_running = GNUNET_TESTING_daemons_running (pg); 913 NULL /* FIXME: topology options */);
752 GNUNET_TESTING_daemons_start_service (pg, "nse", wait_time, &nse_started_cb,
753 NULL);
754
755} 914}
756 915
757 916
758/** 917/**
759 * Function that will be called whenever two daemons are connected by 918 * Actual main function that runs the emulation.
760 * the testing library.
761 * 919 *
762 * @param cls closure 920 * @param cls unused
763 * @param first peer id for first daemon 921 * @param args remaining args, unused
764 * @param second peer id for the second daemon 922 * @param cfgfile name of the configuration
765 * @param distance distance between the connected peers 923 * @param cfg configuration handle
766 * @param first_cfg config for the first daemon
767 * @param second_cfg config for the second daemon
768 * @param first_daemon handle for the first daemon
769 * @param second_daemon handle for the second daemon
770 * @param emsg error message (NULL on success)
771 */ 924 */
772static void 925static void
773connect_cb (void *cls, const struct GNUNET_PeerIdentity *first,
774 const struct GNUNET_PeerIdentity *second, uint32_t distance,
775 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
776 const struct GNUNET_CONFIGURATION_Handle *second_cfg,
777 struct GNUNET_TESTING_Daemon *first_daemon,
778 struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg)
779{
780 if (emsg == NULL)
781 total_connections++;
782}
783
784
785static void
786run (void *cls, char *const *args, const char *cfgfile, 926run (void *cls, char *const *args, const char *cfgfile,
787 const struct GNUNET_CONFIGURATION_Handle *cfg) 927 const struct GNUNET_CONFIGURATION_Handle *cfg)
788{ 928{
789 char *temp_str; 929 char *tok;
790 struct GNUNET_TESTING_Host *hosts; 930 unsigned int num;
791 char *data_filename;
792 931
793 ok = 1; 932 ok = 1;
794 //testing_cfg = GNUNET_CONFIGURATION_create ();
795 testing_cfg = GNUNET_CONFIGURATION_dup (cfg); 933 testing_cfg = GNUNET_CONFIGURATION_dup (cfg);
796 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); 934 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n");
797#if VERBOSE 935 if (verbose)
798 GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", 936 GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing",
799 "use_progressbars", "YES"); 937 "use_progressbars", "YES");
800#endif 938 if (NULL == num_peer_spec)
801 if (GNUNET_OK !=
802 GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing",
803 "num_peers", &num_peers))
804 {
805 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
806 "Option TESTING:NUM_PEERS is required!\n");
807 return;
808 }
809
810 if (GNUNET_OK !=
811 GNUNET_CONFIGURATION_get_value_time (testing_cfg, "nse-profiler",
812 "WAIT_TIME", &wait_time))
813 {
814 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
815 "Option nse-profiler:wait_time is required!\n");
816 return;
817 }
818
819 if (GNUNET_OK !=
820 GNUNET_CONFIGURATION_get_value_time (testing_cfg, "nse",
821 "INTERVAL", &interval))
822 { 939 {
823 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 940 fprintf (stderr, "You need to specify the number of peers to run\n");
824 "Option nse:interval is required!\n");
825 return; 941 return;
826 } 942 }
827 943 for (tok = strtok (num_peer_spec, ","); NULL != tok; tok = strtok (NULL, ","))
828 if (GNUNET_OK != 944 {
829 GNUNET_CONFIGURATION_get_value_number (testing_cfg, "nse-profiler", 945 if (1 != sscanf (tok, "%u", &num))
830 "connection_limit", 946 {
831 &connection_limit)) 947 fprintf (stderr, "You need to specify numbers, not `%s'\n", tok);
832 { 948 return;
833 connection_limit = 0; 949 }
834 } 950 if (0 == num)
835 951 {
836 if (GNUNET_OK != 952 fprintf (stderr, "Refusing to run a round with 0 peers\n");
837 GNUNET_CONFIGURATION_get_value_string (testing_cfg, "nse-profiler", 953 return;
838 "topology_output_file", 954 }
839 &topology_file)) 955 GNUNET_array_grow (num_peers_in_round, num_rounds, num);
840 { 956 num_peers = GNUNET_MAX (num_peers, num);
841 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 957 }
842 "Option nse-profiler:topology_output_file is required!\n"); 958 if (0 == num_peers)
843 return; 959 {
844 } 960 fprintf (stderr, "Refusing to run a testbed with no rounds\n");
845 961 return;
846 if (GNUNET_OK == 962 }
847 GNUNET_CONFIGURATION_get_value_string (testing_cfg, "nse-profiler", 963 daemons = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer*) * num_peers);
848 "data_output_file", 964 if ( (NULL != data_filename) &&
849 &data_filename)) 965 (NULL == (data_file =
850 { 966 GNUNET_DISK_file_open (data_filename,
851 data_file = 967 GNUNET_DISK_OPEN_READWRITE |
852 GNUNET_DISK_file_open (data_filename, 968 GNUNET_DISK_OPEN_TRUNCATE |
853 GNUNET_DISK_OPEN_READWRITE | 969 GNUNET_DISK_OPEN_CREATE,
854 GNUNET_DISK_OPEN_TRUNCATE | 970 GNUNET_DISK_PERM_USER_READ |
855 GNUNET_DISK_OPEN_CREATE, 971 GNUNET_DISK_PERM_USER_WRITE))) )
856 GNUNET_DISK_PERM_USER_READ | 972 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
857 GNUNET_DISK_PERM_USER_WRITE); 973 "open",
858 if (data_file == NULL) 974 data_filename);
859 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", 975
860 data_filename); 976 if ( (NULL != output_filename) &&
861 GNUNET_free (data_filename); 977 (NULL == (output_file =
862 } 978 GNUNET_DISK_file_open (output_filename,
863 979 GNUNET_DISK_OPEN_READWRITE |
864 if (GNUNET_YES == 980 GNUNET_DISK_OPEN_CREATE,
865 GNUNET_CONFIGURATION_get_value_string (cfg, "nse-profiler", "output_file", 981 GNUNET_DISK_PERM_USER_READ |
866 &temp_str)) 982 GNUNET_DISK_PERM_USER_WRITE))) )
867 { 983 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open",
868 output_file = 984 output_filename);
869 GNUNET_DISK_file_open (temp_str, 985
870 GNUNET_DISK_OPEN_READWRITE | 986 if (NULL ==
871 GNUNET_DISK_OPEN_CREATE, 987 (copro = GNUNET_TESTBED_controller_start (controller_ip, NULL,
872 GNUNET_DISK_PERM_USER_READ | 988 cfg,
873 GNUNET_DISK_PERM_USER_WRITE); 989 &controller_start_cb, NULL)))
874 if (output_file == NULL) 990 {
875 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", 991 fprintf (stderr,
876 temp_str); 992 "Failed to start controller\n");
877 } 993 return;
878 GNUNET_free_non_null (temp_str); 994 }
879 995 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
880 hosts = GNUNET_TESTING_hosts_load (testing_cfg); 996 &shutdown_task, NULL);
881
882 pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT,
883 &connect_cb, &my_cb, NULL, hosts);
884 GNUNET_assert (pg != NULL);
885 shutdown_handle =
886 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
887 &shutdown_task, NULL);
888} 997}
889 998
890 999
891
892/** 1000/**
893 * nse-profiler command line options 1001 * Main function.
1002 *
1003 * @return 0 on success
894 */ 1004 */
895static struct GNUNET_GETOPT_CommandLineOption options[] = {
896 {'V', "verbose", NULL,
897 gettext_noop ("be verbose (print progress information)"),
898 0, &GNUNET_GETOPT_set_one, &verbose},
899 GNUNET_GETOPT_OPTION_END
900};
901
902
903int 1005int
904main (int argc, char *const *argv) 1006main (int argc, char *const *argv)
905{ 1007{
1008 static struct GNUNET_GETOPT_CommandLineOption options[] = {
1009 {'C', "connections", "COUNT",
1010 gettext_noop ("limit to the number of connections to NSE services, 0 for none"),
1011 1, &GNUNET_GETOPT_set_string, &num_peer_spec},
1012 {'d', "details", "FILENAME",
1013 gettext_noop ("name of the file for writing connection information and statistics"),
1014 1, &GNUNET_GETOPT_set_string, &data_filename},
1015 {'H', "hosts", "FILENAME",
1016 gettext_noop ("name of the file with the login information for the testbed"),
1017 1, &GNUNET_GETOPT_set_string, &hosts_file},
1018 {'i', "ip", "CONTROLLER_IP",
1019 gettext_noop ("IP address of this system as seen by the rest of the testbed"),
1020 1, &GNUNET_GETOPT_set_string, &controller_ip},
1021 {'I', "interval", "DELAY",
1022 gettext_noop ("delay between queries to statistics during a round"),
1023 1, &GNUNET_GETOPT_set_relative_time, &interval},
1024 {'t', "topology", "FILENAME",
1025 gettext_noop ("prefix of the filenames we use for writing the topology for each round"),
1026 1, &GNUNET_GETOPT_set_string, &topology_file},
1027 {'o', "output", "FILENAME",
1028 gettext_noop ("name of the file for writing the main results"),
1029 1, &GNUNET_GETOPT_set_string, &output_filename},
1030 {'p', "peers", "NETWORKSIZESPEC",
1031 gettext_noop ("Number of peers to run in each round, separated by commas"),
1032 1, &GNUNET_GETOPT_set_string, &num_peer_spec},
1033 {'V', "verbose", NULL,
1034 gettext_noop ("be verbose (print progress information)"),
1035 0, &GNUNET_GETOPT_increment_value, &verbose},
1036 {'w', "wait", "DELAY",
1037 gettext_noop ("delay between rounds"),
1038 1, &GNUNET_GETOPT_set_relative_time, &wait_time},
1039 GNUNET_GETOPT_OPTION_END
1040 };
906 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 1041 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
907 return 2; 1042 return 2;
908 1043 GNUNET_log_setup ("nse-profiler", "WARNING", NULL);
909 GNUNET_log_setup ("nse-profiler",
910 "WARNING",
911 NULL);
912 if (GNUNET_OK != 1044 if (GNUNET_OK !=
913 GNUNET_PROGRAM_run (argc, argv, "nse-profiler", 1045 GNUNET_PROGRAM_run (argc, argv, "nse-profiler",
914 gettext_noop 1046 gettext_noop
915 ("Measure quality and performance of the NSE service."), 1047 ("Measure quality and performance of the NSE service."),
916 options, &run, NULL)) 1048 options, &run, NULL))
917 ok = 1; 1049 ok = 1;
918#if REMOVE_DIR
919 GNUNET_DISK_directory_remove ("/tmp/nse-profiler");
920#endif
921 return ok; 1050 return ok;
922} 1051}
923 1052