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:
Srivats P 2023-06-26 13:01:11 +05:30
parent 1fa84ec644
commit 5eb2ad1979
5 changed files with 40 additions and 14 deletions

View File

@ -293,6 +293,7 @@ message StreamStats {
optional double tx_duration = 3; // in seconds
optional uint64 latency = 4; // in nanoseconds
optional uint64 jitter = 5; // in nanoseconds
optional uint64 rx_pkts = 11;
optional uint64 rx_bytes = 12;

View File

@ -26,7 +26,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#include "devicemanager.h"
#include "interfaceinfo.h"
#include "packetbuffer.h"
#include "streamtiming.h"
#include <QString>
#include <QIODevice>
@ -886,9 +885,9 @@ void AbstractPort::stats(PortStats *stats)
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)
@ -909,12 +908,14 @@ void AbstractPort::streamStats(uint guid, OstProto::StreamStatsList *stats)
{
StreamStatsTuple sst = streamStats_.value(guid);
OstProto::StreamStats *s = stats->add_stream_stats();
StreamTiming::Stats t = streamTimingStats(guid);
s->mutable_stream_guid()->set_id(guid);
s->mutable_port_id()->set_id(id());
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_bytes(sst.tx_bytes);
@ -941,12 +942,14 @@ void AbstractPort::streamStatsAll(OstProto::StreamStatsList *stats)
i.next();
StreamStatsTuple sst = i.value();
OstProto::StreamStats *s = stats->add_stream_stats();
StreamTiming::Stats t = streamTimingStats(i.key());
s->mutable_stream_guid()->set_id(i.key());
s->mutable_port_id()->set_id(id());
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_bytes(sst.tx_bytes);

View File

@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#include "../common/protocol.pb.h"
#include "streamstats.h"
#include "streamtiming.h"
#include <QList>
#include <QReadWriteLock>
@ -34,7 +35,6 @@ struct InterfaceInfo;
class PacketBuffer;
class QIODevice;
class StreamBase;
class StreamTiming;
// TODO: send notification back to client(s)
#define Xnotify qWarning
@ -125,7 +125,7 @@ public:
void stats(PortStats *stats);
void resetStats() { epochStats_ = stats_; }
quint64 streamTimingDelay(uint guid);
StreamTiming::Stats streamTimingStats(uint guid);
void clearStreamTiming(uint guid = UINT_MAX);
// FIXME: combine single and All calls?

View File

@ -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);
// Process anything pending first
@ -72,13 +74,16 @@ quint64 StreamTiming::delay(uint portId, uint guid)
QMutexLocker locker(&timingLock_);
if (!timing_.contains(portId))
return 0;
return stats;
Timing t = timing_.value(portId)->value(guid);
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)
@ -127,6 +132,12 @@ int StreamTiming::processRecords()
PortTiming *portTiming = timing_.value(portId);
Timing &guidTiming = (*portTiming)[guid];
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++;
count++;
@ -136,10 +147,10 @@ int StreamTiming::processRecords()
diff.tv_sec, diff.tv_nsec,
rxTime.tv_sec, rxTime.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,
guidTiming.sumDelays.tv_sec, guidTiming.sumDelays.tv_nsec,
guidTiming.countDelays);
guidTiming.countDelays, guidTiming.sumJitter);
}
i = rxHash_.erase(i);
}

View File

@ -34,6 +34,12 @@ class StreamTiming : public QObject
{
Q_OBJECT
public:
struct Stats
{
quint64 latency;
quint64 jitter;
};
bool recordTxTime(uint portId, uint guid, uint ttagId,
const struct timespec &timestamp);
bool recordRxTime(uint portId, uint guid, uint ttagId,
@ -47,7 +53,7 @@ public:
bool recordTxTime(uint portId, uint *ttagList, int count,
const struct timespec &timestamp);
quint64 delay(uint portId, uint guid);
Stats stats(uint portId, uint guid);
void clear(uint portId, uint guid = SignProtocol::kInvalidGuid);
static StreamTiming* instance();
@ -72,8 +78,13 @@ private:
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 timespec sumDelays; // nanosec resolution
struct timespec lastDelay;
quint64 sumJitter; // nanosec resolution
uint countDelays;
};