winlin

for bug #251, support mic(message iovs cache). 2.0.61

@@ -634,6 +634,10 @@ SrsSource::SrsSource(SrsRequest* req) @@ -634,6 +634,10 @@ SrsSource::SrsSource(SrsRequest* req)
634 634
635 _srs_config->subscribe(this); 635 _srs_config->subscribe(this);
636 atc = _srs_config->get_atc(_req->vhost); 636 atc = _srs_config->get_atc(_req->vhost);
  637 +
  638 +#ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  639 + chunk_size = 0;
  640 +#endif
637 } 641 }
638 642
639 SrsSource::~SrsSource() 643 SrsSource::~SrsSource()
@@ -860,6 +864,26 @@ int SrsSource::on_reload_vhost_dvr(string vhost) @@ -860,6 +864,26 @@ int SrsSource::on_reload_vhost_dvr(string vhost)
860 return ret; 864 return ret;
861 } 865 }
862 866
  867 +int SrsSource::on_reload_vhost_chunk_size(string vhost)
  868 +{
  869 + int ret = ERROR_SUCCESS;
  870 +
  871 + if (_req->vhost != vhost) {
  872 + return ret;
  873 + }
  874 +
  875 +#ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  876 + int size = _srs_config->get_chunk_size(_req->vhost);
  877 + if (chunk_size != size) {
  878 + srs_warn("connected clients will error for mic chunk_size changed %d=>%d",
  879 + chunk_size, size);
  880 + }
  881 + chunk_size = size;
  882 +#endif
  883 +
  884 + return ret;
  885 +}
  886 +
863 int SrsSource::on_reload_vhost_transcode(string vhost) 887 int SrsSource::on_reload_vhost_transcode(string vhost)
864 { 888 {
865 int ret = ERROR_SUCCESS; 889 int ret = ERROR_SUCCESS;
@@ -1089,6 +1113,14 @@ int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata @@ -1089,6 +1113,14 @@ int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata
1089 } 1113 }
1090 srs_verbose("initialize shared ptr metadata success."); 1114 srs_verbose("initialize shared ptr metadata success.");
1091 1115
  1116 +#ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  1117 + if ((ret = cache_metadata->mic_evaluate(chunk_size)) != ERROR_SUCCESS) {
  1118 + srs_error("mic metadata iovs failed, chunk_size=%d. ret=%d", chunk_size, ret);
  1119 + return ret;
  1120 + }
  1121 + srs_info("mic metadata iovs ok, chunk_size=%d", chunk_size);
  1122 +#endif
  1123 +
1092 // copy to all consumer 1124 // copy to all consumer
1093 if (true) { 1125 if (true) {
1094 std::vector<SrsConsumer*>::iterator it; 1126 std::vector<SrsConsumer*>::iterator it;
@@ -1130,6 +1162,14 @@ int SrsSource::on_audio(SrsCommonMessage* __audio) @@ -1130,6 +1162,14 @@ int SrsSource::on_audio(SrsCommonMessage* __audio)
1130 } 1162 }
1131 srs_verbose("initialize shared ptr audio success."); 1163 srs_verbose("initialize shared ptr audio success.");
1132 1164
  1165 +#ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  1166 + if ((ret = msg.mic_evaluate(chunk_size)) != ERROR_SUCCESS) {
  1167 + srs_error("mic audio iovs failed, chunk_size=%d. ret=%d", chunk_size, ret);
  1168 + return ret;
  1169 + }
  1170 + srs_info("mic audio iovs ok, chunk_size=%d", chunk_size);
  1171 +#endif
  1172 +
1133 #ifdef SRS_AUTO_HLS 1173 #ifdef SRS_AUTO_HLS
1134 if ((ret = hls->on_audio(&msg)) != ERROR_SUCCESS) { 1174 if ((ret = hls->on_audio(&msg)) != ERROR_SUCCESS) {
1135 srs_warn("hls process audio message failed, ignore and disable hls. ret=%d", ret); 1175 srs_warn("hls process audio message failed, ignore and disable hls. ret=%d", ret);
@@ -1240,6 +1280,14 @@ int SrsSource::on_video(SrsCommonMessage* __video) @@ -1240,6 +1280,14 @@ int SrsSource::on_video(SrsCommonMessage* __video)
1240 } 1280 }
1241 srs_verbose("initialize shared ptr video success."); 1281 srs_verbose("initialize shared ptr video success.");
1242 1282
  1283 +#ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  1284 + if ((ret = msg.mic_evaluate(chunk_size)) != ERROR_SUCCESS) {
  1285 + srs_error("mic video iovs failed, chunk_size=%d. ret=%d", chunk_size, ret);
  1286 + return ret;
  1287 + }
  1288 + srs_info("mic video iovs ok, chunk_size=%d", chunk_size);
  1289 +#endif
  1290 +
