From 756826756abe4b5059e7de68f70f1b9f340cf762 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 13 Apr 2020 15:24:41 +0800 Subject: [PATCH 01/35] Refactor RTP encrypt --- trunk/src/app/srs_app_rtc_conn.cpp | 71 +++++++++++++++++------------- trunk/src/app/srs_app_rtc_conn.hpp | 5 ++- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index cd0e8b0b3..1d975ea74 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -386,7 +386,7 @@ srs_error_t SrsDtlsSession::protect_rtp(char* out_buf, const char* in_buf, int& return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed"); } -srs_error_t SrsDtlsSession::protect_rtp2(char* buf, int* pnn_buf, SrsRtpPacket2* pkt) +srs_error_t SrsDtlsSession::protect_rtp2(void* rtp_hdr, int* len_ptr) { srs_error_t err = srs_success; @@ -394,14 +394,7 @@ srs_error_t SrsDtlsSession::protect_rtp2(char* buf, int* pnn_buf, SrsRtpPacket2* return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect"); } - SrsBuffer stream(buf, *pnn_buf); - if ((err = pkt->encode(&stream)) != srs_success) { - return srs_error_wrap(err, "encode packet"); - } - - *pnn_buf = stream.pos(); - - if (srtp_protect(srtp_send, buf, pnn_buf) != 0) { + if (srtp_protect(srtp_send, rtp_hdr, len_ptr) != 0) { return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect"); } @@ -587,14 +580,15 @@ srs_error_t SrsRtcSenderThread::cycle() continue; } - int nn = 0; int nn_rtp_pkts = 0; - if ((err = send_messages(source, msgs.msgs, msg_count, sendonly_ukt, &nn, &nn_rtp_pkts)) != srs_success) { + if ((err = send_messages(source, msgs.msgs, msg_count, sendonly_ukt, &nn_rtp_pkts)) != srs_success) { srs_warn("send err %s", srs_error_summary(err).c_str()); srs_error_reset(err); } + int nn = 0; for (int i = 0; i < msg_count; i++) { SrsSharedPtrMessage* msg = msgs.msgs[i]; + nn += msg->size; srs_freep(msg); } @@ -608,7 +602,7 @@ srs_error_t SrsRtcSenderThread::cycle() srs_error_t SrsRtcSenderThread::send_messages( SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, - SrsUdpMuxSocket* skt, int* pnn, int* pnn_rtp_pkts + SrsUdpMuxSocket* skt, int* pnn_rtp_pkts ) { srs_error_t err = srs_success; @@ -618,10 +612,34 @@ srs_error_t SrsRtcSenderThread::send_messages( // Covert kernel messages to RTP packets. vector packets; + if ((err = messages_to_packets(source, msgs, nb_msgs, packets)) != srs_success) { + for (int j = 0; j < (int)packets.size(); j++) { + SrsRtpPacket2* packet = packets[j]; + srs_freep(packet); + } + return err; + } + + *pnn_rtp_pkts += (int)packets.size(); + + for (int j = 0; j < (int)packets.size(); j++) { + SrsRtpPacket2* packet = packets[j]; + if ((err = send_packet(packet, skt)) != srs_success) { + srs_warn("send err %s", srs_error_summary(err).c_str()); srs_error_reset(err); + } + srs_freep(packet); + } + + return err; +} + +srs_error_t SrsRtcSenderThread::messages_to_packets( + SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, vector& packets +) { + srs_error_t err = srs_success; for (int i = 0; i < nb_msgs; i++) { SrsSharedPtrMessage* msg = msgs[i]; - *pnn += msg->size; SrsRtpPacket2* packet = NULL; if (msg->is_audio()) { @@ -632,7 +650,6 @@ srs_error_t SrsRtcSenderThread::send_messages( } packets.push_back(packet); } - continue; } @@ -675,16 +692,6 @@ srs_error_t SrsRtcSenderThread::send_messages( } } - *pnn_rtp_pkts += (int)packets.size(); - - for (int j = 0; j < (int)packets.size(); j++) { - SrsRtpPacket2* packet = packets[j]; - if ((err = send_packet(packet, skt)) != srs_success) { - srs_warn("send err %s", srs_error_summary(err).c_str()); srs_error_reset(err); - } - srs_freep(packet); - } - return err; } @@ -701,15 +708,10 @@ srs_error_t SrsRtcSenderThread::send_packet(SrsRtpPacket2* pkt, SrsUdpMuxSocket* return srs_error_wrap(err, "fetch msghdr"); } char* buf = (char*)mhdr->msg_hdr.msg_iov->iov_base; - - // Length of iov, default size. int length = kRtpPacketSize; - if (rtc_session->encrypt) { - if ((err = rtc_session->dtls_session->protect_rtp2(buf, &length, pkt)) != srs_success) { - return srs_error_wrap(err, "srtp protect"); - } - } else { + // Marshal packet to bytes. + if (true) { SrsBuffer stream(buf, length); if ((err = pkt->encode(&stream)) != srs_success) { return srs_error_wrap(err, "encode packet"); @@ -717,6 +719,13 @@ srs_error_t SrsRtcSenderThread::send_packet(SrsRtpPacket2* pkt, SrsUdpMuxSocket* length = stream.pos(); } + // Whether encrypt the RTP bytes. + if (rtc_session->encrypt) { + if ((err = rtc_session->dtls_session->protect_rtp2(buf, &length)) != srs_success) { + return srs_error_wrap(err, "srtp protect"); + } + } + sockaddr_in* addr = (sockaddr_in*)skt->peer_addr(); socklen_t addrlen = (socklen_t)skt->peer_addrlen(); diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 3fef015c6..a0c370942 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -105,7 +105,7 @@ public: srs_error_t on_dtls_application_data(const char* data, const int len); public: srs_error_t protect_rtp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); - srs_error_t protect_rtp2(char* buf, int* pnn_buf, SrsRtpPacket2* pkt); + srs_error_t protect_rtp2(void* rtp_hdr, int* len_ptr); srs_error_t unprotect_rtp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); srs_error_t protect_rtcp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); srs_error_t unprotect_rtcp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); @@ -152,7 +152,8 @@ public: public: virtual srs_error_t cycle(); private: - srs_error_t send_messages(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsUdpMuxSocket* skt, int* pnn, int* pnn_rtp_pkts); + srs_error_t send_messages(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsUdpMuxSocket* skt, int* pnn_rtp_pkts); + srs_error_t messages_to_packets(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, std::vector& packets); srs_error_t send_packet(SrsRtpPacket2* pkt, SrsUdpMuxSocket* skt); private: srs_error_t packet_opus(SrsSample* sample, SrsRtpPacket2** ppacket); From 048301d9eb906bd1c8a7a3902a478fc064d96491 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 13 Apr 2020 15:37:32 +0800 Subject: [PATCH 02/35] Refactor RTP sender --- trunk/src/app/srs_app_rtc_conn.cpp | 80 +++++++++++++++--------------- trunk/src/app/srs_app_rtc_conn.hpp | 4 +- 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 1d975ea74..922f81c38 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -581,7 +581,7 @@ srs_error_t SrsRtcSenderThread::cycle() } int nn_rtp_pkts = 0; - if ((err = send_messages(source, msgs.msgs, msg_count, sendonly_ukt, &nn_rtp_pkts)) != srs_success) { + if ((err = send_messages(sendonly_ukt, source, msgs.msgs, msg_count, &nn_rtp_pkts)) != srs_success) { srs_warn("send err %s", srs_error_summary(err).c_str()); srs_error_reset(err); } @@ -601,8 +601,7 @@ srs_error_t SrsRtcSenderThread::cycle() } srs_error_t SrsRtcSenderThread::send_messages( - SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, - SrsUdpMuxSocket* skt, int* pnn_rtp_pkts + SrsUdpMuxSocket* skt, SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, int* pnn_rtp_pkts ) { srs_error_t err = srs_success; @@ -620,13 +619,12 @@ srs_error_t SrsRtcSenderThread::send_messages( return err; } + // Send out RTP packets *pnn_rtp_pkts += (int)packets.size(); + err = send_packets(skt, packets); for (int j = 0; j < (int)packets.size(); j++) { SrsRtpPacket2* packet = packets[j]; - if ((err = send_packet(packet, skt)) != srs_success) { - srs_warn("send err %s", srs_error_summary(err).c_str()); srs_error_reset(err); - } srs_freep(packet); } @@ -695,48 +693,52 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( return err; } -srs_error_t SrsRtcSenderThread::send_packet(SrsRtpPacket2* pkt, SrsUdpMuxSocket* skt) +srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, vector& packets) { srs_error_t err = srs_success; - ISrsUdpSender* sender = skt->sender(); + for (vector::iterator it = packets.begin(); it != packets.end(); ++it) { + SrsRtpPacket2* packet = *it; + ISrsUdpSender* sender = skt->sender(); - // Fetch a cached message from queue. - // TODO: FIXME: Maybe encrypt in async, so the state of mhdr maybe not ready. - mmsghdr* mhdr = NULL; - if ((err = sender->fetch(&mhdr)) != srs_success) { - return srs_error_wrap(err, "fetch msghdr"); - } - char* buf = (char*)mhdr->msg_hdr.msg_iov->iov_base; - int length = kRtpPacketSize; - - // Marshal packet to bytes. - if (true) { - SrsBuffer stream(buf, length); - if ((err = pkt->encode(&stream)) != srs_success) { - return srs_error_wrap(err, "encode packet"); + // Fetch a cached message from queue. + // TODO: FIXME: Maybe encrypt in async, so the state of mhdr maybe not ready. + mmsghdr* mhdr = NULL; + if ((err = sender->fetch(&mhdr)) != srs_success) { + return srs_error_wrap(err, "fetch msghdr"); } - length = stream.pos(); - } + char* buf = (char*)mhdr->msg_hdr.msg_iov->iov_base; + int length = kRtpPacketSize; - // Whether encrypt the RTP bytes. - if (rtc_session->encrypt) { - if ((err = rtc_session->dtls_session->protect_rtp2(buf, &length)) != srs_success) { - return srs_error_wrap(err, "srtp protect"); + // Marshal packet to bytes. + if (true) { + SrsBuffer stream(buf, length); + if ((err = packet->encode(&stream)) != srs_success) { + return srs_error_wrap(err, "encode packet"); + } + length = stream.pos(); + } + + // Whether encrypt the RTP bytes. + if (rtc_session->encrypt) { + if ((err = rtc_session->dtls_session->protect_rtp2(buf, &length)) != srs_success) { + return srs_error_wrap(err, "srtp protect"); + } + } + + sockaddr_in* addr = (sockaddr_in*)skt->peer_addr(); + socklen_t addrlen = (socklen_t)skt->peer_addrlen(); + + mhdr->msg_hdr.msg_name = (sockaddr_in*)addr; + mhdr->msg_hdr.msg_namelen = (socklen_t)addrlen; + mhdr->msg_hdr.msg_iov->iov_len = length; + mhdr->msg_len = 0; + + if ((err = sender->sendmmsg(mhdr)) != srs_success) { + return srs_error_wrap(err, "send msghdr"); } } - sockaddr_in* addr = (sockaddr_in*)skt->peer_addr(); - socklen_t addrlen = (socklen_t)skt->peer_addrlen(); - - mhdr->msg_hdr.msg_name = (sockaddr_in*)addr; - mhdr->msg_hdr.msg_namelen = (socklen_t)addrlen; - mhdr->msg_hdr.msg_iov->iov_len = length; - mhdr->msg_len = 0; - - if ((err = sender->sendmmsg(mhdr)) != srs_success) { - return srs_error_wrap(err, "send msghdr"); - } return err; } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index a0c370942..180872144 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -152,9 +152,9 @@ public: public: virtual srs_error_t cycle(); private: - srs_error_t send_messages(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsUdpMuxSocket* skt, int* pnn_rtp_pkts); + srs_error_t send_messages(SrsUdpMuxSocket* skt, SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, int* pnn_rtp_pkts); srs_error_t messages_to_packets(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, std::vector& packets); - srs_error_t send_packet(SrsRtpPacket2* pkt, SrsUdpMuxSocket* skt); + srs_error_t send_packets(SrsUdpMuxSocket* skt, std::vector& packets); private: srs_error_t packet_opus(SrsSample* sample, SrsRtpPacket2** ppacket); private: From 440089639536b75825d217ada0bdac6378d5b6ae Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 13 Apr 2020 16:50:24 +0800 Subject: [PATCH 03/35] Refactor code for merge_nalus and gso --- trunk/conf/full.conf | 7 ++ trunk/src/app/srs_app_config.cpp | 36 +++++++++- trunk/src/app/srs_app_config.hpp | 2 + trunk/src/app/srs_app_rtc_conn.cpp | 105 +++++++++++++++++++++-------- trunk/src/app/srs_app_rtc_conn.hpp | 32 +++++++-- 5 files changed, 149 insertions(+), 33 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 7304edd06..64b920f5b 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -435,6 +435,13 @@ rtc_server { # and net.core.rmem_default or just increase this to get larger UDP recv and send buffer. # default: 4 reuseport 4; + # Whether merge multiple NALUs into one. + # @see https://github.com/ossrs/srs/issues/307#issuecomment-612806318 + # default: off + merge_nalus off; + # Whether enable GSO to send out RTP packets. + # default: off + gso off; } vhost rtc.vhost.srs.com { diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index d3e790426..bc6c5c8bb 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3614,7 +3614,7 @@ srs_error_t SrsConfig::check_normal_config() for (int i = 0; conf && i < (int)conf->directives.size(); i++) { string n = conf->at(i)->name; if (n != "enabled" && n != "listen" && n != "dir" && n != "candidate" && n != "ecdsa" - && n != "sendmmsg" && n != "encrypt" && n != "reuseport") { + && n != "sendmmsg" && n != "encrypt" && n != "reuseport" && n != "gso" && n != "merge_nalus") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal rtc_server.%s", n.c_str()); } } @@ -4772,6 +4772,40 @@ int SrsConfig::get_rtc_server_reuseport() return reuseport; } +bool SrsConfig::get_rtc_server_merge_nalus() +{ + static int DEFAULT = false; + + SrsConfDirective* conf = root->get("rtc_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("merge_nalus"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_FALSE(conf->arg0()); +} + +bool SrsConfig::get_rtc_server_gso() +{ + static int DEFAULT = false; + + SrsConfDirective* conf = root->get("rtc_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("gso"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_FALSE(conf->arg0()); +} + SrsConfDirective* SrsConfig::get_rtc(string vhost) { SrsConfDirective* conf = get_vhost(vhost); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index ba46984e3..8093a50a4 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -528,6 +528,8 @@ public: virtual int get_rtc_server_sendmmsg(); virtual bool get_rtc_server_encrypt(); virtual int get_rtc_server_reuseport(); + virtual bool get_rtc_server_merge_nalus(); + virtual bool get_rtc_server_gso(); SrsConfDirective* get_rtc(std::string vhost); bool get_rtc_enabled(std::string vhost); diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 922f81c38..bbf9b7990 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -449,6 +449,25 @@ srs_error_t SrsDtlsSession::unprotect_rtcp(char* out_buf, const char* in_buf, in return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed"); } +SrsRtcPackets::SrsRtcPackets(bool gso, bool merge_nalus) +{ + is_gso = gso; + should_merge_nalus = merge_nalus; + + nn_rtp_pkts = nn_samples = 0; + nn_audios = nn_videos = 0; +} + +SrsRtcPackets::~SrsRtcPackets() +{ + vector::iterator it; + for (it = packets.begin(); it != packets.end(); ++it ) { + SrsRtpPacket2* packet = *it; + srs_freep(packet); + } + packets.clear(); +} + SrsRtcSenderThread::SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid) : sendonly_ukt(NULL) { @@ -457,15 +476,21 @@ SrsRtcSenderThread::SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int rtc_session = s; sendonly_ukt = u->copy_sendonly(); + gso = false; + merge_nalus = false; audio_timestamp = 0; audio_sequence = 0; video_sequence = 0; + + _srs_config->subscribe(this); } SrsRtcSenderThread::~SrsRtcSenderThread() { + _srs_config->unsubscribe(this); + srs_freep(trd); srs_freep(sendonly_ukt); } @@ -480,9 +505,35 @@ srs_error_t SrsRtcSenderThread::initialize(const uint32_t& vssrc, const uint32_t video_payload_type = v_pt; audio_payload_type = a_pt; + gso = _srs_config->get_rtc_server_gso(); + merge_nalus = _srs_config->get_rtc_server_merge_nalus(); + srs_trace("RTC sender video(ssrc=%d, pt=%d), audio(ssrc=%d, pt=%d), package(gso=%d, merge_nalus=%d)", + video_ssrc, video_payload_type, audio_ssrc, audio_payload_type, gso, merge_nalus); + return err; } +srs_error_t SrsRtcSenderThread::on_reload_rtc_server() +{ + if (true) { + bool v = _srs_config->get_rtc_server_gso(); + if (gso != v) { + srs_trace("Reload gso %d=>%d", gso, v); + gso = v; + } + } + + if (true) { + bool v = _srs_config->get_rtc_server_merge_nalus(); + if (merge_nalus != v) { + srs_trace("Reload merge_nalus %d=>%d", merge_nalus, v); + merge_nalus = v; + } + } + + return srs_success; +} + int SrsRtcSenderThread::cid() { return trd->cid(); @@ -580,28 +631,27 @@ srs_error_t SrsRtcSenderThread::cycle() continue; } - int nn_rtp_pkts = 0; - if ((err = send_messages(sendonly_ukt, source, msgs.msgs, msg_count, &nn_rtp_pkts)) != srs_success) { + SrsRtcPackets pkts(gso, merge_nalus); + if ((err = send_messages(sendonly_ukt, source, msgs.msgs, msg_count, pkts)) != srs_success) { srs_warn("send err %s", srs_error_summary(err).c_str()); srs_error_reset(err); } - int nn = 0; for (int i = 0; i < msg_count; i++) { SrsSharedPtrMessage* msg = msgs.msgs[i]; - nn += msg->size; srs_freep(msg); } pprint->elapse(); if (pprint->can_print()) { // TODO: FIXME: Print stat like frame/s, packet/s, loss_packets. - srs_trace("-> RTC PLAY %d msgs, %d packets, %d bytes", msg_count, nn_rtp_pkts, nn); + srs_trace("-> RTC PLAY %d msgs, %d samples, %d packets, %d audios, %d videos, %d bytes", + msg_count, pkts.nn_samples, pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_videos, pkts.nn_bytes); } } } srs_error_t SrsRtcSenderThread::send_messages( - SrsUdpMuxSocket* skt, SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, int* pnn_rtp_pkts + SrsUdpMuxSocket* skt, SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets ) { srs_error_t err = srs_success; @@ -610,53 +660,53 @@ srs_error_t SrsRtcSenderThread::send_messages( } // Covert kernel messages to RTP packets. - vector packets; if ((err = messages_to_packets(source, msgs, nb_msgs, packets)) != srs_success) { - for (int j = 0; j < (int)packets.size(); j++) { - SrsRtpPacket2* packet = packets[j]; - srs_freep(packet); - } return err; } - // Send out RTP packets - *pnn_rtp_pkts += (int)packets.size(); - err = send_packets(skt, packets); + packets.nn_rtp_pkts = (int)packets.packets.size(); - for (int j = 0; j < (int)packets.size(); j++) { - SrsRtpPacket2* packet = packets[j]; - srs_freep(packet); + // Send out RTP packets + if ((err = send_packets(skt, packets)) != srs_success) { + return err; } return err; } srs_error_t SrsRtcSenderThread::messages_to_packets( - SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, vector& packets + SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets ) { srs_error_t err = srs_success; for (int i = 0; i < nb_msgs; i++) { SrsSharedPtrMessage* msg = msgs[i]; + packets.nn_bytes += msg->size; + packets.nn_samples += msg->nn_extra_payloads() + msg->nn_samples(); + SrsRtpPacket2* packet = NULL; if (msg->is_audio()) { + packets.nn_audios++; + for (int i = 0; i < msg->nn_extra_payloads(); i++) { SrsSample* sample = msg->extra_payloads() + i; if ((err = packet_opus(sample, &packet)) != srs_success) { return srs_error_wrap(err, "opus package"); } - packets.push_back(packet); + packets.packets.push_back(packet); } continue; } + packets.nn_videos++; + // Well, for each IDR, we append a SPS/PPS before it, which is packaged in STAP-A. if (msg->has_idr()) { if ((err = packet_stap_a(source, msg, &packet)) != srs_success) { return srs_error_wrap(err, "packet stap-a"); } - packets.push_back(packet); + packets.packets.push_back(packet); } for (int i = 0; i < msg->nn_samples(); i++) { @@ -677,14 +727,14 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( if (i == msg->nn_samples() - 1) { packet->rtp_header.set_marker(true); } - packets.push_back(packet); + packets.packets.push_back(packet); } else { if ((err = packet_fu_a(msg, sample, kRtpMaxPayloadSize, packets)) != srs_success) { return srs_error_wrap(err, "packet fu-a"); } if (i == msg->nn_samples() - 1) { - packets.back()->rtp_header.set_marker(true); + packets.packets.back()->rtp_header.set_marker(true); } } } @@ -693,11 +743,12 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( return err; } -srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, vector& packets) +srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets& packets) { srs_error_t err = srs_success; - for (vector::iterator it = packets.begin(); it != packets.end(); ++it) { + vector::iterator it; + for (it = packets.packets.begin(); it != packets.packets.end(); ++it) { SrsRtpPacket2* packet = *it; ISrsUdpSender* sender = skt->sender(); @@ -766,7 +817,7 @@ srs_error_t SrsRtcSenderThread::packet_opus(SrsSample* sample, SrsRtpPacket2** p return err; } -srs_error_t SrsRtcSenderThread::packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* sample, int fu_payload_size, vector& packets) +srs_error_t SrsRtcSenderThread::packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* sample, int fu_payload_size, SrsRtcPackets& packets) { srs_error_t err = srs_success; @@ -780,7 +831,7 @@ srs_error_t SrsRtcSenderThread::packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* int packet_size = srs_min(nb_left, fu_payload_size); SrsRtpPacket2* packet = new SrsRtpPacket2(); - packets.push_back(packet); + packets.packets.push_back(packet); packet->rtp_header.set_timestamp(msg->timestamp * 90); packet->rtp_header.set_sequence(video_sequence++); @@ -1513,8 +1564,8 @@ srs_error_t SrsUdpMuxSender::on_reload_rtc_server() { int v = _srs_config->get_rtc_server_sendmmsg(); if (max_sendmmsg != v) { + srs_trace("Reload max_sendmmsg %d=>%d", max_sendmmsg, v); max_sendmmsg = v; - srs_trace("Reload max_sendmmsg=%d", max_sendmmsg); } return srs_success; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 180872144..906765888 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -117,7 +117,24 @@ private: srs_error_t srtp_recv_init(); }; -class SrsRtcSenderThread : public ISrsCoroutineHandler +class SrsRtcPackets +{ +public: + bool is_gso; + bool should_merge_nalus; +public: + int nn_bytes; + int nn_rtp_pkts; + int nn_samples; + int nn_audios; + int nn_videos; + std::vector packets; +public: + SrsRtcPackets(bool gso, bool merge_nalus); + virtual ~SrsRtcPackets(); +}; + +class SrsRtcSenderThread : virtual public ISrsCoroutineHandler, virtual public ISrsReloadHandler { protected: SrsCoroutine* trd; @@ -136,11 +153,16 @@ private: uint16_t video_sequence; public: SrsUdpMuxSocket* sendonly_ukt; + bool merge_nalus; + bool gso; public: SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid); virtual ~SrsRtcSenderThread(); public: srs_error_t initialize(const uint32_t& vssrc, const uint32_t& assrc, const uint16_t& v_pt, const uint16_t& a_pt); +// interface ISrsReloadHandler +public: + virtual srs_error_t on_reload_rtc_server(); public: virtual int cid(); public: @@ -152,13 +174,13 @@ public: public: virtual srs_error_t cycle(); private: - srs_error_t send_messages(SrsUdpMuxSocket* skt, SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, int* pnn_rtp_pkts); - srs_error_t messages_to_packets(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, std::vector& packets); - srs_error_t send_packets(SrsUdpMuxSocket* skt, std::vector& packets); + srs_error_t send_messages(SrsUdpMuxSocket* skt, SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets); + srs_error_t messages_to_packets(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets); + srs_error_t send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets& packets); private: srs_error_t packet_opus(SrsSample* sample, SrsRtpPacket2** ppacket); private: - srs_error_t packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* sample, int fu_payload_size, std::vector& packets); + srs_error_t packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* sample, int fu_payload_size, SrsRtcPackets& packets); srs_error_t packet_single_nalu(SrsSharedPtrMessage* msg, SrsSample* sample, SrsRtpPacket2** ppacket); srs_error_t packet_stap_a(SrsSource* source, SrsSharedPtrMessage* msg, SrsRtpPacket2** ppacket); }; From 5d23bb6a8abecb0596ec47451e08490a90588111 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 13 Apr 2020 17:11:46 +0800 Subject: [PATCH 04/35] Refactor code for merge_nalus --- trunk/src/app/srs_app_rtc_conn.cpp | 46 +++++++++++++++++++++--------- trunk/src/app/srs_app_rtc_conn.hpp | 2 ++ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index bbf9b7990..2f4ef86c8 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -454,8 +454,9 @@ SrsRtcPackets::SrsRtcPackets(bool gso, bool merge_nalus) is_gso = gso; should_merge_nalus = merge_nalus; - nn_rtp_pkts = nn_samples = 0; - nn_audios = nn_videos = 0; + nn_rtp_pkts = 0; + nn_audios = nn_extras = 0; + nn_videos = nn_samples = 0; } SrsRtcPackets::~SrsRtcPackets() @@ -644,8 +645,8 @@ srs_error_t SrsRtcSenderThread::cycle() pprint->elapse(); if (pprint->can_print()) { // TODO: FIXME: Print stat like frame/s, packet/s, loss_packets. - srs_trace("-> RTC PLAY %d msgs, %d samples, %d packets, %d audios, %d videos, %d bytes", - msg_count, pkts.nn_samples, pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_videos, pkts.nn_bytes); + srs_trace("-> RTC PLAY %d msgs, %d packets, %d audios, %d extras, %d videos, %d samples, %d bytes", + msg_count, pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, pkts.nn_samples, pkts.nn_bytes); } } } @@ -682,14 +683,21 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( for (int i = 0; i < nb_msgs; i++) { SrsSharedPtrMessage* msg = msgs[i]; + // Update stats. packets.nn_bytes += msg->size; - packets.nn_samples += msg->nn_extra_payloads() + msg->nn_samples(); + int nn_extra_payloads = msg->nn_extra_payloads(); + packets.nn_extras += nn_extra_payloads; + + int nn_samples = msg->nn_samples(); + packets.nn_samples += nn_samples; + + // For audio, we transcoded AAC to opus in extra payloads. SrsRtpPacket2* packet = NULL; if (msg->is_audio()) { packets.nn_audios++; - for (int i = 0; i < msg->nn_extra_payloads(); i++) { + for (int i = 0; i < nn_extra_payloads; i++) { SrsSample* sample = msg->extra_payloads() + i; if ((err = packet_opus(sample, &packet)) != srs_success) { return srs_error_wrap(err, "opus package"); @@ -699,6 +707,7 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( continue; } + // For video, we should process all NALUs in samples. packets.nn_videos++; // Well, for each IDR, we append a SPS/PPS before it, which is packaged in STAP-A. @@ -709,6 +718,15 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( packets.packets.push_back(packet); } + // If merge Nalus, we pcakges all NALUs(samples) as one NALU, in a RTP or FUA packet. + if (packets.should_merge_nalus && nn_samples > 1) { + if ((err = packet_nalus(msg, packets)) != srs_success) { + return srs_error_wrap(err, "packet stap-a"); + } + continue; + } + + // By default, we package each NALU(sample) to a RTP or FUA packet. for (int i = 0; i < msg->nn_samples(); i++) { SrsSample* sample = msg->samples() + i; @@ -723,19 +741,15 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( if ((err = packet_single_nalu(msg, sample, &packet)) != srs_success) { return srs_error_wrap(err, "packet single nalu"); } - - if (i == msg->nn_samples() - 1) { - packet->rtp_header.set_marker(true); - } packets.packets.push_back(packet); } else { if ((err = packet_fu_a(msg, sample, kRtpMaxPayloadSize, packets)) != srs_success) { return srs_error_wrap(err, "packet fu-a"); } + } - if (i == msg->nn_samples() - 1) { - packets.packets.back()->rtp_header.set_marker(true); - } + if (i == nn_samples - 1) { + packets.packets.back()->rtp_header.set_marker(true); } } } @@ -793,6 +807,12 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets return err; } +srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPackets& packets) +{ + srs_error_t err = srs_success; + return err; +} + srs_error_t SrsRtcSenderThread::packet_opus(SrsSample* sample, SrsRtpPacket2** ppacket) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 906765888..c10cc1305 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -126,6 +126,7 @@ public: int nn_bytes; int nn_rtp_pkts; int nn_samples; + int nn_extras; int nn_audios; int nn_videos; std::vector packets; @@ -181,6 +182,7 @@ private: srs_error_t packet_opus(SrsSample* sample, SrsRtpPacket2** ppacket); private: srs_error_t packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* sample, int fu_payload_size, SrsRtcPackets& packets); + srs_error_t packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPackets& packets); srs_error_t packet_single_nalu(SrsSharedPtrMessage* msg, SrsSample* sample, SrsRtpPacket2** ppacket); srs_error_t packet_stap_a(SrsSource* source, SrsSharedPtrMessage* msg, SrsRtpPacket2** ppacket); }; From 96059e0d420c1cfae109234fa6efe5f6d53c1425 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 13 Apr 2020 19:23:17 +0800 Subject: [PATCH 05/35] For #307, support merge multiple slices/NALUs to one NALU/RTP/FUA --- trunk/conf/full.conf | 4 +- trunk/src/app/srs_app_config.cpp | 4 +- trunk/src/app/srs_app_rtc_conn.cpp | 93 ++++++++++++++++++++-- trunk/src/kernel/srs_kernel_codec.cpp | 8 ++ trunk/src/kernel/srs_kernel_codec.hpp | 2 + trunk/src/kernel/srs_kernel_rtp.cpp | 108 +++++++++++++++++++++++++- trunk/src/kernel/srs_kernel_rtp.hpp | 24 ++++++ 7 files changed, 230 insertions(+), 13 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 64b920f5b..caadce385 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -437,8 +437,8 @@ rtc_server { reuseport 4; # Whether merge multiple NALUs into one. # @see https://github.com/ossrs/srs/issues/307#issuecomment-612806318 - # default: off - merge_nalus off; + # default: on + merge_nalus on; # Whether enable GSO to send out RTP packets. # default: off gso off; diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index bc6c5c8bb..f60a1782e 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -4774,7 +4774,7 @@ int SrsConfig::get_rtc_server_reuseport() bool SrsConfig::get_rtc_server_merge_nalus() { - static int DEFAULT = false; + static int DEFAULT = true; SrsConfDirective* conf = root->get("rtc_server"); if (!conf) { @@ -4786,7 +4786,7 @@ bool SrsConfig::get_rtc_server_merge_nalus() return DEFAULT; } - return SRS_CONF_PERFER_FALSE(conf->arg0()); + return SRS_CONF_PERFER_TRUE(conf->arg0()); } bool SrsConfig::get_rtc_server_gso() diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 2f4ef86c8..dfc3faf8e 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -727,7 +727,7 @@ srs_error_t SrsRtcSenderThread::messages_to_packets( } // By default, we package each NALU(sample) to a RTP or FUA packet. - for (int i = 0; i < msg->nn_samples(); i++) { + for (int i = 0; i < nn_samples; i++) { SrsSample* sample = msg->samples() + i; // We always ignore bframe here, if config to discard bframe, @@ -810,6 +810,81 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPackets& packets) { srs_error_t err = srs_success; + + SrsRtpRawNALUs* raw = new SrsRtpRawNALUs(); + + for (int i = 0; i < msg->nn_samples(); i++) { + SrsSample* sample = msg->samples() + i; + + // We always ignore bframe here, if config to discard bframe, + // the bframe flag will not be set. + if (sample->bframe) { + continue; + } + + raw->push_back(sample->copy()); + } + + // Ignore empty. + int nn_bytes = raw->nb_bytes(); + if (nn_bytes <= 0) { + srs_freep(raw); + return err; + } + + const int kRtpMaxPayloadSize = 1200; + if (nn_bytes < kRtpMaxPayloadSize) { + // Package NALUs in a single RTP packet. + SrsRtpPacket2* packet = new SrsRtpPacket2(); + packet->rtp_header.set_timestamp(msg->timestamp * 90); + packet->rtp_header.set_sequence(video_sequence++); + packet->rtp_header.set_ssrc(video_ssrc); + packet->rtp_header.set_payload_type(video_payload_type); + packet->payload = raw; + packets.packets.push_back(packet); + } else { + SrsAutoFree(SrsRtpRawNALUs, raw); + + // Package NALUs in FU-A RTP packets. + int fu_payload_size = kRtpMaxPayloadSize; + + // The first byte is store in FU-A header. + uint8_t header = raw->skip_first_byte(); + uint8_t nal_type = header & kNalTypeMask; + int nb_left = nn_bytes - 1; + + int num_of_packet = 1 + (nn_bytes - 1) / fu_payload_size; + for (int i = 0; i < num_of_packet; ++i) { + int packet_size = srs_min(nb_left, fu_payload_size); + + SrsRtpPacket2* packet = new SrsRtpPacket2(); + packets.packets.push_back(packet); + + packet->rtp_header.set_timestamp(msg->timestamp * 90); + packet->rtp_header.set_sequence(video_sequence++); + packet->rtp_header.set_ssrc(video_ssrc); + packet->rtp_header.set_payload_type(video_payload_type); + + SrsRtpFUAPayload* fua = new SrsRtpFUAPayload(); + packet->payload = fua; + + fua->nri = (SrsAvcNaluType)header; + fua->nalu_type = (SrsAvcNaluType)nal_type; + fua->start = bool(i == 0); + fua->end = bool(i == num_of_packet - 1); + + if ((err = raw->read_samples(fua->nalus, packet_size)) != srs_success) { + return srs_error_wrap(err, "read samples %d bytes, left %d, total %d", packet_size, nb_left, nn_bytes); + } + + nb_left -= packet_size; + } + } + + if (!packets.packets.empty()) { + packets.packets.back()->rtp_header.set_marker(true); + } + return err; } @@ -866,10 +941,10 @@ srs_error_t SrsRtcSenderThread::packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* fua->start = bool(i == 0); fua->end = bool(i == num_of_packet - 1); - SrsSample* sample = new SrsSample(); - sample->bytes = p; - sample->size = packet_size; - fua->nalus.push_back(sample); + SrsSample* fragment_sample = new SrsSample(); + fragment_sample->bytes = p; + fragment_sample->size = packet_size; + fua->nalus.push_back(fragment_sample); p += packet_size; nb_left -= packet_size; @@ -889,11 +964,13 @@ srs_error_t SrsRtcSenderThread::packet_single_nalu(SrsSharedPtrMessage* msg, Srs packet->rtp_header.set_ssrc(video_ssrc); packet->rtp_header.set_payload_type(video_payload_type); - SrsRtpRawPayload* raw = new SrsRtpRawPayload(); + SrsRtpRawNALUs* raw = new SrsRtpRawNALUs(); packet->payload = raw; - raw->payload = sample->bytes; - raw->nn_payload = sample->size; + SrsSample* p = new SrsSample(); + p->bytes = sample->bytes; + p->size = sample->size; + raw->push_back(p); *ppacket = packet; diff --git a/trunk/src/kernel/srs_kernel_codec.cpp b/trunk/src/kernel/srs_kernel_codec.cpp index a351dcc52..e0789c236 100644 --- a/trunk/src/kernel/srs_kernel_codec.cpp +++ b/trunk/src/kernel/srs_kernel_codec.cpp @@ -409,6 +409,14 @@ srs_error_t SrsSample::parse_bframe() return err; } +SrsSample* SrsSample::copy() +{ + SrsSample* p = new SrsSample(); + p->bytes = bytes; + p->size = size; + return p; +} + SrsCodecConfig::SrsCodecConfig() { } diff --git a/trunk/src/kernel/srs_kernel_codec.hpp b/trunk/src/kernel/srs_kernel_codec.hpp index 49447b5de..9c74e1387 100644 --- a/trunk/src/kernel/srs_kernel_codec.hpp +++ b/trunk/src/kernel/srs_kernel_codec.hpp @@ -542,6 +542,8 @@ public: public: // If we need to know whether sample is bframe, we have to parse the NALU payload. srs_error_t parse_bframe(); + // Copy sample, share the bytes pointer. + SrsSample* copy(); }; /** diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp index d00140005..ae044d4a2 100644 --- a/trunk/src/kernel/srs_kernel_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -229,6 +229,112 @@ srs_error_t SrsRtpRawPayload::encode(SrsBuffer* buf) return srs_success; } +SrsRtpRawNALUs::SrsRtpRawNALUs() +{ + cursor = 0; + nn_bytes = 0; +} + +SrsRtpRawNALUs::~SrsRtpRawNALUs() +{ + vector::iterator it; + for (it = nalus.begin(); it != nalus.end(); ++it) { + SrsSample* p = *it; + srs_freep(p); + } + nalus.clear(); +} + +void SrsRtpRawNALUs::push_back(SrsSample* sample) +{ + if (sample->size <= 0) { + return; + } + + if (!nalus.empty()) { + SrsSample* p = new SrsSample(); + p->bytes = (char*)"\0\0\1"; + p->size = 3; + nn_bytes += 3; + nalus.push_back(p); + } + + nn_bytes += sample->size; + nalus.push_back(sample); +} + +uint8_t SrsRtpRawNALUs::skip_first_byte() +{ + srs_assert (cursor >= 0 && nn_bytes > 0 && cursor < nn_bytes); + cursor++; + return uint8_t(nalus[0]->bytes[0]); +} + +srs_error_t SrsRtpRawNALUs::read_samples(vector& samples, int size) +{ + if (cursor + size < 0 || cursor + size > nn_bytes) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "cursor=%d, max=%d, size=%d", cursor, nn_bytes, size); + } + + int pos = cursor; + cursor += size; + int left = size; + + vector::iterator it; + for (it = nalus.begin(); it != nalus.end() && left > 0; ++it) { + SrsSample* p = *it; + + // Ignore previous consumed samples. + if (pos && pos - p->size >= 0) { + pos -= p->size; + continue; + } + + // Now, we are working at the sample. + int nn = srs_min(left, p->size - pos); + srs_assert(nn > 0); + + SrsSample* sample = new SrsSample(); + sample->bytes = p->bytes + pos; + sample->size = nn; + samples.push_back(sample); + + left -= nn; + pos = 0; + } + + return srs_success; +} + +int SrsRtpRawNALUs::nb_bytes() +{ + int size = 0; + + vector::iterator it; + for (it = nalus.begin(); it != nalus.end(); ++it) { + SrsSample* p = *it; + size += p->size; + } + + return size; +} + +srs_error_t SrsRtpRawNALUs::encode(SrsBuffer* buf) +{ + vector::iterator it; + for (it = nalus.begin(); it != nalus.end(); ++it) { + SrsSample* p = *it; + + if (!buf->require(p->size)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", p->size); + } + + buf->write_bytes(p->bytes, p->size); + } + + return srs_success; +} + SrsRtpSTAPPayload::SrsRtpSTAPPayload() { nri = (SrsAvcNaluType)0; @@ -339,7 +445,7 @@ srs_error_t SrsRtpFUAPayload::encode(SrsBuffer* buf) for (it = nalus.begin(); it != nalus.end(); ++it) { SrsSample* p = *it; if (!buf->require(p->size)) { - return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2 + p->size); + return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", p->size); } buf->write_bytes(p->bytes, p->size); diff --git a/trunk/src/kernel/srs_kernel_rtp.hpp b/trunk/src/kernel/srs_kernel_rtp.hpp index 975b2b463..7733b431f 100644 --- a/trunk/src/kernel/srs_kernel_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtp.hpp @@ -95,6 +95,7 @@ public: virtual srs_error_t encode(SrsBuffer* buf); }; +// Single payload data. class SrsRtpRawPayload : public ISrsEncoder { public: @@ -110,6 +111,28 @@ public: virtual srs_error_t encode(SrsBuffer* buf); }; +// Multiple NALUs, automatically insert 001 between NALUs. +class SrsRtpRawNALUs : public ISrsEncoder +{ +private: + std::vector nalus; + int nn_bytes; + int cursor; +public: + SrsRtpRawNALUs(); + virtual ~SrsRtpRawNALUs(); +public: + void push_back(SrsSample* sample); +public: + uint8_t skip_first_byte(); + srs_error_t read_samples(std::vector& samples, int size); +// interface ISrsEncoder +public: + virtual int nb_bytes(); + virtual srs_error_t encode(SrsBuffer* buf); +}; + +// STAP-A, for multiple NALUs. class SrsRtpSTAPPayload : public ISrsEncoder { public: @@ -127,6 +150,7 @@ public: virtual srs_error_t encode(SrsBuffer* buf); }; +// FU-A, for one NALU with multiple fragments. class SrsRtpFUAPayload : public ISrsEncoder { public: From bfe40f011550beab984a2e24486fc1b132109068 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 13 Apr 2020 19:50:40 +0800 Subject: [PATCH 06/35] Check pkg-config --- trunk/auto/depends.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index 1ed7e3aa3..7c4e96141 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -110,7 +110,11 @@ function Ubuntu_prepare() echo "The valgrind-dev is installed." fi fi - + + pkg-config --version >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then + echo "Please install pkg-config"; exit -1; + fi + echo "Tools for Ubuntu are installed." return 0 } @@ -191,6 +195,10 @@ function Centos_prepare() echo "The valgrind-devel is installed." fi fi + + pkg-config --version --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then + echo "Please install pkg-config"; exit -1; + fi echo "Tools for Centos are installed." return 0 From 3b7240b8e0a360ce7db09f9c183c7b4a59518dd1 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 13 Apr 2020 23:40:30 +0800 Subject: [PATCH 07/35] For #307, support linux GSO for RTC --- trunk/conf/full.conf | 1 + trunk/src/app/srs_app_config.cpp | 10 +- trunk/src/app/srs_app_rtc_conn.cpp | 185 ++++++++++++++++++++++++++++- trunk/src/app/srs_app_rtc_conn.hpp | 4 +- 4 files changed, 193 insertions(+), 7 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index caadce385..57e64bf1b 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -440,6 +440,7 @@ rtc_server { # default: on merge_nalus on; # Whether enable GSO to send out RTP packets. + # @remark Linux only, for other OS always disabled. # default: off gso off; } diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index f60a1782e..f7f69a381 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -4803,7 +4803,15 @@ bool SrsConfig::get_rtc_server_gso() return DEFAULT; } - return SRS_CONF_PERFER_FALSE(conf->arg0()); + bool v = SRS_CONF_PERFER_FALSE(conf->arg0()); + +#ifdef SRS_AUTO_OSX + if (v) { + srs_warn("GSO is for Linux only"); + } + v = false; +#endif + return v; } SrsConfDirective* SrsConfig::get_rtc(string vhost) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index dfc3faf8e..b51cb236c 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -33,6 +33,11 @@ using namespace std; #include #include +#include +#ifndef UDP_SEGMENT +#define UDP_SEGMENT 103 +#endif + #include #include @@ -451,7 +456,7 @@ srs_error_t SrsDtlsSession::unprotect_rtcp(char* out_buf, const char* in_buf, in SrsRtcPackets::SrsRtcPackets(bool gso, bool merge_nalus) { - is_gso = gso; + use_gso = gso; should_merge_nalus = merge_nalus; nn_rtp_pkts = 0; @@ -662,15 +667,25 @@ srs_error_t SrsRtcSenderThread::send_messages( // Covert kernel messages to RTP packets. if ((err = messages_to_packets(source, msgs, nb_msgs, packets)) != srs_success) { - return err; + return srs_error_wrap(err, "messages to packets"); } packets.nn_rtp_pkts = (int)packets.packets.size(); - // Send out RTP packets - if ((err = send_packets(skt, packets)) != srs_success) { +#ifndef SRS_AUTO_OSX + // If enabled GSO, send out some packets in a msghdr. + if (packets.use_gso) { + if ((err = send_packets2(skt, packets)) != srs_success) { + return srs_error_wrap(err, "gso send"); + } return err; } +#endif + + // By default, we send packets by sendmmsg. + if ((err = send_packets(skt, packets)) != srs_success) { + return srs_error_wrap(err, "raw send"); + } return err; } @@ -761,10 +776,13 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets { srs_error_t err = srs_success; + ISrsUdpSender* sender = skt->sender(); + vector::iterator it; for (it = packets.packets.begin(); it != packets.packets.end(); ++it) { SrsRtpPacket2* packet = *it; - ISrsUdpSender* sender = skt->sender(); + + int nn_packet = packet->nb_bytes(); // Fetch a cached message from queue. // TODO: FIXME: Maybe encrypt in async, so the state of mhdr maybe not ready. @@ -807,6 +825,157 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets return err; } +// TODO: FIXME: We can gather and pad audios, because they have similar size. +srs_error_t SrsRtcSenderThread::send_packets2(SrsUdpMuxSocket* skt, SrsRtcPackets& packets) +{ + srs_error_t err = srs_success; + + ISrsUdpSender* sender = skt->sender(); + + // Previous handler, if has the same size, we can use GSO. + mmsghdr* gso_mhdr = NULL; int gso_size = 0; int gso_encrypt = 0; int gso_cursor = 0; + // GSO, N packets has same length, the final one may not. + bool use_gso = false; bool gso_final = false; + + int nn_packets = (int)packets.packets.size(); + for (int i = 0; i < nn_packets; i++) { + SrsRtpPacket2* packet = packets.packets[i]; + + // The handler to send message. + mmsghdr* mhdr = NULL; + + // Check whether we can use GSO to send it. + int nn_packet = packet->nb_bytes(); + + if ((gso_size && gso_size == nn_packet) || (use_gso && !gso_final)) { + use_gso = true; + gso_final = (gso_size && gso_size != nn_packet); + mhdr = gso_mhdr; + + // We need to increase the iov and cursor. + int nb_iovs = mhdr->msg_hdr.msg_iovlen; + if (gso_cursor >= nb_iovs - 1) { + int nn_new_iovs = nb_iovs; + mhdr->msg_hdr.msg_iovlen = nb_iovs + nn_new_iovs; + mhdr->msg_hdr.msg_iov = (iovec*)realloc(mhdr->msg_hdr.msg_iov, sizeof(iovec) * (nb_iovs + nn_new_iovs)); + memset(mhdr->msg_hdr.msg_iov + nb_iovs, 0, sizeof(iovec) * nn_new_iovs); + } + gso_cursor++; + + // Create payload cache for RTP packet. + iovec* p = mhdr->msg_hdr.msg_iov + gso_cursor; + if (!p->iov_base) { + p->iov_base = new char[kRtpPacketSize]; + p->iov_len = kRtpPacketSize; + } + } else { + // Fetch a cached message from queue. + // TODO: FIXME: Maybe encrypt in async, so the state of mhdr maybe not ready. + if ((err = sender->fetch(&mhdr)) != srs_success) { + return srs_error_wrap(err, "fetch msghdr"); + } + + // Reset the iovec, we should never change the msg_iovlen. + for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { + iovec* p = mhdr->msg_hdr.msg_iov + j; + p->iov_len = 0; + } + + gso_mhdr = mhdr; + gso_size = nn_packet; + gso_cursor = 0; + } + + // Change the state according to the next packet. + if (i < nn_packets - 1) { + SrsRtpPacket2* next_packet = (i < nn_packets - 1)? packets.packets[i + 1]:NULL; + int nn_next_packet = next_packet? next_packet->nb_bytes() : 0; + + // If GSO, but next is bigger than this one, we must enter the final state. + if (use_gso && !gso_final) { + gso_final = (nn_packet < nn_next_packet); + } + + // If not GSO, maybe the first fresh packet, we should see whether the next packet is smaller than this one, + // if smaller, we can still enter GSO. + if (!use_gso) { + use_gso = (nn_packet >= nn_next_packet); + } + } + + // Marshal packet to bytes. + iovec* iov = mhdr->msg_hdr.msg_iov + gso_cursor; + iov->iov_len = kRtpPacketSize; + + if (true) { + SrsBuffer stream((char*)iov->iov_base, iov->iov_len); + if ((err = packet->encode(&stream)) != srs_success) { + return srs_error_wrap(err, "encode packet"); + } + iov->iov_len = stream.pos(); + } + + // Whether encrypt the RTP bytes. + if (rtc_session->encrypt) { + int nn_encrypt = (int)iov->iov_len; + if ((err = rtc_session->dtls_session->protect_rtp2(iov->iov_base, &nn_encrypt)) != srs_success) { + return srs_error_wrap(err, "srtp protect"); + } + iov->iov_len = (size_t)nn_encrypt; + } + + // If GSO, they must has same size, except the final one. + if (use_gso && !gso_final && gso_encrypt && gso_encrypt != (int)iov->iov_len) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "GSO size=%d/%d, encrypt=%d/%d", gso_size, nn_packet, gso_encrypt, iov->iov_len); + } + + if (use_gso && !gso_final) { + gso_encrypt = iov->iov_len; + } + + // If exceed the max GSO size, set to final. + if (use_gso && gso_cursor > 64) { + gso_final = true; + } + + // For last message, or final gso, or determined not using GSO, send it now. + if (i == nn_packets - 1 || gso_final || !use_gso) { + sockaddr_in* addr = (sockaddr_in*)skt->peer_addr(); + socklen_t addrlen = (socklen_t)skt->peer_addrlen(); + + mhdr->msg_hdr.msg_name = (sockaddr_in*)addr; + mhdr->msg_hdr.msg_namelen = (socklen_t)addrlen; + mhdr->msg_hdr.msg_controllen = 0; + mhdr->msg_len = 0; + + if (use_gso) { +#ifndef SRS_AUTO_OSX + if (!mhdr->msg_hdr.msg_control) { + mhdr->msg_hdr.msg_control = new char[mhdr->msg_hdr.msg_controllen]; + } + mhdr->msg_hdr.msg_controllen = CMSG_SPACE(sizeof(uint16_t)); + + cmsghdr* cm = CMSG_FIRSTHDR(&mhdr->msg_hdr); + cm->cmsg_level = SOL_UDP; + cm->cmsg_type = UDP_SEGMENT; + cm->cmsg_len = CMSG_LEN(sizeof(uint16_t)); + *((uint16_t*)CMSG_DATA(cm)) = gso_encrypt; +#endif + } + + if ((err = sender->sendmmsg(mhdr)) != srs_success) { + return srs_error_wrap(err, "send msghdr"); + } + + // Reset the GSO flag. + gso_mhdr = NULL; gso_size = 0; gso_encrypt = 0; gso_cursor = 0; + use_gso = gso_final = false; + } + } + + return err; +} + srs_error_t SrsRtcSenderThread::packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPackets& packets) { srs_error_t err = srs_success; @@ -1536,6 +1705,11 @@ void SrsUdpMuxSender::free_mhdrs(std::vector& mhdrs) for (int i = 0; i < (int)mhdrs.size(); i++) { mmsghdr* hdr = &mhdrs[i]; + // Free control for GSO. + char* msg_control = (char*)hdr->msg_hdr.msg_control; + srs_freep(msg_control); + + // Free iovec. for (int j = (int)hdr->msg_hdr.msg_iovlen - 1; j >= 0 ; j--) { iovec* iov = hdr->msg_hdr.msg_iov + j; char* data = (char*)iov->iov_base; @@ -1543,6 +1717,7 @@ void SrsUdpMuxSender::free_mhdrs(std::vector& mhdrs) srs_freep(iov); } } + mhdrs.clear(); } srs_error_t SrsUdpMuxSender::fetch(mmsghdr** pphdr) diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index c10cc1305..748374290 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -120,7 +120,7 @@ private: class SrsRtcPackets { public: - bool is_gso; + bool use_gso; bool should_merge_nalus; public: int nn_bytes; @@ -129,6 +129,7 @@ public: int nn_extras; int nn_audios; int nn_videos; +public: std::vector packets; public: SrsRtcPackets(bool gso, bool merge_nalus); @@ -178,6 +179,7 @@ private: srs_error_t send_messages(SrsUdpMuxSocket* skt, SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets); srs_error_t messages_to_packets(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets); srs_error_t send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets& packets); + srs_error_t send_packets2(SrsUdpMuxSocket* skt, SrsRtcPackets& packets); private: srs_error_t packet_opus(SrsSample* sample, SrsRtpPacket2** ppacket); private: From 89a247d9bc7c6dd5391870fce2e818482bc0408d Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 13 Apr 2020 23:57:03 +0800 Subject: [PATCH 08/35] Remove unused code --- trunk/src/app/srs_app_rtc_conn.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index b51cb236c..a5d8a886b 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -782,8 +782,6 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets for (it = packets.packets.begin(); it != packets.packets.end(); ++it) { SrsRtpPacket2* packet = *it; - int nn_packet = packet->nb_bytes(); - // Fetch a cached message from queue. // TODO: FIXME: Maybe encrypt in async, so the state of mhdr maybe not ready. mmsghdr* mhdr = NULL; From 8a71ce62db9d3222804c58823819f68c2d9016af Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 09:20:21 +0800 Subject: [PATCH 09/35] For #307, allow dedicated cache for GSO. --- trunk/conf/full.conf | 4 + trunk/src/app/srs_app_config.cpp | 28 +++- trunk/src/app/srs_app_config.hpp | 1 + trunk/src/app/srs_app_http_api.cpp | 13 +- trunk/src/app/srs_app_listener.hpp | 4 + trunk/src/app/srs_app_rtc_conn.cpp | 209 ++++++++++++++++++++++------ trunk/src/app/srs_app_rtc_conn.hpp | 10 ++ trunk/src/app/srs_app_statistic.cpp | 74 +++++++++- trunk/src/app/srs_app_statistic.hpp | 8 +- 9 files changed, 303 insertions(+), 48 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 57e64bf1b..45156da17 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -443,6 +443,10 @@ rtc_server { # @remark Linux only, for other OS always disabled. # default: off gso off; + # Whether GSO uses dedicated cache. Share the same mmsghdr cache if not dedicated. + # For Linux 3.*, we must use dedicated cache for GSO. + # default: off + gso_dedicated off; } vhost rtc.vhost.srs.com { diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index f7f69a381..9693a17fa 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3614,7 +3614,8 @@ srs_error_t SrsConfig::check_normal_config() for (int i = 0; conf && i < (int)conf->directives.size(); i++) { string n = conf->at(i)->name; if (n != "enabled" && n != "listen" && n != "dir" && n != "candidate" && n != "ecdsa" - && n != "sendmmsg" && n != "encrypt" && n != "reuseport" && n != "gso" && n != "merge_nalus") { + && n != "sendmmsg" && n != "encrypt" && n != "reuseport" && n != "gso" && n != "merge_nalus" + && n != "gso_dedicated") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal rtc_server.%s", n.c_str()); } } @@ -4814,6 +4815,31 @@ bool SrsConfig::get_rtc_server_gso() return v; } +bool SrsConfig::get_rtc_server_gso_dedicated() +{ + static int DEFAULT = false; + + SrsConfDirective* conf = root->get("rtc_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("gso_dedicated"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + bool v = SRS_CONF_PERFER_FALSE(conf->arg0()); + +#ifdef SRS_AUTO_OSX + if (v != DEFAULT) { + srs_warn("GSO is for Linux only"); + } +#endif + + return v; +} + SrsConfDirective* SrsConfig::get_rtc(string vhost) { SrsConfDirective* conf = get_vhost(vhost); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 8093a50a4..bfc6f373f 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -530,6 +530,7 @@ public: virtual int get_rtc_server_reuseport(); virtual bool get_rtc_server_merge_nalus(); virtual bool get_rtc_server_gso(); + virtual bool get_rtc_server_gso_dedicated(); SrsConfDirective* get_rtc(std::string vhost); bool get_rtc_enabled(std::string vhost); diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 1f3749b7a..6d7df56fa 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1622,7 +1622,7 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* data->set("query", p); p->set("target", SrsJsonAny::str(target.c_str())); - p->set("help", SrsJsonAny::str("?target=writev|sendmmsg")); + p->set("help", SrsJsonAny::str("?target=writev|sendmmsg|gso|udp")); } if (target.empty() || target == "writev") { @@ -1634,7 +1634,7 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* } } - if (target.empty() || target == "sendmmsg") { + if (target.empty() || target == "sendmmsg" || target == "udp") { SrsJsonObject* p = SrsJsonAny::object(); data->set("sendmmsg", p); if ((err = stat->dumps_perf_sendmmsg(p)) != srs_success) { @@ -1643,6 +1643,15 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* } } + if (target.empty() || target == "gso" || target == "udp") { + SrsJsonObject* p = SrsJsonAny::object(); + data->set("gso", p); + if ((err = stat->dumps_perf_gso(p)) != srs_success) { + int code = srs_error_code(err); srs_error_reset(err); + return srs_api_response_code(w, r, code); + } + } + return srs_api_response(w, r, obj->dumps()); } diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp index 8ef384dd9..ec503cf6b 100644 --- a/trunk/src/app/srs_app_listener.hpp +++ b/trunk/src/app/srs_app_listener.hpp @@ -139,6 +139,10 @@ public: public: // Fetch a mmsghdr from sender's cache. virtual srs_error_t fetch(mmsghdr** pphdr) = 0; + // For Linux kernel 3.*, we must use isolate APIs for GSO, + // that is, sendmmsg does not work with GSO. + // Fetch a mmsghdr from sender's cache. + virtual srs_error_t gso_fetch(mmsghdr** pphdr) = 0; // Notify the sender to send out the msg. virtual srs_error_t sendmmsg(mmsghdr* hdr) = 0; }; diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index a5d8a886b..cdf02d68c 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -866,22 +866,6 @@ srs_error_t SrsRtcSenderThread::send_packets2(SrsUdpMuxSocket* skt, SrsRtcPacket p->iov_base = new char[kRtpPacketSize]; p->iov_len = kRtpPacketSize; } - } else { - // Fetch a cached message from queue. - // TODO: FIXME: Maybe encrypt in async, so the state of mhdr maybe not ready. - if ((err = sender->fetch(&mhdr)) != srs_success) { - return srs_error_wrap(err, "fetch msghdr"); - } - - // Reset the iovec, we should never change the msg_iovlen. - for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { - iovec* p = mhdr->msg_hdr.msg_iov + j; - p->iov_len = 0; - } - - gso_mhdr = mhdr; - gso_size = nn_packet; - gso_cursor = 0; } // Change the state according to the next packet. @@ -901,6 +885,32 @@ srs_error_t SrsRtcSenderThread::send_packets2(SrsUdpMuxSocket* skt, SrsRtcPacket } } + // Now, we fetch the msg from cache. + if (!mhdr) { + // Fetch a cached message from queue. + // TODO: FIXME: Maybe encrypt in async, so the state of mhdr maybe not ready. + if (use_gso) { + err = sender->gso_fetch(&mhdr); + } else { + err = sender->fetch(&mhdr); + } + if (err != srs_success) { + return srs_error_wrap(err, "fetch msghdr"); + } + + // Reset the iovec, we should never change the msg_iovlen. + for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { + iovec* p = mhdr->msg_hdr.msg_iov + j; + p->iov_len = 0; + } + + // Now, GSO will use this message and size. + if (use_gso) { + gso_mhdr = mhdr; + gso_size = nn_packet; + } + } + // Marshal packet to bytes. iovec* iov = mhdr->msg_hdr.msg_iov + gso_cursor; iov->iov_len = kRtpPacketSize; @@ -946,25 +956,37 @@ srs_error_t SrsRtcSenderThread::send_packets2(SrsUdpMuxSocket* skt, SrsRtcPacket mhdr->msg_hdr.msg_controllen = 0; mhdr->msg_len = 0; - if (use_gso) { #ifndef SRS_AUTO_OSX + if (use_gso) { + mhdr->msg_hdr.msg_controllen = CMSG_SPACE(sizeof(uint16_t)); if (!mhdr->msg_hdr.msg_control) { mhdr->msg_hdr.msg_control = new char[mhdr->msg_hdr.msg_controllen]; } - mhdr->msg_hdr.msg_controllen = CMSG_SPACE(sizeof(uint16_t)); cmsghdr* cm = CMSG_FIRSTHDR(&mhdr->msg_hdr); cm->cmsg_level = SOL_UDP; cm->cmsg_type = UDP_SEGMENT; cm->cmsg_len = CMSG_LEN(sizeof(uint16_t)); *((uint16_t*)CMSG_DATA(cm)) = gso_encrypt; -#endif + + // Private message, use it to store the cursor. + mhdr->msg_len = gso_cursor + 1; } +#endif if ((err = sender->sendmmsg(mhdr)) != srs_success) { return srs_error_wrap(err, "send msghdr"); } +#ifdef SRS_DEBUG + srs_warn("packet SN=%d %d bytes", nn_packet, packet->rtp_header.get_sequence()); + for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { + iovec* iov = mhdr->msg_hdr.msg_iov + j; + srs_warn("%s #%d/%d/%d, %d bytes, size %d/%d", (use_gso? "GSO":"RAW"), j, gso_cursor + 1, + mhdr->msg_hdr.msg_iovlen, iov->iov_len, gso_size, gso_encrypt); + } +#endif + // Reset the GSO flag. gso_mhdr = NULL; gso_size = 0; gso_encrypt = 0; gso_cursor = 0; use_gso = gso_final = false; @@ -1662,6 +1684,7 @@ SrsUdpMuxSender::SrsUdpMuxSender(SrsRtcServer* s) trd = new SrsDummyCoroutine(); cache_pos = 0; + gso_cache_pos = 0; _srs_config->subscribe(this); } @@ -1678,6 +1701,12 @@ SrsUdpMuxSender::~SrsUdpMuxSender() free_mhdrs(cache); cache.clear(); + + free_mhdrs(gso_hotspot); + gso_hotspot.clear(); + + free_mhdrs(gso_cache); + gso_cache.clear(); } srs_error_t SrsUdpMuxSender::initialize(srs_netfd_t fd) @@ -1693,7 +1722,10 @@ srs_error_t SrsUdpMuxSender::initialize(srs_netfd_t fd) } max_sendmmsg = _srs_config->get_rtc_server_sendmmsg(); - srs_trace("UDP sender #%d init ok, max_sendmmsg=%d", srs_netfd_fileno(fd), max_sendmmsg); + bool gso = _srs_config->get_rtc_server_gso(); + gso_dedicated = _srs_config->get_rtc_server_gso_dedicated(); + srs_trace("UDP sender #%d init ok, max_sendmmsg=%d, gso=%d, gso-dedicated=%d", + srs_netfd_fileno(fd), max_sendmmsg, gso, gso_dedicated); return err; } @@ -1738,6 +1770,34 @@ srs_error_t SrsUdpMuxSender::fetch(mmsghdr** pphdr) return srs_success; } +srs_error_t SrsUdpMuxSender::gso_fetch(mmsghdr** pphdr) +{ + // When GSO share cache, we use the same cache with non-GSO. + if (!gso_dedicated) { + return fetch(pphdr); + } + + // TODO: FIXME: Maybe need to shrink? + if (gso_cache_pos >= (int)gso_cache.size()) { + mmsghdr mhdr; + memset(&mhdr, 0, sizeof(mmsghdr)); + + mhdr.msg_hdr.msg_iovlen = 1; + mhdr.msg_hdr.msg_iov = new iovec(); + mhdr.msg_hdr.msg_iov->iov_base = new char[kRtpPacketSize]; + mhdr.msg_hdr.msg_iov->iov_len = kRtpPacketSize; + mhdr.msg_len = 0; + + mhdr.msg_hdr.msg_controllen = CMSG_SPACE(sizeof(uint16_t)); + mhdr.msg_hdr.msg_control = new char[mhdr.msg_hdr.msg_controllen]; + + gso_cache.push_back(mhdr); + } + + *pphdr = &gso_cache[gso_cache_pos++]; + return srs_success; +} + srs_error_t SrsUdpMuxSender::sendmmsg(mmsghdr* hdr) { if (waiting_msgs) { @@ -1752,11 +1812,9 @@ srs_error_t SrsUdpMuxSender::cycle() { srs_error_t err = srs_success; - uint64_t nn_msgs = 0; - uint64_t nn_msgs_last = 0; - int nn_msgs_max = 0; - int nn_loop = 0; - int nn_wait = 0; + uint64_t nn_msgs = 0; uint64_t nn_msgs_last = 0; int nn_msgs_max = 0; + uint64_t nn_gso_msgs = 0; uint64_t nn_gso_iovs = 0; int nn_gso_msgs_max = 0; int nn_gso_iovs_max = 0; + int nn_loop = 0; int nn_wait = 0; srs_utime_t time_last = srs_get_system_time(); SrsStatistic* stat = SrsStatistic::instance(); @@ -1771,7 +1829,9 @@ srs_error_t SrsUdpMuxSender::cycle() nn_loop++; int pos = cache_pos; - if (pos <= 0) { + int gso_pos = gso_cache_pos; + int gso_iovs = 0; + if (pos <= 0 && gso_pos == 0) { waiting_msgs = true; nn_wait++; srs_cond_wait(cond); @@ -1782,22 +1842,73 @@ srs_error_t SrsUdpMuxSender::cycle() cache.swap(hotspot); cache_pos = 0; - mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; - for (; p < end; p += max_sendmmsg) { - int vlen = (int)(end - p); - vlen = srs_min(max_sendmmsg, vlen); + if (gso_dedicated) { + gso_cache.swap(gso_hotspot); + gso_cache_pos = 0; + } - int r0 = srs_sendmmsg(lfd, p, (unsigned int)vlen, 0, SRS_UTIME_NO_TIMEOUT); - if (r0 != vlen) { - srs_warn("sendmsg %d msgs, %d done", vlen, r0); + // Send out GSO in dedicated queue. + if (gso_dedicated && gso_pos > 0) { + mmsghdr* p = &gso_hotspot[0]; mmsghdr* end = p + gso_pos; + for (; p < end; p++) { + // Private message, use it to store the cursor. + int real_iovs = p->msg_len; + p->msg_len = 0; + + // Send out GSO message. + int r0 = srs_sendmsg(lfd, &p->msg_hdr, 0, SRS_UTIME_NO_TIMEOUT); + if (r0 < 0) { + srs_warn("sendmsg err, r0=%d", r0); + } + + nn_gso_msgs++; nn_gso_iovs += real_iovs; gso_iovs += real_iovs; + stat->perf_gso_on_packets(real_iovs); + } + } + + // Send out all messages, may GSO if shared cache. + if (pos > 0) { + mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; + + // For shared GSO cache, stat the messages. + if (!gso_dedicated) { + for (p = &hotspot[0]; p < end; p++) { + if (!p->msg_len) { + continue; + } + + // Private message, use it to store the cursor. + int real_iovs = p->msg_len; + p->msg_len = 0; + + gso_pos++; nn_gso_msgs++; nn_gso_iovs += real_iovs; gso_iovs += real_iovs; + stat->perf_gso_on_packets(real_iovs); + } } - stat->perf_mw_on_packets(vlen); + // Send out all messages. + for (p = &hotspot[0]; p < end; p += max_sendmmsg) { + int vlen = (int)(end - p); + vlen = srs_min(max_sendmmsg, vlen); + + int r0 = srs_sendmmsg(lfd, p, (unsigned int)vlen, 0, SRS_UTIME_NO_TIMEOUT); + if (r0 != vlen) { + srs_warn("sendmmsg %d msgs, %d done", vlen, r0); + } + + stat->perf_sendmmsg_on_packets(vlen); + } } // Increase total messages. - nn_msgs += pos; - nn_msgs_max = srs_max(pos, nn_msgs_max); + int nn_pos = pos; + if (gso_dedicated) { + nn_pos = pos + gso_pos; + } + nn_msgs += nn_pos; + nn_msgs_max = srs_max(nn_pos, nn_msgs_max); + nn_gso_msgs_max = srs_max(gso_pos, nn_gso_msgs_max); + nn_gso_iovs_max = srs_max(gso_iovs, nn_gso_iovs_max); pprint->elapse(); if (pprint->can_print()) { @@ -1819,11 +1930,12 @@ srs_error_t SrsUdpMuxSender::cycle() pps_unit = "(k)"; pps_last /= 1000; pps_average /= 1000; } - srs_trace("-> RTC #%d SEND %d/%d/%" PRId64 ", pps %d/%d%s, schedule %d/%d, sessions %d, cache %d/%d by sendmmsg %d", - srs_netfd_fileno(lfd), pos, nn_msgs_max, nn_msgs, pps_average, pps_last, pps_unit.c_str(), nn_loop, nn_wait, - (int)server->nn_sessions(), (int)cache.size(), (int)hotspot.size(), max_sendmmsg); + srs_trace("-> RTC #%d SEND %d/%d/%" PRId64 ", gso %d/%d/%" PRId64 ", gso-iovs %d/%d/%" PRId64 ", pps %d/%d%s, schedule %d/%d, sessions %d, cache %d/%d, sendmmsg %d", + srs_netfd_fileno(lfd), nn_pos, nn_msgs_max, nn_msgs, gso_pos, nn_gso_msgs_max, nn_gso_msgs, gso_iovs, nn_gso_iovs_max, nn_gso_iovs, pps_average, pps_last, pps_unit.c_str(), + nn_loop, nn_wait, (int)server->nn_sessions(), (int)cache.size(), (int)gso_cache.size(), max_sendmmsg); nn_msgs_last = nn_msgs; time_last = srs_get_system_time(); nn_loop = nn_wait = nn_msgs_max = 0; + nn_gso_msgs_max = 0; nn_gso_iovs_max = 0; } } @@ -1832,10 +1944,21 @@ srs_error_t SrsUdpMuxSender::cycle() srs_error_t SrsUdpMuxSender::on_reload_rtc_server() { - int v = _srs_config->get_rtc_server_sendmmsg(); - if (max_sendmmsg != v) { - srs_trace("Reload max_sendmmsg %d=>%d", max_sendmmsg, v); - max_sendmmsg = v; + if (true) { + int v = _srs_config->get_rtc_server_sendmmsg(); + if (max_sendmmsg != v) { + srs_trace("Reload max_sendmmsg %d=>%d", max_sendmmsg, v); + max_sendmmsg = v; + } + } + + if (true) { + bool gso = _srs_config->get_rtc_server_gso(); + bool v = _srs_config->get_rtc_server_gso_dedicated(); + if (gso_dedicated != v) { + srs_trace("Reload gso=%d, gso-dedicated %d=>%d", gso, gso_dedicated, v); + gso_dedicated = v; + } } return srs_success; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 748374290..263420cd7 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -273,6 +273,15 @@ private: int cache_pos; // The max number of messages for sendmmsg. If 1, we use sendmsg to send. int max_sendmmsg; + // Whether GSO shares the same mmsghdr cache. + // If not shared, use dedicated cache for GSO. + bool gso_dedicated; +private: + // For Linux kernel 3.*, we must use isolate queue for GSO, + // that is, sendmmsg does not work with GSO. + std::vector gso_hotspot; + std::vector gso_cache; + int gso_cache_pos; public: SrsUdpMuxSender(SrsRtcServer* s); virtual ~SrsUdpMuxSender(); @@ -282,6 +291,7 @@ private: void free_mhdrs(std::vector& mhdrs); public: virtual srs_error_t fetch(mmsghdr** pphdr); + virtual srs_error_t gso_fetch(mmsghdr** pphdr); virtual srs_error_t sendmmsg(mmsghdr* hdr); virtual srs_error_t cycle(); // interface ISrsReloadHandler diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index be3874ff7..2e33b7cb6 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -267,6 +267,7 @@ SrsStatistic::SrsStatistic() perf_msgs = new SrsStatisticCategory(); perf_sys = new SrsStatisticCategory(); perf_sendmmsg = new SrsStatisticCategory(); + perf_gso = new SrsStatisticCategory(); } SrsStatistic::~SrsStatistic() @@ -305,6 +306,7 @@ SrsStatistic::~SrsStatistic() srs_freep(perf_msgs); srs_freep(perf_sys); srs_freep(perf_sendmmsg); + srs_freep(perf_gso); } SrsStatistic* SrsStatistic::instance() @@ -738,7 +740,7 @@ srs_error_t SrsStatistic::dumps_perf_writev(SrsJsonObject* obj) return err; } -void SrsStatistic::perf_mw_on_packets(int nb_msgs) +void SrsStatistic::perf_sendmmsg_on_packets(int nb_msgs) { // For perf msgs, the nb_msgs stat. // a: =1 @@ -808,6 +810,76 @@ srs_error_t SrsStatistic::dumps_perf_sendmmsg(SrsJsonObject* obj) return err; } +void SrsStatistic::perf_gso_on_packets(int nb_msgs) +{ + // For perf msgs, the nb_msgs stat. + // a: =1 + // b: <3 + // c: <6 + // d: <9 + // e: <16 + // f: <32 + // g: <64 + // h: <128 + // i: <512 + // j: >=512 + if (nb_msgs == 1) { + perf_gso->a++; + } else if (nb_msgs < 3) { + perf_gso->b++; + } else if (nb_msgs < 6) { + perf_gso->c++; + } else if (nb_msgs < 9) { + perf_gso->d++; + } else if (nb_msgs < 16) { + perf_gso->e++; + } else if (nb_msgs < 32) { + perf_gso->f++; + } else if (nb_msgs < 64) { + perf_gso->g++; + } else if (nb_msgs < 128) { + perf_gso->h++; + } else if (nb_msgs < 512) { + perf_gso->i++; + } else { + perf_gso->j++; + } +} + +srs_error_t SrsStatistic::dumps_perf_gso(SrsJsonObject* obj) +{ + srs_error_t err = srs_success; + + if (true) { + SrsJsonObject* p = SrsJsonAny::object(); + obj->set("msgs", p); + + // For perf msgs, the nb_msgs stat. + // a: =1 + // b: <3 + // c: <6 + // d: <9 + // e: <16 + // f: <32 + // g: <64 + // h: <128 + // i: <512 + // j: >=512 + p->set("lt_2", SrsJsonAny::integer(perf_gso->a)); + p->set("lt_3", SrsJsonAny::integer(perf_gso->b)); + p->set("lt_6", SrsJsonAny::integer(perf_gso->c)); + p->set("lt_9", SrsJsonAny::integer(perf_gso->d)); + p->set("lt_16", SrsJsonAny::integer(perf_gso->e)); + p->set("lt_32", SrsJsonAny::integer(perf_gso->f)); + p->set("lt_64", SrsJsonAny::integer(perf_gso->g)); + p->set("lt_128", SrsJsonAny::integer(perf_gso->h)); + p->set("lt_512", SrsJsonAny::integer(perf_gso->i)); + p->set("gt_512", SrsJsonAny::integer(perf_gso->j)); + } + + return err; +} + SrsStatisticVhost* SrsStatistic::create_vhost(SrsRequest* req) { SrsStatisticVhost* vhost = NULL; diff --git a/trunk/src/app/srs_app_statistic.hpp b/trunk/src/app/srs_app_statistic.hpp index 339e95b26..553bc9650 100644 --- a/trunk/src/app/srs_app_statistic.hpp +++ b/trunk/src/app/srs_app_statistic.hpp @@ -170,6 +170,7 @@ private: SrsStatisticCategory* perf_msgs; SrsStatisticCategory* perf_sys; SrsStatisticCategory* perf_sendmmsg; + SrsStatisticCategory* perf_gso; private: SrsStatistic(); virtual ~SrsStatistic(); @@ -238,9 +239,14 @@ public: virtual srs_error_t dumps_perf_writev(SrsJsonObject* obj); public: // Stat for packets UDP sendmmsg, nb_msgs is the vlen for sendmmsg. - virtual void perf_mw_on_packets(int nb_msgs); + virtual void perf_sendmmsg_on_packets(int nb_msgs); // Dumps the perf statistic data for UDP sendmmsg, for performance analysis. virtual srs_error_t dumps_perf_sendmmsg(SrsJsonObject* obj); +public: + // Stat for packets UDP GSO, nb_msgs is the vlen for sendmmsg. + virtual void perf_gso_on_packets(int nb_msgs); + // Dumps the perf statistic data for UDP GSO, for performance analysis. + virtual srs_error_t dumps_perf_gso(SrsJsonObject* obj); private: virtual SrsStatisticVhost* create_vhost(SrsRequest* req); virtual SrsStatisticStream* create_stream(SrsStatisticVhost* vhost, SrsRequest* req); From 23c68a922c7f0d6cd974e87fe1447720d9770ef6 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 10:05:55 +0800 Subject: [PATCH 10/35] Refine GSO for RTC --- trunk/src/app/srs_app_rtc_conn.cpp | 94 ++++++++++++++++-------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index cdf02d68c..2d3726043 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -947,7 +947,21 @@ srs_error_t SrsRtcSenderThread::send_packets2(SrsUdpMuxSocket* skt, SrsRtcPacket } // For last message, or final gso, or determined not using GSO, send it now. - if (i == nn_packets - 1 || gso_final || !use_gso) { + bool do_send = (i == nn_packets - 1 || gso_final || !use_gso); + +#if defined(SRS_DEBUG) + srs_trace("packet SSRC=%d, SN=%d, %d bytes", packet->rtp_header.get_ssrc(), + packet->rtp_header.get_sequence(), nn_packet); + if (do_send) { + for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { + iovec* iov = mhdr->msg_hdr.msg_iov + j; + srs_trace("%s #%d/%d/%d, %d bytes, size %d/%d", (use_gso? "GSO":"RAW"), j, gso_cursor + 1, + mhdr->msg_hdr.msg_iovlen, iov->iov_len, gso_size, gso_encrypt); + } + } +#endif + + if (do_send) { sockaddr_in* addr = (sockaddr_in*)skt->peer_addr(); socklen_t addrlen = (socklen_t)skt->peer_addrlen(); @@ -978,15 +992,6 @@ srs_error_t SrsRtcSenderThread::send_packets2(SrsUdpMuxSocket* skt, SrsRtcPacket return srs_error_wrap(err, "send msghdr"); } -#ifdef SRS_DEBUG - srs_warn("packet SN=%d %d bytes", nn_packet, packet->rtp_header.get_sequence()); - for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { - iovec* iov = mhdr->msg_hdr.msg_iov + j; - srs_warn("%s #%d/%d/%d, %d bytes, size %d/%d", (use_gso? "GSO":"RAW"), j, gso_cursor + 1, - mhdr->msg_hdr.msg_iovlen, iov->iov_len, gso_size, gso_encrypt); - } -#endif - // Reset the GSO flag. gso_mhdr = NULL; gso_size = 0; gso_encrypt = 0; gso_cursor = 0; use_gso = gso_final = false; @@ -1847,6 +1852,41 @@ srs_error_t SrsUdpMuxSender::cycle() gso_cache_pos = 0; } + // Collect informations for GSO + if (!gso_dedicated && pos > 0) { + // For shared GSO cache, stat the messages. + mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; + for (p = &hotspot[0]; p < end; p++) { + if (!p->msg_len) { + continue; + } + + // Private message, use it to store the cursor. + int real_iovs = p->msg_len; + p->msg_len = 0; + + gso_pos++; nn_gso_msgs++; nn_gso_iovs += real_iovs; gso_iovs += real_iovs; + stat->perf_gso_on_packets(real_iovs); + } + } + + // Send out all messages, may GSO if shared cache. + if (false && pos > 0) { + // Send out all messages. + mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; + for (p = &hotspot[0]; p < end; p += max_sendmmsg) { + int vlen = (int)(end - p); + vlen = srs_min(max_sendmmsg, vlen); + + int r0 = srs_sendmmsg(lfd, p, (unsigned int)vlen, 0, SRS_UTIME_NO_TIMEOUT); + if (r0 != vlen) { + srs_warn("sendmmsg %d msgs, %d done", vlen, r0); + } + + stat->perf_sendmmsg_on_packets(vlen); + } + } + // Send out GSO in dedicated queue. if (gso_dedicated && gso_pos > 0) { mmsghdr* p = &gso_hotspot[0]; mmsghdr* end = p + gso_pos; @@ -1866,40 +1906,6 @@ srs_error_t SrsUdpMuxSender::cycle() } } - // Send out all messages, may GSO if shared cache. - if (pos > 0) { - mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; - - // For shared GSO cache, stat the messages. - if (!gso_dedicated) { - for (p = &hotspot[0]; p < end; p++) { - if (!p->msg_len) { - continue; - } - - // Private message, use it to store the cursor. - int real_iovs = p->msg_len; - p->msg_len = 0; - - gso_pos++; nn_gso_msgs++; nn_gso_iovs += real_iovs; gso_iovs += real_iovs; - stat->perf_gso_on_packets(real_iovs); - } - } - - // Send out all messages. - for (p = &hotspot[0]; p < end; p += max_sendmmsg) { - int vlen = (int)(end - p); - vlen = srs_min(max_sendmmsg, vlen); - - int r0 = srs_sendmmsg(lfd, p, (unsigned int)vlen, 0, SRS_UTIME_NO_TIMEOUT); - if (r0 != vlen) { - srs_warn("sendmmsg %d msgs, %d done", vlen, r0); - } - - stat->perf_sendmmsg_on_packets(vlen); - } - } - // Increase total messages. int nn_pos = pos; if (gso_dedicated) { From feaf98eb69bcdc99ab0bd102582cb0cd2520956d Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 10:58:53 +0800 Subject: [PATCH 11/35] For #307, remove dedicate GSO cache --- trunk/conf/full.conf | 6 +- trunk/src/app/srs_app_config.cpp | 28 +------- trunk/src/app/srs_app_config.hpp | 1 - trunk/src/app/srs_app_listener.hpp | 4 -- trunk/src/app/srs_app_rtc_conn.cpp | 100 ++++------------------------- trunk/src/app/srs_app_rtc_conn.hpp | 10 --- 6 files changed, 13 insertions(+), 136 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 45156da17..2e40a387e 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -440,13 +440,9 @@ rtc_server { # default: on merge_nalus on; # Whether enable GSO to send out RTP packets. - # @remark Linux only, for other OS always disabled. + # @remark Linux 4.18+ only, for other OS always disabled. # default: off gso off; - # Whether GSO uses dedicated cache. Share the same mmsghdr cache if not dedicated. - # For Linux 3.*, we must use dedicated cache for GSO. - # default: off - gso_dedicated off; } vhost rtc.vhost.srs.com { diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 9693a17fa..f7f69a381 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3614,8 +3614,7 @@ srs_error_t SrsConfig::check_normal_config() for (int i = 0; conf && i < (int)conf->directives.size(); i++) { string n = conf->at(i)->name; if (n != "enabled" && n != "listen" && n != "dir" && n != "candidate" && n != "ecdsa" - && n != "sendmmsg" && n != "encrypt" && n != "reuseport" && n != "gso" && n != "merge_nalus" - && n != "gso_dedicated") { + && n != "sendmmsg" && n != "encrypt" && n != "reuseport" && n != "gso" && n != "merge_nalus") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal rtc_server.%s", n.c_str()); } } @@ -4815,31 +4814,6 @@ bool SrsConfig::get_rtc_server_gso() return v; } -bool SrsConfig::get_rtc_server_gso_dedicated() -{ - static int DEFAULT = false; - - SrsConfDirective* conf = root->get("rtc_server"); - if (!conf) { - return DEFAULT; - } - - conf = conf->get("gso_dedicated"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - bool v = SRS_CONF_PERFER_FALSE(conf->arg0()); - -#ifdef SRS_AUTO_OSX - if (v != DEFAULT) { - srs_warn("GSO is for Linux only"); - } -#endif - - return v; -} - SrsConfDirective* SrsConfig::get_rtc(string vhost) { SrsConfDirective* conf = get_vhost(vhost); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index bfc6f373f..8093a50a4 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -530,7 +530,6 @@ public: virtual int get_rtc_server_reuseport(); virtual bool get_rtc_server_merge_nalus(); virtual bool get_rtc_server_gso(); - virtual bool get_rtc_server_gso_dedicated(); SrsConfDirective* get_rtc(std::string vhost); bool get_rtc_enabled(std::string vhost); diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp index ec503cf6b..8ef384dd9 100644 --- a/trunk/src/app/srs_app_listener.hpp +++ b/trunk/src/app/srs_app_listener.hpp @@ -139,10 +139,6 @@ public: public: // Fetch a mmsghdr from sender's cache. virtual srs_error_t fetch(mmsghdr** pphdr) = 0; - // For Linux kernel 3.*, we must use isolate APIs for GSO, - // that is, sendmmsg does not work with GSO. - // Fetch a mmsghdr from sender's cache. - virtual srs_error_t gso_fetch(mmsghdr** pphdr) = 0; // Notify the sender to send out the msg. virtual srs_error_t sendmmsg(mmsghdr* hdr) = 0; }; diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 2d3726043..773ac594c 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -813,6 +813,7 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets mhdr->msg_hdr.msg_name = (sockaddr_in*)addr; mhdr->msg_hdr.msg_namelen = (socklen_t)addrlen; mhdr->msg_hdr.msg_iov->iov_len = length; + mhdr->msg_hdr.msg_controllen = 0; mhdr->msg_len = 0; if ((err = sender->sendmmsg(mhdr)) != srs_success) { @@ -889,12 +890,7 @@ srs_error_t SrsRtcSenderThread::send_packets2(SrsUdpMuxSocket* skt, SrsRtcPacket if (!mhdr) { // Fetch a cached message from queue. // TODO: FIXME: Maybe encrypt in async, so the state of mhdr maybe not ready. - if (use_gso) { - err = sender->gso_fetch(&mhdr); - } else { - err = sender->fetch(&mhdr); - } - if (err != srs_success) { + if ((err = sender->fetch(&mhdr)) != srs_success) { return srs_error_wrap(err, "fetch msghdr"); } @@ -1689,7 +1685,6 @@ SrsUdpMuxSender::SrsUdpMuxSender(SrsRtcServer* s) trd = new SrsDummyCoroutine(); cache_pos = 0; - gso_cache_pos = 0; _srs_config->subscribe(this); } @@ -1706,12 +1701,6 @@ SrsUdpMuxSender::~SrsUdpMuxSender() free_mhdrs(cache); cache.clear(); - - free_mhdrs(gso_hotspot); - gso_hotspot.clear(); - - free_mhdrs(gso_cache); - gso_cache.clear(); } srs_error_t SrsUdpMuxSender::initialize(srs_netfd_t fd) @@ -1728,9 +1717,7 @@ srs_error_t SrsUdpMuxSender::initialize(srs_netfd_t fd) max_sendmmsg = _srs_config->get_rtc_server_sendmmsg(); bool gso = _srs_config->get_rtc_server_gso(); - gso_dedicated = _srs_config->get_rtc_server_gso_dedicated(); - srs_trace("UDP sender #%d init ok, max_sendmmsg=%d, gso=%d, gso-dedicated=%d", - srs_netfd_fileno(fd), max_sendmmsg, gso, gso_dedicated); + srs_trace("UDP sender #%d init ok, max_sendmmsg=%d, gso=%d", srs_netfd_fileno(fd), max_sendmmsg, gso); return err; } @@ -1775,34 +1762,6 @@ srs_error_t SrsUdpMuxSender::fetch(mmsghdr** pphdr) return srs_success; } -srs_error_t SrsUdpMuxSender::gso_fetch(mmsghdr** pphdr) -{ - // When GSO share cache, we use the same cache with non-GSO. - if (!gso_dedicated) { - return fetch(pphdr); - } - - // TODO: FIXME: Maybe need to shrink? - if (gso_cache_pos >= (int)gso_cache.size()) { - mmsghdr mhdr; - memset(&mhdr, 0, sizeof(mmsghdr)); - - mhdr.msg_hdr.msg_iovlen = 1; - mhdr.msg_hdr.msg_iov = new iovec(); - mhdr.msg_hdr.msg_iov->iov_base = new char[kRtpPacketSize]; - mhdr.msg_hdr.msg_iov->iov_len = kRtpPacketSize; - mhdr.msg_len = 0; - - mhdr.msg_hdr.msg_controllen = CMSG_SPACE(sizeof(uint16_t)); - mhdr.msg_hdr.msg_control = new char[mhdr.msg_hdr.msg_controllen]; - - gso_cache.push_back(mhdr); - } - - *pphdr = &gso_cache[gso_cache_pos++]; - return srs_success; -} - srs_error_t SrsUdpMuxSender::sendmmsg(mmsghdr* hdr) { if (waiting_msgs) { @@ -1834,7 +1793,7 @@ srs_error_t SrsUdpMuxSender::cycle() nn_loop++; int pos = cache_pos; - int gso_pos = gso_cache_pos; + int gso_pos = 0; int gso_iovs = 0; if (pos <= 0 && gso_pos == 0) { waiting_msgs = true; @@ -1847,13 +1806,8 @@ srs_error_t SrsUdpMuxSender::cycle() cache.swap(hotspot); cache_pos = 0; - if (gso_dedicated) { - gso_cache.swap(gso_hotspot); - gso_cache_pos = 0; - } - // Collect informations for GSO - if (!gso_dedicated && pos > 0) { + if (pos > 0) { // For shared GSO cache, stat the messages. mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; for (p = &hotspot[0]; p < end; p++) { @@ -1871,7 +1825,7 @@ srs_error_t SrsUdpMuxSender::cycle() } // Send out all messages, may GSO if shared cache. - if (false && pos > 0) { + if (pos > 0) { // Send out all messages. mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; for (p = &hotspot[0]; p < end; p += max_sendmmsg) { @@ -1887,32 +1841,9 @@ srs_error_t SrsUdpMuxSender::cycle() } } - // Send out GSO in dedicated queue. - if (gso_dedicated && gso_pos > 0) { - mmsghdr* p = &gso_hotspot[0]; mmsghdr* end = p + gso_pos; - for (; p < end; p++) { - // Private message, use it to store the cursor. - int real_iovs = p->msg_len; - p->msg_len = 0; - - // Send out GSO message. - int r0 = srs_sendmsg(lfd, &p->msg_hdr, 0, SRS_UTIME_NO_TIMEOUT); - if (r0 < 0) { - srs_warn("sendmsg err, r0=%d", r0); - } - - nn_gso_msgs++; nn_gso_iovs += real_iovs; gso_iovs += real_iovs; - stat->perf_gso_on_packets(real_iovs); - } - } - // Increase total messages. - int nn_pos = pos; - if (gso_dedicated) { - nn_pos = pos + gso_pos; - } - nn_msgs += nn_pos; - nn_msgs_max = srs_max(nn_pos, nn_msgs_max); + nn_msgs += pos; + nn_msgs_max = srs_max(pos, nn_msgs_max); nn_gso_msgs_max = srs_max(gso_pos, nn_gso_msgs_max); nn_gso_iovs_max = srs_max(gso_iovs, nn_gso_iovs_max); @@ -1936,9 +1867,9 @@ srs_error_t SrsUdpMuxSender::cycle() pps_unit = "(k)"; pps_last /= 1000; pps_average /= 1000; } - srs_trace("-> RTC #%d SEND %d/%d/%" PRId64 ", gso %d/%d/%" PRId64 ", gso-iovs %d/%d/%" PRId64 ", pps %d/%d%s, schedule %d/%d, sessions %d, cache %d/%d, sendmmsg %d", - srs_netfd_fileno(lfd), nn_pos, nn_msgs_max, nn_msgs, gso_pos, nn_gso_msgs_max, nn_gso_msgs, gso_iovs, nn_gso_iovs_max, nn_gso_iovs, pps_average, pps_last, pps_unit.c_str(), - nn_loop, nn_wait, (int)server->nn_sessions(), (int)cache.size(), (int)gso_cache.size(), max_sendmmsg); + srs_trace("-> RTC #%d SEND %d/%d/%" PRId64 ", gso %d/%d/%" PRId64 ", gso-iovs %d/%d/%" PRId64 ", pps %d/%d%s, schedule %d/%d, sessions %d, cache %d, sendmmsg %d", + srs_netfd_fileno(lfd), pos, nn_msgs_max, nn_msgs, gso_pos, nn_gso_msgs_max, nn_gso_msgs, gso_iovs, nn_gso_iovs_max, nn_gso_iovs, pps_average, pps_last, pps_unit.c_str(), + nn_loop, nn_wait, (int)server->nn_sessions(), (int)cache.size(), max_sendmmsg); nn_msgs_last = nn_msgs; time_last = srs_get_system_time(); nn_loop = nn_wait = nn_msgs_max = 0; nn_gso_msgs_max = 0; nn_gso_iovs_max = 0; @@ -1958,15 +1889,6 @@ srs_error_t SrsUdpMuxSender::on_reload_rtc_server() } } - if (true) { - bool gso = _srs_config->get_rtc_server_gso(); - bool v = _srs_config->get_rtc_server_gso_dedicated(); - if (gso_dedicated != v) { - srs_trace("Reload gso=%d, gso-dedicated %d=>%d", gso, gso_dedicated, v); - gso_dedicated = v; - } - } - return srs_success; } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 263420cd7..748374290 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -273,15 +273,6 @@ private: int cache_pos; // The max number of messages for sendmmsg. If 1, we use sendmsg to send. int max_sendmmsg; - // Whether GSO shares the same mmsghdr cache. - // If not shared, use dedicated cache for GSO. - bool gso_dedicated; -private: - // For Linux kernel 3.*, we must use isolate queue for GSO, - // that is, sendmmsg does not work with GSO. - std::vector gso_hotspot; - std::vector gso_cache; - int gso_cache_pos; public: SrsUdpMuxSender(SrsRtcServer* s); virtual ~SrsUdpMuxSender(); @@ -291,7 +282,6 @@ private: void free_mhdrs(std::vector& mhdrs); public: virtual srs_error_t fetch(mmsghdr** pphdr); - virtual srs_error_t gso_fetch(mmsghdr** pphdr); virtual srs_error_t sendmmsg(mmsghdr* hdr); virtual srs_error_t cycle(); // interface ISrsReloadHandler From 2cd580f50061971e9ac22ecdd76c89f313fe80d0 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 11:26:45 +0800 Subject: [PATCH 12/35] For #307, disable GSO < linux 4.18.0 --- trunk/src/app/srs_app_config.cpp | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index f7f69a381..39ef44a76 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -33,6 +33,10 @@ #include #include #include +#ifdef __linux__ +#include +#include +#endif #include #include @@ -4805,12 +4809,25 @@ bool SrsConfig::get_rtc_server_gso() bool v = SRS_CONF_PERFER_FALSE(conf->arg0()); -#ifdef SRS_AUTO_OSX - if (v) { - srs_warn("GSO is for Linux only"); - } - v = false; + bool gso_disabled = false; +#if !defined(__linux__) + gso_disabled = true; + srs_warn("GSO is for Linux 4.18+ only"); +#else + #if LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0) + utsname un = {0}; + int r0 = uname(&un); + if (r0 || strcmp(un.release, "4.18.0") < 0) { + gso_disabled = true; + } + srs_warn("GSO is for Linux 4.18+ only, r0=%d, %s", r0, un.release); + #endif #endif + + if (v && gso_disabled) { + v = false; + } + return v; } From 8ba3d78e868d6cc16922ac09a2f8c37278685a0b Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 11:30:21 +0800 Subject: [PATCH 13/35] Refine logs for GSO --- trunk/src/app/srs_app_config.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 39ef44a76..f50ab799e 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -4812,7 +4812,7 @@ bool SrsConfig::get_rtc_server_gso() bool gso_disabled = false; #if !defined(__linux__) gso_disabled = true; - srs_warn("GSO is for Linux 4.18+ only"); + srs_warn("GSO is disabled, for Linux 4.18+ only"); #else #if LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0) utsname un = {0}; @@ -4820,7 +4820,7 @@ bool SrsConfig::get_rtc_server_gso() if (r0 || strcmp(un.release, "4.18.0") < 0) { gso_disabled = true; } - srs_warn("GSO is for Linux 4.18+ only, r0=%d, %s", r0, un.release); + srs_warn("GSO is disabled, for Linux 4.18+ only, r0=%d, kernel=%s", r0, un.release); #endif #endif From 24eb61156f6fd42329e42493f735041f520bb801 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 11:39:22 +0800 Subject: [PATCH 14/35] Refine logs for GSO --- trunk/src/app/srs_app_config.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index f50ab799e..d5b0022c3 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -4812,16 +4812,18 @@ bool SrsConfig::get_rtc_server_gso() bool gso_disabled = false; #if !defined(__linux__) gso_disabled = true; - srs_warn("GSO is disabled, for Linux 4.18+ only"); -#else - #if LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0) + if (v) { + srs_warn("GSO is disabled, for Linux 4.18+ only"); + } +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0) + if (v) { utsname un = {0}; int r0 = uname(&un); if (r0 || strcmp(un.release, "4.18.0") < 0) { gso_disabled = true; + srs_warn("GSO is disabled, for Linux 4.18+ only, r0=%d, kernel=%s", r0, un.release); } - srs_warn("GSO is disabled, for Linux 4.18+ only, r0=%d, kernel=%s", r0, un.release); - #endif + } #endif if (v && gso_disabled) { From b6a929f9cfb9096bfbca5207a50b4fbb2079708d Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 11:41:23 +0800 Subject: [PATCH 15/35] Enable GSO by default --- trunk/conf/full.conf | 4 ++-- trunk/src/app/srs_app_config.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 2e40a387e..581e4daa3 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -441,8 +441,8 @@ rtc_server { merge_nalus on; # Whether enable GSO to send out RTP packets. # @remark Linux 4.18+ only, for other OS always disabled. - # default: off - gso off; + # default: on + gso on; } vhost rtc.vhost.srs.com { diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index d5b0022c3..3d44d63f5 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -4795,7 +4795,7 @@ bool SrsConfig::get_rtc_server_merge_nalus() bool SrsConfig::get_rtc_server_gso() { - static int DEFAULT = false; + static int DEFAULT = true; SrsConfDirective* conf = root->get("rtc_server"); if (!conf) { @@ -4807,7 +4807,7 @@ bool SrsConfig::get_rtc_server_gso() return DEFAULT; } - bool v = SRS_CONF_PERFER_FALSE(conf->arg0()); + bool v = SRS_CONF_PERFER_TRUE(conf->arg0()); bool gso_disabled = false; #if !defined(__linux__) From 39853160d1b30f1191e1b3f0806d07d950180eae Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 11:49:59 +0800 Subject: [PATCH 16/35] Refactor default config --- trunk/src/app/srs_app_config.cpp | 55 ++++++++++++++++++-------------- trunk/src/app/srs_app_config.hpp | 7 +++- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 3d44d63f5..956bc99b0 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -4751,12 +4751,20 @@ int SrsConfig::get_rtc_server_sendmmsg() int SrsConfig::get_rtc_server_reuseport() { -#if defined(SO_REUSEPORT) - static int DEFAULT = 4; -#else - static int DEFAULT = 1; + int v = get_rtc_server_reuseport2(); + +#if !defined(SO_REUSEPORT) + srs_warn("REUSEPORT not supported, reset %d to %d", reuseport, DEFAULT); + v = 1 #endif + return v; +} + +int SrsConfig::get_rtc_server_reuseport2() +{ + static int DEFAULT = 4; + SrsConfDirective* conf = root->get("rtc_server"); if (!conf) { return DEFAULT; @@ -4767,13 +4775,7 @@ int SrsConfig::get_rtc_server_reuseport() return DEFAULT; } - int reuseport = ::atoi(conf->arg0().c_str()); -#if !defined(SO_REUSEPORT) - srs_warn("REUSEPORT not supported, reset %d to %d", reuseport, DEFAULT); - reuseport = DEFAULT -#endif - - return reuseport; + return ::atoi(conf->arg0().c_str()); } bool SrsConfig::get_rtc_server_merge_nalus() @@ -4795,19 +4797,7 @@ bool SrsConfig::get_rtc_server_merge_nalus() bool SrsConfig::get_rtc_server_gso() { - static int DEFAULT = true; - - SrsConfDirective* conf = root->get("rtc_server"); - if (!conf) { - return DEFAULT; - } - - conf = conf->get("gso"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - bool v = SRS_CONF_PERFER_TRUE(conf->arg0()); + bool v = get_rtc_server_gso2(); bool gso_disabled = false; #if !defined(__linux__) @@ -4833,6 +4823,23 @@ bool SrsConfig::get_rtc_server_gso() return v; } +bool SrsConfig::get_rtc_server_gso2() +{ + static int DEFAULT = true; + + SrsConfDirective* conf = root->get("rtc_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("gso"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_TRUE(conf->arg0()); +} + SrsConfDirective* SrsConfig::get_rtc(string vhost) { SrsConfDirective* conf = get_vhost(vhost); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 8093a50a4..96524c33a 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -528,9 +528,14 @@ public: virtual int get_rtc_server_sendmmsg(); virtual bool get_rtc_server_encrypt(); virtual int get_rtc_server_reuseport(); +private: + virtual int get_rtc_server_reuseport2(); +public: virtual bool get_rtc_server_merge_nalus(); virtual bool get_rtc_server_gso(); - +private: + virtual bool get_rtc_server_gso2(); +public: SrsConfDirective* get_rtc(std::string vhost); bool get_rtc_enabled(std::string vhost); bool get_rtc_bframe_discard(std::string vhost); From 5b406d68d699ddd5488be45254dc16dcd8741f17 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 13:34:24 +0800 Subject: [PATCH 17/35] Refine pithy print --- trunk/src/app/srs_app_listener.cpp | 2 +- trunk/src/app/srs_app_rtc_conn.cpp | 10 +++++----- trunk/src/app/srs_app_rtc_conn.hpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/trunk/src/app/srs_app_listener.cpp b/trunk/src/app/srs_app_listener.cpp index 2117983be..3294c79f5 100755 --- a/trunk/src/app/srs_app_listener.cpp +++ b/trunk/src/app/srs_app_listener.cpp @@ -499,7 +499,7 @@ srs_error_t SrsUdpMuxListener::cycle() pps_unit = "(k)"; pps_last /= 10000; pps_average /= 10000; } - srs_trace("<- RTC #%d RECV %" PRId64 ", pps %d/%d%s, schedule %" PRId64, + srs_trace("<- RTC RECV #%d, udp %" PRId64 ", pps %d/%d%s, schedule %" PRId64, srs_netfd_fileno(lfd), nn_msgs_stage, pps_average, pps_last, pps_unit.c_str(), nn_loop); nn_msgs_last = nn_msgs; time_last = srs_get_system_time(); nn_loop = 0; nn_msgs_stage = 0; diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 773ac594c..863bdb95d 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -675,7 +675,7 @@ srs_error_t SrsRtcSenderThread::send_messages( #ifndef SRS_AUTO_OSX // If enabled GSO, send out some packets in a msghdr. if (packets.use_gso) { - if ((err = send_packets2(skt, packets)) != srs_success) { + if ((err = send_packets_gso(skt, packets)) != srs_success) { return srs_error_wrap(err, "gso send"); } return err; @@ -825,7 +825,7 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets } // TODO: FIXME: We can gather and pad audios, because they have similar size. -srs_error_t SrsRtcSenderThread::send_packets2(SrsUdpMuxSocket* skt, SrsRtcPackets& packets) +srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPackets& packets) { srs_error_t err = srs_success; @@ -1867,9 +1867,9 @@ srs_error_t SrsUdpMuxSender::cycle() pps_unit = "(k)"; pps_last /= 1000; pps_average /= 1000; } - srs_trace("-> RTC #%d SEND %d/%d/%" PRId64 ", gso %d/%d/%" PRId64 ", gso-iovs %d/%d/%" PRId64 ", pps %d/%d%s, schedule %d/%d, sessions %d, cache %d, sendmmsg %d", - srs_netfd_fileno(lfd), pos, nn_msgs_max, nn_msgs, gso_pos, nn_gso_msgs_max, nn_gso_msgs, gso_iovs, nn_gso_iovs_max, nn_gso_iovs, pps_average, pps_last, pps_unit.c_str(), - nn_loop, nn_wait, (int)server->nn_sessions(), (int)cache.size(), max_sendmmsg); + srs_trace("-> RTC SEND #%d, sessions %d, udp %d/%d/%" PRId64 ", gso %d/%d/%" PRId64 ", iovs %d/%d/%" PRId64 ", pps %d/%d%s", + srs_netfd_fileno(lfd), (int)server->nn_sessions(), pos, nn_msgs_max, nn_msgs, gso_pos, nn_gso_msgs_max, nn_gso_msgs, gso_iovs, nn_gso_iovs_max, nn_gso_iovs, + pps_average, pps_last, pps_unit.c_str()); nn_msgs_last = nn_msgs; time_last = srs_get_system_time(); nn_loop = nn_wait = nn_msgs_max = 0; nn_gso_msgs_max = 0; nn_gso_iovs_max = 0; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 748374290..89c46e916 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -179,7 +179,7 @@ private: srs_error_t send_messages(SrsUdpMuxSocket* skt, SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets); srs_error_t messages_to_packets(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets); srs_error_t send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets& packets); - srs_error_t send_packets2(SrsUdpMuxSocket* skt, SrsRtcPackets& packets); + srs_error_t send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPackets& packets); private: srs_error_t packet_opus(SrsSample* sample, SrsRtpPacket2** ppacket); private: From 03a03e41748d7495d01ca1286626ab7b97b5856c Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 13:47:23 +0800 Subject: [PATCH 18/35] Refine stat for GSO --- trunk/src/app/srs_app_http_api.cpp | 6 +-- trunk/src/app/srs_app_rtc_conn.cpp | 4 ++ trunk/src/app/srs_app_statistic.cpp | 73 +++++++++------------------ trunk/src/app/srs_app_statistic.hpp | 4 -- trunk/src/protocol/srs_rtmp_stack.cpp | 5 -- trunk/src/protocol/srs_rtmp_stack.hpp | 3 -- 6 files changed, 31 insertions(+), 64 deletions(-) diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 6d7df56fa..fd4e9b2bb 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1622,7 +1622,7 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* data->set("query", p); p->set("target", SrsJsonAny::str(target.c_str())); - p->set("help", SrsJsonAny::str("?target=writev|sendmmsg|gso|udp")); + p->set("help", SrsJsonAny::str("?target=writev|sendmmsg|gso")); } if (target.empty() || target == "writev") { @@ -1634,7 +1634,7 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* } } - if (target.empty() || target == "sendmmsg" || target == "udp") { + if (target.empty() || target == "sendmmsg") { SrsJsonObject* p = SrsJsonAny::object(); data->set("sendmmsg", p); if ((err = stat->dumps_perf_sendmmsg(p)) != srs_success) { @@ -1643,7 +1643,7 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* } } - if (target.empty() || target == "gso" || target == "udp") { + if (target.empty() || target == "gso") { SrsJsonObject* p = SrsJsonAny::object(); data->set("gso", p); if ((err = stat->dumps_perf_gso(p)) != srs_success) { diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 863bdb95d..f70cf279d 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -609,6 +609,8 @@ srs_error_t SrsRtcSenderThread::cycle() SrsPithyPrint* pprint = SrsPithyPrint::create_rtc_play(); SrsAutoFree(SrsPithyPrint, pprint); + SrsStatistic* stat = SrsStatistic::instance(); + while (true) { if ((err = trd->pull()) != srs_success) { return srs_error_wrap(err, "rtc sender thread"); @@ -647,6 +649,8 @@ srs_error_t SrsRtcSenderThread::cycle() srs_freep(msg); } + stat->perf_mw_on_msgs(msg_count, pkts.nn_bytes, pkts.nn_rtp_pkts); + pprint->elapse(); if (pprint->can_print()) { // TODO: FIXME: Print stat like frame/s, packet/s, loss_packets. diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index 2e33b7cb6..228fa8344 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -265,7 +265,6 @@ SrsStatistic::SrsStatistic() perf_iovs = new SrsStatisticCategory(); perf_msgs = new SrsStatisticCategory(); - perf_sys = new SrsStatisticCategory(); perf_sendmmsg = new SrsStatisticCategory(); perf_gso = new SrsStatisticCategory(); } @@ -304,7 +303,6 @@ SrsStatistic::~SrsStatistic() srs_freep(perf_iovs); srs_freep(perf_msgs); - srs_freep(perf_sys); srs_freep(perf_sendmmsg); srs_freep(perf_gso); } @@ -591,28 +589,28 @@ void SrsStatistic::perf_mw_on_msgs(int nb_msgs, int bytes_msgs, int nb_iovs) { // For perf msgs, the nb_msgs stat. // a: =1 - // b: <10 - // c: <100 - // d: <200 - // e: <300 - // f: <400 - // g: <500 + // b: <3 + // c: <6 + // d: <12 + // e: <128 + // f: <256 + // g: <512 // h: <600 // i: <1000 // j: >=1000 if (nb_msgs == 1) { perf_msgs->a++; - } else if (nb_msgs < 10) { + } else if (nb_msgs < 3) { perf_msgs->b++; - } else if (nb_msgs < 100) { + } else if (nb_msgs < 6) { perf_msgs->c++; - } else if (nb_msgs < 200) { + } else if (nb_msgs < 12) { perf_msgs->d++; - } else if (nb_msgs < 300) { + } else if (nb_msgs < 128) { perf_msgs->e++; - } else if (nb_msgs < 400) { + } else if (nb_msgs < 256) { perf_msgs->f++; - } else if (nb_msgs < 500) { + } else if (nb_msgs < 512) { perf_msgs->g++; } else if (nb_msgs < 600) { perf_msgs->h++; @@ -654,18 +652,6 @@ void SrsStatistic::perf_mw_on_msgs(int nb_msgs, int bytes_msgs, int nb_iovs) } else { perf_iovs->j++; } - - // Stat the syscalls. - // a: number of syscalls of msgs. - perf_sys->a++; -} - -void SrsStatistic::perf_mw_on_packets(int nb_pkts, int bytes_pkts, int nb_iovs) -{ - // Stat the syscalls. - // a: number of syscalls of msgs. - // b: number of syscalls of pkts. - perf_sys->b++; } srs_error_t SrsStatistic::dumps_perf_writev(SrsJsonObject* obj) @@ -678,22 +664,22 @@ srs_error_t SrsStatistic::dumps_perf_writev(SrsJsonObject* obj) // For perf msgs, the nb_msgs stat. // a: =1 - // b: <10 - // c: <100 - // d: <200 - // e: <300 - // f: <400 - // g: <500 + // b: <3 + // c: <6 + // d: <12 + // e: <128 + // f: <256 + // g: <512 // h: <600 // i: <1000 // j: >=1000 p->set("lt_2", SrsJsonAny::integer(perf_msgs->a)); - p->set("lt_10", SrsJsonAny::integer(perf_msgs->b)); - p->set("lt_100", SrsJsonAny::integer(perf_msgs->c)); - p->set("lt_200", SrsJsonAny::integer(perf_msgs->d)); - p->set("lt_300", SrsJsonAny::integer(perf_msgs->e)); - p->set("lt_400", SrsJsonAny::integer(perf_msgs->f)); - p->set("lt_500", SrsJsonAny::integer(perf_msgs->g)); + p->set("lt_3", SrsJsonAny::integer(perf_msgs->b)); + p->set("lt_6", SrsJsonAny::integer(perf_msgs->c)); + p->set("lt_12", SrsJsonAny::integer(perf_msgs->d)); + p->set("lt_128", SrsJsonAny::integer(perf_msgs->e)); + p->set("lt_256", SrsJsonAny::integer(perf_msgs->f)); + p->set("lt_512", SrsJsonAny::integer(perf_msgs->g)); p->set("lt_600", SrsJsonAny::integer(perf_msgs->h)); p->set("lt_1000", SrsJsonAny::integer(perf_msgs->i)); p->set("gt_1000", SrsJsonAny::integer(perf_msgs->j)); @@ -726,17 +712,6 @@ srs_error_t SrsStatistic::dumps_perf_writev(SrsJsonObject* obj) p->set("gt_1024", SrsJsonAny::integer(perf_iovs->j)); } - if (true) { - SrsJsonObject* p = SrsJsonAny::object(); - obj->set("sys", p); - - // Stat the syscalls. - // a: number of syscalls of msgs. - // b: number of syscalls of pkts. - p->set("msgs", SrsJsonAny::integer(perf_sys->a)); - p->set("pkts", SrsJsonAny::integer(perf_sys->b)); - } - return err; } diff --git a/trunk/src/app/srs_app_statistic.hpp b/trunk/src/app/srs_app_statistic.hpp index 553bc9650..ae73f49de 100644 --- a/trunk/src/app/srs_app_statistic.hpp +++ b/trunk/src/app/srs_app_statistic.hpp @@ -168,7 +168,6 @@ private: // The perf stat for mw(merged write). SrsStatisticCategory* perf_iovs; SrsStatisticCategory* perf_msgs; - SrsStatisticCategory* perf_sys; SrsStatisticCategory* perf_sendmmsg; SrsStatisticCategory* perf_gso; private: @@ -232,9 +231,6 @@ public: // Stat for packets merged written, nb_msgs is the number of RTMP messages, // bytes_msgs is the total bytes of RTMP messages, nb_iovs is the total number of iovec. virtual void perf_mw_on_msgs(int nb_msgs, int bytes_msgs, int nb_iovs); - // Stat for packets merged written, nb_pkts is the number of or chunk packets, - // bytes_pkts is the total bytes of or chunk packets, nb_iovs is the total number of iovec. - virtual void perf_mw_on_packets(int nb_pkts, int bytes_pkts, int nb_iovs); // Dumps the perf statistic data for TCP writev, for performance analysis. virtual srs_error_t dumps_perf_writev(SrsJsonObject* obj); public: diff --git a/trunk/src/protocol/srs_rtmp_stack.cpp b/trunk/src/protocol/srs_rtmp_stack.cpp index 6c0889d3f..835746805 100644 --- a/trunk/src/protocol/srs_rtmp_stack.cpp +++ b/trunk/src/protocol/srs_rtmp_stack.cpp @@ -627,11 +627,6 @@ srs_error_t SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msg if ((er = skt->writev(iovs, 2, NULL)) != srs_success) { return srs_error_wrap(err, "writev"); } - - // Notify about perf stat. - if (perf) { - perf->perf_mw_on_packets(1, payload_size, 2); - } } } diff --git a/trunk/src/protocol/srs_rtmp_stack.hpp b/trunk/src/protocol/srs_rtmp_stack.hpp index 470347cac..eea0c5a50 100644 --- a/trunk/src/protocol/srs_rtmp_stack.hpp +++ b/trunk/src/protocol/srs_rtmp_stack.hpp @@ -157,9 +157,6 @@ public: // Stat for packets merged written, nb_msgs is the number of RTMP messages, // bytes_msgs is the total bytes of RTMP messages, nb_iovs is the total number of iovec. virtual void perf_mw_on_msgs(int nb_msgs, int bytes_msgs, int nb_iovs) = 0; - // Stat for packets merged written, nb_pkts is the number of or chunk packets, - // bytes_pkts is the total bytes of or chunk packets, nb_iovs is the total number of iovec. - virtual void perf_mw_on_packets(int nb_pkts, int bytes_pkts, int nb_iovs) = 0; }; // The protocol provides the rtmp-message-protocol services, From fdc0c44b7e571f645da0e1f50af8117d63dd7116 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 13:55:55 +0800 Subject: [PATCH 19/35] For #307, for realtime, change wait messages from 0 to 2 --- trunk/src/app/srs_app_http_stream.cpp | 2 + trunk/src/app/srs_app_rtc_conn.cpp | 2 +- trunk/src/app/srs_app_rtmp_conn.cpp | 2 +- trunk/src/app/srs_app_statistic.cpp | 64 ++++++++++++------------- trunk/src/core/srs_core_performance.hpp | 4 ++ 5 files changed, 40 insertions(+), 34 deletions(-) diff --git a/trunk/src/app/srs_app_http_stream.cpp b/trunk/src/app/srs_app_http_stream.cpp index 6609c3852..95c1f03fd 100755 --- a/trunk/src/app/srs_app_http_stream.cpp +++ b/trunk/src/app/srs_app_http_stream.cpp @@ -680,6 +680,8 @@ srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess err = streaming_send_messages(enc, msgs.msgs, count); } + // TODO: FIXME: Update the stat. + // free the messages. for (int i = 0; i < count; i++) { SrsSharedPtrMessage* msg = msgs.msgs[i]; diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index f70cf279d..abee62bc0 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -619,7 +619,7 @@ srs_error_t SrsRtcSenderThread::cycle() #ifdef SRS_PERF_QUEUE_COND_WAIT if (realtime) { // for realtime, min required msgs is 0, send when got one+ msgs. - consumer->wait(0, mw_sleep); + consumer->wait(SRS_PERF_MW_MIN_MSGS_FOR_RTC_REALTIME, mw_sleep); } else { // for no-realtime, got some msgs then send. consumer->wait(SRS_PERF_MW_MIN_MSGS_FOR_RTC, mw_sleep); diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index d312d4ab2..d06d79a42 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -732,7 +732,7 @@ srs_error_t SrsRtmpConn::do_playing(SrsSource* source, SrsConsumer* consumer, Sr // @see https://github.com/ossrs/srs/issues/257 if (realtime) { // for realtime, min required msgs is 0, send when got one+ msgs. - consumer->wait(0, mw_sleep); + consumer->wait(SRS_PERF_MW_MIN_MSGS_REALTIME, mw_sleep); } else { // for no-realtime, got some msgs then send. consumer->wait(SRS_PERF_MW_MIN_MSGS, mw_sleep); diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index 228fa8344..62ba28764 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -588,31 +588,31 @@ srs_error_t SrsStatistic::dumps_clients(SrsJsonArray* arr, int start, int count) void SrsStatistic::perf_mw_on_msgs(int nb_msgs, int bytes_msgs, int nb_iovs) { // For perf msgs, the nb_msgs stat. - // a: =1 - // b: <3 - // c: <6 - // d: <12 - // e: <128 - // f: <256 - // g: <512 - // h: <600 + // a: <3 + // b: <5 + // c: <9 + // d: <16 + // e: <32 + // f: <64 + // g: <128 + // h: <256 // i: <1000 // j: >=1000 - if (nb_msgs == 1) { + if (nb_msgs < 3) { perf_msgs->a++; - } else if (nb_msgs < 3) { + } else if (nb_msgs < 5) { perf_msgs->b++; - } else if (nb_msgs < 6) { + } else if (nb_msgs < 9) { perf_msgs->c++; - } else if (nb_msgs < 12) { + } else if (nb_msgs < 16) { perf_msgs->d++; - } else if (nb_msgs < 128) { + } else if (nb_msgs < 32) { perf_msgs->e++; - } else if (nb_msgs < 256) { + } else if (nb_msgs < 64) { perf_msgs->f++; - } else if (nb_msgs < 512) { + } else if (nb_msgs < 128) { perf_msgs->g++; - } else if (nb_msgs < 600) { + } else if (nb_msgs < 256) { perf_msgs->h++; } else if (nb_msgs < 1000) { perf_msgs->i++; @@ -663,24 +663,24 @@ srs_error_t SrsStatistic::dumps_perf_writev(SrsJsonObject* obj) obj->set("msgs", p); // For perf msgs, the nb_msgs stat. - // a: =1 - // b: <3 - // c: <6 - // d: <12 - // e: <128 - // f: <256 - // g: <512 - // h: <600 + // a: <3 + // b: <5 + // c: <9 + // d: <16 + // e: <32 + // f: <64 + // g: <128 + // h: <256 // i: <1000 // j: >=1000 - p->set("lt_2", SrsJsonAny::integer(perf_msgs->a)); - p->set("lt_3", SrsJsonAny::integer(perf_msgs->b)); - p->set("lt_6", SrsJsonAny::integer(perf_msgs->c)); - p->set("lt_12", SrsJsonAny::integer(perf_msgs->d)); - p->set("lt_128", SrsJsonAny::integer(perf_msgs->e)); - p->set("lt_256", SrsJsonAny::integer(perf_msgs->f)); - p->set("lt_512", SrsJsonAny::integer(perf_msgs->g)); - p->set("lt_600", SrsJsonAny::integer(perf_msgs->h)); + p->set("lt_3", SrsJsonAny::integer(perf_msgs->a)); + p->set("lt_5", SrsJsonAny::integer(perf_msgs->b)); + p->set("lt_9", SrsJsonAny::integer(perf_msgs->c)); + p->set("lt_16", SrsJsonAny::integer(perf_msgs->d)); + p->set("lt_32", SrsJsonAny::integer(perf_msgs->e)); + p->set("lt_64", SrsJsonAny::integer(perf_msgs->f)); + p->set("lt_128", SrsJsonAny::integer(perf_msgs->g)); + p->set("lt_256", SrsJsonAny::integer(perf_msgs->h)); p->set("lt_1000", SrsJsonAny::integer(perf_msgs->i)); p->set("gt_1000", SrsJsonAny::integer(perf_msgs->j)); } diff --git a/trunk/src/core/srs_core_performance.hpp b/trunk/src/core/srs_core_performance.hpp index 07c1e1539..adc38f3fa 100644 --- a/trunk/src/core/srs_core_performance.hpp +++ b/trunk/src/core/srs_core_performance.hpp @@ -127,8 +127,12 @@ */ #define SRS_PERF_QUEUE_COND_WAIT #ifdef SRS_PERF_QUEUE_COND_WAIT + // For RTMP, use larger wait queue. #define SRS_PERF_MW_MIN_MSGS 8 + #define SRS_PERF_MW_MIN_MSGS_REALTIME 4 + // For RTC, use smaller wait queue. #define SRS_PERF_MW_MIN_MSGS_FOR_RTC 4 + #define SRS_PERF_MW_MIN_MSGS_FOR_RTC_REALTIME 2 #endif /** * the default value of vhost for From 7574dbefb1c8fada887986591d21a49a706f941a Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 14:02:54 +0800 Subject: [PATCH 20/35] For #307, support sendmmsg, GSO and reuseport. 4.0.23 --- README.md | 1 + trunk/src/app/srs_app_statistic.cpp | 80 ++++++++++++------------- trunk/src/core/srs_core_performance.hpp | 4 +- trunk/src/core/srs_core_version4.hpp | 2 +- 4 files changed, 44 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 728152999..270a7569a 100755 --- a/README.md +++ b/README.md @@ -157,6 +157,7 @@ For previous versions, please read: ## V4 changes +* v4.0, 2020-04-14, For [#307][bug #307], support sendmmsg, GSO and reuseport. 4.0.23 * v4.0, 2020-04-05, For [#307][bug #307], SRTP ASM only works with openssl-1.0, auto detect it. 4.0.22 * v4.0, 2020-04-04, Merge RTC and GB28181, with bugs fixed. 4.0.21 * v4.0, 2020-04-04, For [#307][bug #307], refine RTC latency from 600ms to 200ms. 4.0.20 diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index 62ba28764..92284c329 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -673,16 +673,16 @@ srs_error_t SrsStatistic::dumps_perf_writev(SrsJsonObject* obj) // h: <256 // i: <1000 // j: >=1000 - p->set("lt_3", SrsJsonAny::integer(perf_msgs->a)); - p->set("lt_5", SrsJsonAny::integer(perf_msgs->b)); - p->set("lt_9", SrsJsonAny::integer(perf_msgs->c)); - p->set("lt_16", SrsJsonAny::integer(perf_msgs->d)); - p->set("lt_32", SrsJsonAny::integer(perf_msgs->e)); - p->set("lt_64", SrsJsonAny::integer(perf_msgs->f)); - p->set("lt_128", SrsJsonAny::integer(perf_msgs->g)); - p->set("lt_256", SrsJsonAny::integer(perf_msgs->h)); - p->set("lt_1000", SrsJsonAny::integer(perf_msgs->i)); - p->set("gt_1000", SrsJsonAny::integer(perf_msgs->j)); + if (perf_msgs->a) p->set("lt_3", SrsJsonAny::integer(perf_msgs->a)); + if (perf_msgs->b) p->set("lt_5", SrsJsonAny::integer(perf_msgs->b)); + if (perf_msgs->c) p->set("lt_9", SrsJsonAny::integer(perf_msgs->c)); + if (perf_msgs->d) p->set("lt_16", SrsJsonAny::integer(perf_msgs->d)); + if (perf_msgs->e) p->set("lt_32", SrsJsonAny::integer(perf_msgs->e)); + if (perf_msgs->f) p->set("lt_64", SrsJsonAny::integer(perf_msgs->f)); + if (perf_msgs->g) p->set("lt_128", SrsJsonAny::integer(perf_msgs->g)); + if (perf_msgs->h) p->set("lt_256", SrsJsonAny::integer(perf_msgs->h)); + if (perf_msgs->i) p->set("lt_1000", SrsJsonAny::integer(perf_msgs->i)); + if (perf_msgs->j) p->set("gt_1000", SrsJsonAny::integer(perf_msgs->j)); } if (true) { @@ -700,16 +700,16 @@ srs_error_t SrsStatistic::dumps_perf_writev(SrsJsonObject* obj) // h: <900 // i: <1024 // j: >=1024 - p->set("lt_3", SrsJsonAny::integer(perf_iovs->a)); - p->set("lt_10", SrsJsonAny::integer(perf_iovs->b)); - p->set("lt_20", SrsJsonAny::integer(perf_iovs->c)); - p->set("lt_200", SrsJsonAny::integer(perf_iovs->d)); - p->set("lt_300", SrsJsonAny::integer(perf_iovs->e)); - p->set("lt_500", SrsJsonAny::integer(perf_iovs->f)); - p->set("lt_700", SrsJsonAny::integer(perf_iovs->g)); - p->set("lt_900", SrsJsonAny::integer(perf_iovs->h)); - p->set("lt_1024", SrsJsonAny::integer(perf_iovs->i)); - p->set("gt_1024", SrsJsonAny::integer(perf_iovs->j)); + if (perf_iovs->a) p->set("lt_3", SrsJsonAny::integer(perf_iovs->a)); + if (perf_iovs->b) p->set("lt_10", SrsJsonAny::integer(perf_iovs->b)); + if (perf_iovs->c) p->set("lt_20", SrsJsonAny::integer(perf_iovs->c)); + if (perf_iovs->d) p->set("lt_200", SrsJsonAny::integer(perf_iovs->d)); + if (perf_iovs->e) p->set("lt_300", SrsJsonAny::integer(perf_iovs->e)); + if (perf_iovs->f) p->set("lt_500", SrsJsonAny::integer(perf_iovs->f)); + if (perf_iovs->g) p->set("lt_700", SrsJsonAny::integer(perf_iovs->g)); + if (perf_iovs->h) p->set("lt_900", SrsJsonAny::integer(perf_iovs->h)); + if (perf_iovs->i) p->set("lt_1024", SrsJsonAny::integer(perf_iovs->i)); + if (perf_iovs->j) p->set("gt_1024", SrsJsonAny::integer(perf_iovs->j)); } return err; @@ -770,16 +770,16 @@ srs_error_t SrsStatistic::dumps_perf_sendmmsg(SrsJsonObject* obj) // h: <600 // i: <1000 // j: >=1000 - p->set("lt_2", SrsJsonAny::integer(perf_sendmmsg->a)); - p->set("lt_10", SrsJsonAny::integer(perf_sendmmsg->b)); - p->set("lt_100", SrsJsonAny::integer(perf_sendmmsg->c)); - p->set("lt_200", SrsJsonAny::integer(perf_sendmmsg->d)); - p->set("lt_300", SrsJsonAny::integer(perf_sendmmsg->e)); - p->set("lt_400", SrsJsonAny::integer(perf_sendmmsg->f)); - p->set("lt_500", SrsJsonAny::integer(perf_sendmmsg->g)); - p->set("lt_600", SrsJsonAny::integer(perf_sendmmsg->h)); - p->set("lt_1000", SrsJsonAny::integer(perf_sendmmsg->i)); - p->set("gt_1000", SrsJsonAny::integer(perf_sendmmsg->j)); + if (perf_sendmmsg->a) p->set("lt_2", SrsJsonAny::integer(perf_sendmmsg->a)); + if (perf_sendmmsg->b) p->set("lt_10", SrsJsonAny::integer(perf_sendmmsg->b)); + if (perf_sendmmsg->c) p->set("lt_100", SrsJsonAny::integer(perf_sendmmsg->c)); + if (perf_sendmmsg->d) p->set("lt_200", SrsJsonAny::integer(perf_sendmmsg->d)); + if (perf_sendmmsg->e) p->set("lt_300", SrsJsonAny::integer(perf_sendmmsg->e)); + if (perf_sendmmsg->f) p->set("lt_400", SrsJsonAny::integer(perf_sendmmsg->f)); + if (perf_sendmmsg->g) p->set("lt_500", SrsJsonAny::integer(perf_sendmmsg->g)); + if (perf_sendmmsg->h) p->set("lt_600", SrsJsonAny::integer(perf_sendmmsg->h)); + if (perf_sendmmsg->i) p->set("lt_1000", SrsJsonAny::integer(perf_sendmmsg->i)); + if (perf_sendmmsg->j) p->set("gt_1000", SrsJsonAny::integer(perf_sendmmsg->j)); } return err; @@ -840,16 +840,16 @@ srs_error_t SrsStatistic::dumps_perf_gso(SrsJsonObject* obj) // h: <128 // i: <512 // j: >=512 - p->set("lt_2", SrsJsonAny::integer(perf_gso->a)); - p->set("lt_3", SrsJsonAny::integer(perf_gso->b)); - p->set("lt_6", SrsJsonAny::integer(perf_gso->c)); - p->set("lt_9", SrsJsonAny::integer(perf_gso->d)); - p->set("lt_16", SrsJsonAny::integer(perf_gso->e)); - p->set("lt_32", SrsJsonAny::integer(perf_gso->f)); - p->set("lt_64", SrsJsonAny::integer(perf_gso->g)); - p->set("lt_128", SrsJsonAny::integer(perf_gso->h)); - p->set("lt_512", SrsJsonAny::integer(perf_gso->i)); - p->set("gt_512", SrsJsonAny::integer(perf_gso->j)); + if (perf_gso->a) p->set("lt_2", SrsJsonAny::integer(perf_gso->a)); + if (perf_gso->b) p->set("lt_3", SrsJsonAny::integer(perf_gso->b)); + if (perf_gso->c) p->set("lt_6", SrsJsonAny::integer(perf_gso->c)); + if (perf_gso->d) p->set("lt_9", SrsJsonAny::integer(perf_gso->d)); + if (perf_gso->e) p->set("lt_16", SrsJsonAny::integer(perf_gso->e)); + if (perf_gso->f) p->set("lt_32", SrsJsonAny::integer(perf_gso->f)); + if (perf_gso->g) p->set("lt_64", SrsJsonAny::integer(perf_gso->g)); + if (perf_gso->h) p->set("lt_128", SrsJsonAny::integer(perf_gso->h)); + if (perf_gso->i) p->set("lt_512", SrsJsonAny::integer(perf_gso->i)); + if (perf_gso->j) p->set("gt_512", SrsJsonAny::integer(perf_gso->j)); } return err; diff --git a/trunk/src/core/srs_core_performance.hpp b/trunk/src/core/srs_core_performance.hpp index adc38f3fa..ea077b89b 100644 --- a/trunk/src/core/srs_core_performance.hpp +++ b/trunk/src/core/srs_core_performance.hpp @@ -131,8 +131,8 @@ #define SRS_PERF_MW_MIN_MSGS 8 #define SRS_PERF_MW_MIN_MSGS_REALTIME 4 // For RTC, use smaller wait queue. - #define SRS_PERF_MW_MIN_MSGS_FOR_RTC 4 - #define SRS_PERF_MW_MIN_MSGS_FOR_RTC_REALTIME 2 + #define SRS_PERF_MW_MIN_MSGS_FOR_RTC 3 + #define SRS_PERF_MW_MIN_MSGS_FOR_RTC_REALTIME 1 #endif /** * the default value of vhost for diff --git a/trunk/src/core/srs_core_version4.hpp b/trunk/src/core/srs_core_version4.hpp index 34fd22900..e47dfdc68 100644 --- a/trunk/src/core/srs_core_version4.hpp +++ b/trunk/src/core/srs_core_version4.hpp @@ -24,6 +24,6 @@ #ifndef SRS_CORE_VERSION4_HPP #define SRS_CORE_VERSION4_HPP -#define SRS_VERSION4_REVISION 22 +#define SRS_VERSION4_REVISION 23 #endif From ba3d293bfd8850135603900b8fa1cf83710d3c5e Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 14:22:30 +0800 Subject: [PATCH 21/35] Refactor stat for frames --- trunk/src/app/srs_app_http_api.cpp | 6 +-- trunk/src/app/srs_app_statistic.cpp | 76 ++++++++++++++--------------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index fd4e9b2bb..e3f36604c 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1622,12 +1622,12 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* data->set("query", p); p->set("target", SrsJsonAny::str(target.c_str())); - p->set("help", SrsJsonAny::str("?target=writev|sendmmsg|gso")); + p->set("help", SrsJsonAny::str("?target=frames|sendmmsg|gso")); } - if (target.empty() || target == "writev") { + if (target.empty() || target == "frames") { SrsJsonObject* p = SrsJsonAny::object(); - data->set("writev", p); + data->set("frames", p); if ((err = stat->dumps_perf_writev(p)) != srs_success) { int code = srs_error_code(err); srs_error_reset(err); return srs_api_response_code(w, r, code); diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index 92284c329..3b122ff81 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -621,33 +621,33 @@ void SrsStatistic::perf_mw_on_msgs(int nb_msgs, int bytes_msgs, int nb_iovs) } // For perf iovs, the nb_iovs stat. - // a: <=2 - // b: <10 - // c: <20 - // d: <200 - // e: <300 - // f: <500 - // g: <700 - // h: <900 - // i: <1024 - // j: >=1024 - if (nb_iovs <= 2) { + // a: <3 + // b: <5 + // c: <9 + // d: <16 + // e: <32 + // f: <64 + // g: <128 + // h: <256 + // i: <1000 + // j: >=1000 + if (nb_iovs < 3) { perf_iovs->a++; - } else if (nb_iovs < 10) { + } else if (nb_iovs < 5) { perf_iovs->b++; - } else if (nb_iovs < 20) { + } else if (nb_iovs < 9) { perf_iovs->c++; - } else if (nb_iovs < 200) { + } else if (nb_iovs < 16) { perf_iovs->d++; - } else if (nb_iovs < 300) { + } else if (nb_iovs < 32) { perf_iovs->e++; - } else if (nb_iovs < 500) { + } else if (nb_iovs < 64) { perf_iovs->f++; - } else if (nb_iovs < 700) { + } else if (nb_iovs < 128) { perf_iovs->g++; - } else if (nb_iovs < 900) { + } else if (nb_iovs < 256) { perf_iovs->h++; - } else if (nb_iovs < 1024) { + } else if (nb_iovs < 1000) { perf_iovs->i++; } else { perf_iovs->j++; @@ -690,26 +690,26 @@ srs_error_t SrsStatistic::dumps_perf_writev(SrsJsonObject* obj) obj->set("iovs", p); // For perf iovs, the nb_iovs stat. - // a: <=2 - // b: <10 - // c: <20 - // d: <200 - // e: <300 - // f: <500 - // g: <700 - // h: <900 - // i: <1024 - // j: >=1024 + // a: <3 + // b: <5 + // c: <9 + // d: <16 + // e: <32 + // f: <64 + // g: <128 + // h: <256 + // i: <1000 + // j: >=1000 if (perf_iovs->a) p->set("lt_3", SrsJsonAny::integer(perf_iovs->a)); - if (perf_iovs->b) p->set("lt_10", SrsJsonAny::integer(perf_iovs->b)); - if (perf_iovs->c) p->set("lt_20", SrsJsonAny::integer(perf_iovs->c)); - if (perf_iovs->d) p->set("lt_200", SrsJsonAny::integer(perf_iovs->d)); - if (perf_iovs->e) p->set("lt_300", SrsJsonAny::integer(perf_iovs->e)); - if (perf_iovs->f) p->set("lt_500", SrsJsonAny::integer(perf_iovs->f)); - if (perf_iovs->g) p->set("lt_700", SrsJsonAny::integer(perf_iovs->g)); - if (perf_iovs->h) p->set("lt_900", SrsJsonAny::integer(perf_iovs->h)); - if (perf_iovs->i) p->set("lt_1024", SrsJsonAny::integer(perf_iovs->i)); - if (perf_iovs->j) p->set("gt_1024", SrsJsonAny::integer(perf_iovs->j)); + if (perf_iovs->b) p->set("lt_5", SrsJsonAny::integer(perf_iovs->b)); + if (perf_iovs->c) p->set("lt_9", SrsJsonAny::integer(perf_iovs->c)); + if (perf_iovs->d) p->set("lt_16", SrsJsonAny::integer(perf_iovs->d)); + if (perf_iovs->e) p->set("lt_32", SrsJsonAny::integer(perf_iovs->e)); + if (perf_iovs->f) p->set("lt_64", SrsJsonAny::integer(perf_iovs->f)); + if (perf_iovs->g) p->set("lt_128", SrsJsonAny::integer(perf_iovs->g)); + if (perf_iovs->h) p->set("lt_256", SrsJsonAny::integer(perf_iovs->h)); + if (perf_iovs->i) p->set("lt_1000", SrsJsonAny::integer(perf_iovs->i)); + if (perf_iovs->j) p->set("gt_1000", SrsJsonAny::integer(perf_iovs->j)); } return err; From 8d5f91f777e64ddea922302677115780543bb4f0 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 18:15:07 +0800 Subject: [PATCH 22/35] For rtc player, use target to overwrite server, vhost and eip. --- trunk/research/players/js/srs.page.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/trunk/research/players/js/srs.page.js b/trunk/research/players/js/srs.page.js index 56ff81e45..3f3b1f6ca 100755 --- a/trunk/research/players/js/srs.page.js +++ b/trunk/research/players/js/srs.page.js @@ -207,6 +207,14 @@ function build_default_hls_url() { } function build_default_rtc_url(query) { + // Use target to overwrite server, vhost and eip. + console.log('?target=x.x.x.x to overwrite server, vhost and eip.'); + if (query.target) { + query.server = query.vhost = query.eip = query.target; + query.user_query.eip = query.target; + delete query.target; + } + var server = (!query.server)? window.location.hostname:query.server; var vhost = (!query.vhost)? window.location.hostname:query.vhost; var app = (!query.app)? "live":query.app; From de343d654762ed044bcf46263a73e8d7510af829 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 18:48:57 +0800 Subject: [PATCH 23/35] Add tool for GSO --- trunk/scripts/perf_gso.py | 35 +++++++++++++++++++++ trunk/src/app/srs_app_statistic.cpp | 48 ++++++++++++++--------------- 2 files changed, 59 insertions(+), 24 deletions(-) create mode 100644 trunk/scripts/perf_gso.py diff --git a/trunk/scripts/perf_gso.py b/trunk/scripts/perf_gso.py new file mode 100644 index 000000000..a1e329275 --- /dev/null +++ b/trunk/scripts/perf_gso.py @@ -0,0 +1,35 @@ +import urllib, sys, json + +url = "http://localhost:1985/api/v1/perf" +if len(sys.argv) > 1: + url = sys.argv[1] +print "Open %s"%(url) + +f = urllib.urlopen(url) +s = f.read() +f.close() +print "Repsonse %s"%(s) + +obj = json.loads(s) +keys = [3, 5, 9, 16, 32, 64, 128, 256, 1000] + +print "" +print("AVFrames"), +for k in keys: + k2 = 'lt_%s'%(k) + p = obj['data']['writev']['msgs'] + if k2 in p: + print(p[k2]), + else: + print(0), + +print "" +print("RTP-Packets"), +for k in keys: + k2 = 'lt_%s'%(k) + p = obj['data']['writev']['iovs'] + if k2 in p: + print(p[k2]), + else: + print(0), + diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index 3b122ff81..a58d5f57a 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -673,16 +673,16 @@ srs_error_t SrsStatistic::dumps_perf_writev(SrsJsonObject* obj) // h: <256 // i: <1000 // j: >=1000 - if (perf_msgs->a) p->set("lt_3", SrsJsonAny::integer(perf_msgs->a)); - if (perf_msgs->b) p->set("lt_5", SrsJsonAny::integer(perf_msgs->b)); - if (perf_msgs->c) p->set("lt_9", SrsJsonAny::integer(perf_msgs->c)); - if (perf_msgs->d) p->set("lt_16", SrsJsonAny::integer(perf_msgs->d)); - if (perf_msgs->e) p->set("lt_32", SrsJsonAny::integer(perf_msgs->e)); - if (perf_msgs->f) p->set("lt_64", SrsJsonAny::integer(perf_msgs->f)); - if (perf_msgs->g) p->set("lt_128", SrsJsonAny::integer(perf_msgs->g)); - if (perf_msgs->h) p->set("lt_256", SrsJsonAny::integer(perf_msgs->h)); - if (perf_msgs->i) p->set("lt_1000", SrsJsonAny::integer(perf_msgs->i)); - if (perf_msgs->j) p->set("gt_1000", SrsJsonAny::integer(perf_msgs->j)); + if (perf_msgs->a) p->set("lt_3", SrsJsonAny::integer(perf_msgs->a)); + if (perf_msgs->b) p->set("lt_5", SrsJsonAny::integer(perf_msgs->b)); + if (perf_msgs->c) p->set("lt_9", SrsJsonAny::integer(perf_msgs->c)); + if (perf_msgs->d) p->set("lt_16", SrsJsonAny::integer(perf_msgs->d)); + if (perf_msgs->e) p->set("lt_32", SrsJsonAny::integer(perf_msgs->e)); + if (perf_msgs->f) p->set("lt_64", SrsJsonAny::integer(perf_msgs->f)); + if (perf_msgs->g) p->set("lt_128", SrsJsonAny::integer(perf_msgs->g)); + if (perf_msgs->h) p->set("lt_256", SrsJsonAny::integer(perf_msgs->h)); + if (perf_msgs->i) p->set("lt_1000", SrsJsonAny::integer(perf_msgs->i)); + if (perf_msgs->j) p->set("gt_1000", SrsJsonAny::integer(perf_msgs->j)); } if (true) { @@ -700,16 +700,16 @@ srs_error_t SrsStatistic::dumps_perf_writev(SrsJsonObject* obj) // h: <256 // i: <1000 // j: >=1000 - if (perf_iovs->a) p->set("lt_3", SrsJsonAny::integer(perf_iovs->a)); - if (perf_iovs->b) p->set("lt_5", SrsJsonAny::integer(perf_iovs->b)); - if (perf_iovs->c) p->set("lt_9", SrsJsonAny::integer(perf_iovs->c)); - if (perf_iovs->d) p->set("lt_16", SrsJsonAny::integer(perf_iovs->d)); - if (perf_iovs->e) p->set("lt_32", SrsJsonAny::integer(perf_iovs->e)); - if (perf_iovs->f) p->set("lt_64", SrsJsonAny::integer(perf_iovs->f)); - if (perf_iovs->g) p->set("lt_128", SrsJsonAny::integer(perf_iovs->g)); - if (perf_iovs->h) p->set("lt_256", SrsJsonAny::integer(perf_iovs->h)); - if (perf_iovs->i) p->set("lt_1000", SrsJsonAny::integer(perf_iovs->i)); - if (perf_iovs->j) p->set("gt_1000", SrsJsonAny::integer(perf_iovs->j)); + if (perf_iovs->a) p->set("lt_3", SrsJsonAny::integer(perf_iovs->a)); + if (perf_iovs->b) p->set("lt_5", SrsJsonAny::integer(perf_iovs->b)); + if (perf_iovs->c) p->set("lt_9", SrsJsonAny::integer(perf_iovs->c)); + if (perf_iovs->d) p->set("lt_16", SrsJsonAny::integer(perf_iovs->d)); + if (perf_iovs->e) p->set("lt_32", SrsJsonAny::integer(perf_iovs->e)); + if (perf_iovs->f) p->set("lt_64", SrsJsonAny::integer(perf_iovs->f)); + if (perf_iovs->g) p->set("lt_128", SrsJsonAny::integer(perf_iovs->g)); + if (perf_iovs->h) p->set("lt_256", SrsJsonAny::integer(perf_iovs->h)); + if (perf_iovs->i) p->set("lt_1000", SrsJsonAny::integer(perf_iovs->i)); + if (perf_iovs->j) p->set("gt_1000", SrsJsonAny::integer(perf_iovs->j)); } return err; @@ -840,14 +840,14 @@ srs_error_t SrsStatistic::dumps_perf_gso(SrsJsonObject* obj) // h: <128 // i: <512 // j: >=512 - if (perf_gso->a) p->set("lt_2", SrsJsonAny::integer(perf_gso->a)); + if (perf_gso->a) p->set("lt_2", SrsJsonAny::integer(perf_gso->a)); if (perf_gso->b) p->set("lt_3", SrsJsonAny::integer(perf_gso->b)); - if (perf_gso->c) p->set("lt_6", SrsJsonAny::integer(perf_gso->c)); - if (perf_gso->d) p->set("lt_9", SrsJsonAny::integer(perf_gso->d)); + if (perf_gso->c) p->set("lt_6", SrsJsonAny::integer(perf_gso->c)); + if (perf_gso->d) p->set("lt_9", SrsJsonAny::integer(perf_gso->d)); if (perf_gso->e) p->set("lt_16", SrsJsonAny::integer(perf_gso->e)); if (perf_gso->f) p->set("lt_32", SrsJsonAny::integer(perf_gso->f)); if (perf_gso->g) p->set("lt_64", SrsJsonAny::integer(perf_gso->g)); - if (perf_gso->h) p->set("lt_128", SrsJsonAny::integer(perf_gso->h)); + if (perf_gso->h) p->set("lt_128", SrsJsonAny::integer(perf_gso->h)); if (perf_gso->i) p->set("lt_512", SrsJsonAny::integer(perf_gso->i)); if (perf_gso->j) p->set("gt_512", SrsJsonAny::integer(perf_gso->j)); } From 7c3522dcb13b1bed5349368f6fe035236ca6b842 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 18:49:26 +0800 Subject: [PATCH 24/35] Add tool for GSO --- trunk/scripts/perf_gso.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 trunk/scripts/perf_gso.py diff --git a/trunk/scripts/perf_gso.py b/trunk/scripts/perf_gso.py old mode 100644 new mode 100755 From 4be1d785b684bbd281fa0dc86903886d61c9d524 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 18:50:21 +0800 Subject: [PATCH 25/35] Add tool for GSO --- trunk/scripts/perf_gso.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/trunk/scripts/perf_gso.py b/trunk/scripts/perf_gso.py index a1e329275..9df63a77c 100755 --- a/trunk/scripts/perf_gso.py +++ b/trunk/scripts/perf_gso.py @@ -1,3 +1,27 @@ +#!/usr/bin/python +''' +The MIT License (MIT) + +Copyright (c) 2013-2016 SRS(ossrs) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +''' + import urllib, sys, json url = "http://localhost:1985/api/v1/perf" From bda7bdee54487bd0c465763b8e16cea83379ee15 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 19:19:46 +0800 Subject: [PATCH 26/35] Change RTC realtime to 0 cache --- trunk/src/core/srs_core_performance.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/trunk/src/core/srs_core_performance.hpp b/trunk/src/core/srs_core_performance.hpp index ea077b89b..7cafa055e 100644 --- a/trunk/src/core/srs_core_performance.hpp +++ b/trunk/src/core/srs_core_performance.hpp @@ -129,10 +129,10 @@ #ifdef SRS_PERF_QUEUE_COND_WAIT // For RTMP, use larger wait queue. #define SRS_PERF_MW_MIN_MSGS 8 - #define SRS_PERF_MW_MIN_MSGS_REALTIME 4 + #define SRS_PERF_MW_MIN_MSGS_REALTIME 0 // For RTC, use smaller wait queue. - #define SRS_PERF_MW_MIN_MSGS_FOR_RTC 3 - #define SRS_PERF_MW_MIN_MSGS_FOR_RTC_REALTIME 1 + #define SRS_PERF_MW_MIN_MSGS_FOR_RTC 2 + #define SRS_PERF_MW_MIN_MSGS_FOR_RTC_REALTIME 0 #endif /** * the default value of vhost for From 97cfae624c9d1eb13cbcfdbd268f5775f68711c1 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 19:23:15 +0800 Subject: [PATCH 27/35] Fix CentOS8 build warnings --- trunk/src/kernel/srs_kernel_flv.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trunk/src/kernel/srs_kernel_flv.cpp b/trunk/src/kernel/srs_kernel_flv.cpp index 00e289feb..28b2d938b 100644 --- a/trunk/src/kernel/srs_kernel_flv.cpp +++ b/trunk/src/kernel/srs_kernel_flv.cpp @@ -383,7 +383,7 @@ void SrsSharedPtrMessage::set_extra_payloads(SrsSample* payloads, int nn_payload ptr->nn_extra_payloads = nn_payloads; ptr->extra_payloads = new SrsSample[nn_payloads]; - memcpy(ptr->extra_payloads, payloads, nn_payloads * sizeof(SrsSample)); + memcpy((void*)ptr->extra_payloads, payloads, nn_payloads * sizeof(SrsSample)); } void SrsSharedPtrMessage::set_samples(SrsSample* samples, int nn_samples) @@ -394,7 +394,7 @@ void SrsSharedPtrMessage::set_samples(SrsSample* samples, int nn_samples) ptr->nn_samples = nn_samples; ptr->samples = new SrsSample[nn_samples]; - memcpy(ptr->samples, samples, nn_samples * sizeof(SrsSample)); + memcpy((void*)ptr->samples, samples, nn_samples * sizeof(SrsSample)); } #endif From 88b1e14db427d93c7baf36d673d9cd7a6c563049 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 19:30:35 +0800 Subject: [PATCH 28/35] Update perf api tool --- trunk/scripts/perf_gso.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/trunk/scripts/perf_gso.py b/trunk/scripts/perf_gso.py index 9df63a77c..5c6f92746 100755 --- a/trunk/scripts/perf_gso.py +++ b/trunk/scripts/perf_gso.py @@ -41,7 +41,10 @@ print "" print("AVFrames"), for k in keys: k2 = 'lt_%s'%(k) - p = obj['data']['writev']['msgs'] + if 'frames' in obj['data']: + p = obj['data']['frames']['msgs'] + else: + p = obj['data']['writev']['msgs'] if k2 in p: print(p[k2]), else: @@ -51,7 +54,10 @@ print "" print("RTP-Packets"), for k in keys: k2 = 'lt_%s'%(k) - p = obj['data']['writev']['iovs'] + if 'frames' in obj['data']: + p = obj['data']['frames']['iovs'] + else: + p = obj['data']['writev']['iovs'] if k2 in p: print(p[k2]), else: From 9d5c855727fe08c5c80020c79ca47079b9ce01b9 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 19:36:43 +0800 Subject: [PATCH 29/35] Update perf api tool --- trunk/scripts/perf_gso.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/scripts/perf_gso.py b/trunk/scripts/perf_gso.py index 5c6f92746..95ef027b5 100755 --- a/trunk/scripts/perf_gso.py +++ b/trunk/scripts/perf_gso.py @@ -38,7 +38,7 @@ obj = json.loads(s) keys = [3, 5, 9, 16, 32, 64, 128, 256, 1000] print "" -print("AVFrames"), +print("AV---Frames"), for k in keys: k2 = 'lt_%s'%(k) if 'frames' in obj['data']: From 8e4ef986298119b6de65b689a160cb53ebaa7644 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 20:12:14 +0800 Subject: [PATCH 30/35] For #307, correct the RTP packet stat. --- trunk/src/app/srs_app_rtc_conn.cpp | 25 ++++++++++++++++++------- trunk/src/app/srs_app_rtc_conn.hpp | 9 +++++++++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index abee62bc0..811cad324 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -654,8 +654,9 @@ srs_error_t SrsRtcSenderThread::cycle() pprint->elapse(); if (pprint->can_print()) { // TODO: FIXME: Print stat like frame/s, packet/s, loss_packets. - srs_trace("-> RTC PLAY %d msgs, %d packets, %d audios, %d extras, %d videos, %d samples, %d bytes", - msg_count, pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, pkts.nn_samples, pkts.nn_bytes); + srs_trace("-> RTC PLAY %d msgs, %d/%d packets, %d audios, %d extras, %d videos, %d samples, %d bytes", + msg_count, pkts.packets.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, + pkts.nn_samples, pkts.nn_bytes); } } } @@ -674,8 +675,6 @@ srs_error_t SrsRtcSenderThread::send_messages( return srs_error_wrap(err, "messages to packets"); } - packets.nn_rtp_pkts = (int)packets.packets.size(); - #ifndef SRS_AUTO_OSX // If enabled GSO, send out some packets in a msghdr. if (packets.use_gso) { @@ -820,6 +819,9 @@ srs_error_t SrsRtcSenderThread::send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets mhdr->msg_hdr.msg_controllen = 0; mhdr->msg_len = 0; + // When we send out a packet, we commit a RTP packet. + packets.nn_rtp_pkts++; + if ((err = sender->sendmmsg(mhdr)) != srs_success) { return srs_error_wrap(err, "send msghdr"); } @@ -833,13 +835,12 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac { srs_error_t err = srs_success; - ISrsUdpSender* sender = skt->sender(); - // Previous handler, if has the same size, we can use GSO. mmsghdr* gso_mhdr = NULL; int gso_size = 0; int gso_encrypt = 0; int gso_cursor = 0; // GSO, N packets has same length, the final one may not. bool use_gso = false; bool gso_final = false; + ISrsUdpSender* sender = skt->sender(); int nn_packets = (int)packets.packets.size(); for (int i = 0; i < nn_packets; i++) { SrsRtpPacket2* packet = packets.packets[i]; @@ -950,7 +951,8 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac bool do_send = (i == nn_packets - 1 || gso_final || !use_gso); #if defined(SRS_DEBUG) - srs_trace("packet SSRC=%d, SN=%d, %d bytes", packet->rtp_header.get_ssrc(), + bool is_video = packet->rtp_header.get_payload_type() == video_payload_type; + srs_trace("Packet %s SSRC=%d, SN=%d, %d bytes", is_video? "Video":"Audio", packet->rtp_header.get_ssrc(), packet->rtp_header.get_sequence(), nn_packet); if (do_send) { for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { @@ -988,6 +990,9 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac } #endif + // When we send out a packet, we commit a RTP packet. + packets.nn_rtp_pkts++; + if ((err = sender->sendmmsg(mhdr)) != srs_success) { return srs_error_wrap(err, "send msghdr"); } @@ -998,6 +1003,11 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac } } +#if defined(SRS_DEBUG) + srs_trace("GSO packets, rtp %d/%d, videos %d/%d", packets.packets.size(), + packets.nn_rtp_pkts, packets.nn_videos, packets.nn_samples, packets.nn_audios, packets.nn_extras); +#endif + return err; } @@ -1816,6 +1826,7 @@ srs_error_t SrsUdpMuxSender::cycle() mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; for (p = &hotspot[0]; p < end; p++) { if (!p->msg_len) { + stat->perf_gso_on_packets(1); continue; } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 89c46e916..2ffe75441 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -117,17 +117,26 @@ private: srs_error_t srtp_recv_init(); }; +// A group of RTP packets. class SrsRtcPackets { public: bool use_gso; bool should_merge_nalus; public: + // The total bytes of RTP packets. int nn_bytes; + // The RTP packets send out by sendmmsg or sendmsg. Note that if many packets group to + // one msghdr by GSO, it's only one RTP packet, because we only send once. int nn_rtp_pkts; + // For video, the samples or NALUs. int nn_samples; + // For audio, the generated extra audio packets. + // For example, when transcoding AAC to opus, may many extra payloads for a audio. int nn_extras; + // The original audio messages. int nn_audios; + // The original video messages. int nn_videos; public: std::vector packets; From a80084289b39266fa7a7023bf6237357e02fd7a8 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 20:12:33 +0800 Subject: [PATCH 31/35] Support debug --- trunk/auto/auto_headers.sh | 6 ++++++ trunk/auto/options.sh | 4 ++++ trunk/scripts/perf_gso.py | 2 +- trunk/src/core/srs_core.hpp | 5 +++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/trunk/auto/auto_headers.sh b/trunk/auto/auto_headers.sh index 84b64319b..d77325395 100755 --- a/trunk/auto/auto_headers.sh +++ b/trunk/auto/auto_headers.sh @@ -171,6 +171,12 @@ else srs_undefine_macro "SRS_AUTO_HAS_SENDMMSG" $SRS_AUTO_HEADERS_H fi +if [ $SRS_DEBUG = YES ]; then + srs_define_macro "SRS_AUTO_DEBUG" $SRS_AUTO_HEADERS_H +else + srs_undefine_macro "SRS_AUTO_DEBUG" $SRS_AUTO_HEADERS_H +fi + # prefix echo "" >> $SRS_AUTO_HEADERS_H echo "#define SRS_AUTO_PREFIX \"${SRS_PREFIX}\"" >> $SRS_AUTO_HEADERS_H diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh index 0e31b05fd..69293fce3 100755 --- a/trunk/auto/options.sh +++ b/trunk/auto/options.sh @@ -122,6 +122,7 @@ SRS_NASM=YES SRS_SRTP_ASM=YES SRS_SENDMMSG=YES SRS_HAS_SENDMMSG=YES +SRS_DEBUG=NO ##################################################################################### # menu @@ -162,6 +163,7 @@ Features: --prefix= The absolute installation path for srs. Default: $SRS_PREFIX --static Whether add '-static' to link options. --gcov Whether enable the GCOV compiler options. + --debug Whether enable the debug code, may hurt performance. --jobs[=N] Allow N jobs at once; infinite jobs with no arg. Used for make in the configure, for example, to make ffmpeg. --log-verbose Whether enable the log verbose level. default: no. @@ -293,6 +295,7 @@ function parse_user_option() { --log-info) SRS_LOG_INFO=YES ;; --log-trace) SRS_LOG_TRACE=YES ;; --gcov) SRS_GCOV=YES ;; + --debug) SRS_DEBUG=YES ;; --arm) SRS_CROSS_BUILD=YES ;; --mips) SRS_CROSS_BUILD=YES ;; @@ -623,6 +626,7 @@ function regenerate_options() { if [ $SRS_LOG_INFO = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --log-info"; fi if [ $SRS_LOG_TRACE = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --log-trace"; fi if [ $SRS_GCOV = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gcov"; fi + if [ $SRS_DEBUG = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --debug"; fi if [[ $SRS_EXTRA_FLAGS != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --extra-flags=\\\"$SRS_EXTRA_FLAGS\\\""; fi if [[ $SRS_BUILD_TAG != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --build-tag=\\\"$SRS_BUILD_TAG\\\""; fi if [[ $SRS_TOOL_CC != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --cc=$SRS_TOOL_CC"; fi diff --git a/trunk/scripts/perf_gso.py b/trunk/scripts/perf_gso.py index 95ef027b5..75df5e527 100755 --- a/trunk/scripts/perf_gso.py +++ b/trunk/scripts/perf_gso.py @@ -35,7 +35,7 @@ f.close() print "Repsonse %s"%(s) obj = json.loads(s) -keys = [3, 5, 9, 16, 32, 64, 128, 256, 1000] +keys = [1, 3, 5, 9, 16, 32, 64, 256, 1000] print "" print("AV---Frames"), diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index c846214b2..725c1bff4 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -33,6 +33,11 @@ // The macros generated by configure script. #include +// Alias for debug. +#ifdef SRS_AUTO_DEBUG +#define SRS_DEBUG +#endif + // To convert macro values to string. // @see https://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification #define SRS_INTERNAL_STR(v) #v From 6cf9933bf38ccb3e24dff8b7f5e104bc8d7c3742 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 21:49:49 +0800 Subject: [PATCH 32/35] For #307, refine gperf api --- trunk/scripts/perf_gso.py | 36 ++- trunk/src/app/srs_app_http_api.cpp | 41 +++- trunk/src/app/srs_app_rtc_conn.cpp | 14 +- trunk/src/app/srs_app_statistic.cpp | 329 ++++++++------------------ trunk/src/app/srs_app_statistic.hpp | 42 +++- trunk/src/protocol/srs_rtmp_stack.cpp | 6 +- trunk/src/protocol/srs_rtmp_stack.hpp | 5 +- 7 files changed, 206 insertions(+), 267 deletions(-) diff --git a/trunk/scripts/perf_gso.py b/trunk/scripts/perf_gso.py index 75df5e527..7b9ef4749 100755 --- a/trunk/scripts/perf_gso.py +++ b/trunk/scripts/perf_gso.py @@ -35,16 +35,25 @@ f.close() print "Repsonse %s"%(s) obj = json.loads(s) -keys = [1, 3, 5, 9, 16, 32, 64, 256, 1000] + +# 2, 3, 5, 9, 16, 32, 64, 128, 256 +keys = ['lt_2', 'lt_3', 'lt_5', 'lt_9', 'lt_16', 'lt_32', 'lt_64', 'lt_128', 'lt_256', 'gt_256'] print "" print("AV---Frames"), for k in keys: - k2 = 'lt_%s'%(k) - if 'frames' in obj['data']: - p = obj['data']['frames']['msgs'] + k2 = '%s'%(k) + p = obj['data']['avframes'] + if k2 in p: + print(p[k2]), else: - p = obj['data']['writev']['msgs'] + print(0), + +print "" +print("RTC--Frames"), +for k in keys: + k2 = '%s'%(k) + p = obj['data']['rtc'] if k2 in p: print(p[k2]), else: @@ -53,11 +62,18 @@ for k in keys: print "" print("RTP-Packets"), for k in keys: - k2 = 'lt_%s'%(k) - if 'frames' in obj['data']: - p = obj['data']['frames']['iovs'] - else: - p = obj['data']['writev']['iovs'] + k2 = '%s'%(k) + p = obj['data']['rtp'] + if k2 in p: + print(p[k2]), + else: + print(0), + +print "" +print("GSO-Packets"), +for k in keys: + k2 = '%s'%(k) + p = obj['data']['gso'] if k2 in p: print(p[k2]), else: diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index e3f36604c..6a83f7a8c 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1622,13 +1622,40 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* data->set("query", p); p->set("target", SrsJsonAny::str(target.c_str())); - p->set("help", SrsJsonAny::str("?target=frames|sendmmsg|gso")); + p->set("help", SrsJsonAny::str("?target=avframes|rtc|rtp|gso|writev_iovs|sendmmsg")); } - if (target.empty() || target == "frames") { + if (target.empty() || target == "avframes") { SrsJsonObject* p = SrsJsonAny::object(); - data->set("frames", p); - if ((err = stat->dumps_perf_writev(p)) != srs_success) { + data->set("avframes", p); + if ((err = stat->dumps_perf_msgs(p)) != srs_success) { + int code = srs_error_code(err); srs_error_reset(err); + return srs_api_response_code(w, r, code); + } + } + + if (target.empty() || target == "rtc") { + SrsJsonObject* p = SrsJsonAny::object(); + data->set("rtc", p); + if ((err = stat->dumps_perf_rtc_packets(p)) != srs_success) { + int code = srs_error_code(err); srs_error_reset(err); + return srs_api_response_code(w, r, code); + } + } + + if (target.empty() || target == "rtp") { + SrsJsonObject* p = SrsJsonAny::object(); + data->set("rtp", p); + if ((err = stat->dumps_perf_rtp_packets(p)) != srs_success) { + int code = srs_error_code(err); srs_error_reset(err); + return srs_api_response_code(w, r, code); + } + } + + if (target.empty() || target == "gso") { + SrsJsonObject* p = SrsJsonAny::object(); + data->set("gso", p); + if ((err = stat->dumps_perf_gso(p)) != srs_success) { int code = srs_error_code(err); srs_error_reset(err); return srs_api_response_code(w, r, code); } @@ -1643,10 +1670,10 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* } } - if (target.empty() || target == "gso") { + if (target.empty() || target == "writev_iovs") { SrsJsonObject* p = SrsJsonAny::object(); - data->set("gso", p); - if ((err = stat->dumps_perf_gso(p)) != srs_success) { + data->set("writev_iovs", p); + if ((err = stat->dumps_perf_writev_iovs(p)) != srs_success) { int code = srs_error_code(err); srs_error_reset(err); return srs_api_response_code(w, r, code); } diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 811cad324..4a00f0c22 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -649,7 +649,14 @@ srs_error_t SrsRtcSenderThread::cycle() srs_freep(msg); } - stat->perf_mw_on_msgs(msg_count, pkts.nn_bytes, pkts.nn_rtp_pkts); + // Stat the original RAW AV frame, maybe h264+aac. + stat->perf_on_msgs(msg_count); + // Stat the RTC packets, RAW AV frame, maybe h.264+opus. + stat->perf_on_rtc_packets(srs_max(pkts.nn_audios, pkts.nn_extras) + pkts.nn_videos); + // Stat the RAW RTP packets, which maybe group by GSO. + stat->perf_on_rtp_packets(pkts.packets.size()); + // Stat the RTP packets going into kernel. + stat->perf_gso_on_packets(pkts.nn_rtp_pkts); pprint->elapse(); if (pprint->can_print()) { @@ -957,6 +964,9 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac if (do_send) { for (int j = 0; j < (int)mhdr->msg_hdr.msg_iovlen; j++) { iovec* iov = mhdr->msg_hdr.msg_iov + j; + if (iov->iov_len <= 0) { + break; + } srs_trace("%s #%d/%d/%d, %d bytes, size %d/%d", (use_gso? "GSO":"RAW"), j, gso_cursor + 1, mhdr->msg_hdr.msg_iovlen, iov->iov_len, gso_size, gso_encrypt); } @@ -1004,7 +1014,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac } #if defined(SRS_DEBUG) - srs_trace("GSO packets, rtp %d/%d, videos %d/%d", packets.packets.size(), + srs_trace("Summary packets, rtp %d/%d, videos %d/%d, audios %d/%d", packets.packets.size(), packets.nn_rtp_pkts, packets.nn_videos, packets.nn_samples, packets.nn_audios, packets.nn_extras); #endif diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index a58d5f57a..8c8d628cf 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -267,6 +267,8 @@ SrsStatistic::SrsStatistic() perf_msgs = new SrsStatisticCategory(); perf_sendmmsg = new SrsStatisticCategory(); perf_gso = new SrsStatisticCategory(); + perf_rtp = new SrsStatisticCategory(); + perf_rtc = new SrsStatisticCategory(); } SrsStatistic::~SrsStatistic() @@ -305,6 +307,8 @@ SrsStatistic::~SrsStatistic() srs_freep(perf_msgs); srs_freep(perf_sendmmsg); srs_freep(perf_gso); + srs_freep(perf_rtp); + srs_freep(perf_rtc); } SrsStatistic* SrsStatistic::instance() @@ -585,272 +589,131 @@ srs_error_t SrsStatistic::dumps_clients(SrsJsonArray* arr, int start, int count) return err; } -void SrsStatistic::perf_mw_on_msgs(int nb_msgs, int bytes_msgs, int nb_iovs) +void SrsStatistic::perf_on_msgs(int nb_msgs) { - // For perf msgs, the nb_msgs stat. - // a: <3 - // b: <5 - // c: <9 - // d: <16 - // e: <32 - // f: <64 - // g: <128 - // h: <256 - // i: <1000 - // j: >=1000 - if (nb_msgs < 3) { - perf_msgs->a++; - } else if (nb_msgs < 5) { - perf_msgs->b++; - } else if (nb_msgs < 9) { - perf_msgs->c++; - } else if (nb_msgs < 16) { - perf_msgs->d++; - } else if (nb_msgs < 32) { - perf_msgs->e++; - } else if (nb_msgs < 64) { - perf_msgs->f++; - } else if (nb_msgs < 128) { - perf_msgs->g++; - } else if (nb_msgs < 256) { - perf_msgs->h++; - } else if (nb_msgs < 1000) { - perf_msgs->i++; - } else { - perf_msgs->j++; - } - - // For perf iovs, the nb_iovs stat. - // a: <3 - // b: <5 - // c: <9 - // d: <16 - // e: <32 - // f: <64 - // g: <128 - // h: <256 - // i: <1000 - // j: >=1000 - if (nb_iovs < 3) { - perf_iovs->a++; - } else if (nb_iovs < 5) { - perf_iovs->b++; - } else if (nb_iovs < 9) { - perf_iovs->c++; - } else if (nb_iovs < 16) { - perf_iovs->d++; - } else if (nb_iovs < 32) { - perf_iovs->e++; - } else if (nb_iovs < 64) { - perf_iovs->f++; - } else if (nb_iovs < 128) { - perf_iovs->g++; - } else if (nb_iovs < 256) { - perf_iovs->h++; - } else if (nb_iovs < 1000) { - perf_iovs->i++; - } else { - perf_iovs->j++; - } + perf_on_packets(perf_msgs, nb_msgs); } -srs_error_t SrsStatistic::dumps_perf_writev(SrsJsonObject* obj) +srs_error_t SrsStatistic::dumps_perf_msgs(SrsJsonObject* obj) { - srs_error_t err = srs_success; - - if (true) { - SrsJsonObject* p = SrsJsonAny::object(); - obj->set("msgs", p); - - // For perf msgs, the nb_msgs stat. - // a: <3 - // b: <5 - // c: <9 - // d: <16 - // e: <32 - // f: <64 - // g: <128 - // h: <256 - // i: <1000 - // j: >=1000 - if (perf_msgs->a) p->set("lt_3", SrsJsonAny::integer(perf_msgs->a)); - if (perf_msgs->b) p->set("lt_5", SrsJsonAny::integer(perf_msgs->b)); - if (perf_msgs->c) p->set("lt_9", SrsJsonAny::integer(perf_msgs->c)); - if (perf_msgs->d) p->set("lt_16", SrsJsonAny::integer(perf_msgs->d)); - if (perf_msgs->e) p->set("lt_32", SrsJsonAny::integer(perf_msgs->e)); - if (perf_msgs->f) p->set("lt_64", SrsJsonAny::integer(perf_msgs->f)); - if (perf_msgs->g) p->set("lt_128", SrsJsonAny::integer(perf_msgs->g)); - if (perf_msgs->h) p->set("lt_256", SrsJsonAny::integer(perf_msgs->h)); - if (perf_msgs->i) p->set("lt_1000", SrsJsonAny::integer(perf_msgs->i)); - if (perf_msgs->j) p->set("gt_1000", SrsJsonAny::integer(perf_msgs->j)); - } - - if (true) { - SrsJsonObject* p = SrsJsonAny::object(); - obj->set("iovs", p); - - // For perf iovs, the nb_iovs stat. - // a: <3 - // b: <5 - // c: <9 - // d: <16 - // e: <32 - // f: <64 - // g: <128 - // h: <256 - // i: <1000 - // j: >=1000 - if (perf_iovs->a) p->set("lt_3", SrsJsonAny::integer(perf_iovs->a)); - if (perf_iovs->b) p->set("lt_5", SrsJsonAny::integer(perf_iovs->b)); - if (perf_iovs->c) p->set("lt_9", SrsJsonAny::integer(perf_iovs->c)); - if (perf_iovs->d) p->set("lt_16", SrsJsonAny::integer(perf_iovs->d)); - if (perf_iovs->e) p->set("lt_32", SrsJsonAny::integer(perf_iovs->e)); - if (perf_iovs->f) p->set("lt_64", SrsJsonAny::integer(perf_iovs->f)); - if (perf_iovs->g) p->set("lt_128", SrsJsonAny::integer(perf_iovs->g)); - if (perf_iovs->h) p->set("lt_256", SrsJsonAny::integer(perf_iovs->h)); - if (perf_iovs->i) p->set("lt_1000", SrsJsonAny::integer(perf_iovs->i)); - if (perf_iovs->j) p->set("gt_1000", SrsJsonAny::integer(perf_iovs->j)); - } - - return err; + return dumps_perf(perf_msgs, obj); } -void SrsStatistic::perf_sendmmsg_on_packets(int nb_msgs) +void SrsStatistic::perf_on_rtc_packets(int nb_packets) { - // For perf msgs, the nb_msgs stat. - // a: =1 - // b: <10 - // c: <100 - // d: <200 - // e: <300 - // f: <400 - // g: <500 - // h: <600 - // i: <1000 - // j: >=1000 - if (nb_msgs == 1) { - perf_sendmmsg->a++; - } else if (nb_msgs < 10) { - perf_sendmmsg->b++; - } else if (nb_msgs < 100) { - perf_sendmmsg->c++; - } else if (nb_msgs < 200) { - perf_sendmmsg->d++; - } else if (nb_msgs < 300) { - perf_sendmmsg->e++; - } else if (nb_msgs < 400) { - perf_sendmmsg->f++; - } else if (nb_msgs < 500) { - perf_sendmmsg->g++; - } else if (nb_msgs < 600) { - perf_sendmmsg->h++; - } else if (nb_msgs < 1000) { - perf_sendmmsg->i++; - } else { - perf_sendmmsg->j++; - } + perf_on_packets(perf_rtc, nb_packets); +} + +srs_error_t SrsStatistic::dumps_perf_rtc_packets(SrsJsonObject* obj) +{ + return dumps_perf(perf_rtc, obj); +} + +void SrsStatistic::perf_on_rtp_packets(int nb_packets) +{ + perf_on_packets(perf_rtp, nb_packets); +} + +srs_error_t SrsStatistic::dumps_perf_rtp_packets(SrsJsonObject* obj) +{ + return dumps_perf(perf_rtp, obj); +} + +void SrsStatistic::perf_gso_on_packets(int nb_packets) +{ + perf_on_packets(perf_gso, nb_packets); +} + +srs_error_t SrsStatistic::dumps_perf_gso(SrsJsonObject* obj) +{ + return dumps_perf(perf_gso, obj); +} + +void SrsStatistic::perf_on_writev_iovs(int nb_iovs) +{ + perf_on_packets(perf_iovs, nb_iovs); +} + +srs_error_t SrsStatistic::dumps_perf_writev_iovs(SrsJsonObject* obj) +{ + return dumps_perf(perf_iovs, obj); +} + +void SrsStatistic::perf_sendmmsg_on_packets(int nb_packets) +{ + perf_on_packets(perf_sendmmsg, nb_packets); } srs_error_t SrsStatistic::dumps_perf_sendmmsg(SrsJsonObject* obj) { - srs_error_t err = srs_success; - - if (true) { - SrsJsonObject* p = SrsJsonAny::object(); - obj->set("msgs", p); - - // For perf msgs, the nb_msgs stat. - // a: =1 - // b: <10 - // c: <100 - // d: <200 - // e: <300 - // f: <400 - // g: <500 - // h: <600 - // i: <1000 - // j: >=1000 - if (perf_sendmmsg->a) p->set("lt_2", SrsJsonAny::integer(perf_sendmmsg->a)); - if (perf_sendmmsg->b) p->set("lt_10", SrsJsonAny::integer(perf_sendmmsg->b)); - if (perf_sendmmsg->c) p->set("lt_100", SrsJsonAny::integer(perf_sendmmsg->c)); - if (perf_sendmmsg->d) p->set("lt_200", SrsJsonAny::integer(perf_sendmmsg->d)); - if (perf_sendmmsg->e) p->set("lt_300", SrsJsonAny::integer(perf_sendmmsg->e)); - if (perf_sendmmsg->f) p->set("lt_400", SrsJsonAny::integer(perf_sendmmsg->f)); - if (perf_sendmmsg->g) p->set("lt_500", SrsJsonAny::integer(perf_sendmmsg->g)); - if (perf_sendmmsg->h) p->set("lt_600", SrsJsonAny::integer(perf_sendmmsg->h)); - if (perf_sendmmsg->i) p->set("lt_1000", SrsJsonAny::integer(perf_sendmmsg->i)); - if (perf_sendmmsg->j) p->set("gt_1000", SrsJsonAny::integer(perf_sendmmsg->j)); - } - - return err; + return dumps_perf(perf_sendmmsg, obj); } -void SrsStatistic::perf_gso_on_packets(int nb_msgs) +void SrsStatistic::perf_on_packets(SrsStatisticCategory* p, int nb_msgs) { - // For perf msgs, the nb_msgs stat. - // a: =1 + // The range for stat: + // 2, 3, 5, 9, 16, 32, 64, 128, 256 + // that is: + // a: <2 // b: <3 - // c: <6 + // c: <5 // d: <9 // e: <16 // f: <32 // g: <64 // h: <128 - // i: <512 - // j: >=512 - if (nb_msgs == 1) { - perf_gso->a++; + // i: <256 + // j: >=256 + if (nb_msgs < 2) { + p->a++; } else if (nb_msgs < 3) { - perf_gso->b++; - } else if (nb_msgs < 6) { - perf_gso->c++; + p->b++; + } else if (nb_msgs < 5) { + p->c++; } else if (nb_msgs < 9) { - perf_gso->d++; + p->d++; } else if (nb_msgs < 16) { - perf_gso->e++; + p->e++; } else if (nb_msgs < 32) { - perf_gso->f++; + p->f++; } else if (nb_msgs < 64) { - perf_gso->g++; + p->g++; } else if (nb_msgs < 128) { - perf_gso->h++; - } else if (nb_msgs < 512) { - perf_gso->i++; + p->h++; + } else if (nb_msgs < 256) { + p->i++; } else { - perf_gso->j++; + p->j++; } } -srs_error_t SrsStatistic::dumps_perf_gso(SrsJsonObject* obj) +srs_error_t SrsStatistic::dumps_perf(SrsStatisticCategory* p, SrsJsonObject* obj) { srs_error_t err = srs_success; - if (true) { - SrsJsonObject* p = SrsJsonAny::object(); - obj->set("msgs", p); - - // For perf msgs, the nb_msgs stat. - // a: =1 - // b: <3 - // c: <6 - // d: <9 - // e: <16 - // f: <32 - // g: <64 - // h: <128 - // i: <512 - // j: >=512 - if (perf_gso->a) p->set("lt_2", SrsJsonAny::integer(perf_gso->a)); - if (perf_gso->b) p->set("lt_3", SrsJsonAny::integer(perf_gso->b)); - if (perf_gso->c) p->set("lt_6", SrsJsonAny::integer(perf_gso->c)); - if (perf_gso->d) p->set("lt_9", SrsJsonAny::integer(perf_gso->d)); - if (perf_gso->e) p->set("lt_16", SrsJsonAny::integer(perf_gso->e)); - if (perf_gso->f) p->set("lt_32", SrsJsonAny::integer(perf_gso->f)); - if (perf_gso->g) p->set("lt_64", SrsJsonAny::integer(perf_gso->g)); - if (perf_gso->h) p->set("lt_128", SrsJsonAny::integer(perf_gso->h)); - if (perf_gso->i) p->set("lt_512", SrsJsonAny::integer(perf_gso->i)); - if (perf_gso->j) p->set("gt_512", SrsJsonAny::integer(perf_gso->j)); - } + // The range for stat: + // 2, 3, 5, 9, 16, 32, 64, 128, 256 + // that is: + // a: <2 + // b: <3 + // c: <5 + // d: <9 + // e: <16 + // f: <32 + // g: <64 + // h: <128 + // i: <256 + // j: >=256 + if (p->a) obj->set("lt_2", SrsJsonAny::integer(p->a)); + if (p->b) obj->set("lt_3", SrsJsonAny::integer(p->b)); + if (p->c) obj->set("lt_5", SrsJsonAny::integer(p->c)); + if (p->d) obj->set("lt_9", SrsJsonAny::integer(p->d)); + if (p->e) obj->set("lt_16", SrsJsonAny::integer(p->e)); + if (p->f) obj->set("lt_32", SrsJsonAny::integer(p->f)); + if (p->g) obj->set("lt_64", SrsJsonAny::integer(p->g)); + if (p->h) obj->set("lt_128", SrsJsonAny::integer(p->h)); + if (p->i) obj->set("lt_256", SrsJsonAny::integer(p->i)); + if (p->j) obj->set("gt_256", SrsJsonAny::integer(p->j)); return err; } diff --git a/trunk/src/app/srs_app_statistic.hpp b/trunk/src/app/srs_app_statistic.hpp index ae73f49de..4626e2d82 100644 --- a/trunk/src/app/srs_app_statistic.hpp +++ b/trunk/src/app/srs_app_statistic.hpp @@ -170,6 +170,8 @@ private: SrsStatisticCategory* perf_msgs; SrsStatisticCategory* perf_sendmmsg; SrsStatisticCategory* perf_gso; + SrsStatisticCategory* perf_rtp; + SrsStatisticCategory* perf_rtc; private: SrsStatistic(); virtual ~SrsStatistic(); @@ -228,21 +230,39 @@ public: // @param count the max count of clients to dump. virtual srs_error_t dumps_clients(SrsJsonArray* arr, int start, int count); public: - // Stat for packets merged written, nb_msgs is the number of RTMP messages, - // bytes_msgs is the total bytes of RTMP messages, nb_iovs is the total number of iovec. - virtual void perf_mw_on_msgs(int nb_msgs, int bytes_msgs, int nb_iovs); - // Dumps the perf statistic data for TCP writev, for performance analysis. - virtual srs_error_t dumps_perf_writev(SrsJsonObject* obj); + // Stat for packets merged written, nb_msgs is the number of RTMP messages. + // For example, publish by FFMPEG, Audio and Video frames. + virtual void perf_on_msgs(int nb_msgs); + virtual srs_error_t dumps_perf_msgs(SrsJsonObject* obj); public: - // Stat for packets UDP sendmmsg, nb_msgs is the vlen for sendmmsg. - virtual void perf_sendmmsg_on_packets(int nb_msgs); - // Dumps the perf statistic data for UDP sendmmsg, for performance analysis. - virtual srs_error_t dumps_perf_sendmmsg(SrsJsonObject* obj); + // Stat for packets merged written, nb_packets is the number of RTC packets. + // For example, a RTMP/AAC audio packet maybe transcoded to two RTC/opus packets. + virtual void perf_on_rtc_packets(int nb_packets); + virtual srs_error_t dumps_perf_rtc_packets(SrsJsonObject* obj); public: - // Stat for packets UDP GSO, nb_msgs is the vlen for sendmmsg. - virtual void perf_gso_on_packets(int nb_msgs); + // Stat for packets merged written, nb_packets is the number of RTP packets. + // For example, a RTC/opus packet maybe package to three RTP packets. + virtual void perf_on_rtp_packets(int nb_packets); + // Dumps the perf statistic data for RTP packets, for performance analysis. + virtual srs_error_t dumps_perf_rtp_packets(SrsJsonObject* obj); +public: + // Stat for packets UDP GSO, nb_packets is the merged RTP packets. + // For example, three RTP/audio packets maybe GSO to one msghdr. + virtual void perf_gso_on_packets(int nb_packets); // Dumps the perf statistic data for UDP GSO, for performance analysis. virtual srs_error_t dumps_perf_gso(SrsJsonObject* obj); +public: + // Stat for TCP writev, nb_iovs is the total number of iovec. + virtual void perf_on_writev_iovs(int nb_iovs); + virtual srs_error_t dumps_perf_writev_iovs(SrsJsonObject* obj); +public: + // Stat for packets UDP sendmmsg, nb_packets is the vlen for sendmmsg. + virtual void perf_sendmmsg_on_packets(int nb_packets); + // Dumps the perf statistic data for UDP sendmmsg, for performance analysis. + virtual srs_error_t dumps_perf_sendmmsg(SrsJsonObject* obj); +private: + virtual void perf_on_packets(SrsStatisticCategory* p, int nb_msgs); + virtual srs_error_t dumps_perf(SrsStatisticCategory* p, SrsJsonObject* obj); private: virtual SrsStatisticVhost* create_vhost(SrsRequest* req); virtual SrsStatisticStream* create_stream(SrsStatisticVhost* vhost, SrsRequest* req); diff --git a/trunk/src/protocol/srs_rtmp_stack.cpp b/trunk/src/protocol/srs_rtmp_stack.cpp index 835746805..4b11e5ec3 100644 --- a/trunk/src/protocol/srs_rtmp_stack.cpp +++ b/trunk/src/protocol/srs_rtmp_stack.cpp @@ -548,7 +548,8 @@ srs_error_t SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msg // Notify about perf stat. if (perf) { - perf->perf_mw_on_msgs(nb_msgs_merged_written, bytes_msgs_merged_written, iov_index); + perf->perf_on_msgs(nb_msgs_merged_written); + perf->perf_on_writev_iovs(iov_index); nb_msgs_merged_written = 0; bytes_msgs_merged_written = 0; } @@ -576,7 +577,8 @@ srs_error_t SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msg // Notify about perf stat. if (perf) { - perf->perf_mw_on_msgs(nb_msgs_merged_written, bytes_msgs_merged_written, iov_index); + perf->perf_on_msgs(nb_msgs_merged_written); + perf->perf_on_writev_iovs(iov_index); nb_msgs_merged_written = 0; bytes_msgs_merged_written = 0; } diff --git a/trunk/src/protocol/srs_rtmp_stack.hpp b/trunk/src/protocol/srs_rtmp_stack.hpp index eea0c5a50..6f311383f 100644 --- a/trunk/src/protocol/srs_rtmp_stack.hpp +++ b/trunk/src/protocol/srs_rtmp_stack.hpp @@ -155,8 +155,9 @@ public: virtual ~ISrsProtocolPerf(); public: // Stat for packets merged written, nb_msgs is the number of RTMP messages, - // bytes_msgs is the total bytes of RTMP messages, nb_iovs is the total number of iovec. - virtual void perf_mw_on_msgs(int nb_msgs, int bytes_msgs, int nb_iovs) = 0; + virtual void perf_on_msgs(int nb_msgs) = 0; + // Stat for TCP writev, nb_iovs is the total number of iovec. + virtual void perf_on_writev_iovs(int nb_iovs) = 0; }; // The protocol provides the rtmp-message-protocol services, From 649f2042daa310c58a873b743c033d10f1783c4d Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 14 Apr 2020 22:16:14 +0800 Subject: [PATCH 33/35] Update perf tool --- trunk/scripts/perf_gso.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/trunk/scripts/perf_gso.py b/trunk/scripts/perf_gso.py index 7b9ef4749..560763e4c 100755 --- a/trunk/scripts/perf_gso.py +++ b/trunk/scripts/perf_gso.py @@ -25,8 +25,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import urllib, sys, json url = "http://localhost:1985/api/v1/perf" -if len(sys.argv) > 1: - url = sys.argv[1] +if len(sys.argv) < 2: + print "Usage: %s "%(sys.argv[0]) + print "For example:" + print " %s http://localhost:1985/api/v1/perf"%(sys.argv[0]) + sys.exit(-1) + +url = sys.argv[1] print "Open %s"%(url) f = urllib.urlopen(url) From dd7b5cf53f583d77a9a765618002b864d2db4566 Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 15 Apr 2020 06:44:09 +0800 Subject: [PATCH 34/35] Fix GSO stat bug --- trunk/src/app/srs_app_rtc_conn.cpp | 4 +--- trunk/src/app/srs_app_statistic.cpp | 2 +- trunk/src/app/srs_app_statistic.hpp | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 4a00f0c22..6cb23f552 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -656,7 +656,7 @@ srs_error_t SrsRtcSenderThread::cycle() // Stat the RAW RTP packets, which maybe group by GSO. stat->perf_on_rtp_packets(pkts.packets.size()); // Stat the RTP packets going into kernel. - stat->perf_gso_on_packets(pkts.nn_rtp_pkts); + stat->perf_on_gso_packets(pkts.nn_rtp_pkts); pprint->elapse(); if (pprint->can_print()) { @@ -1836,7 +1836,6 @@ srs_error_t SrsUdpMuxSender::cycle() mmsghdr* p = &hotspot[0]; mmsghdr* end = p + pos; for (p = &hotspot[0]; p < end; p++) { if (!p->msg_len) { - stat->perf_gso_on_packets(1); continue; } @@ -1845,7 +1844,6 @@ srs_error_t SrsUdpMuxSender::cycle() p->msg_len = 0; gso_pos++; nn_gso_msgs++; nn_gso_iovs += real_iovs; gso_iovs += real_iovs; - stat->perf_gso_on_packets(real_iovs); } } diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index 8c8d628cf..ccbdabfe8 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -619,7 +619,7 @@ srs_error_t SrsStatistic::dumps_perf_rtp_packets(SrsJsonObject* obj) return dumps_perf(perf_rtp, obj); } -void SrsStatistic::perf_gso_on_packets(int nb_packets) +void SrsStatistic::perf_on_gso_packets(int nb_packets) { perf_on_packets(perf_gso, nb_packets); } diff --git a/trunk/src/app/srs_app_statistic.hpp b/trunk/src/app/srs_app_statistic.hpp index 4626e2d82..0926fce0c 100644 --- a/trunk/src/app/srs_app_statistic.hpp +++ b/trunk/src/app/srs_app_statistic.hpp @@ -248,7 +248,7 @@ public: public: // Stat for packets UDP GSO, nb_packets is the merged RTP packets. // For example, three RTP/audio packets maybe GSO to one msghdr. - virtual void perf_gso_on_packets(int nb_packets); + virtual void perf_on_gso_packets(int nb_packets); // Dumps the perf statistic data for UDP GSO, for performance analysis. virtual srs_error_t dumps_perf_gso(SrsJsonObject* obj); public: From c143c80fd644e3a78d4e7dc19532693b4b9adb1a Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 15 Apr 2020 07:10:41 +0800 Subject: [PATCH 35/35] Fix GSO stat bug --- trunk/scripts/perf_gso.py | 12 ++++++++---- trunk/src/app/srs_app_rtc_conn.cpp | 10 ++++++++-- trunk/src/app/srs_app_statistic.cpp | 6 ++++++ trunk/src/app/srs_app_statistic.hpp | 2 ++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/trunk/scripts/perf_gso.py b/trunk/scripts/perf_gso.py index 560763e4c..707e6c6b5 100755 --- a/trunk/scripts/perf_gso.py +++ b/trunk/scripts/perf_gso.py @@ -46,41 +46,45 @@ keys = ['lt_2', 'lt_3', 'lt_5', 'lt_9', 'lt_16', 'lt_32', 'lt_64', 'lt_128', 'lt print "" print("AV---Frames"), +p = obj['data']['avframes'] for k in keys: k2 = '%s'%(k) - p = obj['data']['avframes'] if k2 in p: print(p[k2]), else: print(0), +print(p['nn']), print "" print("RTC--Frames"), +p = obj['data']['rtc'] for k in keys: k2 = '%s'%(k) - p = obj['data']['rtc'] if k2 in p: print(p[k2]), else: print(0), +print(p['nn']), print "" print("RTP-Packets"), +p = obj['data']['rtp'] for k in keys: k2 = '%s'%(k) - p = obj['data']['rtp'] if k2 in p: print(p[k2]), else: print(0), +print(p['nn']), print "" print("GSO-Packets"), +p = obj['data']['gso'] for k in keys: k2 = '%s'%(k) - p = obj['data']['gso'] if k2 in p: print(p[k2]), else: print(0), +print(p['nn']), diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 6cb23f552..a01e6305c 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -652,11 +652,17 @@ srs_error_t SrsRtcSenderThread::cycle() // Stat the original RAW AV frame, maybe h264+aac. stat->perf_on_msgs(msg_count); // Stat the RTC packets, RAW AV frame, maybe h.264+opus. - stat->perf_on_rtc_packets(srs_max(pkts.nn_audios, pkts.nn_extras) + pkts.nn_videos); + int nn_rtc_packets = srs_max(pkts.nn_audios, pkts.nn_extras) + pkts.nn_videos; + stat->perf_on_rtc_packets(nn_rtc_packets); // Stat the RAW RTP packets, which maybe group by GSO. stat->perf_on_rtp_packets(pkts.packets.size()); // Stat the RTP packets going into kernel. stat->perf_on_gso_packets(pkts.nn_rtp_pkts); +#if defined(SRS_DEBUG) + srs_trace("RTC PLAY packets, msgs %d/%d, rtp %d, gso %d, %d audios, %d extras, %d videos, %d samples, %d bytes", + msg_count, nn_rtc_packets, pkts.packets.size(), pkts.nn_rtp_pkts, pkts.nn_audios, pkts.nn_extras, pkts.nn_videos, + pkts.nn_samples, pkts.nn_bytes); +#endif pprint->elapse(); if (pprint->can_print()) { @@ -1014,7 +1020,7 @@ srs_error_t SrsRtcSenderThread::send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPac } #if defined(SRS_DEBUG) - srs_trace("Summary packets, rtp %d/%d, videos %d/%d, audios %d/%d", packets.packets.size(), + srs_trace("RTC PLAY summary, rtp %d/%d, videos %d/%d, audios %d/%d", packets.packets.size(), packets.nn_rtp_pkts, packets.nn_videos, packets.nn_samples, packets.nn_audios, packets.nn_extras); #endif diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index ccbdabfe8..01abcd446 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -236,6 +236,8 @@ srs_error_t SrsStatisticClient::dumps(SrsJsonObject* obj) SrsStatisticCategory::SrsStatisticCategory() { + nn = 0; + a = 0; b = 0; c = 0; @@ -685,6 +687,8 @@ void SrsStatistic::perf_on_packets(SrsStatisticCategory* p, int nb_msgs) } else { p->j++; } + + p->nn += nb_msgs; } srs_error_t SrsStatistic::dumps_perf(SrsStatisticCategory* p, SrsJsonObject* obj) @@ -715,6 +719,8 @@ srs_error_t SrsStatistic::dumps_perf(SrsStatisticCategory* p, SrsJsonObject* obj if (p->i) obj->set("lt_256", SrsJsonAny::integer(p->i)); if (p->j) obj->set("gt_256", SrsJsonAny::integer(p->j)); + obj->set("nn", SrsJsonAny::integer(p->nn)); + return err; } diff --git a/trunk/src/app/srs_app_statistic.hpp b/trunk/src/app/srs_app_statistic.hpp index 0926fce0c..0d9905f75 100644 --- a/trunk/src/app/srs_app_statistic.hpp +++ b/trunk/src/app/srs_app_statistic.hpp @@ -124,6 +124,8 @@ public: class SrsStatisticCategory { +public: + uint64_t nn; public: uint64_t a; uint64_t b;