Skip to content
This repository has been archived by the owner on Apr 14, 2024. It is now read-only.

Commit

Permalink
Calculate per stream jitter using latency values
Browse files Browse the repository at this point in the history
We calculate "average jitter".

The changes include only the server side, not the client/GUI side which will
be done in a future commit.
  • Loading branch information
pstavirs committed Jun 26, 2023
1 parent 1fa84ec commit 5eb2ad1
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 14 deletions.
1 change: 1 addition & 0 deletions common/protocol.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
13 changes: 8 additions & 5 deletions server/abstractport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand All @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions server/abstractport.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -34,7 +35,6 @@ struct InterfaceInfo;
class PacketBuffer;
class QIODevice;
class StreamBase;
class StreamTiming;

// TODO: send notification back to client(s)
#define Xnotify qWarning
Expand Down Expand Up @@ -125,7 +125,7 @@ class AbstractPort
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?
Expand Down
23 changes: 17 additions & 6 deletions server/streamtiming.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;

stats.latency = timespecToNsecs(t.sumDelays)/t.countDelays;
stats.jitter = t.sumJitter/(t.countDelays-1);

return timespecToNsecs(t.sumDelays)/t.countDelays;
return stats;
}

void StreamTiming::clear(uint portId, uint guid)
Expand Down Expand Up @@ -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++;
Expand All @@ -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);
}
Expand Down
13 changes: 12 additions & 1 deletion server/streamtiming.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -47,7 +53,7 @@ class StreamTiming : public QObject
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();
Expand All @@ -72,8 +78,13 @@ public slots:
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;
};

Expand Down

0 comments on commit 5eb2ad1

Please sign in to comment.