1243 #ifdef SRS_AUTO_HLS 1291 #ifdef SRS_AUTO_HLS
1244 if ((ret = hls->on_video(&msg)) != ERROR_SUCCESS) { 1292 if ((ret = hls->on_video(&msg)) != ERROR_SUCCESS) {
1245 srs_warn("hls process video message failed, ignore and disable hls. ret=%d", ret); 1293 srs_warn("hls process video message failed, ignore and disable hls. ret=%d", ret);
@@ -1491,6 +1539,11 @@ int SrsSource::on_publish() @@ -1491,6 +1539,11 @@ int SrsSource::on_publish()
1491 return ret; 1539 return ret;
1492 } 1540 }
1493 #endif 1541 #endif
  1542 +
  1543 +#ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  1544 + chunk_size = _srs_config->get_chunk_size(_req->vhost);
  1545 + srs_trace("mic use chunk_size=%d to send msgs", chunk_size);
  1546 +#endif
1494 1547
1495 return ret; 1548 return ret;
1496 } 1549 }
@@ -352,6 +352,11 @@ private: @@ -352,6 +352,11 @@ private:
352 std::vector<SrsForwarder*> forwarders; 352 std::vector<SrsForwarder*> forwarders;
353 // for aggregate message 353 // for aggregate message
354 SrsStream* aggregate_stream; 354 SrsStream* aggregate_stream;
  355 +#ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  356 + // the chunk size for mic,
  357 + // update when publish stream.
  358 + int chunk_size;
  359 +#endif
355 private: 360 private:
356 /** 361 /**
357 * the sample rate of audio in metadata. 362 * the sample rate of audio in metadata.
@@ -396,6 +401,7 @@ public: @@ -396,6 +401,7 @@ public:
396 virtual int on_reload_vhost_forward(std::string vhost); 401 virtual int on_reload_vhost_forward(std::string vhost);
397 virtual int on_reload_vhost_hls(std::string vhost); 402 virtual int on_reload_vhost_hls(std::string vhost);
398 virtual int on_reload_vhost_dvr(std::string vhost); 403 virtual int on_reload_vhost_dvr(std::string vhost);
  404 + virtual int on_reload_vhost_chunk_size(std::string vhost);
399 virtual int on_reload_vhost_transcode(std::string vhost); 405 virtual int on_reload_vhost_transcode(std::string vhost);
400 // for the tools callback 406 // for the tools callback
401 public: 407 public:
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR 2 32 #define VERSION_MAJOR 2
33 #define VERSION_MINOR 0 33 #define VERSION_MINOR 0
34 -#define VERSION_REVISION 60 34 +#define VERSION_REVISION 61
35 // server info. 35 // server info.
36 #define RTMP_SIG_SRS_KEY "SRS" 36 #define RTMP_SIG_SRS_KEY "SRS"
37 #define RTMP_SIG_SRS_ROLE "origin/edge server" 37 #define RTMP_SIG_SRS_ROLE "origin/edge server"
@@ -104,6 +104,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -104,6 +104,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
104 */ 104 */
105 #define SRS_PERF_MW_MSGS 128 105 #define SRS_PERF_MW_MSGS 128
106 /** 106 /**
  107 +* use iovs cache in each msg,
  108 +* for the shared ptr message, we calc once and used for every copy.
  109 +* @see https://github.com/winlinvip/simple-rtmp-server/issues/251
  110 +* @remark if enable this, donot use protocol iovs cache.
  111 +* @remark when reload change the chunk size, previous clients error.
  112 +*/
  113 +#undef SRS_PERF_MW_MSG_IOVS_CACHE
  114 +
  115 +/**
107 * whether set the socket send buffer size. 116 * whether set the socket send buffer size.
108 * @see https://github.com/winlinvip/simple-rtmp-server/issues/251 117 * @see https://github.com/winlinvip/simple-rtmp-server/issues/251
109 */ 118 */
@@ -134,6 +134,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -134,6 +134,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
134 #define ERROR_OpenSslSha256DigestSize 2037 134 #define ERROR_OpenSslSha256DigestSize 2037
135 #define ERROR_OpenSslGetPeerPublicKey 2038 135 #define ERROR_OpenSslGetPeerPublicKey 2038
136 #define ERROR_OpenSslComputeSharedKey 2039 136 #define ERROR_OpenSslComputeSharedKey 2039
  137 +#define ERROR_RTMP_MIC_CHUNKSIZE_CHANGED 2040
137 // 138 //
138 // system control message, 139 // system control message,
139 // not an error, but special control logic. 140 // not an error, but special control logic.
@@ -149,6 +149,11 @@ void show_macro_features() @@ -149,6 +149,11 @@ void show_macro_features()
149 #endif 149 #endif
150 srs_trace("system default latency in ms: mw(0-%d) + mr(0-%d) + play-queue(0-%d)", 150 srs_trace("system default latency in ms: mw(0-%d) + mr(0-%d) + play-queue(0-%d)",
151 SRS_PERF_MW_SLEEP, possible_mr_latency, SRS_PERF_PLAY_QUEUE*1000); 151 SRS_PERF_MW_SLEEP, possible_mr_latency, SRS_PERF_PLAY_QUEUE*1000);
  152 +
  153 +#ifndef SRS_PERF_MW_MSG_IOVS_CACHE
  154 + srs_warn("MIC(message iovs cache) enabled, the connected clients will be"
  155 + "disconneted when reload changed the chunk_size.");
  156 +#endif
152 } 157 }
153 158
154 void check_macro_features() 159 void check_macro_features()
@@ -387,16 +387,110 @@ SrsSharedPtrMessage::__SrsSharedPtr::__SrsSharedPtr() @@ -387,16 +387,110 @@ SrsSharedPtrMessage::__SrsSharedPtr::__SrsSharedPtr()
387 payload = NULL; 387 payload = NULL;
388 size = 0; 388 size = 0;
389 shared_count = 0; 389 shared_count = 0;
  390 +
  391 +#ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  392 + nb_iovs = 0;
  393 + iovs = NULL;
  394 + chunk_size = 0;
  395 +#endif
390 } 396 }
391 397
392 SrsSharedPtrMessage::__SrsSharedPtr::~__SrsSharedPtr() 398 SrsSharedPtrMessage::__SrsSharedPtr::~__SrsSharedPtr()
393 { 399 {
394 srs_freep(payload); 400 srs_freep(payload);
  401 +
  402 +#ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  403 + srs_freep(iovs);
  404 +#endif
395 } 405 }
396 406
  407 +#ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  408 +int SrsSharedPtrMessage::__SrsSharedPtr::mic_evaluate(
  409 + SrsMessageHeader* mh, int chunk_size
  410 +) {
  411 + int ret = ERROR_SUCCESS;
  412 +
  413 + // use the chunk size, shuold not be changed.
  414 + this->chunk_size = chunk_size;
  415 +
  416 + // ignore size
  417 + srs_chunk_header(mic_c0, mh, true);
  418 + mic_c3 = 0xC0 | (mh->perfer_cid & 0x3F);
  419 +
  420 + // calc number of iovs
  421 + nb_chunks = mh->payload_length / chunk_size;
  422 + if (mh->payload_length % chunk_size) {
  423 + nb_chunks++;
  424 + }
  425 + nb_iovs = 1/*cid*/ + 1/*size*/ + 1 /*type*/+ 1/*chunk*/;
  426 + // left chunks, always cid+chunk.
  427 + if (nb_chunks > 0) {
  428 + nb_iovs += (nb_chunks - 1) * 2;
  429 + }
  430 +
  431 + // create iovs
  432 + srs_freep(iovs);
  433 + iovs = new iovec[nb_iovs];
  434 +
  435 + // for payload chunks.
  436 + char* p = payload;
  437 + char* end = p + size;
  438 + iovec* iov = iovs + 0;
  439 + while (p < end) {
  440 + // size of payload.
  441 + int payload_size = srs_min(chunk_size, end - p);
  442 +
  443 + // header, c0 or c3
  444 + if (p == payload) {
  445 + // c0, cid+size+type
  446 + // cid, 1B
  447 + iov[0].iov_base = mic_c0;
  448 + iov[0].iov_len = 1;
  449 +
  450 + // size(payload length), 3B
  451 + iov[1].iov_base = mic_c0 + 4;
  452 + iov[1].iov_len = 3;
  453 +
  454 + // type(message type)
  455 + iov[2].iov_base = mic_c0 + 7;
  456 + iov[2].iov_len = 1;
  457 +
  458 + // chunk
  459 + iov[3].iov_base = p;
  460 + iov[3].iov_len = payload_size;
  461 +
  462 + // move to next iovs.
  463 + iov += 4;
  464 + } else {
  465 + // c3
  466 + iov[0].iov_base = &mic_c3;
  467 + iov[0].iov_len = 1;
  468 +
  469 + // chunk
  470 + iov[1].iov_base = p;
  471 + iov[1].iov_len = payload_size;
  472 +
  473 + // move to next iovs.
  474 + iov += 2;
  475 + }
  476 +
  477 + // to next chunk
  478 + p += payload_size;
  479 + }
  480 +
  481 + return ret;
  482 +}
  483 +#endif
  484 +
