diff options
author | Torne (Richard Coles) <torne@google.com> | 2014-11-27 15:55:08 +0000 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2014-11-27 15:55:08 +0000 |
commit | 7f11db722e2af5d4e21e711545372830ca4221d4 (patch) | |
tree | c90cc37abc1e68c2584ba0aff932369b1e7155de /media/cast | |
parent | be0db613a3916853a2abecc9b0bd869b7640022e (diff) | |
download | chromium_org-7f11db722e2af5d4e21e711545372830ca4221d4.tar.gz |
Merge from Chromium at DEPS revision 40.0.2214.10
This commit was generated by merge_to_master.py.
Change-Id: I0a543d3dd13b8f5d3ca1d0a6b04cf4d1a280b98a
Diffstat (limited to 'media/cast')
-rw-r--r-- | media/cast/logging/logging_defines.h | 5 | ||||
-rw-r--r-- | media/cast/logging/stats_event_subscriber.cc | 229 | ||||
-rw-r--r-- | media/cast/logging/stats_event_subscriber.h | 44 | ||||
-rw-r--r-- | media/cast/logging/stats_event_subscriber_unittest.cc | 185 |
4 files changed, 360 insertions, 103 deletions
diff --git a/media/cast/logging/logging_defines.h b/media/cast/logging/logging_defines.h index 021a3c99a7..0f57fe982d 100644 --- a/media/cast/logging/logging_defines.h +++ b/media/cast/logging/logging_defines.h @@ -65,7 +65,10 @@ struct FrameEvent { EventMediaType media_type; - // Render / playout delay. Only set for FRAME_PLAYOUT events. + // Only set for FRAME_PLAYOUT events. + // If this value is zero the frame is rendered on time. + // If this value is positive it means the frame is rendered late. + // If this value is negative it means the frame is rendered early. base::TimeDelta delay_delta; // Whether the frame is a key frame. Only set for video FRAME_ENCODED event. diff --git a/media/cast/logging/stats_event_subscriber.cc b/media/cast/logging/stats_event_subscriber.cc index b22812e446..c42affa401 100644 --- a/media/cast/logging/stats_event_subscriber.cc +++ b/media/cast/logging/stats_event_subscriber.cc @@ -101,7 +101,12 @@ StatsEventSubscriber::StatsEventSubscriber( : event_media_type_(event_media_type), clock_(clock), offset_estimator_(offset_estimator), + capture_latency_datapoints_(0), + encode_time_datapoints_(0), + queueing_latency_datapoints_(0), network_latency_datapoints_(0), + packet_latency_datapoints_(0), + frame_latency_datapoints_(0), e2e_latency_datapoints_(0), num_frames_dropped_by_encoder_(0), num_frames_late_(0), @@ -150,7 +155,9 @@ void StatsEventSubscriber::OnReceiveFrameEvent(const FrameEvent& frame_event) { RecordE2ELatency(frame_event); base::TimeDelta delay_delta = frame_event.delay_delta; histograms_[PLAYOUT_DELAY_MS_HISTO]->Add(delay_delta.InMillisecondsF()); - if (delay_delta <= base::TimeDelta()) + + // Positive delay_delta means the frame is late. + if (delay_delta > base::TimeDelta()) num_frames_late_++; } @@ -182,7 +189,7 @@ void StatsEventSubscriber::OnReceivePacketEvent( if (type == PACKET_SENT_TO_NETWORK || type == PACKET_RECEIVED) { - RecordNetworkLatency(packet_event); + RecordPacketRelatedLatencies(packet_event); } else if (type == PACKET_RETRANSMITTED) { // We only measure network latency using packets that doesn't have to be // retransmitted as there is precisely one sent-receive timestamp pairs. @@ -226,6 +233,8 @@ scoped_ptr<base::DictionaryValue> StatsEventSubscriber::GetStats() const { stats->SetDouble(CastStatToString(it->first), round(it->second * 1000.0) / 1000.0); } + + // Populate all histograms. for (HistogramMap::const_iterator it = histograms_.begin(); it != histograms_.end(); ++it) { @@ -244,8 +253,18 @@ void StatsEventSubscriber::Reset() { frame_stats_.clear(); packet_stats_.clear(); + total_capture_latency_ = base::TimeDelta(); + capture_latency_datapoints_ = 0; + total_encode_time_ = base::TimeDelta(); + encode_time_datapoints_ = 0; + total_queueing_latency_ = base::TimeDelta(); + queueing_latency_datapoints_ = 0; total_network_latency_ = base::TimeDelta(); network_latency_datapoints_ = 0; + total_packet_latency_ = base::TimeDelta(); + packet_latency_datapoints_ = 0; + total_frame_latency_ = base::TimeDelta(); + frame_latency_datapoints_ = 0; total_e2e_latency_ = base::TimeDelta(); e2e_latency_datapoints_ = 0; num_frames_dropped_by_encoder_ = 0; @@ -269,47 +288,75 @@ const char* StatsEventSubscriber::CastStatToString(CastStat stat) { STAT_ENUM_TO_STRING(CAPTURE_FPS); STAT_ENUM_TO_STRING(ENCODE_FPS); STAT_ENUM_TO_STRING(DECODE_FPS); + STAT_ENUM_TO_STRING(AVG_CAPTURE_LATENCY_MS); STAT_ENUM_TO_STRING(AVG_ENCODE_TIME_MS); - STAT_ENUM_TO_STRING(AVG_PLAYOUT_DELAY_MS); + STAT_ENUM_TO_STRING(AVG_QUEUEING_LATENCY_MS); STAT_ENUM_TO_STRING(AVG_NETWORK_LATENCY_MS); + STAT_ENUM_TO_STRING(AVG_PACKET_LATENCY_MS); + STAT_ENUM_TO_STRING(AVG_FRAME_LATENCY_MS); STAT_ENUM_TO_STRING(AVG_E2E_LATENCY_MS); STAT_ENUM_TO_STRING(ENCODE_KBPS); STAT_ENUM_TO_STRING(TRANSMISSION_KBPS); STAT_ENUM_TO_STRING(RETRANSMISSION_KBPS); - STAT_ENUM_TO_STRING(PACKET_LOSS_FRACTION); STAT_ENUM_TO_STRING(MS_SINCE_LAST_RECEIVER_RESPONSE); STAT_ENUM_TO_STRING(NUM_FRAMES_CAPTURED); STAT_ENUM_TO_STRING(NUM_FRAMES_DROPPED_BY_ENCODER); STAT_ENUM_TO_STRING(NUM_FRAMES_LATE); STAT_ENUM_TO_STRING(NUM_PACKETS_SENT); STAT_ENUM_TO_STRING(NUM_PACKETS_RETRANSMITTED); + STAT_ENUM_TO_STRING(NUM_PACKETS_RECEIVED); STAT_ENUM_TO_STRING(NUM_PACKETS_RTX_REJECTED); STAT_ENUM_TO_STRING(FIRST_EVENT_TIME_MS); STAT_ENUM_TO_STRING(LAST_EVENT_TIME_MS); STAT_ENUM_TO_STRING(CAPTURE_LATENCY_MS_HISTO); - STAT_ENUM_TO_STRING(ENCODE_LATENCY_MS_HISTO); + STAT_ENUM_TO_STRING(ENCODE_TIME_MS_HISTO); + STAT_ENUM_TO_STRING(QUEUEING_LATENCY_MS_HISTO); + STAT_ENUM_TO_STRING(NETWORK_LATENCY_MS_HISTO); STAT_ENUM_TO_STRING(PACKET_LATENCY_MS_HISTO); STAT_ENUM_TO_STRING(FRAME_LATENCY_MS_HISTO); + STAT_ENUM_TO_STRING(E2E_LATENCY_MS_HISTO); STAT_ENUM_TO_STRING(PLAYOUT_DELAY_MS_HISTO); } NOTREACHED(); return ""; } -const int kMaxLatencyBucketMs = 800; -const int kBucketWidthMs = 20; +const int kDefaultMaxLatencyBucketMs = 800; +const int kDefaultBucketWidthMs = 20; + +// For small latency values. +const int kSmallMaxLatencyBucketMs = 100; +const int kSmallBucketWidthMs = 5; + +// For large latency values. +const int kLargeMaxLatencyBucketMs = 1200; +const int kLargeBucketWidthMs = 50; void StatsEventSubscriber::InitHistograms() { - histograms_[CAPTURE_LATENCY_MS_HISTO].reset( - new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs)); - histograms_[ENCODE_LATENCY_MS_HISTO].reset( - new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs)); + histograms_[E2E_LATENCY_MS_HISTO].reset( + new SimpleHistogram(0, kLargeMaxLatencyBucketMs, + kLargeBucketWidthMs)); + histograms_[QUEUEING_LATENCY_MS_HISTO].reset( + new SimpleHistogram(0, kDefaultMaxLatencyBucketMs, + kDefaultBucketWidthMs)); + histograms_[NETWORK_LATENCY_MS_HISTO].reset( + new SimpleHistogram(0, kDefaultMaxLatencyBucketMs, + kDefaultBucketWidthMs)); histograms_[PACKET_LATENCY_MS_HISTO].reset( - new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs)); + new SimpleHistogram(0, kDefaultMaxLatencyBucketMs, + kDefaultBucketWidthMs)); histograms_[FRAME_LATENCY_MS_HISTO].reset( - new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs)); + new SimpleHistogram(0, kDefaultMaxLatencyBucketMs, + kDefaultBucketWidthMs)); histograms_[PLAYOUT_DELAY_MS_HISTO].reset( - new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs)); + new SimpleHistogram(0, kSmallMaxLatencyBucketMs, + kSmallBucketWidthMs)); + histograms_[CAPTURE_LATENCY_MS_HISTO].reset( + new SimpleHistogram(0, kSmallMaxLatencyBucketMs, + kSmallBucketWidthMs)); + histograms_[ENCODE_TIME_MS_HISTO].reset( + new SimpleHistogram(0, kSmallMaxLatencyBucketMs, + kSmallBucketWidthMs)); } void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const { @@ -325,7 +372,6 @@ void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const { end_time, FRAME_ENCODED, ENCODE_FPS, stats_map); PopulateFpsStat( end_time, FRAME_DECODED, DECODE_FPS, stats_map); - PopulatePlayoutDelayStat(stats_map); PopulateFrameBitrateStat(end_time, stats_map); PopulatePacketBitrateStat(end_time, PACKET_SENT_TO_NETWORK, @@ -335,14 +381,38 @@ void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const { PACKET_RETRANSMITTED, RETRANSMISSION_KBPS, stats_map); - PopulatePacketLossPercentageStat(stats_map); PopulateFrameCountStat(FRAME_CAPTURE_END, NUM_FRAMES_CAPTURED, stats_map); PopulatePacketCountStat(PACKET_SENT_TO_NETWORK, NUM_PACKETS_SENT, stats_map); PopulatePacketCountStat( PACKET_RETRANSMITTED, NUM_PACKETS_RETRANSMITTED, stats_map); + PopulatePacketCountStat(PACKET_RECEIVED, NUM_PACKETS_RECEIVED, stats_map); PopulatePacketCountStat( PACKET_RTX_REJECTED, NUM_PACKETS_RTX_REJECTED, stats_map); + if (capture_latency_datapoints_ > 0) { + double avg_capture_latency_ms = + total_capture_latency_.InMillisecondsF() / + capture_latency_datapoints_; + stats_map->insert( + std::make_pair(AVG_CAPTURE_LATENCY_MS, avg_capture_latency_ms)); + } + + if (encode_time_datapoints_ > 0) { + double avg_encode_time_ms = + total_encode_time_.InMillisecondsF() / + encode_time_datapoints_; + stats_map->insert( + std::make_pair(AVG_ENCODE_TIME_MS, avg_encode_time_ms)); + } + + if (queueing_latency_datapoints_ > 0) { + double avg_queueing_latency_ms = + total_queueing_latency_.InMillisecondsF() / + queueing_latency_datapoints_; + stats_map->insert( + std::make_pair(AVG_QUEUEING_LATENCY_MS, avg_queueing_latency_ms)); + } + if (network_latency_datapoints_ > 0) { double avg_network_latency_ms = total_network_latency_.InMillisecondsF() / @@ -351,6 +421,21 @@ void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const { std::make_pair(AVG_NETWORK_LATENCY_MS, avg_network_latency_ms)); } + if (packet_latency_datapoints_ > 0) { + double avg_packet_latency_ms = + total_packet_latency_.InMillisecondsF() / + packet_latency_datapoints_; + stats_map->insert( + std::make_pair(AVG_PACKET_LATENCY_MS, avg_packet_latency_ms)); + } + + if (frame_latency_datapoints_ > 0) { + double avg_frame_latency_ms = + total_frame_latency_.InMillisecondsF() / frame_latency_datapoints_; + stats_map->insert( + std::make_pair(AVG_FRAME_LATENCY_MS, avg_frame_latency_ms)); + } + if (e2e_latency_datapoints_ > 0) { double avg_e2e_latency_ms = total_e2e_latency_.InMillisecondsF() / e2e_latency_datapoints_; @@ -378,6 +463,13 @@ void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const { } } +StatsEventSubscriber::SimpleHistogram* +StatsEventSubscriber::GetHistogramForTesting( + CastStat stats) const { + DCHECK(histograms_.find(stats) != histograms_.end()); + return histograms_.find(stats)->second.get(); +} + bool StatsEventSubscriber::GetReceiverOffset(base::TimeDelta* offset) { base::TimeDelta receiver_offset_lower_bound; base::TimeDelta receiver_offset_upper_bound; @@ -403,7 +495,7 @@ void StatsEventSubscriber::MaybeInsertFrameInfo(RtpTimestamp rtp_timestamp, if (recent_frame_infos_.size() >= kMaxFrameInfoMapSize) { FrameInfoMap::iterator erase_it = recent_frame_infos_.begin(); - if (erase_it->second.encode_time.is_null()) + if (erase_it->second.encode_end_time.is_null()) num_frames_dropped_by_encoder_++; recent_frame_infos_.erase(erase_it); } @@ -419,13 +511,15 @@ void StatsEventSubscriber::RecordFrameCaptureTime( void StatsEventSubscriber::RecordCaptureLatency(const FrameEvent& frame_event) { FrameInfoMap::iterator it = recent_frame_infos_.find(frame_event.rtp_timestamp); - if (it == recent_frame_infos_.end()) + if (it == recent_frame_infos_.end()) { return; + } if (!it->second.capture_time.is_null()) { - double capture_latency_ms = - (it->second.capture_time - frame_event.timestamp).InMillisecondsF(); - histograms_[CAPTURE_LATENCY_MS_HISTO]->Add(capture_latency_ms); + base::TimeDelta latency = frame_event.timestamp - it->second.capture_time; + total_capture_latency_ += latency; + capture_latency_datapoints_++; + histograms_[CAPTURE_LATENCY_MS_HISTO]->Add(latency.InMillisecondsF()); } it->second.capture_end_time = frame_event.timestamp; @@ -436,18 +530,20 @@ void StatsEventSubscriber::RecordEncodeLatency(const FrameEvent& frame_event) { recent_frame_infos_.find(frame_event.rtp_timestamp); if (it == recent_frame_infos_.end()) { FrameInfo frame_info; - frame_info.encode_time = frame_event.timestamp; + frame_info.encode_end_time = frame_event.timestamp; MaybeInsertFrameInfo(frame_event.rtp_timestamp, frame_info); return; } if (!it->second.capture_end_time.is_null()) { - double encode_latency_ms = - (frame_event.timestamp - it->second.capture_end_time).InMillisecondsF(); - histograms_[ENCODE_LATENCY_MS_HISTO]->Add(encode_latency_ms); + base::TimeDelta latency = + frame_event.timestamp - it->second.capture_end_time; + total_encode_time_ += latency; + encode_time_datapoints_++; + histograms_[ENCODE_TIME_MS_HISTO]->Add(latency.InMillisecondsF()); } - it->second.encode_time = frame_event.timestamp; + it->second.encode_end_time = frame_event.timestamp; } void StatsEventSubscriber::RecordFrameTxLatency(const FrameEvent& frame_event) { @@ -456,7 +552,7 @@ void StatsEventSubscriber::RecordFrameTxLatency(const FrameEvent& frame_event) { if (it == recent_frame_infos_.end()) return; - if (it->second.encode_time.is_null()) + if (it->second.encode_end_time.is_null()) return; base::TimeDelta receiver_offset; @@ -464,9 +560,10 @@ void StatsEventSubscriber::RecordFrameTxLatency(const FrameEvent& frame_event) { return; base::TimeTicks sender_time = frame_event.timestamp - receiver_offset; - double frame_tx_latency_ms = - (sender_time - it->second.encode_time).InMillisecondsF(); - histograms_[FRAME_LATENCY_MS_HISTO]->Add(frame_tx_latency_ms); + base::TimeDelta latency = sender_time - it->second.encode_end_time; + total_frame_latency_ += latency; + frame_latency_datapoints_++; + histograms_[FRAME_LATENCY_MS_HISTO]->Add(latency.InMillisecondsF()); } void StatsEventSubscriber::RecordE2ELatency(const FrameEvent& frame_event) { @@ -482,8 +579,10 @@ void StatsEventSubscriber::RecordE2ELatency(const FrameEvent& frame_event) { // Playout time is event time + playout delay. base::TimeTicks playout_time = frame_event.timestamp + frame_event.delay_delta - receiver_offset; - total_e2e_latency_ += playout_time - it->second.capture_time; + base::TimeDelta latency = playout_time - it->second.capture_time; + total_e2e_latency_ += latency; e2e_latency_datapoints_++; + histograms_[E2E_LATENCY_MS_HISTO]->Add(latency.InMillisecondsF()); } void StatsEventSubscriber::UpdateLastResponseTime( @@ -502,8 +601,23 @@ void StatsEventSubscriber::ErasePacketSentTime( packet_sent_times_.erase(key); } -void StatsEventSubscriber::RecordNetworkLatency( +void StatsEventSubscriber::RecordPacketRelatedLatencies( const PacketEvent& packet_event) { + // Log queueing latency. + if (packet_event.type == PACKET_SENT_TO_NETWORK) { + FrameInfoMap::iterator it = + recent_frame_infos_.find(packet_event.rtp_timestamp); + if (it != recent_frame_infos_.end()) { + base::TimeDelta latency = + packet_event.timestamp - it->second.encode_end_time; + total_queueing_latency_ += latency; + queueing_latency_datapoints_++; + histograms_[QUEUEING_LATENCY_MS_HISTO]->Add( + latency.InMillisecondsF()); + } + } + + // Log network latency and total packet latency; base::TimeDelta receiver_offset; if (!GetReceiverOffset(&receiver_offset)) return; @@ -535,17 +649,28 @@ void StatsEventSubscriber::RecordNetworkLatency( match = true; } if (match) { + packet_sent_times_.erase(it); + // Subtract by offset. packet_received_time -= receiver_offset; base::TimeDelta latency_delta = packet_received_time - packet_sent_time; total_network_latency_ += latency_delta; network_latency_datapoints_++; - - histograms_[PACKET_LATENCY_MS_HISTO]->Add( + histograms_[NETWORK_LATENCY_MS_HISTO]->Add( latency_delta.InMillisecondsF()); - packet_sent_times_.erase(it); + // Log total network latency. + FrameInfoMap::iterator frame_it = + recent_frame_infos_.find(packet_event.rtp_timestamp); + if (frame_it != recent_frame_infos_.end()) { + base::TimeDelta latency = + packet_received_time - frame_it->second.encode_end_time; + total_packet_latency_ += latency; + packet_latency_datapoints_++; + histograms_[PACKET_LATENCY_MS_HISTO]->Add( + latency.InMillisecondsF()); + } } } } @@ -583,18 +708,6 @@ void StatsEventSubscriber::PopulatePacketCountStat(CastLoggingEvent event, } } -void StatsEventSubscriber::PopulatePlayoutDelayStat(StatsMap* stats_map) const { - FrameStatsMap::const_iterator it = frame_stats_.find(FRAME_PLAYOUT); - if (it != frame_stats_.end()) { - double avg_delay_ms = 0.0; - base::TimeDelta sum_delay = it->second.sum_delay; - int count = it->second.event_counter; - if (count != 0) - avg_delay_ms = sum_delay.InMillisecondsF() / count; - stats_map->insert(std::make_pair(AVG_PLAYOUT_DELAY_MS, avg_delay_ms)); - } -} - void StatsEventSubscriber::PopulateFrameBitrateStat(base::TimeTicks end_time, StatsMap* stats_map) const { FrameStatsMap::const_iterator it = frame_stats_.find(FRAME_ENCODED); @@ -626,28 +739,6 @@ void StatsEventSubscriber::PopulatePacketBitrateStat( } } -void StatsEventSubscriber::PopulatePacketLossPercentageStat( - StatsMap* stats_map) const { - // We assume that retransmission means that the packet's previous - // (re)transmission was lost. - // This means the percentage of packet loss is - // (# of retransmit events) / (# of transmit + retransmit events). - PacketStatsMap::const_iterator sent_it = - packet_stats_.find(PACKET_SENT_TO_NETWORK); - if (sent_it == packet_stats_.end()) - return; - PacketStatsMap::const_iterator retransmitted_it = - packet_stats_.find(PACKET_RETRANSMITTED); - int sent_count = sent_it->second.event_counter; - int retransmitted_count = 0; - if (retransmitted_it != packet_stats_.end()) - retransmitted_count = retransmitted_it->second.event_counter; - double packet_loss_fraction = static_cast<double>(retransmitted_count) / - (sent_count + retransmitted_count); - stats_map->insert( - std::make_pair(PACKET_LOSS_FRACTION, packet_loss_fraction)); -} - StatsEventSubscriber::FrameLogStats::FrameLogStats() : event_counter(0), sum_size(0) {} StatsEventSubscriber::FrameLogStats::~FrameLogStats() {} diff --git a/media/cast/logging/stats_event_subscriber.h b/media/cast/logging/stats_event_subscriber.h index 20394021bd..3e8c83b153 100644 --- a/media/cast/logging/stats_event_subscriber.h +++ b/media/cast/logging/stats_event_subscriber.h @@ -57,6 +57,7 @@ class StatsEventSubscriber : public RawEventSubscriber { FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, PlayoutDelay); FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, E2ELatency); FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, Packets); + FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, Histograms); static const size_t kMaxFrameInfoMapSize = 100; @@ -113,15 +114,22 @@ class StatsEventSubscriber : public RawEventSubscriber { ENCODE_FPS, // Decode frame rate. DECODE_FPS, + // Average capture latency in milliseconds. + AVG_CAPTURE_LATENCY_MS, // Average encode duration in milliseconds. - // TODO(imcheng): This stat is not populated yet because we do not have - // the time when encode started. Record it in FRAME_ENCODED event. AVG_ENCODE_TIME_MS, - // Average playout delay in milliseconds. - AVG_PLAYOUT_DELAY_MS, + // Duration from when a frame is encoded to when the packet is first + // sent. + AVG_QUEUEING_LATENCY_MS, // Duration from when a packet is transmitted to when it is received. // This measures latency from sender to receiver. AVG_NETWORK_LATENCY_MS, + // Duration from when a frame is encoded to when the packet is first + // received. + AVG_PACKET_LATENCY_MS, + // Average latency between frame encoded and the moment when the frame + // is fully received. + AVG_FRAME_LATENCY_MS, // Duration from when a frame is captured to when it should be played out. AVG_E2E_LATENCY_MS, // Encode bitrate in kbps. @@ -130,8 +138,6 @@ class StatsEventSubscriber : public RawEventSubscriber { TRANSMISSION_KBPS, // Packet retransmission bitrate in kbps. RETRANSMISSION_KBPS, - // Fraction of packet loss. - PACKET_LOSS_FRACTION, // Duration in milliseconds since last receiver response. MS_SINCE_LAST_RECEIVER_RESPONSE, // Number of frames captured. @@ -144,6 +150,8 @@ class StatsEventSubscriber : public RawEventSubscriber { NUM_PACKETS_SENT, // Number of packets that were retransmitted. NUM_PACKETS_RETRANSMITTED, + // Number of packets that were received by receiver. + NUM_PACKETS_RECEIVED, // Number of packets that had their retransmission cancelled. NUM_PACKETS_RTX_REJECTED, // Unix time in milliseconds of first event since reset. @@ -153,9 +161,12 @@ class StatsEventSubscriber : public RawEventSubscriber { // Histograms CAPTURE_LATENCY_MS_HISTO, - ENCODE_LATENCY_MS_HISTO, + ENCODE_TIME_MS_HISTO, + QUEUEING_LATENCY_MS_HISTO, + NETWORK_LATENCY_MS_HISTO, PACKET_LATENCY_MS_HISTO, FRAME_LATENCY_MS_HISTO, + E2E_LATENCY_MS_HISTO, PLAYOUT_DELAY_MS_HISTO }; @@ -165,7 +176,7 @@ class StatsEventSubscriber : public RawEventSubscriber { base::TimeTicks capture_time; base::TimeTicks capture_end_time; - base::TimeTicks encode_time; + base::TimeTicks encode_end_time; bool encoded; }; @@ -186,6 +197,9 @@ class StatsEventSubscriber : public RawEventSubscriber { // Assigns |stats_map| with stats data. Used for testing. void GetStatsInternal(StatsMap* stats_map) const; + // Return a histogram of the type specified. + SimpleHistogram* GetHistogramForTesting(CastStat stats) const; + void UpdateFirstLastEventTime(base::TimeTicks timestamp, bool is_receiver_event); bool GetReceiverOffset(base::TimeDelta* offset); @@ -198,7 +212,7 @@ class StatsEventSubscriber : public RawEventSubscriber { void RecordE2ELatency(const FrameEvent& frame_event); void RecordPacketSentTime(const PacketEvent& packet_event); void ErasePacketSentTime(const PacketEvent& packet_event); - void RecordNetworkLatency(const PacketEvent& packet_event); + void RecordPacketRelatedLatencies(const PacketEvent& packet_event); void UpdateLastResponseTime(base::TimeTicks receiver_time); void PopulateFpsStat(base::TimeTicks now, @@ -211,13 +225,11 @@ class StatsEventSubscriber : public RawEventSubscriber { void PopulatePacketCountStat(CastLoggingEvent event, CastStat stat, StatsMap* stats_map) const; - void PopulatePlayoutDelayStat(StatsMap* stats_map) const; void PopulateFrameBitrateStat(base::TimeTicks now, StatsMap* stats_map) const; void PopulatePacketBitrateStat(base::TimeTicks now, CastLoggingEvent event, CastStat stat, StatsMap* stats_map) const; - void PopulatePacketLossPercentageStat(StatsMap* stats_map) const; const EventMediaType event_media_type_; @@ -230,8 +242,18 @@ class StatsEventSubscriber : public RawEventSubscriber { FrameStatsMap frame_stats_; PacketStatsMap packet_stats_; + base::TimeDelta total_capture_latency_; + int capture_latency_datapoints_; + base::TimeDelta total_encode_time_; + int encode_time_datapoints_; + base::TimeDelta total_queueing_latency_; + int queueing_latency_datapoints_; base::TimeDelta total_network_latency_; int network_latency_datapoints_; + base::TimeDelta total_packet_latency_; + int packet_latency_datapoints_; + base::TimeDelta total_frame_latency_; + int frame_latency_datapoints_; base::TimeDelta total_e2e_latency_; int e2e_latency_datapoints_; diff --git a/media/cast/logging/stats_event_subscriber_unittest.cc b/media/cast/logging/stats_event_subscriber_unittest.cc index 41388e0ade..570e2ccf3a 100644 --- a/media/cast/logging/stats_event_subscriber_unittest.cc +++ b/media/cast/logging/stats_event_subscriber_unittest.cc @@ -131,6 +131,11 @@ TEST_F(StatsEventSubscriberTest, CaptureEncode) { ASSERT_TRUE(it != stats_map.end()); EXPECT_DOUBLE_EQ(it->second, static_cast<double>(dropped_frames)); + + it = stats_map.find(StatsEventSubscriber::AVG_CAPTURE_LATENCY_MS); + ASSERT_TRUE(it != stats_map.end()); + + EXPECT_DOUBLE_EQ(it->second, static_cast<double>(0.01)); } TEST_F(StatsEventSubscriberTest, Encode) { @@ -236,12 +241,10 @@ TEST_F(StatsEventSubscriberTest, PlayoutDelay) { uint32 rtp_timestamp = 0; uint32 frame_id = 0; int num_frames = 10; - int total_delay_ms = 0; int late_frames = 0; for (int i = 0, delay_ms = -50; i < num_frames; i++, delay_ms += 10) { base::TimeDelta delay = base::TimeDelta::FromMilliseconds(delay_ms); - total_delay_ms += delay_ms; - if (delay_ms <= 0) + if (delay_ms > 0) late_frames++; cast_environment_->Logging()->InsertFrameEventWithDelay( receiver_clock_.NowTicks(), @@ -259,14 +262,8 @@ TEST_F(StatsEventSubscriberTest, PlayoutDelay) { StatsEventSubscriber::StatsMap stats_map; subscriber_->GetStatsInternal(&stats_map); - StatsEventSubscriber::StatsMap::iterator it = - stats_map.find(StatsEventSubscriber::AVG_PLAYOUT_DELAY_MS); - ASSERT_TRUE(it != stats_map.end()); - - EXPECT_DOUBLE_EQ( - it->second, static_cast<double>(total_delay_ms) / num_frames); - - it = stats_map.find(StatsEventSubscriber::NUM_FRAMES_LATE); + StatsEventSubscriber::StatsMap::iterator it = stats_map.find( + StatsEventSubscriber::NUM_FRAMES_LATE); ASSERT_TRUE(it != stats_map.end()); EXPECT_DOUBLE_EQ(it->second, late_frames); @@ -326,10 +323,22 @@ TEST_F(StatsEventSubscriberTest, Packets) { base::TimeTicks start_time = sender_clock_->NowTicks(); int total_size = 0; int retransmit_total_size = 0; - base::TimeDelta total_latency; + base::TimeDelta total_network_latency; + base::TimeDelta total_queueing_latency; + base::TimeDelta total_packet_latency; int num_packets_transmitted = 0; + int num_packets_received = 0; int num_packets_retransmitted = 0; int num_packets_rtx_rejected = 0; + + base::TimeTicks sender_encoded_time = sender_clock_->NowTicks(); + base::TimeTicks receiver_encoded_time = receiver_clock_.NowTicks(); + cast_environment_->Logging()->InsertFrameEvent(sender_encoded_time, + FRAME_ENCODED, + VIDEO_EVENT, + rtp_timestamp, + 0); + // Every 2nd packet will be retransmitted once. // Every 4th packet will be retransmitted twice. // Every 8th packet will be retransmitted 3 times + 1 rejected retransmission. @@ -346,12 +355,15 @@ TEST_F(StatsEventSubscriberTest, Packets) { num_packets - 1, size); num_packets_transmitted++; + total_queueing_latency += sender_clock_->NowTicks() - sender_encoded_time; int latency_micros = 20000 + base::RandInt(-10000, 10000); base::TimeDelta latency = base::TimeDelta::FromMicroseconds(latency_micros); // Latency is only recorded for packets that aren't retransmitted. if (i % 2 != 0) { - total_latency += latency; + total_network_latency += latency; + total_packet_latency += + receiver_clock_.NowTicks() - receiver_encoded_time + latency; num_latency_recorded_packets++; } @@ -428,6 +440,7 @@ TEST_F(StatsEventSubscriberTest, Packets) { i, num_packets - 1, size); + num_packets_received++; } base::TimeTicks end_time = sender_clock_->NowTicks(); @@ -436,15 +449,28 @@ TEST_F(StatsEventSubscriberTest, Packets) { StatsEventSubscriber::StatsMap stats_map; subscriber_->GetStatsInternal(&stats_map); - // Measure AVG_NETWORK_LATENCY_MS, TRANSMISSION_KBPS, RETRANSMISSION_KBPS, - // and PACKET_LOSS_FRACTION. + // Measure AVG_NETWORK_LATENCY_MS, TRANSMISSION_KBPS, RETRANSMISSION_KBPS. StatsEventSubscriber::StatsMap::iterator it = stats_map.find(StatsEventSubscriber::AVG_NETWORK_LATENCY_MS); ASSERT_TRUE(it != stats_map.end()); EXPECT_DOUBLE_EQ( it->second, - total_latency.InMillisecondsF() / num_latency_recorded_packets); + total_network_latency.InMillisecondsF() / num_latency_recorded_packets); + + it = stats_map.find(StatsEventSubscriber::AVG_QUEUEING_LATENCY_MS); + ASSERT_TRUE(it != stats_map.end()); + + EXPECT_DOUBLE_EQ( + it->second, + total_queueing_latency.InMillisecondsF() / num_packets); + + it = stats_map.find(StatsEventSubscriber::AVG_PACKET_LATENCY_MS); + ASSERT_TRUE(it != stats_map.end()); + + EXPECT_DOUBLE_EQ( + it->second, + total_packet_latency.InMillisecondsF() / num_latency_recorded_packets); it = stats_map.find(StatsEventSubscriber::TRANSMISSION_KBPS); ASSERT_TRUE(it != stats_map.end()); @@ -459,17 +485,15 @@ TEST_F(StatsEventSubscriberTest, Packets) { static_cast<double>(retransmit_total_size) / duration.InMillisecondsF() * 8); - it = stats_map.find(StatsEventSubscriber::PACKET_LOSS_FRACTION); + it = stats_map.find(StatsEventSubscriber::NUM_PACKETS_SENT); ASSERT_TRUE(it != stats_map.end()); - EXPECT_DOUBLE_EQ( - it->second, - static_cast<double>(num_packets_retransmitted) / num_packets_transmitted); + EXPECT_DOUBLE_EQ(it->second, static_cast<double>(num_packets)); - it = stats_map.find(StatsEventSubscriber::NUM_PACKETS_SENT); + it = stats_map.find(StatsEventSubscriber::NUM_PACKETS_RECEIVED); ASSERT_TRUE(it != stats_map.end()); - EXPECT_DOUBLE_EQ(it->second, static_cast<double>(num_packets)); + EXPECT_DOUBLE_EQ(it->second, static_cast<double>(num_packets_received)); it = stats_map.find(StatsEventSubscriber::NUM_PACKETS_RETRANSMITTED); ASSERT_TRUE(it != stats_map.end()); @@ -482,5 +506,122 @@ TEST_F(StatsEventSubscriberTest, Packets) { EXPECT_DOUBLE_EQ(it->second, static_cast<double>(num_packets_rtx_rejected)); } +bool CheckHistogramHasValue(base::ListValue* values, + const std::string& bucket, int expected_count) { + for (size_t i = 0; i < values->GetSize(); ++i) { + const base::DictionaryValue* dict = NULL; + values->GetDictionary(i, &dict); + if (!dict->HasKey(bucket)) + continue; + int bucket_count = 0; + if (!dict->GetInteger(bucket, &bucket_count)) + return false; + return bucket_count == expected_count; + } + return false; +} + +TEST_F(StatsEventSubscriberTest, Histograms) { + Init(VIDEO_EVENT); + AdvanceClocks(base::TimeDelta::FromMilliseconds(123)); + + uint32 rtp_timestamp = 123; + uint32 frame_id = 0; + + // 10 Frames with capture latency in the bucket of "10-14"ms. + // 10 Frames with encode time in the bucket of "15-19"ms. + for (int i = 0; i < 10; ++i) { + ++frame_id; + ++rtp_timestamp; + cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(), + FRAME_CAPTURE_BEGIN, + VIDEO_EVENT, + rtp_timestamp, + frame_id); + AdvanceClocks(base::TimeDelta::FromMilliseconds(10)); + cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(), + FRAME_CAPTURE_END, + VIDEO_EVENT, + rtp_timestamp, + frame_id); + AdvanceClocks(base::TimeDelta::FromMilliseconds(15)); + cast_environment_->Logging()->InsertEncodedFrameEvent( + sender_clock_->NowTicks(), + FRAME_ENCODED, + VIDEO_EVENT, + rtp_timestamp, + frame_id, + 1024, + true, + 5678); + } + + // Send 3 packets for the last frame. + // Queueing latencies are 100ms, 200ms and 300ms. + for (int i = 0; i < 3; ++i) { + AdvanceClocks(base::TimeDelta::FromMilliseconds(100)); + cast_environment_->Logging()->InsertPacketEvent(sender_clock_->NowTicks(), + PACKET_SENT_TO_NETWORK, + VIDEO_EVENT, + rtp_timestamp, + 0, + i, + 2, + 123); + } + + // Receive 3 packets for the last frame. + // Network latencies are 100ms, 200ms and 300ms. + // Packet latencies are 400ms. + AdvanceClocks(base::TimeDelta::FromMilliseconds(100)); + for (int i = 0; i < 3; ++i) { + cast_environment_->Logging()->InsertPacketEvent(receiver_clock_.NowTicks(), + PACKET_RECEIVED, + VIDEO_EVENT, + rtp_timestamp, + 0, + i, + 2, + 123); + } + + StatsEventSubscriber::SimpleHistogram* histogram; + scoped_ptr<base::ListValue> values; + + histogram = subscriber_->GetHistogramForTesting( + StatsEventSubscriber::CAPTURE_LATENCY_MS_HISTO); + ASSERT_TRUE(histogram); + values = histogram->GetHistogram().Pass(); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "10-14", 10)); + + histogram = subscriber_->GetHistogramForTesting( + StatsEventSubscriber::ENCODE_TIME_MS_HISTO); + ASSERT_TRUE(histogram); + values = histogram->GetHistogram().Pass(); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "15-19", 10)); + + histogram = subscriber_->GetHistogramForTesting( + StatsEventSubscriber::QUEUEING_LATENCY_MS_HISTO); + ASSERT_TRUE(histogram); + values = histogram->GetHistogram().Pass(); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "100-119", 1)); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "200-219", 1)); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "300-319", 1)); + + histogram = subscriber_->GetHistogramForTesting( + StatsEventSubscriber::NETWORK_LATENCY_MS_HISTO); + ASSERT_TRUE(histogram); + values = histogram->GetHistogram().Pass(); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "100-119", 1)); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "200-219", 1)); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "300-319", 1)); + + histogram = subscriber_->GetHistogramForTesting( + StatsEventSubscriber::PACKET_LATENCY_MS_HISTO); + ASSERT_TRUE(histogram); + values = histogram->GetHistogram().Pass(); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "400-419", 3)); +} + } // namespace cast } // namespace media |