一.接口名称
// perfmon with Byte counters for better bitrate estimation.
SRT_API int srt_bstats(SRTSOCKET u, SRT_TRACEBSTATS * perf, int clear);
// permon with Byte counters and instantaneous stats instead of moving averages for Snd/Rcvbuffer sizes.
SRT_API int srt_bistats(SRTSOCKET u, SRT_TRACEBSTATS * perf, int clear, int instantaneous);
int srt_bstats(SRTSOCKET u, SRT_TRACEBSTATS * perf, int clear) { return CUDT::bstats(u, perf, 0!= clear); }
int srt_bistats(SRTSOCKET u, SRT_TRACEBSTATS * perf, int clear, int instantaneous) { return CUDT::bstats(u, perf, 0!= clear, 0!= instantaneous); }
二.调用流程
int SrtTarget::Write(const char* data, size_t size, ostream &out_stats)
{
static unsigned long counter = 1;
int stat = srt_sendmsg2(m_sock, data, (int) size, nullptr);
if (stat == SRT_ERROR)
{
return stat;
}
const bool need_bw_report = transmit_bw_report && (counter % transmit_bw_report) == transmit_bw_report - 1;
const bool need_stats_report = transmit_stats_report && (counter % transmit_stats_report) == transmit_stats_report - 1;
if (need_bw_report || need_stats_report)
{
CBytePerfMon perf;
srt_bstats(m_sock, &perf, need_stats_report && !transmit_total_stats);
if (stats_writer != nullptr)
{
if (need_bw_report)
cerr << stats_writer->WriteBandwidth(perf.mbpsBandwidth) << std::flush;
if (need_stats_report)
out_stats << stats_writer->WriteStats(m_sock, perf) << std::flush;
}
}
++counter;
return stat;
}
int SrtSource::Read(size_t chunk, bytevector& data, ostream &out_stats)
{
static unsigned long counter = 1;
if (data.size() < chunk)
data.resize(chunk);
const int stat = srt_recvmsg(m_sock, data.data(), (int) chunk);
if (stat <= 0)
{
data.clear();
return stat;
}
chunk = size_t(stat);
if (chunk < data.size())
data.resize(chunk);
const bool need_bw_report = transmit_bw_report && (counter % transmit_bw_report) == transmit_bw_report - 1;
const bool need_stats_report = transmit_stats_report && (counter % transmit_stats_report) == transmit_stats_report - 1;
if (need_bw_report || need_stats_report)
{
CBytePerfMon perf;
srt_bstats(m_sock, &perf, need_stats_report && !transmit_total_stats);
if (stats_writer != nullptr)
{
if (need_bw_report)
cerr << stats_writer->WriteBandwidth(perf.mbpsBandwidth) << std::flush;
if (need_stats_report)
out_stats << stats_writer->WriteStats(m_sock, perf) << std::flush;
}
}
++counter;
return stat;
}
三.接口内部实现
void CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous)
{
if (!m_bConnected)
throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0);
if (m_bBroken || m_bClosing)
throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
CGuard statsguard(m_StatsLock);
uint64_t currtime = CTimer::getTime();
perf->msTimeStamp = (currtime - m_stats.startTime) / 1000;
perf->pktSent = m_stats.traceSent;
perf->pktRecv = m_stats.traceRecv;
perf->pktSndLoss = m_stats.traceSndLoss;
perf->pktRcvLoss = m_stats.traceRcvLoss;
perf->pktRetrans = m_stats.traceRetrans;
perf->pktRcvRetrans = m_stats.traceRcvRetrans;
perf->pktSentACK = m_stats.sentACK;
perf->pktRecvACK = m_stats.recvACK;
perf->pktSentNAK = m_stats.sentNAK;
perf->pktRecvNAK = m_stats.recvNAK;
perf->usSndDuration = m_stats.sndDuration;
perf->pktReorderDistance = m_stats.traceReorderDistance;
perf->pktReorderTolerance = m_iReorderTolerance;
perf->pktRcvAvgBelatedTime = m_stats.traceBelatedTime;
perf->pktRcvBelated = m_stats.traceRcvBelated;
perf->pktSndFilterExtra = m_stats.sndFilterExtra;
perf->pktRcvFilterExtra = m_stats.rcvFilterExtra;
perf->pktRcvFilterSupply = m_stats.rcvFilterSupply;
perf->pktRcvFilterLoss = m_stats.rcvFilterLoss;
/* perf byte counters include all headers (SRT+UDP+IP) */
const int pktHdrSize = CPacket::HDR_SIZE + CPacket::UDP_HDR_SIZE;
perf->byteSent = m_stats.traceBytesSent + (m_stats.traceSent * pktHdrSize);
perf->byteRecv = m_stats.traceBytesRecv + (m_stats.traceRecv * pktHdrSize);
perf->byteRetrans = m_stats.traceBytesRetrans + (m_stats.traceRetrans * pktHdrSize);
#ifdef SRT_ENABLE_LOSTBYTESCOUNT
perf->byteRcvLoss = m_stats.traceRcvBytesLoss + (m_stats.traceRcvLoss * pktHdrSize);
#endif
perf->pktSndDrop = m_stats.traceSndDrop;
perf->pktRcvDrop = m_stats.traceRcvDrop + m_stats.traceRcvUndecrypt;
perf->byteSndDrop = m_stats.traceSndBytesDrop + (m_stats.traceSndDrop * pktHdrSize);
perf->byteRcvDrop =
m_stats.traceRcvBytesDrop + (m_stats.traceRcvDrop * pktHdrSize) + m_stats.traceRcvBytesUndecrypt;
perf->pktRcvUndecrypt = m_stats.traceRcvUndecrypt;
perf->byteRcvUndecrypt = m_stats.traceRcvBytesUndecrypt;
perf->pktSentTotal = m_stats.sentTotal;
perf->pktRecvTotal = m_stats.recvTotal;
perf->pktSndLossTotal = m_stats.sndLossTotal;
perf->pktRcvLossTotal = m_stats.rcvLossTotal;
perf->pktRetransTotal = m_stats.retransTotal;
perf->pktSentACKTotal = m_stats.sentACKTotal;
perf->pktRecvACKTotal = m_stats.recvACKTotal;
perf->pktSentNAKTotal = m_stats.sentNAKTotal;
perf->pktRecvNAKTotal = m_stats.recvNAKTotal;
perf->usSndDurationTotal = m_stats.m_sndDurationTotal;
perf->byteSentTotal = m_stats.bytesSentTotal + (m_stats.sentTotal * pktHdrSize);
perf->byteRecvTotal = m_stats.bytesRecvTotal + (m_stats.recvTotal * pktHdrSize);
perf->byteRetransTotal = m_stats.bytesRetransTotal + (m_stats.retransTotal * pktHdrSize);
perf->pktSndFilterExtraTotal = m_stats.sndFilterExtraTotal;
perf->pktRcvFilterExtraTotal = m_stats.rcvFilterExtraTotal;
perf->pktRcvFilterSupplyTotal = m_stats.rcvFilterSupplyTotal;
perf->pktRcvFilterLossTotal = m_stats.rcvFilterLossTotal;
#ifdef SRT_ENABLE_LOSTBYTESCOUNT
perf->byteRcvLossTotal = m_stats.rcvBytesLossTotal + (m_stats.rcvLossTotal * pktHdrSize);
#endif
perf->pktSndDropTotal = m_stats.sndDropTotal;
perf->pktRcvDropTotal = m_stats.rcvDropTotal + m_stats.m_rcvUndecryptTotal;
perf->byteSndDropTotal = m_stats.sndBytesDropTotal + (m_stats.sndDropTotal * pktHdrSize);
perf->byteRcvDropTotal =
m_stats.rcvBytesDropTotal + (m_stats.rcvDropTotal * pktHdrSize) + m_stats.m_rcvBytesUndecryptTotal;
perf->pktRcvUndecryptTotal = m_stats.m_rcvUndecryptTotal;
perf->byteRcvUndecryptTotal = m_stats.m_rcvBytesUndecryptTotal;
//<
double interval = double(currtime - m_stats.lastSampleTime);
//>mod
perf->mbpsSendRate = double(perf->byteSent) * 8.0 / interval;
perf->mbpsRecvRate = double(perf->byteRecv) * 8.0 / interval;
//<
perf->usPktSndPeriod = m_ullInterval_tk / double(m_ullCPUFrequency);
perf->pktFlowWindow = m_iFlowWindowSize;
perf->pktCongestionWindow = (int)m_dCongestionWindow;
perf->pktFlightSize = CSeqNo::seqlen(m_iSndLastAck, CSeqNo::incseq(m_iSndCurrSeqNo)) - 1;
perf->msRTT = (double)m_iRTT / 1000.0;
//>new
perf->msSndTsbPdDelay = m_bPeerTsbPd ? m_iPeerTsbPdDelay_ms : 0;
perf->msRcvTsbPdDelay = m_bTsbPd ? m_iTsbPdDelay_ms : 0;
perf->byteMSS = m_iMSS;
perf->mbpsMaxBW = m_llMaxBW > 0 ? Bps2Mbps(m_llMaxBW) : m_CongCtl.ready() ? Bps2Mbps(m_CongCtl->sndBandwidth()) : 0;
//<
uint32_t availbw = (uint64_t)(m_iBandwidth == 1 ? m_RcvTimeWindow.getBandwidth() : m_iBandwidth);
perf->mbpsBandwidth = Bps2Mbps(availbw * (m_iMaxSRTPayloadSize + pktHdrSize));
if (pthread_mutex_trylock(&m_ConnectionLock) == 0)
{
if (m_pSndBuffer)
{
#ifdef SRT_ENABLE_SNDBUFSZ_MAVG
if (instantaneous)
{
/* Get instant SndBuf instead of moving average for application-based Algorithm
(such as NAE) in need of fast reaction to network condition changes. */
perf->pktSndBuf = m_pSndBuffer->getCurrBufSize(Ref(perf->byteSndBuf), Ref(perf->msSndBuf));
}
else
{
perf->pktSndBuf = m_pSndBuffer->getAvgBufSize(Ref(perf->byteSndBuf), Ref(perf->msSndBuf));
}
#else
perf->pktSndBuf = m_pSndBuffer->getCurrBufSize(Ref(perf->byteSndBuf), Ref(perf->msSndBuf));
#endif
perf->byteSndBuf += (perf->pktSndBuf * pktHdrSize);
//<
perf->byteAvailSndBuf = (m_iSndBufSize - perf->pktSndBuf) * m_iMSS;
}
else
{
perf->byteAvailSndBuf = 0;
// new>
perf->pktSndBuf = 0;
perf->byteSndBuf = 0;
perf->msSndBuf = 0;
//<
}
if (m_pRcvBuffer)
{
perf->byteAvailRcvBuf = m_pRcvBuffer->getAvailBufSize() * m_iMSS;
// new>
#ifdef SRT_ENABLE_RCVBUFSZ_MAVG
if (instantaneous) // no need for historical API for Rcv side
{
perf->pktRcvBuf = m_pRcvBuffer->getRcvDataSize(perf->byteRcvBuf, perf->msRcvBuf);
}
else
{
perf->pktRcvBuf = m_pRcvBuffer->getRcvAvgDataSize(perf->byteRcvBuf, perf->msRcvBuf);
}
#else
perf->pktRcvBuf = m_pRcvBuffer->getRcvDataSize(perf->byteRcvBuf, perf->msRcvBuf);
#endif
//<
}
else
{
perf->byteAvailRcvBuf = 0;
// new>
perf->pktRcvBuf = 0;
perf->byteRcvBuf = 0;
perf->msRcvBuf = 0;
//<
}
pthread_mutex_unlock(&m_ConnectionLock);
}
else
{
perf->byteAvailSndBuf = 0;
perf->byteAvailRcvBuf = 0;
// new>
perf->pktSndBuf = 0;
perf->byteSndBuf = 0;
perf->msSndBuf = 0;
perf->byteRcvBuf = 0;
perf->msRcvBuf = 0;
//<
}
if (clear)
{
m_stats.traceSndDrop = 0;
m_stats.traceRcvDrop = 0;
m_stats.traceSndBytesDrop = 0;
m_stats.traceRcvBytesDrop = 0;
m_stats.traceRcvUndecrypt = 0;
m_stats.traceRcvBytesUndecrypt = 0;
// new>
m_stats.traceBytesSent = m_stats.traceBytesRecv = m_stats.traceBytesRetrans = 0;
//<
m_stats.traceSent = m_stats.traceRecv = m_stats.traceSndLoss = m_stats.traceRcvLoss = m_stats.traceRetrans =
m_stats.sentACK = m_stats.recvACK = m_stats.sentNAK = m_stats.recvNAK = 0;
m_stats.sndDuration = 0;
m_stats.traceRcvRetrans = 0;
m_stats.traceRcvBelated = 0;
#ifdef SRT_ENABLE_LOSTBYTESCOUNT
m_stats.traceRcvBytesLoss = 0;
#endif
m_stats.sndFilterExtra = 0;
m_stats.rcvFilterExtra = 0;
m_stats.rcvFilterSupply = 0;
m_stats.rcvFilterLoss = 0;
m_stats.lastSampleTime = currtime;
}
}
参考资料:
https://github.com/Haivision/srt
[github releases]: https://github.com/Haivision/srt/releases