397 SrsSharedPtrMessage::SrsSharedPtrMessage() 485 SrsSharedPtrMessage::SrsSharedPtrMessage()
398 { 486 {
399 ptr = NULL; 487 ptr = NULL;
  488 +
  489 +#ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  490 + mic_etime_present = false;
  491 + iovs = NULL;
  492 + nb_iovs = 0;
  493 +#endif
400 } 494 }
401 495
402 SrsSharedPtrMessage::~SrsSharedPtrMessage() 496 SrsSharedPtrMessage::~SrsSharedPtrMessage()
@@ -408,6 +502,10 @@ SrsSharedPtrMessage::~SrsSharedPtrMessage() @@ -408,6 +502,10 @@ SrsSharedPtrMessage::~SrsSharedPtrMessage()
408 ptr->shared_count--; 502 ptr->shared_count--;
409 } 503 }
410 } 504 }
  505 +
  506 +#ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  507 + srs_freep(iovs);
  508 +#endif
411 } 509 }
412 510
413 int SrsSharedPtrMessage::create(SrsCommonMessage* msg) 511 int SrsSharedPtrMessage::create(SrsCommonMessage* msg)
@@ -479,6 +577,153 @@ SrsSharedPtrMessage* SrsSharedPtrMessage::copy() @@ -479,6 +577,153 @@ SrsSharedPtrMessage* SrsSharedPtrMessage::copy()
479 return copy; 577 return copy;
480 } 578 }
481 579
  580 +#ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  581 +int SrsSharedPtrMessage::mic_evaluate(int chunk_size)
  582 +{
  583 + int ret = ERROR_SUCCESS;
  584 +
  585 + // when chunk size changed, error to disconnect the client..
  586 + if (ptr->chunk_size > 0 && chunk_size != ptr->chunk_size) {
  587 + ret = ERROR_RTMP_MIC_CHUNKSIZE_CHANGED;
  588 + srs_warn("mic chunk size changed %d=>%d, ret=%d",
  589 + ptr->chunk_size, chunk_size, ret);
  590 + return ret;
  591 + }
  592 +
  593 + // calc the shared ptr iovs at the first time.
  594 + if (ptr->chunk_size <= 0) {
  595 + if ((ret = ptr->mic_evaluate(&header, chunk_size)) != ERROR_SUCCESS) {
  596 + srs_warn("mic evaluate source iovs failed. ret=%d", ret);
  597 + return ret;
  598 + }
  599 + }
  600 +
  601 + // calc the private iovs
  602 + char* pp = NULL;
  603 +
  604 + // timestamp for c0/c3
  605 + u_int32_t timestamp = (u_int32_t)header.timestamp;
  606 + mic_etime_present = timestamp >= RTMP_EXTENDED_TIMESTAMP;
  607 +
  608 + // chunk message header, 11 bytes
  609 + // timestamp, 3bytes, big-endian
  610 + char* p = mic_c0_time;
  611 + if (!mic_etime_present) {
  612 + pp = (char*)&timestamp;
  613 + *p++ = pp[2];
  614 + *p++ = pp[1];
  615 + *p++ = pp[0];
  616 + } else {
  617 + *p++ = 0xFF;
  618 + *p++ = 0xFF;
  619 + *p++ = 0xFF;
  620 + }
  621 +
  622 + // stream_id, 4bytes, little-endian
  623 + p = mic_c0_sid;
  624 + pp = (char*)&header.stream_id;
  625 + *p++ = pp[0];
  626 + *p++ = pp[1];
  627 + *p++ = pp[2];
  628 + *p++ = pp[3];
  629 +
  630 + // for c0
  631 + // chunk extended timestamp header, 0 or 4 bytes, big-endian
  632 + //
  633 + // for c3:
  634 + // chunk extended timestamp header, 0 or 4 bytes, big-endian
  635 + // 6.1.3. Extended Timestamp
  636 + // This field is transmitted only when the normal time stamp in the
  637 + // chunk message header is set to 0x00ffffff. If normal time stamp is
  638 + // set to any value less than 0x00ffffff, this field MUST NOT be
  639 + // present. This field MUST NOT be present if the timestamp field is not
  640 + // present. Type 3 chunks MUST NOT have this field.
  641 + // adobe changed for Type3 chunk:
  642 + // FMLE always sendout the extended-timestamp,
  643 + // must send the extended-timestamp to FMS,
  644 + // must send the extended-timestamp to flash-player.
  645 + // @see: ngx_rtmp_prepare_message
  646 + // @see: http://blog.csdn.net/win_lin/article/details/13363699
  647 + // TODO: FIXME: extract to outer.
  648 + p = mic_etime;
  649 + if (mic_etime_present) {
  650 + pp = (char*)&timestamp;
  651 + *p++ = pp[3];
  652 + *p++ = pp[2];
  653 + *p++ = pp[1];
  654 + *p++ = pp[0];
  655 + }
  656 +
  657 + // calc number of iovs.
  658 + nb_iovs = 1/*time*/ + 1/*sid*/;
  659 + // insert etime before all chunks.
  660 + if (mic_etime_present) {
  661 + nb_iovs += ptr->nb_chunks;
  662 + }
  663 +
  664 + // create iovs
  665 + srs_freep(iovs);
  666 + iovs = new iovec[nb_iovs];
  667 +
  668 + // time, 3B
  669 + iovs[0].iov_base = mic_c0_time;
  670 + iovs[0].iov_len = 3;
  671 +
  672 + // sid, 4B
  673 + iovs[1].iov_base = mic_c0_sid;
  674 + iovs[1].iov_len = 4;
  675 +
  676 + // etime, 4B for each chunks.
  677 + for (int i = 2; i < nb_iovs; i++) {
  678 + iovs[i].iov_base = mic_etime;
  679 + iovs[i].iov_len = 4;
  680 + }
  681 +
  682 + return ret;
  683 +}
  684 +
  685 +int SrsSharedPtrMessage::mic_iovs_count()
  686 +{
  687 + return nb_iovs + ptr->nb_iovs;
  688 +}
  689 +
  690 +int SrsSharedPtrMessage::mic_iovs_dump(iovec* _iovs, int _nb_iovs)
  691 +{
  692 + int shared_index = 0;
  693 + int private_index = 0;
  694 + int index = 0;
  695 +
  696 + // dumps all.
  697 + srs_assert(nb_iovs + ptr->nb_iovs <= _nb_iovs);
  698 +
  699 + // dump the c0 chunk
  700 + _iovs[index++] = ptr->iovs[shared_index++]; // cid
  701 + _iovs[index++] = iovs[private_index++]; // time
  702 + _iovs[index++] = ptr->iovs[shared_index++]; // size
  703 + _iovs[index++] = ptr->iovs[shared_index++]; // type
  704 + _iovs[index++] = iovs[private_index++]; // sid
  705 + if (mic_etime_present) {
  706 + _iovs[index++] = iovs[private_index++]; // etime
  707 + }
  708 + _iovs[index++] = ptr->iovs[shared_index++]; // chunk
  709 +
  710 + // dump left c3 chunks
  711 + for (int i = 1; i < ptr->nb_chunks; i++) {
  712 + _iovs[index++] = ptr->iovs[shared_index++]; // cid
  713 + if (mic_etime_present) {
  714 + _iovs[index++] = iovs[private_index++]; // etime
  715 + }
  716 + _iovs[index++] = ptr->iovs[shared_index++]; // chunk
  717 + }
  718 +
  719 + srs_assert(index == private_index + shared_index);
  720 + srs_assert(index == nb_iovs + ptr->nb_iovs);
  721 + srs_assert(index <= _nb_iovs);
  722 +
  723 + return nb_iovs + ptr->nb_iovs;
  724 +}
  725 +#endif
  726 +
