A simple addition with significant performance implications:
sicslowpan tags TCP packets with the PACKETBUF_ATTR_PACKET_TYPE_STREAM flag, which makes the underlying power-saving MAC layer keep the radio on for some time after transmitting the packet. This allows reply packets to be processed directly, significantly increasing TCP latency and throughput.
This commit is contained in:
parent
0a12f6da77
commit
5aab2eb77d
4 changed files with 133 additions and 34 deletions
|
@ -28,7 +28,7 @@
|
|||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
* $Id: lpp.c,v 1.26 2009/10/19 11:25:54 nifi Exp $
|
||||
* $Id: lpp.c,v 1.27 2009/11/02 11:58:56 adamdunkels Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -79,6 +79,7 @@
|
|||
#define WITH_ENCOUNTER_OPTIMIZATION 1
|
||||
#define WITH_ADAPTIVE_OFF_TIME 0
|
||||
#define WITH_PENDING_BROADCAST 1
|
||||
#define WITH_STREAMING 1
|
||||
|
||||
#ifdef LPP_CONF_LISTEN_TIME
|
||||
#define LISTEN_TIME LPP_CONF_LISTEN_TIME
|
||||
|
@ -180,6 +181,13 @@ struct encounter {
|
|||
#define MAX_ENCOUNTERS 4
|
||||
LIST(encounter_list);
|
||||
MEMB(encounter_memb, struct encounter, MAX_ENCOUNTERS);
|
||||
|
||||
#if WITH_STREAMING
|
||||
static uint8_t is_streaming;
|
||||
static struct ctimer stream_probe_timer, stream_off_timer;
|
||||
#define STREAM_PROBE_TIME CLOCK_SECOND / 128
|
||||
#define STREAM_OFF_TIME CLOCK_SECOND / 2
|
||||
#endif /* WITH_STREAMING */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
turn_radio_on(void)
|
||||
|
@ -191,7 +199,7 @@ turn_radio_on(void)
|
|||
static void
|
||||
turn_radio_off(void)
|
||||
{
|
||||
if(lpp_is_on) {
|
||||
if(lpp_is_on && is_streaming == 0) {
|
||||
radio->off();
|
||||
}
|
||||
/* leds_off(LEDS_YELLOW);*/
|
||||
|
@ -247,6 +255,12 @@ turn_radio_on_callback(void *packet)
|
|||
/* printf("enc\n");*/
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
stream_off(void *dummy)
|
||||
{
|
||||
is_streaming = 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* This function goes through all encounters to see if it finds a
|
||||
matching neighbor. If so, we set a ctimer that will turn on the
|
||||
radio just before we expect the neighbor to send a probe packet. If
|
||||
|
@ -261,6 +275,18 @@ turn_radio_on_for_neighbor(rimeaddr_t *neighbor, struct queue_list_item *i)
|
|||
{
|
||||
struct encounter *e;
|
||||
|
||||
#if WITH_STREAMING
|
||||
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
|
||||
PACKETBUF_ATTR_PACKET_TYPE_STREAM) {
|
||||
is_streaming = 1;
|
||||
turn_radio_on();
|
||||
list_add(queued_packets_list, i);
|
||||
ctimer_set(&stream_off_timer, STREAM_OFF_TIME,
|
||||
stream_off, NULL);
|
||||
return;
|
||||
}
|
||||
#endif /* WITH_STREAMING */
|
||||
|
||||
if(rimeaddr_cmp(neighbor, &rimeaddr_null)) {
|
||||
#if ! WITH_PENDING_BROADCAST
|
||||
/* We have been asked to turn on the radio for a broadcast, so we
|
||||
|
@ -402,6 +428,19 @@ send_probe(void)
|
|||
compower_accumulate(&compower_idle_activity);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
send_stream_probe(void *dummy)
|
||||
{
|
||||
/* Turn on the radio for sending a probe packet and
|
||||
anticipating a data packet from a neighbor. */
|
||||
turn_radio_on();
|
||||
|
||||
/* Send a probe packet. */
|
||||
send_probe();
|
||||
|
||||
is_streaming = 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
num_packets_to_send(void)
|
||||
{
|
||||
|
@ -718,6 +757,13 @@ read_packet(void)
|
|||
/* Send a probe packet to catch any reply from the other node. */
|
||||
restart_dutycycle(PROBE_AFTER_TRANSMISSION_TIME);
|
||||
#endif /* WITH_PROBE_AFTER_TRANSMISSION */
|
||||
|
||||
#if WITH_STREAMING
|
||||
if(is_streaming) {
|
||||
ctimer_set(&stream_probe_timer, STREAM_PROBE_TIME,
|
||||
send_stream_probe, NULL);
|
||||
}
|
||||
#endif /* WITH_STREAMING */
|
||||
}
|
||||
|
||||
#if WITH_ACK_OPTIMIZATION
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
* $Id: xmac.c,v 1.39 2009/10/19 21:27:02 adamdunkels Exp $
|
||||
* $Id: xmac.c,v 1.40 2009/11/02 11:58:56 adamdunkels Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -54,6 +54,10 @@
|
|||
|
||||
#include "contiki-conf.h"
|
||||
|
||||
#ifdef EXPERIMENT_SETUP
|
||||
#include "experiment-setup.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define WITH_CHANNEL_CHECK 0 /* Seems to work badly when enabled */
|
||||
|
@ -160,12 +164,12 @@ static const struct radio_driver *radio;
|
|||
#define PRINTF(...) printf(__VA_ARGS__)
|
||||
#define PRINTDEBUG(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#undef LEDS_ON
|
||||
/*#undef LEDS_ON
|
||||
#undef LEDS_OFF
|
||||
#undef LEDS_TOGGLE
|
||||
#define LEDS_ON(x)
|
||||
#define LEDS_OFF(x)
|
||||
#define LEDS_TOGGLE(x)
|
||||
#define LEDS_TOGGLE(x)*/
|
||||
#define PRINTF(...)
|
||||
#define PRINTDEBUG(...)
|
||||
#endif
|
||||
|
@ -205,6 +209,11 @@ LIST(encounter_list);
|
|||
MEMB(encounter_memb, struct encounter, MAX_ENCOUNTERS);
|
||||
#endif /* WITH_ENCOUNTER_OPTIMIZATION */
|
||||
|
||||
static uint8_t is_streaming;
|
||||
static rimeaddr_t is_streaming_to, is_streaming_to_too;
|
||||
static rtimer_clock_t stream_until;
|
||||
#define DEFAULT_STREAM_TIME (RTIMER_ARCH_SECOND)
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b)? (a) : (b))
|
||||
#endif /* MIN */
|
||||
|
@ -229,7 +238,8 @@ on(void)
|
|||
static void
|
||||
off(void)
|
||||
{
|
||||
if(xmac_is_on && radio_is_on != 0 && is_listening == 0) {
|
||||
if(xmac_is_on && radio_is_on != 0 && is_listening == 0 &&
|
||||
is_streaming == 0) {
|
||||
radio_is_on = 0;
|
||||
radio->off();
|
||||
LEDS_OFF(LEDS_RED);
|
||||
|
@ -244,6 +254,14 @@ powercycle(struct rtimer *t, void *ptr)
|
|||
rtimer_clock_t should_be, adjust;
|
||||
#endif /* WITH_TIMESYNCH */
|
||||
|
||||
if(is_streaming) {
|
||||
if(!RTIMER_CLOCK_LT(RTIMER_NOW(), stream_until)) {
|
||||
is_streaming = 0;
|
||||
rimeaddr_copy(&is_streaming_to, &rimeaddr_null);
|
||||
rimeaddr_copy(&is_streaming_to_too, &rimeaddr_null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PT_BEGIN(&pt);
|
||||
|
||||
|
@ -438,6 +456,8 @@ send_packet(void)
|
|||
int is_reliable;
|
||||
struct encounter *e;
|
||||
struct queuebuf *packet;
|
||||
int is_already_streaming = 0;
|
||||
|
||||
|
||||
#if WITH_RANDOM_WAIT_BEFORE_SEND
|
||||
{
|
||||
|
@ -445,6 +465,7 @@ send_packet(void)
|
|||
while(RTIMER_CLOCK_LT(RTIMER_NOW(), t));
|
||||
}
|
||||
#endif /* WITH_RANDOM_WAIT_BEFORE_SEND */
|
||||
|
||||
|
||||
/* Create the X-MAC header for the data packet. */
|
||||
packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
|
||||
|
@ -473,8 +494,8 @@ send_packet(void)
|
|||
len = framer_get()->create();
|
||||
strobe_len = len + sizeof(struct xmac_hdr);
|
||||
if(len == 0 || strobe_len > sizeof(strobe)) {
|
||||
/* Failed to send */
|
||||
PRINTF("xmac: send failed, too large header\n");
|
||||
/* Failed to send */
|
||||
PRINTF("xmac: send failed, too large header\n");
|
||||
return 0;
|
||||
}
|
||||
memcpy(strobe, packetbuf_hdrptr(), len);
|
||||
|
@ -493,25 +514,48 @@ send_packet(void)
|
|||
|
||||
#if WITH_CHANNEL_CHECK
|
||||
/* Check if there are other strobes in the air. */
|
||||
waiting_for_packet = 1;
|
||||
on();
|
||||
t0 = RTIMER_NOW();
|
||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + xmac_config.strobe_wait_time * 2)) {
|
||||
len = radio->read(&strobe.hdr, sizeof(strobe.hdr));
|
||||
if(len > 0) {
|
||||
someone_is_sending = 1;
|
||||
if(!someone_is_sending) {
|
||||
waiting_for_packet = 1;
|
||||
on();
|
||||
t0 = RTIMER_NOW();
|
||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + xmac_config.strobe_wait_time * 2)) {
|
||||
len = radio->read(&strobe.hdr, sizeof(strobe.hdr));
|
||||
if(len > 0) {
|
||||
someone_is_sending = 1;
|
||||
}
|
||||
}
|
||||
waiting_for_packet = 0;
|
||||
}
|
||||
waiting_for_packet = 0;
|
||||
|
||||
while(someone_is_sending);
|
||||
|
||||
#endif /* WITH_CHANNEL_CHECK */
|
||||
|
||||
|
||||
|
||||
/* By setting we_are_sending to one, we ensure that the rtimer
|
||||
powercycle interrupt do not interfere with us sending the packet. */
|
||||
we_are_sending = 1;
|
||||
|
||||
#if WITH_STREAMING
|
||||
if(is_streaming == 1 &&
|
||||
(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
|
||||
&is_streaming_to) ||
|
||||
rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
|
||||
&is_streaming_to_too))) {
|
||||
is_already_streaming = 1;
|
||||
}
|
||||
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
|
||||
PACKETBUF_ATTR_PACKET_TYPE_STREAM) {
|
||||
is_streaming = 1;
|
||||
if(rimeaddr_cmp(&is_streaming_to, &rimeaddr_null)) {
|
||||
rimeaddr_copy(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
|
||||
} else if(!rimeaddr_cmp(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER))) {
|
||||
rimeaddr_copy(&is_streaming_to_too, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
|
||||
}
|
||||
stream_until = RTIMER_NOW() + DEFAULT_STREAM_TIME;
|
||||
}
|
||||
#endif /* WITH_STREAMING */
|
||||
|
||||
off();
|
||||
|
||||
#if WITH_ENCOUNTER_OPTIMIZATION
|
||||
|
@ -539,7 +583,8 @@ send_packet(void)
|
|||
#if WITH_ACK_OPTIMIZATION
|
||||
/* Wait until the receiver is expected to be awake */
|
||||
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) !=
|
||||
PACKETBUF_ATTR_PACKET_TYPE_ACK) {
|
||||
PACKETBUF_ATTR_PACKET_TYPE_ACK &&
|
||||
is_streaming == 0) {
|
||||
/* Do not wait if we are sending an ACK, because then the
|
||||
receiver will already be awake. */
|
||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected));
|
||||
|
@ -564,6 +609,8 @@ send_packet(void)
|
|||
on();
|
||||
}
|
||||
|
||||
if(!is_already_streaming) {
|
||||
|
||||
watchdog_stop();
|
||||
got_strobe_ack = 0;
|
||||
for(strobes = 0;
|
||||
|
@ -624,37 +671,36 @@ send_packet(void)
|
|||
on();
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
#if WITH_ACK_OPTIMIZATION
|
||||
/* If we have received the strobe ACK, and we are sending a packet
|
||||
that will need an upper layer ACK (as signified by the
|
||||
PACKETBUF_ATTR_RELIABLE packet attribute), we keep the radio on. */
|
||||
if(got_strobe_ack && (packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
|
||||
packetbuf_attr(PACKETBUF_ATTR_ERELIABLE))) {
|
||||
|
||||
#if WITH_ACK_OPTIMIZATION
|
||||
packetbuf_attr(PACKETBUF_ATTR_ERELIABLE) ||
|
||||
packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
|
||||
PACKETBUF_ATTR_PACKET_TYPE_STREAM)) {
|
||||
on(); /* Wait for ACK packet */
|
||||
waiting_for_packet = 1;
|
||||
#else /* WITH_ACK_OPTIMIZATION */
|
||||
off();
|
||||
#endif /* WITH_ACK_OPTIMIZATION */
|
||||
|
||||
} else {
|
||||
|
||||
off(); /* shell ping don't seem to work with off() here, so we'll
|
||||
keep it on() for a while. */
|
||||
off();
|
||||
}
|
||||
#else /* WITH_ACK_OPTIMIZATION */
|
||||
off();
|
||||
#endif /* WITH_ACK_OPTIMIZATION */
|
||||
|
||||
/* restore the packet to send */
|
||||
queuebuf_to_packetbuf(packet);
|
||||
queuebuf_free(packet);
|
||||
|
||||
/* Send the data packet. */
|
||||
if(is_broadcast || got_strobe_ack) {
|
||||
if(is_broadcast || got_strobe_ack || is_streaming) {
|
||||
radio->send(packetbuf_hdrptr(), packetbuf_totlen());
|
||||
}
|
||||
|
||||
#if WITH_ENCOUNTER_OPTIMIZATION
|
||||
if(got_strobe_ack) {
|
||||
if(got_strobe_ack && !is_streaming) {
|
||||
register_encounter(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time);
|
||||
}
|
||||
#endif /* WITH_ENCOUNTER_OPTIMIZATION */
|
||||
|
@ -738,7 +784,6 @@ read_packet(void)
|
|||
hdr = packetbuf_dataptr();
|
||||
|
||||
if(hdr->dispatch != DISPATCH) {
|
||||
|
||||
someone_is_sending = 0;
|
||||
if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
|
||||
&rimeaddr_node_addr) ||
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
* $Id: packetbuf.h,v 1.3 2009/10/19 21:28:11 adamdunkels Exp $
|
||||
* $Id: packetbuf.h,v 1.4 2009/11/02 11:58:56 adamdunkels Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -316,6 +316,8 @@ extern const char *packetbuf_attr_strings[];
|
|||
|
||||
#define PACKETBUF_ATTR_PACKET_TYPE_DATA 0
|
||||
#define PACKETBUF_ATTR_PACKET_TYPE_ACK 1
|
||||
#define PACKETBUF_ATTR_PACKET_TYPE_STREAM 2
|
||||
|
||||
enum {
|
||||
PACKETBUF_ATTR_NONE,
|
||||
PACKETBUF_ATTR_CHANNEL,
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
* $Id: sicslowpan.c,v 1.9 2009/09/18 16:37:17 nifi Exp $
|
||||
* $Id: sicslowpan.c,v 1.10 2009/11/02 11:58:56 adamdunkels Exp $
|
||||
*/
|
||||
/**
|
||||
* \file
|
||||
|
@ -1139,7 +1139,12 @@ output(uip_lladdr_t *localdest)
|
|||
/* reset rime buffer */
|
||||
packetbuf_clear();
|
||||
rime_ptr = packetbuf_dataptr();
|
||||
|
||||
|
||||
if(UIP_IP_BUF->proto == UIP_PROTO_TCP) {
|
||||
packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
|
||||
PACKETBUF_ATTR_PACKET_TYPE_STREAM);
|
||||
}
|
||||
|
||||
/*
|
||||
* The destination address will be tagged to each outbound
|
||||
* packet. If the argument localdest is NULL, we are sending a
|
||||
|
@ -1445,6 +1450,7 @@ input(const struct mac_driver *r)
|
|||
sicslowpan_len = 0;
|
||||
processed_ip_len = 0;
|
||||
#endif /* SICSLOWPAN_CONF_FRAG */
|
||||
|
||||
tcpip_input();
|
||||
#if SICSLOWPAN_CONF_FRAG
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue