Code changes to improve transmit performance in Windows. Windows top-speed performance is now at par with Linux in my tests, however for fixed (high) rate transmit, accuracy is not good - need to find ways to improve that.

Fixes issue 33
Fixes issue 39
This commit is contained in:
Srivats P. 2011-10-16 08:04:09 +05:30
parent e9ea3d7934
commit 626ca8ad0e
6 changed files with 99 additions and 25 deletions

View File

@ -44,6 +44,7 @@ AbstractPort::AbstractPort(int id, const char *device)
isSendQueueDirty_ = false;
linkState_ = OstProto::LinkStateUnknown;
minPacketSetSize_ = 1;
memset((void*) &stats_, 0, sizeof(stats_));
resetStats();
@ -138,7 +139,6 @@ void AbstractPort::updatePacketList()
void AbstractPort::updatePacketListSequential()
{
const int kMinLoopSize = 16;
long sec = 0;
long nsec = 0;
@ -191,7 +191,7 @@ void AbstractPort::updatePacketListSequential()
case OstProto::StreamControl::e_su_packets:
x = frameVariableCount;
n = 2;
while (x < kMinLoopSize)
while (x < minPacketSetSize_)
x = frameVariableCount*n++;
n = streamList_[i]->numPackets() / x;
y = streamList_[i]->numPackets() % x;

View File

@ -98,6 +98,7 @@ protected:
bool isUsable_;
OstProto::Port data_;
OstProto::LinkState linkState_;
ulong minPacketSetSize_;
struct PortStats stats_;
//! \todo Need lock for stats access/update

View File

@ -42,6 +42,7 @@ LinuxPort::LinuxPort(int id, const char *device)
monitor_ = new StatsMonitor();
data_.set_is_exclusive_control(hasExclusiveControl());
minPacketSetSize_ = 16;
qDebug("adding dev to all ports list <%s>", device);
allPorts_.append(this);

View File

@ -49,6 +49,25 @@ static long inline udiffTimeStamp(const TimeStamp *start, const TimeStamp *end)
return usecs;
}
#elif defined(Q_OS_WIN32)
static quint64 gTicksFreq;
typedef LARGE_INTEGER TimeStamp;
static void inline getTimeStamp(TimeStamp* stamp)
{
QueryPerformanceCounter(stamp);
}
static long inline udiffTimeStamp(const TimeStamp *start, const TimeStamp *end)
{
if (end->QuadPart > start->QuadPart)
return (end->QuadPart - start->QuadPart)*long(1e6)/gTicksFreq;
else
{
// FIXME: incorrect! what's the max value for this counter before
// it rolls over?
return (start->QuadPart)*long(1e6)/gTicksFreq;
}
}
#else
typedef int TimeStamp;
static void inline getTimeStamp(TimeStamp*) {}
@ -256,7 +275,7 @@ PcapPort::PortTransmitter::PortTransmitter(const char *device)
#ifdef Q_OS_WIN32
LARGE_INTEGER freq;
if (QueryPerformanceFrequency(&freq))
ticksFreq_ = freq.QuadPart;
gTicksFreq = ticksFreq_ = freq.QuadPart;
else
Q_ASSERT_X(false, "PortTransmitter::PortTransmitter",
"This Win32 platform does not support performance counter");
@ -331,15 +350,18 @@ bool PcapPort::PortTransmitter::appendToPacketList(long sec, long nsec,
if (currentPacketSequence_ == NULL ||
!currentPacketSequence_->hasFreeSpace(2*sizeof(pcap_pkthdr)+length))
{
// Add a zero len packet at end of currentSendQueue_ for
// inter-sendQ timing
if (currentPacketSequence_ != NULL)
{
pcap_pkthdr hdr = pktHdr;
hdr.caplen = 0;
pcap_sendqueue_queue(packetSequenceList_.last()->sendQueue_,
&hdr, (u_char*)packet);
long usecs;
usecs = (pktHdr.ts.tv_sec
- currentPacketSequence_->lastPacket_->ts.tv_sec)
* long(1e6);
usecs += (pktHdr.ts.tv_usec
- currentPacketSequence_->lastPacket_->ts.tv_usec);
currentPacketSequence_->usecDelay_ = usecs;
}
//! \todo (LOW): calculate sendqueue size
currentPacketSequence_ = new PacketSequence;
@ -350,8 +372,7 @@ bool PcapPort::PortTransmitter::appendToPacketList(long sec, long nsec,
sizeof(pcap_pkthdr) + length));
}
if (pcap_sendqueue_queue(currentPacketSequence_->sendQueue_, &pktHdr,
(u_char*) packet) < 0)
if (currentPacketSequence_->appendPacket(&pktHdr, (u_char*) packet) < 0)
{
op = false;
}
@ -419,17 +440,20 @@ void PcapPort::PortTransmitter::run()
const int kSyncTransmit = 1;
int i;
long overHead = 0;
long overHead = 0; // overHead should be negative or zero
qDebug("packetSequenceList_.size = %d", packetSequenceList_.size());
if (packetSequenceList_.size() <= 0)
return;
for(i = 0; i < packetSequenceList_.size(); i++) {
qDebug("sendQ[%d]: rptCnt = %d, rptSz = %d usecDelay = %ld", i,
qDebug("sendQ[%d]: rptCnt = %d, rptSz = %d, usecDelay = %ld", i,
packetSequenceList_.at(i)->repeatCount_,
packetSequenceList_.at(i)->repeatSize_,
packetSequenceList_.at(i)->usecDelay_);
qDebug("sendQ[%d]: pkts = %ld, usecDuration = %ld", i,
packetSequenceList_.at(i)->packets_,
packetSequenceList_.at(i)->usecDuration_);
}
for(i = 0; i < packetSequenceList_.size(); i++)
@ -443,14 +467,41 @@ _restart:
{
for (int k = 0; k < rptSz; k++)
{
int ret = sendQueueTransmit(handle_,
packetSequenceList_.at(i+k)->sendQueue_,
int ret;
PacketSequence *seq = packetSequenceList_.at(i+k);
#ifdef Q_OS_WIN32
TimeStamp ovrStart, ovrEnd;
if (seq->usecDuration_ <= long(1e6)) // 1s
{
getTimeStamp(&ovrStart);
ret = pcap_sendqueue_transmit(handle_,
seq->sendQueue_, kSyncTransmit);
if (ret >= 0)
{
stats_->txPkts += seq->packets_;
stats_->txBytes += seq->bytes_;
getTimeStamp(&ovrEnd);
overHead += seq->usecDuration_
- udiffTimeStamp(&ovrStart, &ovrEnd);
}
if (stop_)
ret = -2;
}
else
{
ret = sendQueueTransmit(handle_, seq->sendQueue_,
overHead, kSyncTransmit);
}
#else
ret = sendQueueTransmit(handle_, seq->sendQueue_,
overHead, kSyncTransmit);
#endif
if (ret >= 0)
{
long usecs = packetSequenceList_.at(i+k)->usecDelay_
+ overHead;
long usecs = seq->usecDelay_ + overHead;
if (usecs > 0)
{
udelay(usecs);
@ -530,14 +581,11 @@ int PcapPort::PortTransmitter::sendQueueTransmit(pcap_t *p,
getTimeStamp(&ovrStart);
}
// A pktLen of size 0 is used at the end of a sendQueue and before
// the next sendQueue - i.e. for inter sendQueue timing
if(pktLen > 0)
{
pcap_sendpacket(p, pkt, pktLen);
stats_->txPkts++;
stats_->txBytes += pktLen;
}
Q_ASSERT(pktLen > 0);
pcap_sendpacket(p, pkt, pktLen);
stats_->txPkts++;
stats_->txBytes += pktLen;
// Step to the next packet in the buffer
hdr = (struct pcap_pkthdr*) (pkt + pktLen);

View File

@ -120,6 +120,10 @@ protected:
public:
PacketSequence() {
sendQueue_ = pcap_sendqueue_alloc(1*1024*1024);
lastPacket_ = NULL;
packets_ = 0;
bytes_ = 0;
usecDuration_ = 0;
repeatCount_ = 1;
repeatSize_ = 1;
usecDelay_ = 0;
@ -133,7 +137,26 @@ protected:
else
return false;
}
int appendPacket(const struct pcap_pkthdr *pktHeader,
const uchar *pktData) {
if (lastPacket_)
{
usecDuration_ += (pktHeader->ts.tv_sec
- lastPacket_->ts.tv_sec) * long(1e6);
usecDuration_ += (pktHeader->ts.tv_usec
- lastPacket_->ts.tv_usec);
}
packets_++;
bytes_ += pktHeader->caplen;
lastPacket_ = (struct pcap_pkthdr *)
(sendQueue_->buffer + sendQueue_->len);
return pcap_sendqueue_queue(sendQueue_, pktHeader, pktData);
}
pcap_send_queue *sendQueue_;
struct pcap_pkthdr *lastPacket_;
long packets_;
long bytes_;
ulong usecDuration_;
int repeatCount_;
int repeatSize_;
long usecDelay_;

View File

@ -44,6 +44,7 @@ WinPcapPort::WinPcapPort(int id, const char *device)
qFatal("failed to alloc oidData");
data_.set_is_exclusive_control(hasExclusiveControl());
minPacketSetSize_ = 256;
}
WinPcapPort::~WinPcapPort()