482 SrsProtocol::AckWindowSize::AckWindowSize() 727 SrsProtocol::AckWindowSize::AckWindowSize()
483 { 728 {
484 ack_window_size = 0; 729 ack_window_size = 0;
@@ -498,8 +743,10 @@ SrsProtocol::SrsProtocol(ISrsProtocolReaderWriter* io) @@ -498,8 +743,10 @@ SrsProtocol::SrsProtocol(ISrsProtocolReaderWriter* io)
498 // each chunk consumers atleast 2 iovs 743 // each chunk consumers atleast 2 iovs
499 srs_assert(nb_out_iovs >= 2); 744 srs_assert(nb_out_iovs >= 2);
500 745
  746 +#ifndef SRS_PERF_MW_MSG_IOVS_CACHE
501 warned_c0c3_cache_dry = false; 747 warned_c0c3_cache_dry = false;
502 auto_response_when_recv = true; 748 auto_response_when_recv = true;
  749 +#endif
503 750
504 cs_cache = NULL; 751 cs_cache = NULL;
505 if (SRS_PERF_CHUNK_STREAM_CACHE > 0) { 752 if (SRS_PERF_CHUNK_STREAM_CACHE > 0) {
@@ -707,6 +954,7 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs) @@ -707,6 +954,7 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs)
707 { 954 {
708 int ret = ERROR_SUCCESS; 955 int ret = ERROR_SUCCESS;
709 956
  957 +#ifndef SRS_PERF_MW_MSG_IOVS_CACHE
710 // TODO: FIXME: use cache system instead. 958 // TODO: FIXME: use cache system instead.
711 int iov_index = 0; 959 int iov_index = 0;
712 iovec* iov = out_iovs + iov_index; 960 iovec* iov = out_iovs + iov_index;
@@ -811,6 +1059,40 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs) @@ -811,6 +1059,40 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs)
811 } 1059 }
812 } 1060 }
813 } 1061 }
  1062 +#else
  1063 + // send all iovs for all msgs.
  1064 + int total_iovs = 0;
  1065 + for (int i = 0; i < nb_msgs; i++) {
  1066 + SrsSharedPtrMessage* msg = msgs[i];
  1067 + if ((ret = msg->mic_evaluate(out_chunk_size)) != ERROR_SUCCESS) {
  1068 + srs_error("mic evaluate failed, chunk=%d. ret=%d", out_chunk_size, ret);
  1069 + return ret;
  1070 + }
  1071 + total_iovs += msg->mic_iovs_count();
  1072 + }
  1073 + srs_verbose("mic nb_iovs=%d, max=%d", total_iovs, nb_out_iovs);
  1074 +
  1075 + // realloc the iovs if exceed,
  1076 + // for we donot know how many messges maybe to send entirely,
  1077 + // we just alloc the iovs, it's ok.
  1078 + if (total_iovs > nb_out_iovs) {
  1079 + srs_warn("resize iovs %d => %d, msgs=%d, max_msgs=%d",
  1080 + nb_out_iovs, total_iovs, nb_msgs, SRS_PERF_MW_MSGS);
  1081 +
  1082 + nb_out_iovs = total_iovs;
  1083 + int realloc_size = sizeof(iovec) * nb_out_iovs;
  1084 + out_iovs = (iovec*)realloc(out_iovs, realloc_size);
  1085 + }
  1086 +
  1087 + // dumps iovs
  1088 + int iov_index = 0;
  1089 + for (int i = 0; i < nb_msgs; i++) {
  1090 + SrsSharedPtrMessage* msg = msgs[i];
  1091 + iov_index += msg->mic_iovs_dump(
  1092 + out_iovs + iov_index, nb_out_iovs - iov_index
  1093 + );
  1094 + }
  1095 +#endif
814 1096
815 // maybe the iovs already sendout when c0c3 cache dry, 1097 // maybe the iovs already sendout when c0c3 cache dry,
816 // so just ignore when no iovs to send. 1098 // so just ignore when no iovs to send.
@@ -824,11 +1106,21 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs) @@ -824,11 +1106,21 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs)
824 iovec* iov = out_iovs + i; 1106 iovec* iov = out_iovs + i;
825 nb_bytes += iov->iov_len; 1107 nb_bytes += iov->iov_len;
826 } 1108 }
  1109 + #ifndef SRS_PERF_MW_MSG_IOVS_CACHE
827 srs_info("mw %d msgs %dB in %d iovs, max_msgs=%d, nb_out_iovs=%d", 1110 srs_info("mw %d msgs %dB in %d iovs, max_msgs=%d, nb_out_iovs=%d",
828 nb_msgs, nb_bytes, iov_index, SRS_PERF_MW_MSGS, nb_out_iovs); 1111 nb_msgs, nb_bytes, iov_index, SRS_PERF_MW_MSGS, nb_out_iovs);
  1112 + #else
  1113 + srs_info("mic nb_iovs=%d, max=%d, msgs=%d %dB",
  1114 + total_iovs, nb_out_iovs, nb_msgs, nb_bytes);
  1115 + #endif
