Commit a27e29d3 authored by Jonathon Duerig's avatar Jonathon Duerig

New least squares time sensitive code. LeastSquaresThroughput now gets a...

New least squares time sensitive code. LeastSquaresThroughput now gets a single average throughput metric over the whole period of the samples and uses time as the x coordinate value for the linear regression.
parent 7293bbc0
......@@ -35,14 +35,20 @@ void LeastSquaresThroughput::localAck(PacketInfo * packet)
sendValid = false;
if (throughput->isAckValid() && delay->isAckValid())
{
throughputSamples[oldest] = throughput->getThroughputInKbps();
// throughputSamples[oldest] = throughput->getThroughputInKbps();
byteSamples[oldest] = throughput->getLastByteCount();
timeSamples[oldest] = throughput->getLastPeriod();
delaySamples[oldest] = delay->getLastDelay();
oldest = (oldest + 1) % SAMPLE_COUNT;
++totalSamples;
if (totalSamples >= SAMPLE_COUNT)
{
int i = 0;
double throughputAverage = 0;
// double throughputAverage = 0;
int byteTotal = 0;
uint32_t timeTotal = 0;
int x_i = 0;
int y_i = 0;
double numA = 0.0;
double numB = 0.0;
double numC = 0.0;
......@@ -54,30 +60,41 @@ void LeastSquaresThroughput::localAck(PacketInfo * packet)
for (; i < SAMPLE_COUNT; ++i)
{
int index = (oldest + i) % SAMPLE_COUNT;
throughputAverage += throughputSamples[index];
// throughputAverage += throughputSamples[index];
byteTotal += byteSamples[SAMPLE_COUNT];
timeTotal += timeSamples[SAMPLE_COUNT];
logWrite(SENSOR_DETAIL, "LeastSquares: Delay sample #%d: %d", i,
delaySamples[index]);
numA += i * delaySamples[index];
numB += i;
numC += delaySamples[index];
denomA += i * i;
denomB += i;
denomC += i;
x_i += timeSamples[SAMPLE_COUNT];
y_i = delaySamples[index];
numA += x_i * y_i;
numB += x_i;
numC += y_i;
denomA += x_i * x_i;
denomB += x_i;
denomC += x_i;
}
throughputAverage /= SAMPLE_COUNT;
// Calculate throughput.
// throughputAverage /= SAMPLE_COUNT;
double throughputAverage = throughput->getThroughputInKbps(timeTotal,
byteTotal);
double num = (numA * numD) - (numB * numC);
double denom = (denomA * denomD) - (denomB * denomC);
// Theoretically denom cannot be 0 because our x values are
// sample numbers which monotonically increase.
double slope = num/denom;
double slope = 0.0;
if (fabs(denom) > 0.00001)
{
slope = num/denom;
}
logWrite(SENSOR, "LeastSquares: SLOPE: %f TPA: %i LR:%i", slope,
static_cast<int>(throughputAverage),lastReport);
if (slope > 0)
if (slope > 0.0)
{
// The closest linear approximation indicates that buffers are
// being filled up, which means that the link was saturated
......
......@@ -27,7 +27,14 @@ private:
// The number of samples kept at any given time.
static const int SAMPLE_COUNT = 5;
// Circular buffers of the last SAMPLE_COUNT samples.
int throughputSamples[SAMPLE_COUNT];
// The number of bytes in each sample. Used for average throughput
// calculation.
int byteSamples[SAMPLE_COUNT];
// The delta time of each sample. This is the difference between
// the time of the ack at that sample and the time of the ack at
// the previous sample (in milliseconds).
uint32_t timeSamples[SAMPLE_COUNT];
// int throughputSamples[SAMPLE_COUNT];
int delaySamples[SAMPLE_COUNT];
// The index of the oldest stored sample.
int oldest;
......
......@@ -17,17 +17,54 @@ int TSThroughputSensor::getThroughputInKbps(void) const
{
if (ackValid)
{
return throughputInKbps;
return getThroughputInKbps(getLastPeriod(), getLastByteCount());
}
else
{
logWrite(ERROR,
"ThroughputSensor::getThroughputInKbps() "
"TSThroughputSensor::getThroughputInKbps() "
"called with invalid data");
return 0;
}
}
int TSThroughputSensor::getThroughputInKbps(uint32_t period,
int byteCount) const
{
double kilobits = byteCount * (8.0/1000.0);
return static_cast<int>(kilobits/(period / 1000.0));
}
uint32_t TSThroughputSensor::getLastPeriod(void) const
{
if (ackValid)
{
return lastPeriod;
}
else
{
logWrite(ERROR,
"TSThroughputSensor::getLastPeriod() called with invalid data");
return 0;
}
}
int TSThroughputSensor::getLastByteCount(void) const
{
if (ackValid)
{
return lastByteCount;
}
else
{
logWrite(ERROR,
"TSThroughputSensor::getLastByteCount() "
"called with invalid data");
return 0;
}
}
void TSThroughputSensor::localSend(PacketInfo *)
{
ackValid = false;
......@@ -58,7 +95,7 @@ void TSThroughputSensor::localAck(PacketInfo * packet)
currentAckTS = htonl(stamps[0]);
}
}
/*
* It would be nice if we could fall back to regular timing instead of
* bailing, maybe that's a feature for someday...
......@@ -67,7 +104,8 @@ void TSThroughputSensor::localAck(PacketInfo * packet)
logWrite(ERROR,"TSThroughputSensor::localAck() got a packet without a "
"timestamp");
ackValid = false;
throughputInKbps = 0;
lastPeriod = 1;
lastByteCount = 0;
lastAckTS = 0;
return;
}
......@@ -76,7 +114,8 @@ void TSThroughputSensor::localAck(PacketInfo * packet)
logWrite(ERROR,"TSThroughputSensor::localAck() got timestamps in reverse "
"order: o=%u,n=%u",lastAckTS,currentAckTS);
ackValid = false;
throughputInKbps = 0;
lastPeriod = 1;
lastByteCount = 0;
lastAckTS = 0;
return;
}
......@@ -88,24 +127,23 @@ void TSThroughputSensor::localAck(PacketInfo * packet)
* period is in arbitrary units decided on by the other end - we assume
* they are in milliseconds XXX: Verify this
*/
int period = currentAckTS - lastAckTS;
double kilobits = packetHistory->getAckedSize() * (8.0/1000.0);
int latest = static_cast<int>(kilobits/(period / 1000.0));
throughputInKbps = latest;
maxThroughput = latest;
lastPeriod = currentAckTS - lastAckTS;
lastByteCount = packetHistory->getAckedSize();
logWrite(SENSOR, "TSTHROUGHPUT: %d kbps (period=%i,kbits=%f)",
latest,period,kilobits);
getThroughputInKbps(), lastPeriod, lastByteCount*(8.0/1000.0));
}
else
{
throughputInKbps = 0;
lastPeriod = 1;
lastByteCount = 0;
ackValid = false;
}
lastAckTS = currentAckTS;
}
else
{
throughputInKbps = 0;
lastPeriod = 1;
lastByteCount = 0;
lastAckTS = 0;
ackValid = false;
}
......
......@@ -18,18 +18,22 @@
class PacketSensor;
class StateSensor;
class TSThroughputSensor : public Sensor
class TSThroughputSensor : public Sensor
{
public:
TSThroughputSensor(PacketSensor const * newPacketHistory,
StateSensor const * newState);
int getThroughputInKbps(void) const;
int getThroughputInKbps(uint32_t period, int byteCount) const;
uint32_t getLastPeriod(void) const;
int getLastByteCount(void) const;
protected:
virtual void localSend(PacketInfo * packet);
virtual void localAck(PacketInfo * packet);
private:
int throughputInKbps;
int maxThroughput;
// int throughputInKbps;
uint32_t lastPeriod;
int lastByteCount;
uint32_t lastAckTS;
PacketSensor const * packetHistory;
StateSensor const * state;
......
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