43 #include "contiki-conf.h"
49 int snprintf(
char *str,
size_t size,
const char *format, ...);
56 #define CONTINUE_EVENT 128
59 unsigned long lpm, cpu, rx, tx;
63 uint16_t sent, received, timedout;
64 unsigned long total_tx_latency;
65 unsigned long total_rx_latency;
66 clock_time_t start, end;
67 struct power power0, power;
72 DATAPATH_COMMAND_NONE,
73 DATAPATH_COMMAND_ECHO_REQUEST,
74 DATAPATH_COMMAND_STREAM_ECHO_REQUEST,
75 DATAPATH_COMMAND_ECHO_REPLY,
80 rtimer_clock_t tx, rx;
81 uint8_t datapath_command;
88 CTRL_COMMAND_STATS_REPLY
96 static struct runicast_conn ctrl;
97 static struct unicast_conn unicast;
98 static struct broadcast_conn broadcast;
99 static struct mesh_conn mesh;
100 static struct rucb_conn rucb;
102 static linkaddr_t receiver;
103 static uint8_t is_sender;
104 static int left_to_send;
106 static struct stats stats;
112 TYPE_UNICAST_PINGPONG = 3,
113 TYPE_UNICAST_STREAM = 4,
116 static uint8_t current_type;
119 PROCESS(shell_netperf_process,
"netperf");
122 "netperf: measure single-hop network performance",
123 &shell_netperf_process);
126 memcpy_misaligned(
void *dest,
const void *source,
int len)
130 const uint8_t *sourceptr;
131 if(((
int)dest & 1) == 1 ||
132 ((
int)source & 1) == 1) {
135 for(i = 0; i < len; ++i) {
136 *destptr++ = *sourceptr++;
139 memcpy(dest, source, len);
144 print_remote_stats(
struct stats *s)
146 unsigned long total_time;
148 printf(
"%d 1 %d %d %d %lu %lu %lu %lu %lu %lu %lu # for automatic processing\n",
150 s->sent, s->received, s->timedout,
152 s->total_tx_latency, s->total_rx_latency,
153 s->power.cpu - s->power0.cpu,
154 s->power.lpm - s->power0.lpm,
155 s->power.rx - s->power0.rx,
156 s->power.tx - s->power0.tx);
158 printf(
"Remote node statistics:\n");
159 total_time = s->power.cpu + s->power.lpm - s->power0.cpu - s->power0.lpm;
160 printf(
" Remote radio duty cycle: rx %lu.%02lu%% tx %lu.%02lu%%\n",
161 (100 * (s->power.rx - s->power0.rx))/total_time,
162 ((10000 * (s->power.rx - s->power0.rx))/total_time) % 100,
163 (100 * (s->power.tx - s->power0.tx))/total_time,
164 ((10000 * (s->power.tx - s->power0.tx))/total_time) % 100);
166 printf(
" Packets: sent %d received %d\n",
167 s->sent, s->received);
171 print_local_stats(
struct stats *s)
173 unsigned long total_time;
175 printf(
"%d 0 %d %d %d %lu %lu %lu %lu %lu %lu %lu # for automatic processing\n",
177 s->sent, s->received, s->timedout,
179 s->total_tx_latency, s->total_rx_latency,
180 s->power.cpu - s->power0.cpu,
181 s->power.lpm - s->power0.lpm,
182 s->power.rx - s->power0.rx,
183 s->power.tx - s->power0.tx);
185 printf(
"Local node statistics:\n");
187 printf(
" Total transfer time: %lu.%02lu seconds, %lu.%02lu packets/second\n",
191 (((100UL * CLOCK_SECOND * s->sent) / (s->end - s->start)) % 100));
193 printf(
" Average round-trip-time: %lu ms (%lu + %lu)\n",
194 (1000 * (s->total_rx_latency + s->total_tx_latency) / s->received) /
196 (1000 * (s->total_tx_latency) / s->received) /
198 (1000 * (s->total_rx_latency) / s->received) /
201 total_time = s->power.cpu + s->power.lpm - s->power0.cpu - s->power0.lpm;
202 printf(
" Radio duty cycle: rx %lu.%02lu%% tx %lu.%02lu%%\n",
203 (100 * (s->power.rx - s->power0.rx))/total_time,
204 ((10000 * (s->power.rx - s->power0.rx))/total_time) % 100,
205 (100 * (s->power.tx - s->power0.tx))/total_time,
206 ((10000 * (s->power.tx - s->power0.tx))/total_time) % 100);
208 printf(
" Packets received: %d.%lu%%, %d of %d\n",
209 100 * s->received / s->sent,
210 (10000L * s->received / s->sent) % 10,
211 s->received, s->sent);
215 sample_power_profile(
struct power *p)
218 p->lpm = energest_type_time(ENERGEST_TYPE_LPM);
219 p->cpu = energest_type_time(ENERGEST_TYPE_CPU);
220 p->rx = energest_type_time(ENERGEST_TYPE_LISTEN);
221 p->tx = energest_type_time(ENERGEST_TYPE_TRANSMIT);
227 memset(&stats, 0,
sizeof(stats));
229 sample_power_profile(&stats.power0);
233 setup_sending(linkaddr_t *to,
int num)
242 finalize_stats(
struct stats *s)
245 sample_power_profile(&stats.power);
248 static unsigned long filesize, bytecount, packetsize;
249 static int download_complete;
251 write_chunk(
struct rucb_conn *c,
int offset,
int flag,
252 char *data,
int datalen)
257 read_chunk(
struct rucb_conn *c,
int offset,
char *to,
int maxsize)
262 if(bytecount + maxsize >= filesize) {
263 size = filesize - bytecount;
265 if(size > packetsize) {
269 if(bytecount == filesize) {
271 download_complete = 1;
276 const static struct rucb_callbacks rucb_callbacks =
277 { write_chunk, read_chunk,
NULL };
280 construct_next_packet(
void)
282 struct datapath_msg *msg;
284 if(left_to_send > 0) {
287 msg->datapath_command = DATAPATH_COMMAND_NONE;
289 #if TIMESYNCH_CONF_ENABLED
292 msg->tx = msg->rx = 0;
302 construct_next_echo(
void)
304 struct datapath_msg *msg;
305 if(construct_next_packet()) {
307 msg->datapath_command = DATAPATH_COMMAND_ECHO_REQUEST;
314 construct_next_stream_echo(
void)
316 struct datapath_msg *msg;
317 if(construct_next_packet()) {
319 msg->datapath_command = DATAPATH_COMMAND_STREAM_ECHO_REQUEST;
320 packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
321 PACKETBUF_ATTR_PACKET_TYPE_STREAM);
328 process_incoming_packet(
void)
332 struct datapath_msg msg_copy;
334 #if TIMESYNCH_CONF_ENABLED
340 memcpy_misaligned(&msg_copy, (uint8_t *)msg,
sizeof(msg_copy));
342 stats.total_tx_latency += msg_copy.rx - msg_copy.tx;
343 stats.total_rx_latency += now - msg_copy.rx;
347 construct_reply(
const linkaddr_t *from)
350 #if TIMESYNCH_CONF_ENABLED
353 rtimer_clock_t now = 0;
356 memcpy_misaligned(&msg->rx, &now,
sizeof(rtimer_clock_t));
358 switch(msg->datapath_command) {
359 case DATAPATH_COMMAND_ECHO_REQUEST:
360 msg->datapath_command = DATAPATH_COMMAND_ECHO_REPLY;
362 case DATAPATH_COMMAND_STREAM_ECHO_REQUEST:
363 msg->datapath_command = DATAPATH_COMMAND_ECHO_REPLY;
364 packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
365 PACKETBUF_ATTR_PACKET_TYPE_STREAM);
368 if(msg->datapath_command == DATAPATH_COMMAND_ECHO_REPLY) {
370 msg->received = stats.received;
378 sent_mesh(
struct mesh_conn *c)
383 timedout_mesh(
struct mesh_conn *c)
386 if(construct_next_echo()) {
393 recv_mesh(
struct mesh_conn *c,
const linkaddr_t *from, uint8_t hops)
395 process_incoming_packet();
397 if(construct_next_echo()) {
401 if(construct_reply(from)) {
407 { recv_mesh, sent_mesh, timedout_mesh };
410 sent_ctrl(
struct runicast_conn *c,
const linkaddr_t *to, uint8_t rexmits)
415 timedout_ctrl(
struct runicast_conn *c,
const linkaddr_t *to, uint8_t rexmits)
417 shell_output_str(&netperf_command,
"netperf control connection failed",
"");
421 recv_ctrl(
struct runicast_conn *c,
const linkaddr_t *from, uint8_t seqno)
423 static uint8_t last_seqno = -1;
427 if(last_seqno == seqno) {
431 switch(msg->command) {
432 case CTRL_COMMAND_STATS:
433 msg->command = CTRL_COMMAND_STATS_REPLY;
434 finalize_stats(&stats);
435 memcpy_misaligned(&msg->stats, &stats,
sizeof(stats));
437 runicast_send(c, from, MAX_RETRIES);
439 case CTRL_COMMAND_STATS_REPLY:
440 memcpy_misaligned(&s, &msg->stats,
sizeof(stats));
441 print_remote_stats(&s);
444 case CTRL_COMMAND_CLEAR:
449 const static struct runicast_callbacks runicast_callbacks =
450 { recv_ctrl, sent_ctrl, timedout_ctrl };
453 send_ctrl_command(
const linkaddr_t *to, uint8_t command)
455 struct ctrl_msg *msg;
459 msg->command = command;
460 return runicast_send(&ctrl, to, MAX_RETRIES);
464 recv_broadcast(
struct broadcast_conn *c,
const linkaddr_t *from)
466 process_incoming_packet();
468 }
else if(construct_reply(from)) {
476 recv_unicast(
struct unicast_conn *c,
const linkaddr_t *from)
478 process_incoming_packet();
481 if(msg->datapath_command == DATAPATH_COMMAND_ECHO_REPLY) {
484 }
else if(construct_reply(from)) {
485 unicast_send(&unicast, from);
488 const static struct unicast_callbacks unicast_callbacks =
495 "netperf [-b|u|p|s] <receiver> <num packets>: perform network measurements to receiver",
"");
497 " -b measure broadcast performance",
"");
499 " -u measure one-way unicast performance",
"");
501 " -p measure ping-pong unicast performance",
"");
503 " -s measure ping-pong stream unicast performance",
"");
507 shell_netperf_init(
void)
509 runicast_open(&ctrl, SHELL_RIME_CHANNEL_NETPERF, &runicast_callbacks);
510 broadcast_open(&broadcast, SHELL_RIME_CHANNEL_NETPERF + 1, &broadcast_callbacks);
511 unicast_open(&unicast, SHELL_RIME_CHANNEL_NETPERF + 2, &unicast_callbacks);
512 mesh_open(&mesh, SHELL_RIME_CHANNEL_NETPERF + 3, &mesh_callbacks);
513 rucb_open(&rucb, SHELL_RIME_CHANNEL_NETPERF + 5, &rucb_callbacks);
520 static linkaddr_t receiver;
523 static char recvstr[40];
524 static int i, num_packets;
525 static uint8_t do_broadcast, do_unicast, do_pingpong, do_stream_pingpong;
529 current_type = TYPE_NONE;
531 do_broadcast = do_unicast = do_pingpong =
532 do_stream_pingpong = 0;
537 while(*args ==
'-') {
539 while(*args !=
' ' &&
551 do_stream_pingpong = 1;
555 while(*args ==
' ') {
562 if(nextptr == data || *nextptr !=
'.') {
571 snprintf(recvstr,
sizeof(recvstr),
"%d.%d",
572 receiver.u8[0], receiver.u8[1]);
576 while(*args ==
' ') {
580 if(nextptr == data || num_packets == 0) {
587 current_type = TYPE_BROADCAST;
591 while(!send_ctrl_command(&receiver, CTRL_COMMAND_CLEAR)) {
596 shell_output_str(&netperf_command,
"Measuring broadcast performance to ", recvstr);
598 setup_sending(&receiver, num_packets);
599 for(i = 0; i < num_packets; ++i) {
600 if(construct_next_packet()) {
608 while(!send_ctrl_command(&receiver, CTRL_COMMAND_STATS)) {
616 finalize_stats(&stats);
617 print_local_stats(&stats);
621 current_type = TYPE_UNICAST;
622 shell_output_str(&netperf_command,
"-------- Unicast one-way --------",
"");
625 while(!send_ctrl_command(&receiver, CTRL_COMMAND_CLEAR)) {
630 shell_output_str(&netperf_command,
"Measuring unicast performance to ", recvstr);
632 setup_sending(&receiver, num_packets);
634 for(i = 0; i < num_packets; ++i) {
635 if(construct_next_packet()) {
636 unicast_send(&unicast, &receiver);
643 while(!send_ctrl_command(&receiver, CTRL_COMMAND_STATS)) {
651 finalize_stats(&stats);
652 print_local_stats(&stats);
655 current_type = TYPE_UNICAST_PINGPONG;
656 shell_output_str(&netperf_command,
"-------- Unicast ping-pong--------",
"");
659 while(!send_ctrl_command(&receiver, CTRL_COMMAND_CLEAR)) {
664 shell_output_str(&netperf_command,
"Measuring two-way unicast performance to ", recvstr);
666 setup_sending(&receiver, num_packets);
668 for(i = 0; i < num_packets; ++i) {
669 if(construct_next_echo()) {
671 unicast_send(&unicast, &receiver);
679 while(!send_ctrl_command(&receiver, CTRL_COMMAND_STATS)) {
687 finalize_stats(&stats);
688 print_local_stats(&stats);
690 if(do_stream_pingpong) {
691 current_type = TYPE_UNICAST_STREAM;
692 shell_output_str(&netperf_command,
"-------- Unicast stream ping-pong--------",
"");
695 while(!send_ctrl_command(&receiver, CTRL_COMMAND_CLEAR)) {
700 shell_output_str(&netperf_command,
"Measuring two-way unicast stream performance to ", recvstr);
702 setup_sending(&receiver, num_packets);
704 for(i = 0; i < num_packets; ++i) {
705 if(construct_next_stream_echo()) {
706 unicast_send(&unicast, &receiver);
714 while(!send_ctrl_command(&receiver, CTRL_COMMAND_STATS)) {
722 finalize_stats(&stats);
723 print_local_stats(&stats);
int mesh_send(struct mesh_conn *c, const linkaddr_t *to)
Send a mesh packet.
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
void shell_output_str(struct shell_command *c, char *text1, const char *text2)
Output strings from a shell command.
#define PROCESS_EXIT()
Exit the currently running process.
#define PROCESS_BEGIN()
Define the beginning of a process.
A brief description of what this file is.
#define NULL
The null pointer.
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Header file for the Rime stack
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
rtimer_clock_t timesynch_time(void)
Get the current time-synchronized time.
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a Rime address.
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
#define PROCESS_END()
Define the end of a process.
CCIF clock_time_t clock_time(void)
Get the current clock time.
unsigned long shell_strtolong(const char *str, const char **retstr)
Convert a string to a number.
Callback structure for broadcast.
void shell_register_command(struct shell_command *c)
Register a command with the shell.
#define PROCESS_PAUSE()
Yield the process for a short while.
#define PROCESS(name, strname)
Declare a process.
int broadcast_send(struct broadcast_conn *c)
Send an identified best-effort broadcast packet.
void packetbuf_clear(void)
Clear and reset the packetbuf.
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
void mesh_open(struct mesh_conn *c, uint16_t channels, const struct mesh_callbacks *callbacks)
Open a mesh connection.
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
void broadcast_open(struct broadcast_conn *c, uint16_t channel, const struct broadcast_callbacks *u)
Set up an identified best-effort broadcast connection.
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
void process_exit(struct process *p)
Cause a process to exit.
#define SHELL_COMMAND(name, command, description, process)
Define a shell command.
#define CLOCK_SECOND
A second, measured in system clock time.