829 #else 1116 #else
  1117 + #ifndef SRS_PERF_MW_MSG_IOVS_CACHE
830 srs_info("mw %d msgs in %d iovs, max_msgs=%d, nb_out_iovs=%d", 1118 srs_info("mw %d msgs in %d iovs, max_msgs=%d, nb_out_iovs=%d",
831 nb_msgs, iov_index, SRS_PERF_MW_MSGS, nb_out_iovs); 1119 nb_msgs, iov_index, SRS_PERF_MW_MSGS, nb_out_iovs);
  1120 + #else
  1121 + srs_info("mic nb_iovs=%d, max=%d, msgs=%d",
  1122 + total_iovs, nb_out_iovs, nb_msgs);
  1123 + #endif
832 #endif 1124 #endif
833 1125
834 // the limits of writev iovs. 1126 // the limits of writev iovs.
@@ -214,14 +214,82 @@ private: @@ -214,14 +214,82 @@ private:
214 class __SrsSharedPtr 214 class __SrsSharedPtr
215 { 215 {
216 public: 216 public:
  217 + // actual shared payload.
217 char* payload; 218 char* payload;
  219 + // size of payload.
218 int size; 220 int size;
  221 + // the reference count
219 int shared_count; 222 int shared_count;
220 - 223 + public:
  224 + // the iovs cache in shared ptr message.
  225 + // @see https://github.com/winlinvip/simple-rtmp-server/issues/251
  226 + #ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  227 + /**
  228 + * the mic(msg iovs cache).
  229 + * why share the cache in msg?
  230 + * all msgs of a source are same for:
  231 + * 1. cid, all use the same cid, copy from src msg.
  232 + * 2. size, all msg size never changed.
  233 + * 3. type, type never changed.
  234 + * 4. chunk size, all connections in a vhost use the same chunk size.
  235 + * the different:
  236 + * 1. time and etime, almost different.
  237 + * 2. stream id, maybe different, but almost the same.
  238 + * @remark, when reload change the chunk size, clients will be disconnected.
  239 + */
  240 + // the c0 shared section for all msgs
  241 + // 1. cid, 1B, same.
  242 + // 2. [*]time, 3B, not same.
  243 + // 3. size, 3B, same.
  244 + // 4. type, 1B, same.
  245 + // 5. [*]stream id, 4B, not same, little-endian.
  246 + // 6. [*]etime, 4B, not same.
  247 + // the stared field must be calced in each msg.
  248 + char mic_c0[16];
  249 + // the c3 headers.
  250 + char mic_c3;
  251 + // the calced iovs for all msg,
  252 + // we assumpt that the chunk size is not changed for a vhost,
  253 + // if do changed, the client will got an error msg and disconnect.
  254 + iovec* iovs;
  255 + int nb_iovs;
  256 + // the msgs source chunk size,
  257 + // which is evaluated the iovs first time,
  258 + // this cannot be changed.
  259 + int chunk_size;
  260 + // the number of chunks.
  261 + int nb_chunks;
  262 + #endif
  263 + public:
221 __SrsSharedPtr(); 264 __SrsSharedPtr();
222 virtual ~__SrsSharedPtr(); 265 virtual ~__SrsSharedPtr();
  266 + public:
  267 + #ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  268 + /**
  269 + * for iovs msg cache, calc the iovs.
  270 + * @param chunk_size use the specified chunk size to evaluate the iovs.
  271 + */
  272 + virtual int mic_evaluate(SrsMessageHeader* mh, int chunk_size);
  273 + #endif
223 }; 274 };
224 __SrsSharedPtr* ptr; 275 __SrsSharedPtr* ptr;
  276 +private:
  277 + // msgs level cache.
  278 +#ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  279 + // the c0 private section for this
  280 + // 1. time, 3B, not same, not used.
  281 + // 2. stream id, 4B, almost the same, little-endian.
  282 + // 3. etime, 4B, optional, always same for all chunk when present.
  283 + // the stared field must be calced in each msg.
  284 + char mic_c0_time[3];
  285 + char mic_c0_sid[4];
  286 + char mic_etime[4];
  287 + // whether etime present.
  288 + bool mic_etime_present;
  289 + // the calced private iovs for this msg
  290 + iovec* iovs;
  291 + int nb_iovs;
  292 +#endif
