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