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:
adamdunkels 2009-11-02 11:58:56 +00:00
parent 0a12f6da77
commit 5aab2eb77d
4 changed files with 133 additions and 34 deletions

View file

@ -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

View file

@ -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) ||

View file

@ -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,

View file

@ -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
}