225 public: 293 public:
226 SrsSharedPtrMessage(); 294 SrsSharedPtrMessage();
227 virtual ~SrsSharedPtrMessage(); 295 virtual ~SrsSharedPtrMessage();
@@ -253,6 +321,23 @@ public: @@ -253,6 +321,23 @@ public:
253 * @remark, assert object is created. 321 * @remark, assert object is created.
254 */ 322 */
255 virtual SrsSharedPtrMessage* copy(); 323 virtual SrsSharedPtrMessage* copy();
  324 +public:
  325 +#ifdef SRS_PERF_MW_MSG_IOVS_CACHE
  326 + /**
  327 + * for iovs msg cache, calc the iovs.
  328 + * @param chunk_size use the specified chunk size to evaluate the iovs.
  329 + */
  330 + virtual int mic_evaluate(int chunk_size);
  331 + /**
  332 + * count the total iovs needed.
  333 + */
  334 + virtual int mic_iovs_count();
  335 + /**
  336 + * dump all iovs, the _nb_iovs must equals to mic_iovs_count().
  337 + * @return the dumped count.
  338 + */
  339 + virtual int mic_iovs_dump(iovec* _iovs, int _nb_iovs);
  340 +#endif
256 }; 341 };
257 342
258 /** 343 /**
@@ -326,6 +411,9 @@ private: @@ -326,6 +411,9 @@ private:
326 */ 411 */
327 iovec* out_iovs; 412 iovec* out_iovs;
328 int nb_out_iovs; 413 int nb_out_iovs;
  414 + // if use iovs cache in each msg,
  415 + // donot use protocol level c0c3 cache.
  416 +#ifndef SRS_PERF_MW_MSG_IOVS_CACHE
329 /** 417 /**
330 * output header cache. 418 * output header cache.
331 * used for type0, 11bytes(or 15bytes with extended timestamp) header. 419 * used for type0, 11bytes(or 15bytes with extended timestamp) header.
@@ -337,6 +425,7 @@ private: @@ -337,6 +425,7 @@ private:
337 char out_c0c3_caches[SRS_CONSTS_C0C3_HEADERS_MAX]; 425 char out_c0c3_caches[SRS_CONSTS_C0C3_HEADERS_MAX];
338 // whether warned user to increase the c0c3 header cache. 426 // whether warned user to increase the c0c3 header cache.
339 bool warned_c0c3_cache_dry; 427 bool warned_c0c3_cache_dry;
  428 +#endif
340 /** 429 /**
341 * output chunk size, default to 128, set by config. 430 * output chunk size, default to 128, set by config.
342 */ 431 */