diff --git a/client/streamstatsmodel.cpp b/client/streamstatsmodel.cpp
index c58044f..8d01f34 100644
--- a/client/streamstatsmodel.cpp
+++ b/client/streamstatsmodel.cpp
@@ -20,6 +20,7 @@ along with this program. If not, see
#include "streamstatsmodel.h"
#include "protocol.pb.h"
+#include "xqlocale.h"
#include
#include
@@ -45,12 +46,22 @@ enum {
kAggrTxPkts,
kAggrRxPkts,
kAggrPktLoss,
+ kTxDuration,
+ kAvgTxFrameRate,
+ kAvgRxFrameRate,
+ kAvgTxBitRate,
+ kAvgRxBitRate,
kMaxAggrStreamStats
};
static QStringList aggrStatTitles = QStringList()
<< "Total\nTx Pkts"
<< "Total\nRx Pkts"
- << "Total\nPkt Loss";
+ << "Total\nPkt Loss"
+ << "Duration\n(secs)"
+ << "Avg\nTx PktRate"
+ << "Avg\nRx PktRate"
+ << "Avg\nTx BitRate"
+ << "Avg\nRx BitRate";
static const uint kAggrGuid = 0xffffffff;
@@ -149,6 +160,26 @@ QVariant StreamStatsModel::data(const QModelIndex &index, int role) const
return QString("%L1").arg(aggrGuidStats_.value(guid).txPkts);
case kAggrPktLoss:
return QString("%L1").arg(aggrGuidStats_.value(guid).pktLoss);
+ case kTxDuration:
+ return QString("%L1").arg(aggrGuidStats_.value(guid).txDuration);
+ case kAvgTxFrameRate:
+ return QString("%L1").arg(
+ aggrGuidStats_.value(guid).txPkts
+ / aggrGuidStats_.value(guid).txDuration);
+ case kAvgRxFrameRate:
+ return QString("%L1").arg(
+ aggrGuidStats_.value(guid).rxPkts
+ / aggrGuidStats_.value(guid).txDuration);
+ case kAvgTxBitRate:
+ return XLocale().toBitRateString(
+ (aggrGuidStats_.value(guid).txBytes
+ + 24 * aggrGuidStats_.value(guid).txPkts) * 8
+ / aggrGuidStats_.value(guid).txDuration);
+ case kAvgRxBitRate:
+ return XLocale().toBitRateString(
+ (aggrGuidStats_.value(guid).rxBytes
+ + 24 * aggrGuidStats_.value(guid).rxPkts) * 8
+ / aggrGuidStats_.value(guid).txDuration);
default:
break;
};
@@ -232,10 +263,18 @@ void StreamStatsModel::appendStreamStatsList(
aggrGuid.rxPkts += ss.rxPkts;
aggrGuid.txPkts += ss.txPkts;
aggrGuid.pktLoss += ss.txPkts - ss.rxPkts;
+ aggrGuid.rxBytes += ss.rxBytes;
+ aggrGuid.txBytes += ss.txBytes;
+ if (s.tx_duration() > aggrGuid.txDuration)
+ aggrGuid.txDuration = s.tx_duration(); // XXX: use largest or avg?
aggrAggr.rxPkts += ss.rxPkts;
aggrAggr.txPkts += ss.txPkts;
aggrAggr.pktLoss += ss.txPkts - ss.rxPkts;
+ aggrAggr.rxBytes += ss.rxBytes;
+ aggrAggr.txBytes += ss.txBytes;
+ if (aggrGuid.txDuration > aggrAggr.txDuration)
+ aggrAggr.txDuration = aggrGuid.txDuration;
if (!portList_.contains(pgp))
portList_.append(pgp);
@@ -246,6 +285,8 @@ void StreamStatsModel::appendStreamStatsList(
if (guidList_.size() && !guidList_.contains(kAggrGuid))
guidList_.append(kAggrGuid);
+ std::sort(guidList_.begin(), guidList_.end());
+
#if QT_VERSION >= 0x040600
endResetModel();
#else
diff --git a/client/streamstatsmodel.h b/client/streamstatsmodel.h
index 664cd47..6f57e1b 100644
--- a/client/streamstatsmodel.h
+++ b/client/streamstatsmodel.h
@@ -61,7 +61,10 @@ private:
struct AggrGuidStats {
quint64 rxPkts;
quint64 txPkts;
+ quint64 rxBytes;
+ quint64 txBytes;
qint64 pktLoss;
+ double txDuration;
};
QList guidList_;
QList portList_;
diff --git a/client/streamstatswindow.cpp b/client/streamstatswindow.cpp
index a45e5ec..d37349f 100644
--- a/client/streamstatswindow.cpp
+++ b/client/streamstatswindow.cpp
@@ -31,7 +31,7 @@ StreamStatsWindow::StreamStatsWindow(QAbstractItemModel *model, QWidget *parent)
: QWidget(parent)
{
setupUi(this);
- streamStats->addAction(actionShowByteCounters);
+ streamStats->addAction(actionShowDetails);
if (id)
setWindowTitle(windowTitle() + QString("(%1)").arg(id));
@@ -39,7 +39,7 @@ StreamStatsWindow::StreamStatsWindow(QAbstractItemModel *model, QWidget *parent)
count++;
filterModel_ = new StreamStatsFilterModel(this);
- filterModel_->setFilterRegExp(QRegExp(".*Pkt.*"));
+ filterModel_->setFilterRegExp(QRegExp(kDefaultFilter_));
filterModel_->setSourceModel(model);
streamStats->setModel(filterModel_);
@@ -56,10 +56,10 @@ StreamStatsWindow::~StreamStatsWindow()
id = 0;
}
-void StreamStatsWindow::on_actionShowByteCounters_triggered(bool checked)
+void StreamStatsWindow::on_actionShowDetails_triggered(bool checked)
{
if (checked)
filterModel_->setFilterRegExp(QRegExp(".*"));
else
- filterModel_->setFilterRegExp(QRegExp(".*Pkt.*"));
+ filterModel_->setFilterRegExp(QRegExp(kDefaultFilter_));
}
diff --git a/client/streamstatswindow.h b/client/streamstatswindow.h
index 88c5fd1..e3c2c5a 100644
--- a/client/streamstatswindow.h
+++ b/client/streamstatswindow.h
@@ -33,9 +33,10 @@ public:
~StreamStatsWindow();
private slots:
- void on_actionShowByteCounters_triggered(bool checked);
+ void on_actionShowDetails_triggered(bool checked);
private:
+ QString kDefaultFilter_{"^(?!Port).*"};
QSortFilterProxyModel *filterModel_;
};
diff --git a/client/streamstatswindow.ui b/client/streamstatswindow.ui
index d6e9f89..2ba52ca 100644
--- a/client/streamstatswindow.ui
+++ b/client/streamstatswindow.ui
@@ -27,12 +27,12 @@ Wait a little bit to see if they appear, otherwise verify your stream stats conf
-
+
true
- Show Byte Counters
+ Show Details
diff --git a/common/protocol.proto b/common/protocol.proto
index 8769e73..d78593a 100644
--- a/common/protocol.proto
+++ b/common/protocol.proto
@@ -290,6 +290,8 @@ message StreamStats {
required PortId port_id = 1;
required StreamGuid stream_guid = 2;
+ optional double tx_duration = 3; // in seconds
+
optional uint64 rx_pkts = 11;
optional uint64 rx_bytes = 12;
optional uint64 tx_pkts = 13;
diff --git a/server/abstractport.cpp b/server/abstractport.cpp
index 7d2f7c0..c173041 100644
--- a/server/abstractport.cpp
+++ b/server/abstractport.cpp
@@ -714,6 +714,8 @@ void AbstractPort::streamStats(uint guid, OstProto::StreamStatsList *stats)
s->mutable_stream_guid()->set_id(guid);
s->mutable_port_id()->set_id(id());
+ s->set_tx_duration(lastTransmitDuration());
+
s->set_tx_pkts(sst.tx_pkts);
s->set_tx_bytes(sst.tx_bytes);
s->set_rx_pkts(sst.rx_pkts);
@@ -725,6 +727,7 @@ void AbstractPort::streamStatsAll(OstProto::StreamStatsList *stats)
{
// FIXME: change input param to a non-OstProto type and/or have
// a getFirst/Next like API?
+ double txDur = lastTransmitDuration();
StreamStatsIterator i(streamStats_);
while (i.hasNext())
{
@@ -735,6 +738,8 @@ void AbstractPort::streamStatsAll(OstProto::StreamStatsList *stats)
s->mutable_stream_guid()->set_id(i.key());
s->mutable_port_id()->set_id(id());
+ s->set_tx_duration(txDur);
+
s->set_tx_pkts(sst.tx_pkts);
s->set_tx_bytes(sst.tx_bytes);
s->set_rx_pkts(sst.rx_pkts);
diff --git a/server/abstractport.h b/server/abstractport.h
index 91d3ff4..ff10b09 100644
--- a/server/abstractport.h
+++ b/server/abstractport.h
@@ -110,6 +110,7 @@ public:
virtual void startTransmit() = 0;
virtual void stopTransmit() = 0;
virtual bool isTransmitOn() = 0;
+ virtual double lastTransmitDuration() = 0;
virtual void startCapture() = 0;
virtual void stopCapture() = 0;
diff --git a/server/pcapport.h b/server/pcapport.h
index cf59119..7b53876 100644
--- a/server/pcapport.h
+++ b/server/pcapport.h
@@ -68,6 +68,9 @@ public:
}
virtual void stopTransmit() { transmitter_->stop(); }
virtual bool isTransmitOn() { return transmitter_->isRunning(); }
+ virtual double lastTransmitDuration() {
+ return transmitter_->lastTxDuration();
+ }
virtual void startCapture() { capturer_->start(); }
virtual void stopCapture() { capturer_->stop(); }
diff --git a/server/pcaptransmitter.cpp b/server/pcaptransmitter.cpp
index bfc6e44..10b878d 100644
--- a/server/pcaptransmitter.cpp
+++ b/server/pcaptransmitter.cpp
@@ -107,6 +107,10 @@ bool PcapTransmitter::isRunning()
{
return txThread_.isRunning();
}
+double PcapTransmitter::lastTxDuration()
+{
+ return txThread_.lastTxDuration();
+}
void PcapTransmitter::updateTxThreadStreamStats()
{
diff --git a/server/pcaptransmitter.h b/server/pcaptransmitter.h
index 77b9909..ad4425d 100644
--- a/server/pcaptransmitter.h
+++ b/server/pcaptransmitter.h
@@ -49,6 +49,7 @@ public:
void start();
void stop();
bool isRunning();
+ double lastTxDuration();
private slots:
void updateTxThreadStreamStats();
private:
diff --git a/server/pcaptxthread.cpp b/server/pcaptxthread.cpp
index e8644f6..45c248c 100644
--- a/server/pcaptxthread.cpp
+++ b/server/pcaptxthread.cpp
@@ -243,6 +243,7 @@ void PcapTxThread::run()
const int kSyncTransmit = 1;
int i;
long overHead = 0; // overHead should be negative or zero
+ TimeStamp startTime, endTime;
qDebug("packetSequenceList_.size = %d", packetSequenceList_.size());
if (packetSequenceList_.size() <= 0)
@@ -260,6 +261,7 @@ void PcapTxThread::run()
lastStats_ = *stats_; // used for stream stats
+ getTimeStamp(&startTime);
state_ = kRunning;
i = 0;
while (i < packetSequenceList_.size())
@@ -348,6 +350,10 @@ _restart:
}
_exit:
+ getTimeStamp(&endTime);
+ lastTxDuration_ = udiffTimeStamp(&startTime, &endTime)/1e6;
+ qDebug("Tx duration = %fs", lastTxDuration_);
+
if (trackStreamStats_)
updateStreamStats();
@@ -388,6 +394,11 @@ bool PcapTxThread::isRunning()
return (state_ == kRunning);
}
+double PcapTxThread::lastTxDuration()
+{
+ return lastTxDuration_;
+}
+
int PcapTxThread::sendQueueTransmit(pcap_t *p,
pcap_send_queue *queue, long &overHead, int sync)
{
diff --git a/server/pcaptxthread.h b/server/pcaptxthread.h
index 5b94ccb..6e18703 100644
--- a/server/pcaptxthread.h
+++ b/server/pcaptxthread.h
@@ -55,6 +55,7 @@ public:
void start();
void stop();
bool isRunning();
+ double lastTxDuration();
private:
enum State
@@ -92,6 +93,8 @@ private:
StatsTuple *stats_;
StatsTuple lastStats_;
StreamStats streamStats_;
+
+ double lastTxDuration_{0.0}; // in secs
};
#endif