diff options
Diffstat (limited to 'chromium/net/quic/quic_connection_logger.cc')
-rw-r--r-- | chromium/net/quic/quic_connection_logger.cc | 448 |
1 files changed, 426 insertions, 22 deletions
diff --git a/chromium/net/quic/quic_connection_logger.cc b/chromium/net/quic/quic_connection_logger.cc index 174d99a58c6..6ac4f5563d9 100644 --- a/chromium/net/quic/quic_connection_logger.cc +++ b/chromium/net/quic/quic_connection_logger.cc @@ -4,6 +4,9 @@ #include "net/quic/quic_connection_logger.h" +#include <algorithm> +#include <string> + #include "base/bind.h" #include "base/callback.h" #include "base/metrics/histogram.h" @@ -11,14 +14,24 @@ #include "base/strings/string_number_conversions.h" #include "base/values.h" #include "net/base/net_log.h" -#include "net/quic/crypto/crypto_handshake.h" +#include "net/base/net_util.h" +#include "net/quic/crypto/crypto_handshake_message.h" +#include "net/quic/crypto/crypto_protocol.h" +#include "net/quic/quic_address_mismatch.h" +#include "net/quic/quic_socket_address_coder.h" +using base::StringPiece; using std::string; namespace net { namespace { +// We have ranges-of-buckets in the cumulative histogram (covering 21 packet +// sequences) of length 2, 3, 4, ... 22. +// Hence the largest sample is bounded by the sum of those numbers. +const int kBoundingSampleInCumulativeHistogram = ((2 + 22) * 21) / 2; + base::Value* NetLogQuicPacketCallback(const IPEndPoint* self_address, const IPEndPoint* peer_address, size_t packet_size, @@ -33,11 +46,13 @@ base::Value* NetLogQuicPacketCallback(const IPEndPoint* self_address, base::Value* NetLogQuicPacketSentCallback( QuicPacketSequenceNumber sequence_number, EncryptionLevel level, + TransmissionType transmission_type, size_t packet_size, WriteResult result, NetLog::LogLevel /* log_level */) { base::DictionaryValue* dict = new base::DictionaryValue(); dict->SetInteger("encryption_level", level); + dict->SetInteger("transmission_type", transmission_type); dict->SetString("packet_sequence_number", base::Uint64ToString(sequence_number)); dict->SetInteger("size", packet_size); @@ -51,19 +66,19 @@ base::Value* NetLogQuicPacketRetransmittedCallback( QuicPacketSequenceNumber old_sequence_number, QuicPacketSequenceNumber new_sequence_number, NetLog::LogLevel /* log_level */) { - base::DictionaryValue* dict = new base::DictionaryValue(); - dict->SetString("old_packet_sequence_number", - base::Uint64ToString(old_sequence_number)); - dict->SetString("new_packet_sequence_number", - base::Uint64ToString(new_sequence_number)); - return dict; + base::DictionaryValue* dict = new base::DictionaryValue(); + dict->SetString("old_packet_sequence_number", + base::Uint64ToString(old_sequence_number)); + dict->SetString("new_packet_sequence_number", + base::Uint64ToString(new_sequence_number)); + return dict; } base::Value* NetLogQuicPacketHeaderCallback(const QuicPacketHeader* header, NetLog::LogLevel /* log_level */) { base::DictionaryValue* dict = new base::DictionaryValue(); - dict->SetString("guid", - base::Uint64ToString(header->public_header.guid)); + dict->SetString("connection_id", + base::Uint64ToString(header->public_header.connection_id)); dict->SetInteger("reset_flag", header->public_header.reset_flag); dict->SetInteger("version_flag", header->public_header.version_flag); dict->SetString("packet_sequence_number", @@ -87,15 +102,12 @@ base::Value* NetLogQuicStreamFrameCallback(const QuicStreamFrame* frame, base::Value* NetLogQuicAckFrameCallback(const QuicAckFrame* frame, NetLog::LogLevel /* log_level */) { base::DictionaryValue* dict = new base::DictionaryValue(); - base::DictionaryValue* sent_info = new base::DictionaryValue(); - dict->Set("sent_info", sent_info); - sent_info->SetString("least_unacked", - base::Uint64ToString(frame->sent_info.least_unacked)); base::DictionaryValue* received_info = new base::DictionaryValue(); dict->Set("received_info", received_info); received_info->SetString( "largest_observed", base::Uint64ToString(frame->received_info.largest_observed)); + received_info->SetBoolean("truncated", frame->received_info.is_truncated); base::ListValue* missing = new base::ListValue(); received_info->Set("missing_packets", missing); const SequenceNumberSet& missing_packets = @@ -114,14 +126,12 @@ base::Value* NetLogQuicCongestionFeedbackFrameCallback( switch (frame->type) { case kInterArrival: { dict->SetString("type", "InterArrival"); - dict->SetInteger("accumulated_number_of_lost_packets", - frame->inter_arrival.accumulated_number_of_lost_packets); base::ListValue* received = new base::ListValue(); dict->Set("received_packets", received); for (TimeMap::const_iterator it = frame->inter_arrival.received_packet_times.begin(); it != frame->inter_arrival.received_packet_times.end(); ++it) { - std::string value = base::Uint64ToString(it->first) + "@" + + string value = base::Uint64ToString(it->first) + "@" + base::Uint64ToString(it->second.ToDebuggingValue()); received->AppendString(value); } @@ -134,10 +144,12 @@ base::Value* NetLogQuicCongestionFeedbackFrameCallback( break; case kTCP: dict->SetString("type", "TCP"); - dict->SetInteger("accumulated_number_of_lost_packets", - frame->tcp.accumulated_number_of_lost_packets); dict->SetInteger("receive_window", frame->tcp.receive_window); break; + case kTCPBBR: + dict->SetString("type", "TCPBBR"); + // TODO(rtenneti): Add support for BBR. + break; } return dict; @@ -162,6 +174,44 @@ base::Value* NetLogQuicConnectionCloseFrameCallback( return dict; } +base::Value* NetLogQuicWindowUpdateFrameCallback( + const QuicWindowUpdateFrame* frame, + NetLog::LogLevel /* log_level */) { + base::DictionaryValue* dict = new base::DictionaryValue(); + dict->SetInteger("stream_id", frame->stream_id); + dict->SetString("byte_offset", base::Uint64ToString(frame->byte_offset)); + return dict; +} + +base::Value* NetLogQuicBlockedFrameCallback( + const QuicBlockedFrame* frame, + NetLog::LogLevel /* log_level */) { + base::DictionaryValue* dict = new base::DictionaryValue(); + dict->SetInteger("stream_id", frame->stream_id); + return dict; +} + +base::Value* NetLogQuicGoAwayFrameCallback( + const QuicGoAwayFrame* frame, + NetLog::LogLevel /* log_level */) { + base::DictionaryValue* dict = new base::DictionaryValue(); + dict->SetInteger("quic_error", frame->error_code); + dict->SetInteger("last_good_stream_id", frame->last_good_stream_id); + dict->SetString("reason_phrase", frame->reason_phrase); + return dict; +} + +base::Value* NetLogQuicStopWaitingFrameCallback( + const QuicStopWaitingFrame* frame, + NetLog::LogLevel /* log_level */) { + base::DictionaryValue* dict = new base::DictionaryValue(); + base::DictionaryValue* sent_info = new base::DictionaryValue(); + dict->Set("sent_info", sent_info); + sent_info->SetString("least_unacked", + base::Uint64ToString(frame->least_unacked)); + return dict; +} + base::Value* NetLogQuicVersionNegotiationPacketCallback( const QuicVersionNegotiationPacket* packet, NetLog::LogLevel /* log_level */) { @@ -198,19 +248,111 @@ void UpdatePacketGapSentHistogram(size_t num_consecutive_missing_packets) { num_consecutive_missing_packets); } +void UpdatePublicResetAddressMismatchHistogram( + const IPEndPoint& server_hello_address, + const IPEndPoint& public_reset_address) { + int sample = GetAddressMismatch(server_hello_address, public_reset_address); + // We are seemingly talking to an older server that does not support the + // feature, so we can't report the results in the histogram. + if (sample < 0) { + return; + } + UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.PublicResetAddressMismatch2", + sample, QUIC_ADDRESS_MISMATCH_MAX); +} + +const char* GetConnectionDescriptionString() { + NetworkChangeNotifier::ConnectionType type = + NetworkChangeNotifier::GetConnectionType(); + const char* description = NetworkChangeNotifier::ConnectionTypeToString(type); + // Most platforms don't distingish Wifi vs Etherenet, and call everything + // CONNECTION_UNKNOWN :-(. We'll tease out some details when we are on WiFi, + // and hopefully leave only ethernet (with no WiFi available) in the + // CONNECTION_UNKNOWN category. This *might* err if there is both ethernet, + // as well as WiFi, where WiFi was not being used that much. + // This function only seems usefully defined on Windows currently. + if (type == NetworkChangeNotifier::CONNECTION_UNKNOWN || + type == NetworkChangeNotifier::CONNECTION_WIFI) { + WifiPHYLayerProtocol wifi_type = GetWifiPHYLayerProtocol(); + switch (wifi_type) { + case WIFI_PHY_LAYER_PROTOCOL_NONE: + // No wifi support or no associated AP. + break; + case WIFI_PHY_LAYER_PROTOCOL_ANCIENT: + // An obsolete modes introduced by the original 802.11, e.g. IR, FHSS. + description = "CONNECTION_WIFI_ANCIENT"; + break; + case WIFI_PHY_LAYER_PROTOCOL_A: + // 802.11a, OFDM-based rates. + description = "CONNECTION_WIFI_802.11a"; + break; + case WIFI_PHY_LAYER_PROTOCOL_B: + // 802.11b, DSSS or HR DSSS. + description = "CONNECTION_WIFI_802.11b"; + break; + case WIFI_PHY_LAYER_PROTOCOL_G: + // 802.11g, same rates as 802.11a but compatible with 802.11b. + description = "CONNECTION_WIFI_802.11g"; + break; + case WIFI_PHY_LAYER_PROTOCOL_N: + // 802.11n, HT rates. + description = "CONNECTION_WIFI_802.11n"; + break; + case WIFI_PHY_LAYER_PROTOCOL_UNKNOWN: + // Unclassified mode or failure to identify. + break; + } + } + return description; +} + +// If |address| is an IPv4-mapped IPv6 address, returns ADDRESS_FAMILY_IPV4 +// instead of ADDRESS_FAMILY_IPV6. Othewise, behaves like GetAddressFamily(). +AddressFamily GetRealAddressFamily(const IPAddressNumber& address) { + return IsIPv4Mapped(address) ? ADDRESS_FAMILY_IPV4 : + GetAddressFamily(address); +} + } // namespace QuicConnectionLogger::QuicConnectionLogger(const BoundNetLog& net_log) : net_log_(net_log), last_received_packet_sequence_number_(0), + last_received_packet_size_(0), largest_received_packet_sequence_number_(0), largest_received_missing_packet_sequence_number_(0), - out_of_order_recieved_packet_count_(0) { + num_out_of_order_received_packets_(0), + num_packets_received_(0), + num_truncated_acks_sent_(0), + num_truncated_acks_received_(0), + num_frames_received_(0), + num_duplicate_frames_received_(0), + connection_description_(GetConnectionDescriptionString()) { } QuicConnectionLogger::~QuicConnectionLogger() { UMA_HISTOGRAM_COUNTS("Net.QuicSession.OutOfOrderPacketsReceived", - out_of_order_recieved_packet_count_); + num_out_of_order_received_packets_); + UMA_HISTOGRAM_COUNTS("Net.QuicSession.TruncatedAcksSent", + num_truncated_acks_sent_); + UMA_HISTOGRAM_COUNTS("Net.QuicSession.TruncatedAcksReceived", + num_truncated_acks_received_); + if (num_frames_received_ > 0) { + int duplicate_stream_frame_per_thousand = + num_duplicate_frames_received_ * 1000 / num_frames_received_; + if (num_packets_received_ < 100) { + UMA_HISTOGRAM_CUSTOM_COUNTS( + "Net.QuicSession.StreamFrameDuplicatedShortConnection", + duplicate_stream_frame_per_thousand, 1, 1000, 75); + } else { + UMA_HISTOGRAM_CUSTOM_COUNTS( + "Net.QuicSession.StreamFrameDuplicatedLongConnection", + duplicate_stream_frame_per_thousand, 1, 1000, 75); + + } + } + + RecordLossHistograms(); } void QuicConnectionLogger::OnFrameAddedToPacket(const QuicFrame& frame) { @@ -226,6 +368,8 @@ void QuicConnectionLogger::OnFrameAddedToPacket(const QuicFrame& frame) { net_log_.AddEvent( NetLog::TYPE_QUIC_SESSION_ACK_FRAME_SENT, base::Bind(&NetLogQuicAckFrameCallback, frame.ack_frame)); + if (frame.ack_frame->received_info.is_truncated) + ++num_truncated_acks_sent_; break; case CONGESTION_FEEDBACK_FRAME: net_log_.AddEvent( @@ -248,6 +392,32 @@ void QuicConnectionLogger::OnFrameAddedToPacket(const QuicFrame& frame) { frame.connection_close_frame)); break; case GOAWAY_FRAME: + net_log_.AddEvent( + NetLog::TYPE_QUIC_SESSION_GOAWAY_FRAME_SENT, + base::Bind(&NetLogQuicGoAwayFrameCallback, + frame.goaway_frame)); + break; + case WINDOW_UPDATE_FRAME: + net_log_.AddEvent( + NetLog::TYPE_QUIC_SESSION_WINDOW_UPDATE_FRAME_SENT, + base::Bind(&NetLogQuicWindowUpdateFrameCallback, + frame.window_update_frame)); + break; + case BLOCKED_FRAME: + net_log_.AddEvent( + NetLog::TYPE_QUIC_SESSION_BLOCKED_FRAME_SENT, + base::Bind(&NetLogQuicBlockedFrameCallback, + frame.blocked_frame)); + break; + case STOP_WAITING_FRAME: + net_log_.AddEvent( + NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_SENT, + base::Bind(&NetLogQuicStopWaitingFrameCallback, + frame.stop_waiting_frame)); + break; + case PING_FRAME: + // PingFrame has no contents to log, so just record that it was sent. + net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PING_FRAME_SENT); break; default: DCHECK(false) << "Illegal frame type: " << frame.type; @@ -257,12 +427,13 @@ void QuicConnectionLogger::OnFrameAddedToPacket(const QuicFrame& frame) { void QuicConnectionLogger::OnPacketSent( QuicPacketSequenceNumber sequence_number, EncryptionLevel level, + TransmissionType transmission_type, const QuicEncryptedPacket& packet, WriteResult result) { net_log_.AddEvent( NetLog::TYPE_QUIC_SESSION_PACKET_SENT, base::Bind(&NetLogQuicPacketSentCallback, sequence_number, level, - packet.length(), result)); + transmission_type, packet.length(), result)); } void QuicConnectionLogger:: OnPacketRetransmitted( @@ -277,6 +448,14 @@ void QuicConnectionLogger:: OnPacketRetransmitted( void QuicConnectionLogger::OnPacketReceived(const IPEndPoint& self_address, const IPEndPoint& peer_address, const QuicEncryptedPacket& packet) { + if (local_address_from_self_.GetFamily() == ADDRESS_FAMILY_UNSPECIFIED) { + local_address_from_self_ = self_address; + UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionTypeFromSelf", + GetRealAddressFamily(self_address.address()), + ADDRESS_FAMILY_LAST); + } + + last_received_packet_size_ = packet.length(); net_log_.AddEvent( NetLog::TYPE_QUIC_SESSION_PACKET_RECEIVED, base::Bind(&NetLogQuicPacketCallback, &self_address, &peer_address, @@ -292,6 +471,7 @@ void QuicConnectionLogger::OnPacketHeader(const QuicPacketHeader& header) { net_log_.AddEvent( NetLog::TYPE_QUIC_SESSION_PACKET_HEADER_RECEIVED, base::Bind(&NetLogQuicPacketHeaderCallback, &header)); + ++num_packets_received_; if (largest_received_packet_sequence_number_ < header.packet_sequence_number) { QuicPacketSequenceNumber delta = header.packet_sequence_number - @@ -304,8 +484,10 @@ void QuicConnectionLogger::OnPacketHeader(const QuicPacketHeader& header) { } largest_received_packet_sequence_number_ = header.packet_sequence_number; } + if (header.packet_sequence_number < received_packets_.size()) + received_packets_[header.packet_sequence_number] = true; if (header.packet_sequence_number < last_received_packet_sequence_number_) { - ++out_of_order_recieved_packet_count_; + ++num_out_of_order_received_packets_; UMA_HISTOGRAM_COUNTS("Net.QuicSession.OutOfOrderGapReceived", last_received_packet_sequence_number_ - header.packet_sequence_number); @@ -324,6 +506,14 @@ void QuicConnectionLogger::OnAckFrame(const QuicAckFrame& frame) { NetLog::TYPE_QUIC_SESSION_ACK_FRAME_RECEIVED, base::Bind(&NetLogQuicAckFrameCallback, &frame)); + const size_t kApproximateLargestSoloAckBytes = 100; + if (last_received_packet_sequence_number_ < received_acks_.size() && + last_received_packet_size_ < kApproximateLargestSoloAckBytes) + received_acks_[last_received_packet_sequence_number_] = true; + + if (frame.received_info.is_truncated) + ++num_truncated_acks_received_; + if (frame.received_info.missing_packets.empty()) return; @@ -367,6 +557,13 @@ void QuicConnectionLogger::OnCongestionFeedbackFrame( base::Bind(&NetLogQuicCongestionFeedbackFrameCallback, &frame)); } +void QuicConnectionLogger::OnStopWaitingFrame( + const QuicStopWaitingFrame& frame) { + net_log_.AddEvent( + NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_RECEIVED, + base::Bind(&NetLogQuicStopWaitingFrameCallback, &frame)); +} + void QuicConnectionLogger::OnRstStreamFrame(const QuicRstStreamFrame& frame) { UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeServer", frame.error_code); @@ -382,9 +579,35 @@ void QuicConnectionLogger::OnConnectionCloseFrame( base::Bind(&NetLogQuicConnectionCloseFrameCallback, &frame)); } +void QuicConnectionLogger::OnWindowUpdateFrame( + const QuicWindowUpdateFrame& frame) { + net_log_.AddEvent( + NetLog::TYPE_QUIC_SESSION_WINDOW_UPDATE_FRAME_RECEIVED, + base::Bind(&NetLogQuicWindowUpdateFrameCallback, &frame)); +} + +void QuicConnectionLogger::OnBlockedFrame(const QuicBlockedFrame& frame) { + net_log_.AddEvent( + NetLog::TYPE_QUIC_SESSION_BLOCKED_FRAME_RECEIVED, + base::Bind(&NetLogQuicBlockedFrameCallback, &frame)); +} + +void QuicConnectionLogger::OnGoAwayFrame(const QuicGoAwayFrame& frame) { + net_log_.AddEvent( + NetLog::TYPE_QUIC_SESSION_GOAWAY_FRAME_RECEIVED, + base::Bind(&NetLogQuicGoAwayFrameCallback, &frame)); +} + +void QuicConnectionLogger::OnPingFrame(const QuicPingFrame& frame) { + // PingFrame has no contents to log, so just record that it was received. + net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PING_FRAME_RECEIVED); +} + void QuicConnectionLogger::OnPublicResetPacket( const QuicPublicResetPacket& packet) { net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PUBLIC_RESET_PACKET_RECEIVED); + UpdatePublicResetAddressMismatchHistogram(local_address_from_shlo_, + packet.client_address); } void QuicConnectionLogger::OnVersionNegotiationPacket( @@ -407,6 +630,19 @@ void QuicConnectionLogger::OnCryptoHandshakeMessageReceived( net_log_.AddEvent( NetLog::TYPE_QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_RECEIVED, base::Bind(&NetLogQuicCryptoHandshakeMessageCallback, &message)); + + if (message.tag() == kSHLO) { + StringPiece address; + QuicSocketAddressCoder decoder; + if (message.GetStringPiece(kCADR, &address) && + decoder.Decode(address.data(), address.size())) { + local_address_from_shlo_ = IPEndPoint(decoder.ip(), decoder.port()); + UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionTypeFromPeer", + GetRealAddressFamily( + local_address_from_shlo_.address()), + ADDRESS_FAMILY_LAST); + } + } } void QuicConnectionLogger::OnCryptoHandshakeMessageSent( @@ -430,4 +666,172 @@ void QuicConnectionLogger::OnSuccessfulVersionNegotiation( NetLog::StringCallback("version", &quic_version)); } +void QuicConnectionLogger::UpdateReceivedFrameCounts( + QuicStreamId stream_id, + int num_frames_received, + int num_duplicate_frames_received) { + if (stream_id != kCryptoStreamId) { + num_frames_received_ += num_frames_received; + num_duplicate_frames_received_ += num_duplicate_frames_received; + } +} + +base::HistogramBase* QuicConnectionLogger::GetPacketSequenceNumberHistogram( + const char* statistic_name) const { + string prefix("Net.QuicSession.PacketReceived_"); + return base::LinearHistogram::FactoryGet( + prefix + statistic_name + connection_description_, + 1, received_packets_.size(), received_packets_.size() + 1, + base::HistogramBase::kUmaTargetedHistogramFlag); +} + +base::HistogramBase* QuicConnectionLogger::Get6PacketHistogram( + const char* which_6) const { + // This histogram takes a binary encoding of the 6 consecutive packets + // received. As a result, there are 64 possible sample-patterns. + string prefix("Net.QuicSession.6PacketsPatternsReceived_"); + return base::LinearHistogram::FactoryGet( + prefix + which_6 + connection_description_, 1, 64, 65, + base::HistogramBase::kUmaTargetedHistogramFlag); +} + +base::HistogramBase* QuicConnectionLogger::Get21CumulativeHistogram( + const char* which_21) const { + // This histogram contains, for each sequence of 21 packets, the results from + // 21 distinct questions about that sequence. Conceptually the histogtram is + // broken into 21 distinct ranges, and one sample is added into each of those + // ranges whenever we process a set of 21 packets. + // There is a little rendundancy, as each "range" must have the same number + // of samples, all told, but the histogram is a tad easier to read this way. + // The questions are: + // Was the first packet present (bucket 0==>no; bucket 1==>yes) + // Of the first two packets, how many were present? (bucket 2==> none; + // bucket 3==> 1 of 2; bucket 4==> 2 of 2) + // Of the first three packets, how many were present? (bucket 5==>none; + // bucket 6==> 1 of 3; bucket 7==> 2 of 3; bucket 8==> 3 of 3). + // etc. + string prefix("Net.QuicSession.21CumulativePacketsReceived_"); + return base::LinearHistogram::FactoryGet( + prefix + which_21 + connection_description_, + 1, kBoundingSampleInCumulativeHistogram, + kBoundingSampleInCumulativeHistogram + 1, + base::HistogramBase::kUmaTargetedHistogramFlag); +} + +// static +void QuicConnectionLogger::AddTo21CumulativeHistogram( + base::HistogramBase* histogram, + int bit_mask_of_packets, + int valid_bits_in_mask) { + DCHECK_LE(valid_bits_in_mask, 21); + DCHECK_LT(bit_mask_of_packets, 1 << 21); + const int blank_bits_in_mask = 21 - valid_bits_in_mask; + DCHECK_EQ(bit_mask_of_packets & ((1 << blank_bits_in_mask) - 1), 0); + bit_mask_of_packets >>= blank_bits_in_mask; + int bits_so_far = 0; + int range_start = 0; + for (int i = 1; i <= valid_bits_in_mask; ++i) { + bits_so_far += bit_mask_of_packets & 1; + bit_mask_of_packets >>= 1; + DCHECK_LT(range_start + bits_so_far, kBoundingSampleInCumulativeHistogram); + histogram->Add(range_start + bits_so_far); + range_start += i + 1; + } +} + +void QuicConnectionLogger::RecordAggregatePacketLossRate() const { + // For short connections under 22 packets in length, we'll rely on the + // Net.QuicSession.21CumulativePacketsReceived_* histogram to indicate packet + // loss rates. This way we avoid tremendously anomalous contributions to our + // histogram. (e.g., if we only got 5 packets, but lost 1, we'd otherwise + // record a 20% loss in this histogram!). We may still get some strange data + // (1 loss in 22 is still high :-/). + if (largest_received_packet_sequence_number_ <= 21) + return; + + QuicPacketSequenceNumber divisor = largest_received_packet_sequence_number_; + QuicPacketSequenceNumber numerator = divisor - num_packets_received_; + if (divisor < 100000) + numerator *= 1000; + else + divisor /= 1000; + string prefix("Net.QuicSession.PacketLossRate_"); + base::HistogramBase* histogram = base::Histogram::FactoryGet( + prefix + connection_description_, 1, 1000, 75, + base::HistogramBase::kUmaTargetedHistogramFlag); + histogram->Add(numerator / divisor); +} + +void QuicConnectionLogger::RecordLossHistograms() const { + if (largest_received_packet_sequence_number_ == 0) + return; // Connection was never used. + RecordAggregatePacketLossRate(); + + base::HistogramBase* is_not_ack_histogram = + GetPacketSequenceNumberHistogram("IsNotAck_"); + base::HistogramBase* is_an_ack_histogram = + GetPacketSequenceNumberHistogram("IsAnAck_"); + base::HistogramBase* packet_arrived_histogram = + GetPacketSequenceNumberHistogram("Ack_"); + base::HistogramBase* packet_missing_histogram = + GetPacketSequenceNumberHistogram("Nack_"); + base::HistogramBase* ongoing_cumulative_packet_histogram = + Get21CumulativeHistogram("Some21s_"); + base::HistogramBase* first_cumulative_packet_histogram = + Get21CumulativeHistogram("First21_"); + base::HistogramBase* six_packet_histogram = Get6PacketHistogram("Some6s_"); + + DCHECK_EQ(received_packets_.size(), received_acks_.size()); + const QuicPacketSequenceNumber last_index = + std::min<QuicPacketSequenceNumber>(received_packets_.size() - 1, + largest_received_packet_sequence_number_); + const QuicPacketSequenceNumber index_of_first_21_contribution = + std::min<QuicPacketSequenceNumber>(21, last_index); + // Bit pattern of consecutively received packets that is maintained as we scan + // through the received_packets_ vector. Less significant bits correspond to + // less recent packets, and only the low order 21 bits are ever defined. + // Bit is 1 iff corresponding packet was received. + int packet_pattern_21 = 0; + // Zero is an invalid packet sequence number. + DCHECK(!received_packets_[0]); + for (size_t i = 1; i <= last_index; ++i) { + if (received_acks_[i]) + is_an_ack_histogram->Add(i); + else + is_not_ack_histogram->Add(i); + + packet_pattern_21 >>= 1; + if (received_packets_[i]) { + packet_arrived_histogram->Add(i); + packet_pattern_21 |= (1 << 20); // Turn on the 21st bit. + } else { + packet_missing_histogram->Add(i); + } + + if (i == index_of_first_21_contribution) { + AddTo21CumulativeHistogram(first_cumulative_packet_histogram, + packet_pattern_21, i); + } + // We'll just record for non-overlapping ranges, to reduce histogramming + // cost for now. Each call does 21 separate histogram additions. + if (i > 21 || i % 21 == 0) { + AddTo21CumulativeHistogram(ongoing_cumulative_packet_histogram, + packet_pattern_21, 21); + } + + if (i < 6) + continue; // Not enough packets to do any pattern recording. + int recent_6_mask = packet_pattern_21 >> 15; + DCHECK_LT(recent_6_mask, 64); + if (i == 6) { + Get6PacketHistogram("First6_")->Add(recent_6_mask); + continue; + } + // Record some overlapping patterns, to get a better picture, since this is + // not very expensive. + if (i % 3 == 0) + six_packet_histogram->Add(recent_6_mask); + } +} + } // namespace net |