Commit c4134e16 authored by Jonathon Duerig's avatar Jonathon Duerig

Added a new sensor which averages packets over a particular period of time...

Added a new sensor which averages packets over a particular period of time rather than a particular number of acks. This provides a proof of concept of coarse-grained measurements reflecting changes in bandwidth. Increased the number of samples that LeastSquaresThroughput uses as a quick way to use coarse-grained measurements easily.
parent c2319c8d
// AverageThroughputSensor.cc
#include "lib.h"
#include "AverageThroughputSensor.h"
#include "TSThroughputSensor.h"
#include "CommandOutput.h"
using namespace std;
AverageThroughputSensor::AverageThroughputSensor(
TSThroughputSensor const * newThroughput)
: throughput(newThroughput)
, latest(0)
, sampleCount(0)
{
}
AverageThroughputSensor::~AverageThroughputSensor()
{
}
void AverageThroughputSensor::localSend(PacketInfo * packet)
{
ackValid = false;
sendValid = true;
}
void AverageThroughputSensor::localAck(PacketInfo * packet)
{
sendValid = false;
if (throughput->isAckValid())
{
Ack newAck;
newAck.size = throughput->getLastByteCount();
newAck.period = throughput->getLastPeriod();
if (sampleCount > 0)
{
// If the buffer is not empty, then we want to put the new ack
// in the slot after latest.
latest = (latest + 1) % MAX_SAMPLE_COUNT;
}
// Otherwise, latest just points to the first ack and we want to
// fill it.
++sampleCount;
samples[latest] = newAck;
int byteSum = 0;
uint32_t periodSum = 0;
int i = 0;
int limit = min(static_cast<int>(MAX_SAMPLE_COUNT), sampleCount);
for (; i < limit && periodSum < AVERAGE_PERIOD; ++i)
{
// Add an extra MAX_SAMPLE_COUNT because taking the mod of a
// negative dividend is undefined (could be negative, could be
// from division rounding up or down, etc.)
int index = (latest - i + MAX_SAMPLE_COUNT) % MAX_SAMPLE_COUNT;
byteSum += samples[index].size;
periodSum += samples[index].period;
}
int result = throughput->getThroughputInKbps(periodSum, byteSum);
logWrite(SENSOR, "AVERAGE_THROUGHPUT: %d, period %u, kilobits %f",
result, periodSum, byteSum*(8.0/1000.0));
ackValid = true;
}
}
// AverageThroughputSensor.h
// A throughput sensor which averages the measure over a minimum
// period of time.
#ifndef AVERAGE_THROUGHPUT_SENSOR_H
#define AVERAGE_THROUGHPUT_SENSOR_H
#include "Sensor.h"
class TSThroughputSensor;
class AverageThroughputSensor : public Sensor
{
public:
AverageThroughputSensor(TSThroughputSensor const * newThroughput);
virtual ~AverageThroughputSensor();
protected:
virtual void localSend(PacketInfo * packet);
virtual void localAck(PacketInfo * packet);
private:
struct Ack
{
Ack() : size(0), period(0) {}
// The size begin acked (in bytes)
int size;
// The amount of time to the previous ack.
uint32_t period;
};
private:
TSThroughputSensor const * throughput;
// The period of time to average over (in milliseconds)
static const uint32_t AVERAGE_PERIOD = 500;
enum { MAX_SAMPLE_COUNT = 100 };
Ack samples[MAX_SAMPLE_COUNT];
int latest;
int sampleCount;
};
#endif
......@@ -25,7 +25,7 @@ private:
DelaySensor const * delay;
// The number of samples kept at any given time.
static const int SAMPLE_COUNT = 5;
static const int SAMPLE_COUNT = 50;
// Circular buffers of the last SAMPLE_COUNT samples.
// The number of bytes in each sample. Used for average throughput
// calculation.
......
......@@ -15,6 +15,7 @@
#include "TSThroughputSensor.h"
#include "EwmaThroughputSensor.h"
#include "LeastSquaresThroughput.h"
#include "AverageThroughputSensor.h"
using namespace std;
......@@ -84,6 +85,9 @@ void SensorList::addSensor(SensorCommand const & newSensor)
case LEAST_SQUARES_THROUGHPUT:
pushLeastSquaresThroughput();
break;
case AVERAGE_THROUGHPUT_SENSOR:
pushAverageThroughputSensor();
break;
default:
logWrite(ERROR,
"Incorrect sensor type (%d). Ignoring add sensor command.",
......@@ -295,3 +299,13 @@ void SensorList::pushLeastSquaresThroughput(void)
depDelaySensor));
pushSensor(current);
}
void SensorList::pushAverageThroughputSensor(void)
{
// Dependency list
pushTSThroughputSensor();
logWrite(SENSOR, "Adding AverageThroughputSensor");
std::auto_ptr<Sensor> current(new AverageThroughputSensor(depTSThroughputSensor));
pushSensor(current);
}
......@@ -58,6 +58,7 @@ private:
void pushTSThroughputSensor(void);
void pushEwmaThroughputSensor(void);
void pushLeastSquaresThroughput(void);
void pushAverageThroughputSensor(void);
private:
// Example dependency
NullSensor const * depNullSensor;
......
......@@ -33,7 +33,18 @@ int TSThroughputSensor::getThroughputInKbps(uint32_t period,
int byteCount) const
{
double kilobits = byteCount * (8.0/1000.0);
return static_cast<int>(kilobits/(period / 1000.0));
int result = 0;
if (period != 0)
{
result = static_cast<int>(kilobits/(period / 1000.0));
}
else
{
logWrite(ERROR,
"TSThroughputSensor::getThroughputInKbps(period, byteCount) "
"called with a '0' period.");
}
return result;
}
uint32_t TSThroughputSensor::getLastPeriod(void) const
......
......@@ -117,7 +117,8 @@ enum SensorType
THROUGHPUT_SENSOR = 6,
EWMA_THROUGHPUT_SENSOR = 7,
LEAST_SQUARES_THROUGHPUT = 8,
TSTHROUGHPUT_SENSOR = 9
TSTHROUGHPUT_SENSOR = 9,
AVERAGE_THROUGHPUT_SENSOR = 10
};
// This is used for the type field in the ConnectionModelCommand.
......
......@@ -273,6 +273,10 @@ void processArgs(int argc, char * argv[])
{
global::replaySensors.push_back(LEAST_SQUARES_THROUGHPUT);
}
else if (optArg == "average-throughput")
{
global::replaySensors.push_back(AVERAGE_THROUGHPUT_SENSOR);
}
else
{
usageMessage(argv[0]);
......
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