Calculate per stream jitter using latency values
We calculate "average jitter". The changes include only the server side, not the client/GUI side which will be done in a future commit.
This commit is contained in:
parent
1fa84ec644
commit
5eb2ad1979
@ -293,6 +293,7 @@ message StreamStats {
|
|||||||
|
|
||||||
optional double tx_duration = 3; // in seconds
|
optional double tx_duration = 3; // in seconds
|
||||||
optional uint64 latency = 4; // in nanoseconds
|
optional uint64 latency = 4; // in nanoseconds
|
||||||
|
optional uint64 jitter = 5; // in nanoseconds
|
||||||
|
|
||||||
optional uint64 rx_pkts = 11;
|
optional uint64 rx_pkts = 11;
|
||||||
optional uint64 rx_bytes = 12;
|
optional uint64 rx_bytes = 12;
|
||||||
|
@ -26,7 +26,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include "devicemanager.h"
|
#include "devicemanager.h"
|
||||||
#include "interfaceinfo.h"
|
#include "interfaceinfo.h"
|
||||||
#include "packetbuffer.h"
|
#include "packetbuffer.h"
|
||||||
#include "streamtiming.h"
|
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
@ -886,9 +885,9 @@ void AbstractPort::stats(PortStats *stats)
|
|||||||
stats_.rxFrameErrors + (maxStatsValue_ - epochStats_.rxFrameErrors);
|
stats_.rxFrameErrors + (maxStatsValue_ - epochStats_.rxFrameErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 AbstractPort::streamTimingDelay(uint guid)
|
StreamTiming::Stats AbstractPort::streamTimingStats(uint guid)
|
||||||
{
|
{
|
||||||
return streamTiming_->delay(id(), guid);
|
return streamTiming_->stats(id(), guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractPort::clearStreamTiming(uint guid)
|
void AbstractPort::clearStreamTiming(uint guid)
|
||||||
@ -909,12 +908,14 @@ void AbstractPort::streamStats(uint guid, OstProto::StreamStatsList *stats)
|
|||||||
{
|
{
|
||||||
StreamStatsTuple sst = streamStats_.value(guid);
|
StreamStatsTuple sst = streamStats_.value(guid);
|
||||||
OstProto::StreamStats *s = stats->add_stream_stats();
|
OstProto::StreamStats *s = stats->add_stream_stats();
|
||||||
|
StreamTiming::Stats t = streamTimingStats(guid);
|
||||||
|
|
||||||
s->mutable_stream_guid()->set_id(guid);
|
s->mutable_stream_guid()->set_id(guid);
|
||||||
s->mutable_port_id()->set_id(id());
|
s->mutable_port_id()->set_id(id());
|
||||||
|
|
||||||
s->set_tx_duration(lastTransmitDuration());
|
s->set_tx_duration(lastTransmitDuration());
|
||||||
s->set_latency(streamTimingDelay(guid));
|
s->set_latency(t.latency);
|
||||||
|
s->set_jitter(t.jitter);
|
||||||
|
|
||||||
s->set_tx_pkts(sst.tx_pkts);
|
s->set_tx_pkts(sst.tx_pkts);
|
||||||
s->set_tx_bytes(sst.tx_bytes);
|
s->set_tx_bytes(sst.tx_bytes);
|
||||||
@ -941,12 +942,14 @@ void AbstractPort::streamStatsAll(OstProto::StreamStatsList *stats)
|
|||||||
i.next();
|
i.next();
|
||||||
StreamStatsTuple sst = i.value();
|
StreamStatsTuple sst = i.value();
|
||||||
OstProto::StreamStats *s = stats->add_stream_stats();
|
OstProto::StreamStats *s = stats->add_stream_stats();
|
||||||
|
StreamTiming::Stats t = streamTimingStats(i.key());
|
||||||
|
|
||||||
s->mutable_stream_guid()->set_id(i.key());
|
s->mutable_stream_guid()->set_id(i.key());
|
||||||
s->mutable_port_id()->set_id(id());
|
s->mutable_port_id()->set_id(id());
|
||||||
|
|
||||||
s->set_tx_duration(txDur);
|
s->set_tx_duration(txDur);
|
||||||
s->set_latency(streamTimingDelay(i.key()));
|
s->set_latency(t.latency);
|
||||||
|
s->set_jitter(t.jitter);
|
||||||
|
|
||||||
s->set_tx_pkts(sst.tx_pkts);
|
s->set_tx_pkts(sst.tx_pkts);
|
||||||
s->set_tx_bytes(sst.tx_bytes);
|
s->set_tx_bytes(sst.tx_bytes);
|
||||||
|
@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
#include "../common/protocol.pb.h"
|
#include "../common/protocol.pb.h"
|
||||||
#include "streamstats.h"
|
#include "streamstats.h"
|
||||||
|
#include "streamtiming.h"
|
||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QReadWriteLock>
|
#include <QReadWriteLock>
|
||||||
@ -34,7 +35,6 @@ struct InterfaceInfo;
|
|||||||
class PacketBuffer;
|
class PacketBuffer;
|
||||||
class QIODevice;
|
class QIODevice;
|
||||||
class StreamBase;
|
class StreamBase;
|
||||||
class StreamTiming;
|
|
||||||
|
|
||||||
// TODO: send notification back to client(s)
|
// TODO: send notification back to client(s)
|
||||||
#define Xnotify qWarning
|
#define Xnotify qWarning
|
||||||
@ -125,7 +125,7 @@ public:
|
|||||||
void stats(PortStats *stats);
|
void stats(PortStats *stats);
|
||||||
void resetStats() { epochStats_ = stats_; }
|
void resetStats() { epochStats_ = stats_; }
|
||||||
|
|
||||||
quint64 streamTimingDelay(uint guid);
|
StreamTiming::Stats streamTimingStats(uint guid);
|
||||||
void clearStreamTiming(uint guid = UINT_MAX);
|
void clearStreamTiming(uint guid = UINT_MAX);
|
||||||
|
|
||||||
// FIXME: combine single and All calls?
|
// FIXME: combine single and All calls?
|
||||||
|
@ -62,8 +62,10 @@ void StreamTiming::stop(uint portId)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 StreamTiming::delay(uint portId, uint guid)
|
StreamTiming::Stats StreamTiming::stats(uint portId, uint guid)
|
||||||
{
|
{
|
||||||
|
Stats stats = {0, 0};
|
||||||
|
|
||||||
Q_ASSERT(guid <= SignProtocol::kMaxGuid);
|
Q_ASSERT(guid <= SignProtocol::kMaxGuid);
|
||||||
|
|
||||||
// Process anything pending first
|
// Process anything pending first
|
||||||
@ -72,13 +74,16 @@ quint64 StreamTiming::delay(uint portId, uint guid)
|
|||||||
QMutexLocker locker(&timingLock_);
|
QMutexLocker locker(&timingLock_);
|
||||||
|
|
||||||
if (!timing_.contains(portId))
|
if (!timing_.contains(portId))
|
||||||
return 0;
|
return stats;
|
||||||
|
|
||||||
Timing t = timing_.value(portId)->value(guid);
|
Timing t = timing_.value(portId)->value(guid);
|
||||||
if (t.countDelays == 0)
|
if (t.countDelays == 0)
|
||||||
return 0;
|
return stats;
|
||||||
|
|
||||||
return timespecToNsecs(t.sumDelays)/t.countDelays;
|
stats.latency = timespecToNsecs(t.sumDelays)/t.countDelays;
|
||||||
|
stats.jitter = t.sumJitter/(t.countDelays-1);
|
||||||
|
|
||||||
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamTiming::clear(uint portId, uint guid)
|
void StreamTiming::clear(uint portId, uint guid)
|
||||||
@ -127,6 +132,12 @@ int StreamTiming::processRecords()
|
|||||||
PortTiming *portTiming = timing_.value(portId);
|
PortTiming *portTiming = timing_.value(portId);
|
||||||
Timing &guidTiming = (*portTiming)[guid];
|
Timing &guidTiming = (*portTiming)[guid];
|
||||||
timespecadd(&guidTiming.sumDelays, &diff, &guidTiming.sumDelays);
|
timespecadd(&guidTiming.sumDelays, &diff, &guidTiming.sumDelays);
|
||||||
|
if (guidTiming.countDelays)
|
||||||
|
guidTiming.sumJitter += abs(
|
||||||
|
diff.tv_sec*long(1e9) + diff.tv_nsec
|
||||||
|
- guidTiming.lastDelay.tv_sec*long(1e9)
|
||||||
|
- guidTiming.lastDelay.tv_nsec);
|
||||||
|
guidTiming.lastDelay = diff;
|
||||||
guidTiming.countDelays++;
|
guidTiming.countDelays++;
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
@ -136,10 +147,10 @@ int StreamTiming::processRecords()
|
|||||||
diff.tv_sec, diff.tv_nsec,
|
diff.tv_sec, diff.tv_nsec,
|
||||||
rxTime.tv_sec, rxTime.tv_nsec,
|
rxTime.tv_sec, rxTime.tv_nsec,
|
||||||
txTime.tv_sec, txTime.tv_nsec);
|
txTime.tv_sec, txTime.tv_nsec);
|
||||||
timingDebug("[%u/%u](%d) total %ld.%09ld count %u",
|
timingDebug("[%u/%u](%d) total %ld.%09ld count %u jittersum %09llu",
|
||||||
i.value().portId, guid, count,
|
i.value().portId, guid, count,
|
||||||
guidTiming.sumDelays.tv_sec, guidTiming.sumDelays.tv_nsec,
|
guidTiming.sumDelays.tv_sec, guidTiming.sumDelays.tv_nsec,
|
||||||
guidTiming.countDelays);
|
guidTiming.countDelays, guidTiming.sumJitter);
|
||||||
}
|
}
|
||||||
i = rxHash_.erase(i);
|
i = rxHash_.erase(i);
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,12 @@ class StreamTiming : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
struct Stats
|
||||||
|
{
|
||||||
|
quint64 latency;
|
||||||
|
quint64 jitter;
|
||||||
|
};
|
||||||
|
|
||||||
bool recordTxTime(uint portId, uint guid, uint ttagId,
|
bool recordTxTime(uint portId, uint guid, uint ttagId,
|
||||||
const struct timespec ×tamp);
|
const struct timespec ×tamp);
|
||||||
bool recordRxTime(uint portId, uint guid, uint ttagId,
|
bool recordRxTime(uint portId, uint guid, uint ttagId,
|
||||||
@ -47,7 +53,7 @@ public:
|
|||||||
bool recordTxTime(uint portId, uint *ttagList, int count,
|
bool recordTxTime(uint portId, uint *ttagList, int count,
|
||||||
const struct timespec ×tamp);
|
const struct timespec ×tamp);
|
||||||
|
|
||||||
quint64 delay(uint portId, uint guid);
|
Stats stats(uint portId, uint guid);
|
||||||
void clear(uint portId, uint guid = SignProtocol::kInvalidGuid);
|
void clear(uint portId, uint guid = SignProtocol::kInvalidGuid);
|
||||||
|
|
||||||
static StreamTiming* instance();
|
static StreamTiming* instance();
|
||||||
@ -72,8 +78,13 @@ private:
|
|||||||
uint portId;
|
uint portId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// XXX: used only as a Qt Container value, so members will get init to 0
|
||||||
|
// when this struct is retrieved from the container due to Qt's default-
|
||||||
|
// cosntructed value semantics
|
||||||
struct Timing {
|
struct Timing {
|
||||||
struct timespec sumDelays; // nanosec resolution
|
struct timespec sumDelays; // nanosec resolution
|
||||||
|
struct timespec lastDelay;
|
||||||
|
quint64 sumJitter; // nanosec resolution
|
||||||
uint countDelays;
|
uint countDelays;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user