Commit 6278d069 authored by Jonathon Duerig's avatar Jonathon Duerig

Added idle/pcap loss avoidance to the system. Plus many miscellaneous...

Added idle/pcap loss avoidance to the system. Plus many miscellaneous debugging statements. Most notable is that there is not debugging output describing the throughput as seen at the offered load level (how much you can write to the socket buffer).
parent 1572945b
......@@ -48,7 +48,10 @@ void DelaySensor::localAck(PacketInfo * packet)
*/
if (state->isAckValid() && packetHistory->isAckValid()
&& !packetHistory->getIsRetransmit()
&& state->getState() == StateSensor::ESTABLISHED)
&& state->getState() == StateSensor::ESTABLISHED
&& (packetHistory->getRegionState() == PacketSensor::VALID_REGION
|| packetHistory->getRegionState()
== PacketSensor::BEGIN_VALID_REGION))
{
Time diff = packet->packetTime - packetHistory->getAckedSendTime();
lastDelay = diff.toMilliseconds();
......
......@@ -5,6 +5,8 @@
#include "KernelTcp.h"
#include "Command.h"
#include "TSThroughputSensor.h"
using namespace std;
namespace
......@@ -36,6 +38,8 @@ KernelTcp::KernelTcp()
, receiveBufferSize(0)
, maxSegmentSize(0)
, useNagles(1)
, debugPrevTime(getCurrentTime())
, debugByteCount(0)
{
}
......@@ -229,6 +233,21 @@ int KernelTcp::writeMessage(int size, WriteResult & result)
{
logWrite(CONNECTION_MODEL,"Buffer is full");
result.bufferFull = true;
Time currentTime = getCurrentTime();
uint32_t timeTotal = (currentTime - debugPrevTime).toMilliseconds();
if (debugByteCount > 0 && timeTotal > 0)
{
logWrite(CONNECTION_MODEL,
"Load estimate: %d kbps, %d kilobits, %d millis",
TSThroughputSensor::getThroughputInKbps(timeTotal,
debugByteCount),
debugByteCount, timeTotal);
debugPrevTime = currentTime;
debugByteCount = 0;
}
// XXX This doesn't make sense. We know that error is -1.
// No point in trying more writes
return bytesWritten + error;
}
......@@ -240,7 +259,9 @@ int KernelTcp::writeMessage(int size, WriteResult & result)
}
else
{
debugByteCount += error;
// Write succeeded, all bytes got written
// XXX Shouldn't this be error?
bytesWritten += bytesToWrite;
}
}
......
......@@ -31,6 +31,9 @@ private:
int maxSegmentSize;
int useNagles;
static const int MAX_WRITESIZE;
private:
Time debugPrevTime;
int debugByteCount;
public:
static pcap_t * pcapDescriptor;
static int pcapfd;
......
......@@ -103,8 +103,9 @@ void LeastSquaresThroughput::localAck(PacketInfo * packet)
// Calculate throughput.
logWrite(SENSOR, "LeastSquares: timeTotal: %d, kilobitTotal: %f",
timeTotal, byteTotal*(8.0/1000.0));
double throughputAverage = throughput->getThroughputInKbps(timeTotal,
byteTotal);
double throughputAverage
= TSThroughputSensor::getThroughputInKbps(timeTotal,
byteTotal);
double num = (numA * numD) - (numB * numC);
double denom = (denomA * denomD) - (denomB * denomC);
......
......@@ -13,6 +13,8 @@ PacketSensor::PacketSensor(StateSensor const * newState)
ackedSize = 0;
ackedSendTime = Time();
isRetransmit = false;
currentRegionState = INVALID_REGION;
lastAckTime = Time();
}
int PacketSensor::getAckedSize(void) const
......@@ -59,8 +61,28 @@ Time const & PacketSensor::getAckedSendTime(void) const
}
}
PacketSensor::RegionState PacketSensor::getRegionState(void) const
{
if (ackValid || sendValid)
{
return currentRegionState;
}
else
{
logWrite(ERROR,
"PacketSensor::getRegionState() called "
"with invalid ack or send data");
return INVALID_REGION;
}
}
void PacketSensor::localSend(PacketInfo * packet)
{
ackValid = false;
if (currentRegionState == BEGIN_VALID_REGION)
{
currentRegionState = VALID_REGION;
}
/*
* Check for window scaling, which is not supported yet by this code. This
* option is only legal on SACK packets. If we decide to support window
......@@ -99,7 +121,6 @@ void PacketSensor::localSend(PacketInfo * packet)
}
// Assume this packet is not a retransmit unless proven otherwise
ackValid = true;
isRetransmit = false;
if (state->isSendValid() && state->getState() == StateSensor::ESTABLISHED)
{
......@@ -159,6 +180,13 @@ void PacketSensor::localSend(PacketInfo * packet)
{
globalSequence.seqStart = record.seqStart;
globalSequence.seqEnd = record.seqEnd;
if (packet->packetTime > lastAckTime)
{
// Only invalidate if this packet happened after the last
// ack packet. This is necessary because of the re-ordering
// problem.
currentRegionState = INVALID_REGION;
}
}
else
{
......@@ -241,6 +269,11 @@ void PacketSensor::localSend(PacketInfo * packet)
void PacketSensor::localAck(PacketInfo * packet)
{
sendValid = false;
lastAckTime = packet->packetTime;
if (currentRegionState == BEGIN_VALID_REGION)
{
currentRegionState = VALID_REGION;
}
// Right now, we don't know whether or not this ACK is for a retransmitted
// packet - we will find out later
isRetransmit = false;
......@@ -366,6 +399,7 @@ void PacketSensor::localAck(PacketInfo * packet)
*/
ackedSize = 0;
ackedSendTime = Time();
bool isRegionValid = true;
rangelist::iterator range;
for (range = ranges.begin(); range != ranges.end(); range++) {
uint32_t range_start = range->start;
......@@ -405,6 +439,7 @@ void PacketSensor::localAck(PacketInfo * packet)
if (firstPacket == unacked.end()) {
logWrite(ERROR, "Range starts in unknown packet");
isRegionValid = false;
ackValid = false;
break;
}
......@@ -518,6 +553,16 @@ void PacketSensor::localAck(PacketInfo * packet)
ackedSendTime = pos->timestamp;
}
/*
* If any of the packets are fake, that means that there have
* been some packets dropped by libpcap. This means, that we
* know that it is invalid.
*/
if (pos->fake)
{
isRegionValid = false;
}
if (pos == lastPacket) {
break;
} else {
......@@ -540,6 +585,9 @@ void PacketSensor::localAck(PacketInfo * packet)
{
globalSequence.seqStart = 0;
globalSequence.seqEnd = 0;
// We don't want to start in INVALID_REGION yet. Since some
// packets are re-ordered, we may have gotten all available
// acks, but not the sends which were actually earlier.
}
else
{
......@@ -548,6 +596,22 @@ void PacketSensor::localAck(PacketInfo * packet)
}
}
if (isRegionValid)
{
if (currentRegionState == INVALID_REGION)
{
currentRegionState = BEGIN_VALID_REGION;
}
else
{
currentRegionState = VALID_REGION;
}
}
else
{
currentRegionState = INVALID_REGION;
}
if (ackedSendTime == Time())
{
logWrite(EXCEPTION, "PacketSensor::localAck() received an ack for only "
......
......@@ -13,6 +13,26 @@ class StateSensor;
class PacketSensor : public Sensor
{
public:
// An INVALID_REGION indicates that either a period of idleness in
// the connection has occurred (all packets have been acked at some
// point, and the next ack has not yet been reached). Or a packet
// loss has occurred and no ack has yet acked only valid packets.
// A BEGIN_VALID_REGION indicates the first packet of a region. This
// can be used as the starting barrier for difference calculations
// in timestamps, for instance. This is set on the first valid ack
// packet. On the next packet, the state is changed to VALID_REGION
// A VALID_REGION indicates that this packet represents a packet in
// the stream when no funny business with packet loss or connection
// idleness has been detected.
enum RegionState
{
INVALID_REGION,
BEGIN_VALID_REGION,
VALID_REGION
};
public:
PacketSensor(StateSensor const * newState);
// Get the size of the acknowledgement in bytes.
......@@ -21,6 +41,7 @@ public:
bool getIsRetransmit(void) const;
// Get the time of the last packet sent which was acked.
Time const & getAckedSendTime(void) const;
RegionState getRegionState(void) const;
protected:
virtual void localSend(PacketInfo * packet);
virtual void localAck(PacketInfo * packet);
......@@ -55,7 +76,7 @@ private:
/*
* We use this to keep track of the ranges being ACKed and SACKed
*/
struct Range
struct Range
{
Range(unsigned int, unsigned int, bool);
unsigned int start;
......@@ -68,6 +89,8 @@ private:
Time ackedSendTime;
SentPacket globalSequence;
bool isRetransmit;
RegionState currentRegionState;
Time lastAckTime;
StateSensor const * state;
......
......@@ -30,7 +30,7 @@ int TSThroughputSensor::getThroughputInKbps(void) const
}
int TSThroughputSensor::getThroughputInKbps(uint32_t period,
int byteCount) const
int byteCount)
{
double kilobits = byteCount * (8.0/1000.0);
int result = 0;
......@@ -87,8 +87,15 @@ void TSThroughputSensor::localAck(PacketInfo * packet)
{
sendValid = false;
if (state->isAckValid() && packetHistory->isAckValid() &&
state->getState() == StateSensor::ESTABLISHED)
state->getState() == StateSensor::ESTABLISHED
&& (packetHistory->getRegionState() == PacketSensor::VALID_REGION
|| packetHistory->getRegionState()
== PacketSensor::BEGIN_VALID_REGION))
{
if (packetHistory->getRegionState() == PacketSensor::BEGIN_VALID_REGION)
{
lastAckTS = 0;
}
/*
* Find the time the other end of this connection says it sent this
* ACK
......@@ -101,7 +108,7 @@ void TSThroughputSensor::localAck(PacketInfo * packet)
*/
if (currentAckTS == 0) {
logWrite(ERROR,"TSThroughputSensor::localAck() got a packet without a "
"timestamp");
"timestamp");
ackValid = false;
lastPeriod = 1;
lastByteCount = 0;
......@@ -111,7 +118,7 @@ void TSThroughputSensor::localAck(PacketInfo * packet)
if (lastAckTS != 0 && currentAckTS < lastAckTS) {
logWrite(ERROR,"TSThroughputSensor::localAck() got timestamps in reverse "
"order: o=%u,n=%u",lastAckTS,currentAckTS);
"order: o=%u,n=%u",lastAckTS,currentAckTS);
ackValid = false;
lastPeriod = 1;
lastByteCount = 0;
......@@ -136,8 +143,8 @@ void TSThroughputSensor::localAck(PacketInfo * packet)
ackValid = false;
deferredBytes += packetHistory->getAckedSize();
logWrite(SENSOR, "TSThroughputSensor::localAck() deferring %i bytes "
"due to zero period (%i total)",
packetHistory->getAckedSize(), deferredBytes);
"due to zero period (%i total)",
packetHistory->getAckedSize(), deferredBytes);
} else {
ackValid = true;
/*
......@@ -149,8 +156,8 @@ void TSThroughputSensor::localAck(PacketInfo * packet)
lastPeriod = period;
lastByteCount = packetHistory->getAckedSize() + deferredBytes;
logWrite(SENSOR, "TSTHROUGHPUT: %d kbps (period=%i,kbits=%f,deferred=%f)",
getThroughputInKbps(), lastPeriod, lastByteCount*(8.0/1000.0),
deferredBytes*(8.0/1000));
getThroughputInKbps(), lastPeriod, lastByteCount*(8.0/1000.0),
deferredBytes*(8.0/1000));
deferredBytes = 0;
}
}
......
......@@ -24,7 +24,7 @@ public:
TSThroughputSensor(PacketSensor const * newPacketHistory,
StateSensor const * newState);
int getThroughputInKbps(void) const;
int getThroughputInKbps(uint32_t period, int byteCount) const;
static int getThroughputInKbps(uint32_t period, int byteCount);
uint32_t getLastPeriod(void) const;
int getLastByteCount(void) const;
protected:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment