1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/quic/quic_connection_logger.h"
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/metrics/histogram.h"
13 #include "base/metrics/sparse_histogram.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/values.h"
16 #include "net/base/net_log.h"
17 #include "net/base/net_util.h"
18 #include "net/quic/crypto/crypto_handshake_message.h"
19 #include "net/quic/crypto/crypto_protocol.h"
20 #include "net/quic/quic_address_mismatch.h"
21 #include "net/quic/quic_socket_address_coder.h"
23 using base::StringPiece;
30 // We have ranges-of-buckets in the cumulative histogram (covering 21 packet
31 // sequences) of length 2, 3, 4, ... 22.
32 // Hence the largest sample is bounded by the sum of those numbers.
33 const int kBoundingSampleInCumulativeHistogram = ((2 + 22) * 21) / 2;
35 base::Value* NetLogQuicPacketCallback(const IPEndPoint* self_address,
36 const IPEndPoint* peer_address,
38 NetLog::LogLevel /* log_level */) {
39 base::DictionaryValue* dict = new base::DictionaryValue();
40 dict->SetString("self_address", self_address->ToString());
41 dict->SetString("peer_address", peer_address->ToString());
42 dict->SetInteger("size", packet_size);
46 base::Value* NetLogQuicPacketSentCallback(
47 QuicPacketSequenceNumber sequence_number,
48 EncryptionLevel level,
49 TransmissionType transmission_type,
52 NetLog::LogLevel /* log_level */) {
53 base::DictionaryValue* dict = new base::DictionaryValue();
54 dict->SetInteger("encryption_level", level);
55 dict->SetInteger("transmission_type", transmission_type);
56 dict->SetString("packet_sequence_number",
57 base::Uint64ToString(sequence_number));
58 dict->SetInteger("size", packet_size);
59 if (result.status != WRITE_STATUS_OK) {
60 dict->SetInteger("net_error", result.error_code);
65 base::Value* NetLogQuicPacketRetransmittedCallback(
66 QuicPacketSequenceNumber old_sequence_number,
67 QuicPacketSequenceNumber new_sequence_number,
68 NetLog::LogLevel /* log_level */) {
69 base::DictionaryValue* dict = new base::DictionaryValue();
70 dict->SetString("old_packet_sequence_number",
71 base::Uint64ToString(old_sequence_number));
72 dict->SetString("new_packet_sequence_number",
73 base::Uint64ToString(new_sequence_number));
77 base::Value* NetLogQuicPacketHeaderCallback(const QuicPacketHeader* header,
78 NetLog::LogLevel /* log_level */) {
79 base::DictionaryValue* dict = new base::DictionaryValue();
80 dict->SetString("connection_id",
81 base::Uint64ToString(header->public_header.connection_id));
82 dict->SetInteger("reset_flag", header->public_header.reset_flag);
83 dict->SetInteger("version_flag", header->public_header.version_flag);
84 dict->SetString("packet_sequence_number",
85 base::Uint64ToString(header->packet_sequence_number));
86 dict->SetInteger("entropy_flag", header->entropy_flag);
87 dict->SetInteger("fec_flag", header->fec_flag);
88 dict->SetInteger("fec_group", header->fec_group);
92 base::Value* NetLogQuicStreamFrameCallback(const QuicStreamFrame* frame,
93 NetLog::LogLevel /* log_level */) {
94 base::DictionaryValue* dict = new base::DictionaryValue();
95 dict->SetInteger("stream_id", frame->stream_id);
96 dict->SetBoolean("fin", frame->fin);
97 dict->SetString("offset", base::Uint64ToString(frame->offset));
98 dict->SetInteger("length", frame->data.TotalBufferSize());
102 base::Value* NetLogQuicAckFrameCallback(const QuicAckFrame* frame,
103 NetLog::LogLevel /* log_level */) {
104 base::DictionaryValue* dict = new base::DictionaryValue();
105 base::DictionaryValue* sent_info = new base::DictionaryValue();
106 dict->Set("sent_info", sent_info);
107 sent_info->SetString("least_unacked",
108 base::Uint64ToString(frame->sent_info.least_unacked));
109 base::DictionaryValue* received_info = new base::DictionaryValue();
110 dict->Set("received_info", received_info);
111 received_info->SetString(
113 base::Uint64ToString(frame->received_info.largest_observed));
114 received_info->SetBoolean("truncated", frame->received_info.is_truncated);
115 base::ListValue* missing = new base::ListValue();
116 received_info->Set("missing_packets", missing);
117 const SequenceNumberSet& missing_packets =
118 frame->received_info.missing_packets;
119 for (SequenceNumberSet::const_iterator it = missing_packets.begin();
120 it != missing_packets.end(); ++it) {
121 missing->AppendString(base::Uint64ToString(*it));
126 base::Value* NetLogQuicCongestionFeedbackFrameCallback(
127 const QuicCongestionFeedbackFrame* frame,
128 NetLog::LogLevel /* log_level */) {
129 base::DictionaryValue* dict = new base::DictionaryValue();
130 switch (frame->type) {
131 case kInterArrival: {
132 dict->SetString("type", "InterArrival");
133 base::ListValue* received = new base::ListValue();
134 dict->Set("received_packets", received);
135 for (TimeMap::const_iterator it =
136 frame->inter_arrival.received_packet_times.begin();
137 it != frame->inter_arrival.received_packet_times.end(); ++it) {
138 string value = base::Uint64ToString(it->first) + "@" +
139 base::Uint64ToString(it->second.ToDebuggingValue());
140 received->AppendString(value);
145 dict->SetString("type", "FixRate");
146 dict->SetInteger("bitrate_in_bytes_per_second",
147 frame->fix_rate.bitrate.ToBytesPerSecond());
150 dict->SetString("type", "TCP");
151 dict->SetInteger("receive_window", frame->tcp.receive_window);
158 base::Value* NetLogQuicRstStreamFrameCallback(
159 const QuicRstStreamFrame* frame,
160 NetLog::LogLevel /* log_level */) {
161 base::DictionaryValue* dict = new base::DictionaryValue();
162 dict->SetInteger("stream_id", frame->stream_id);
163 dict->SetInteger("quic_rst_stream_error", frame->error_code);
164 dict->SetString("details", frame->error_details);
168 base::Value* NetLogQuicConnectionCloseFrameCallback(
169 const QuicConnectionCloseFrame* frame,
170 NetLog::LogLevel /* log_level */) {
171 base::DictionaryValue* dict = new base::DictionaryValue();
172 dict->SetInteger("quic_error", frame->error_code);
173 dict->SetString("details", frame->error_details);
177 base::Value* NetLogQuicWindowUpdateFrameCallback(
178 const QuicWindowUpdateFrame* frame,
179 NetLog::LogLevel /* log_level */) {
180 base::DictionaryValue* dict = new base::DictionaryValue();
181 dict->SetInteger("stream_id", frame->stream_id);
182 dict->SetString("byte_offset", base::Uint64ToString(frame->byte_offset));
186 base::Value* NetLogQuicBlockedFrameCallback(
187 const QuicBlockedFrame* frame,
188 NetLog::LogLevel /* log_level */) {
189 base::DictionaryValue* dict = new base::DictionaryValue();
190 dict->SetInteger("stream_id", frame->stream_id);
194 base::Value* NetLogQuicStopWaitingFrameCallback(
195 const QuicStopWaitingFrame* frame,
196 NetLog::LogLevel /* log_level */) {
197 base::DictionaryValue* dict = new base::DictionaryValue();
198 base::DictionaryValue* sent_info = new base::DictionaryValue();
199 dict->Set("sent_info", sent_info);
200 sent_info->SetString("least_unacked",
201 base::Uint64ToString(frame->least_unacked));
205 base::Value* NetLogQuicVersionNegotiationPacketCallback(
206 const QuicVersionNegotiationPacket* packet,
207 NetLog::LogLevel /* log_level */) {
208 base::DictionaryValue* dict = new base::DictionaryValue();
209 base::ListValue* versions = new base::ListValue();
210 dict->Set("versions", versions);
211 for (QuicVersionVector::const_iterator it = packet->versions.begin();
212 it != packet->versions.end(); ++it) {
213 versions->AppendString(QuicVersionToString(*it));
218 base::Value* NetLogQuicCryptoHandshakeMessageCallback(
219 const CryptoHandshakeMessage* message,
220 NetLog::LogLevel /* log_level */) {
221 base::DictionaryValue* dict = new base::DictionaryValue();
222 dict->SetString("quic_crypto_handshake_message", message->DebugString());
226 base::Value* NetLogQuicOnConnectionClosedCallback(
229 NetLog::LogLevel /* log_level */) {
230 base::DictionaryValue* dict = new base::DictionaryValue();
231 dict->SetInteger("quic_error", error);
232 dict->SetBoolean("from_peer", from_peer);
236 void UpdatePacketGapSentHistogram(size_t num_consecutive_missing_packets) {
237 UMA_HISTOGRAM_COUNTS("Net.QuicSession.PacketGapSent",
238 num_consecutive_missing_packets);
241 void UpdatePublicResetAddressMismatchHistogram(
242 const IPEndPoint& server_hello_address,
243 const IPEndPoint& public_reset_address) {
244 int sample = GetAddressMismatch(server_hello_address, public_reset_address);
245 // We are seemingly talking to an older server that does not support the
246 // feature, so we can't report the results in the histogram.
250 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.PublicResetAddressMismatch",
251 sample, QUIC_ADDRESS_MISMATCH_MAX);
254 const char* GetConnectionDescriptionString() {
255 NetworkChangeNotifier::ConnectionType type =
256 NetworkChangeNotifier::GetConnectionType();
257 const char* description = NetworkChangeNotifier::ConnectionTypeToString(type);
258 // Most platforms don't distingish Wifi vs Etherenet, and call everything
259 // CONNECTION_UNKNOWN :-(. We'll tease out some details when we are on WiFi,
260 // and hopefully leave only ethernet (with no WiFi available) in the
261 // CONNECTION_UNKNOWN category. This *might* err if there is both ethernet,
262 // as well as WiFi, where WiFi was not being used that much.
263 // This function only seems usefully defined on Windows currently.
264 if (type == NetworkChangeNotifier::CONNECTION_UNKNOWN ||
265 type == NetworkChangeNotifier::CONNECTION_WIFI) {
266 WifiPHYLayerProtocol wifi_type = GetWifiPHYLayerProtocol();
268 case WIFI_PHY_LAYER_PROTOCOL_NONE:
269 // No wifi support or no associated AP.
271 case WIFI_PHY_LAYER_PROTOCOL_ANCIENT:
272 // An obsolete modes introduced by the original 802.11, e.g. IR, FHSS.
273 description = "CONNECTION_WIFI_ANCIENT";
275 case WIFI_PHY_LAYER_PROTOCOL_A:
276 // 802.11a, OFDM-based rates.
277 description = "CONNECTION_WIFI_802.11a";
279 case WIFI_PHY_LAYER_PROTOCOL_B:
280 // 802.11b, DSSS or HR DSSS.
281 description = "CONNECTION_WIFI_802.11b";
283 case WIFI_PHY_LAYER_PROTOCOL_G:
284 // 802.11g, same rates as 802.11a but compatible with 802.11b.
285 description = "CONNECTION_WIFI_802.11g";
287 case WIFI_PHY_LAYER_PROTOCOL_N:
288 // 802.11n, HT rates.
289 description = "CONNECTION_WIFI_802.11n";
291 case WIFI_PHY_LAYER_PROTOCOL_UNKNOWN:
292 // Unclassified mode or failure to identify.
302 QuicConnectionLogger::QuicConnectionLogger(const BoundNetLog& net_log)
304 last_received_packet_sequence_number_(0),
305 last_received_packet_size_(0),
306 largest_received_packet_sequence_number_(0),
307 largest_received_missing_packet_sequence_number_(0),
308 num_out_of_order_received_packets_(0),
309 num_packets_received_(0),
310 num_truncated_acks_sent_(0),
311 num_truncated_acks_received_(0),
312 num_frames_received_(0),
313 num_duplicate_frames_received_(0),
314 connection_description_(GetConnectionDescriptionString()) {
317 QuicConnectionLogger::~QuicConnectionLogger() {
318 UMA_HISTOGRAM_COUNTS("Net.QuicSession.OutOfOrderPacketsReceived",
319 num_out_of_order_received_packets_);
320 UMA_HISTOGRAM_COUNTS("Net.QuicSession.TruncatedAcksSent",
321 num_truncated_acks_sent_);
322 UMA_HISTOGRAM_COUNTS("Net.QuicSession.TruncatedAcksReceived",
323 num_truncated_acks_received_);
324 if (num_frames_received_ > 0) {
325 int duplicate_stream_frame_per_thousand =
326 num_duplicate_frames_received_ * 1000 / num_frames_received_;
327 if (num_packets_received_ < 100) {
328 UMA_HISTOGRAM_CUSTOM_COUNTS(
329 "Net.QuicSession.StreamFrameDuplicatedShortConnection",
330 duplicate_stream_frame_per_thousand, 1, 1000, 75);
332 UMA_HISTOGRAM_CUSTOM_COUNTS(
333 "Net.QuicSession.StreamFrameDuplicatedLongConnection",
334 duplicate_stream_frame_per_thousand, 1, 1000, 75);
339 RecordLossHistograms();
342 void QuicConnectionLogger::OnFrameAddedToPacket(const QuicFrame& frame) {
343 switch (frame.type) {
348 NetLog::TYPE_QUIC_SESSION_STREAM_FRAME_SENT,
349 base::Bind(&NetLogQuicStreamFrameCallback, frame.stream_frame));
353 NetLog::TYPE_QUIC_SESSION_ACK_FRAME_SENT,
354 base::Bind(&NetLogQuicAckFrameCallback, frame.ack_frame));
355 if (frame.ack_frame->received_info.is_truncated)
356 ++num_truncated_acks_sent_;
358 case CONGESTION_FEEDBACK_FRAME:
360 NetLog::TYPE_QUIC_SESSION_CONGESTION_FEEDBACK_FRAME_SENT,
361 base::Bind(&NetLogQuicCongestionFeedbackFrameCallback,
362 frame.congestion_feedback_frame));
364 case RST_STREAM_FRAME:
365 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeClient",
366 frame.rst_stream_frame->error_code);
368 NetLog::TYPE_QUIC_SESSION_RST_STREAM_FRAME_SENT,
369 base::Bind(&NetLogQuicRstStreamFrameCallback,
370 frame.rst_stream_frame));
372 case CONNECTION_CLOSE_FRAME:
374 NetLog::TYPE_QUIC_SESSION_CONNECTION_CLOSE_FRAME_SENT,
375 base::Bind(&NetLogQuicConnectionCloseFrameCallback,
376 frame.connection_close_frame));
380 case WINDOW_UPDATE_FRAME:
382 NetLog::TYPE_QUIC_SESSION_WINDOW_UPDATE_FRAME_SENT,
383 base::Bind(&NetLogQuicWindowUpdateFrameCallback,
384 frame.window_update_frame));
388 NetLog::TYPE_QUIC_SESSION_BLOCKED_FRAME_SENT,
389 base::Bind(&NetLogQuicBlockedFrameCallback,
390 frame.blocked_frame));
392 case STOP_WAITING_FRAME:
394 NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_SENT,
395 base::Bind(&NetLogQuicStopWaitingFrameCallback,
396 frame.stop_waiting_frame));
399 DCHECK(false) << "Illegal frame type: " << frame.type;
403 void QuicConnectionLogger::OnPacketSent(
404 QuicPacketSequenceNumber sequence_number,
405 EncryptionLevel level,
406 TransmissionType transmission_type,
407 const QuicEncryptedPacket& packet,
408 WriteResult result) {
410 NetLog::TYPE_QUIC_SESSION_PACKET_SENT,
411 base::Bind(&NetLogQuicPacketSentCallback, sequence_number, level,
412 transmission_type, packet.length(), result));
415 void QuicConnectionLogger:: OnPacketRetransmitted(
416 QuicPacketSequenceNumber old_sequence_number,
417 QuicPacketSequenceNumber new_sequence_number) {
419 NetLog::TYPE_QUIC_SESSION_PACKET_RETRANSMITTED,
420 base::Bind(&NetLogQuicPacketRetransmittedCallback,
421 old_sequence_number, new_sequence_number));
424 void QuicConnectionLogger::OnPacketReceived(const IPEndPoint& self_address,
425 const IPEndPoint& peer_address,
426 const QuicEncryptedPacket& packet) {
427 if (local_address_from_self_.GetFamily() == ADDRESS_FAMILY_UNSPECIFIED) {
428 local_address_from_self_ = self_address;
429 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionTypeFromSelf",
430 self_address.GetFamily(),
431 ADDRESS_FAMILY_LAST);
434 last_received_packet_size_ = packet.length();
436 NetLog::TYPE_QUIC_SESSION_PACKET_RECEIVED,
437 base::Bind(&NetLogQuicPacketCallback, &self_address, &peer_address,
441 void QuicConnectionLogger::OnProtocolVersionMismatch(
442 QuicVersion received_version) {
443 // TODO(rtenneti): Add logging.
446 void QuicConnectionLogger::OnPacketHeader(const QuicPacketHeader& header) {
448 NetLog::TYPE_QUIC_SESSION_PACKET_HEADER_RECEIVED,
449 base::Bind(&NetLogQuicPacketHeaderCallback, &header));
450 ++num_packets_received_;
451 if (largest_received_packet_sequence_number_ <
452 header.packet_sequence_number) {
453 QuicPacketSequenceNumber delta = header.packet_sequence_number -
454 largest_received_packet_sequence_number_;
456 // There is a gap between the largest packet previously received and
457 // the current packet. This indicates either loss, or out-of-order
459 UMA_HISTOGRAM_COUNTS("Net.QuicSession.PacketGapReceived", delta - 1);
461 largest_received_packet_sequence_number_ = header.packet_sequence_number;
463 if (header.packet_sequence_number < received_packets_.size())
464 received_packets_[header.packet_sequence_number] = true;
465 if (header.packet_sequence_number < last_received_packet_sequence_number_) {
466 ++num_out_of_order_received_packets_;
467 UMA_HISTOGRAM_COUNTS("Net.QuicSession.OutOfOrderGapReceived",
468 last_received_packet_sequence_number_ -
469 header.packet_sequence_number);
471 last_received_packet_sequence_number_ = header.packet_sequence_number;
474 void QuicConnectionLogger::OnStreamFrame(const QuicStreamFrame& frame) {
476 NetLog::TYPE_QUIC_SESSION_STREAM_FRAME_RECEIVED,
477 base::Bind(&NetLogQuicStreamFrameCallback, &frame));
480 void QuicConnectionLogger::OnAckFrame(const QuicAckFrame& frame) {
482 NetLog::TYPE_QUIC_SESSION_ACK_FRAME_RECEIVED,
483 base::Bind(&NetLogQuicAckFrameCallback, &frame));
485 const size_t kApproximateLargestSoloAckBytes = 100;
486 if (last_received_packet_sequence_number_ < received_acks_.size() &&
487 last_received_packet_size_ < kApproximateLargestSoloAckBytes)
488 received_acks_[last_received_packet_sequence_number_] = true;
490 if (frame.received_info.is_truncated)
491 ++num_truncated_acks_received_;
493 if (frame.received_info.missing_packets.empty())
496 SequenceNumberSet missing_packets = frame.received_info.missing_packets;
497 SequenceNumberSet::const_iterator it = missing_packets.lower_bound(
498 largest_received_missing_packet_sequence_number_);
499 if (it == missing_packets.end())
502 if (*it == largest_received_missing_packet_sequence_number_) {
504 if (it == missing_packets.end())
507 // Scan through the list and log consecutive ranges of missing packets.
508 size_t num_consecutive_missing_packets = 0;
509 QuicPacketSequenceNumber previous_missing_packet = *it - 1;
510 while (it != missing_packets.end()) {
511 if (previous_missing_packet == *it - 1) {
512 ++num_consecutive_missing_packets;
514 DCHECK_NE(0u, num_consecutive_missing_packets);
515 UpdatePacketGapSentHistogram(num_consecutive_missing_packets);
516 // Make sure this packet it included in the count.
517 num_consecutive_missing_packets = 1;
519 previous_missing_packet = *it;
522 if (num_consecutive_missing_packets != 0) {
523 UpdatePacketGapSentHistogram(num_consecutive_missing_packets);
525 largest_received_missing_packet_sequence_number_ =
526 *missing_packets.rbegin();
529 void QuicConnectionLogger::OnCongestionFeedbackFrame(
530 const QuicCongestionFeedbackFrame& frame) {
532 NetLog::TYPE_QUIC_SESSION_CONGESTION_FEEDBACK_FRAME_RECEIVED,
533 base::Bind(&NetLogQuicCongestionFeedbackFrameCallback, &frame));
536 void QuicConnectionLogger::OnStopWaitingFrame(
537 const QuicStopWaitingFrame& frame) {
539 NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_RECEIVED,
540 base::Bind(&NetLogQuicStopWaitingFrameCallback, &frame));
543 void QuicConnectionLogger::OnRstStreamFrame(const QuicRstStreamFrame& frame) {
544 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeServer",
547 NetLog::TYPE_QUIC_SESSION_RST_STREAM_FRAME_RECEIVED,
548 base::Bind(&NetLogQuicRstStreamFrameCallback, &frame));
551 void QuicConnectionLogger::OnConnectionCloseFrame(
552 const QuicConnectionCloseFrame& frame) {
554 NetLog::TYPE_QUIC_SESSION_CONNECTION_CLOSE_FRAME_RECEIVED,
555 base::Bind(&NetLogQuicConnectionCloseFrameCallback, &frame));
558 void QuicConnectionLogger::OnPublicResetPacket(
559 const QuicPublicResetPacket& packet) {
560 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PUBLIC_RESET_PACKET_RECEIVED);
561 UpdatePublicResetAddressMismatchHistogram(local_address_from_shlo_,
562 packet.client_address);
565 void QuicConnectionLogger::OnVersionNegotiationPacket(
566 const QuicVersionNegotiationPacket& packet) {
568 NetLog::TYPE_QUIC_SESSION_VERSION_NEGOTIATION_PACKET_RECEIVED,
569 base::Bind(&NetLogQuicVersionNegotiationPacketCallback, &packet));
572 void QuicConnectionLogger::OnRevivedPacket(
573 const QuicPacketHeader& revived_header,
574 base::StringPiece payload) {
576 NetLog::TYPE_QUIC_SESSION_PACKET_HEADER_REVIVED,
577 base::Bind(&NetLogQuicPacketHeaderCallback, &revived_header));
580 void QuicConnectionLogger::OnCryptoHandshakeMessageReceived(
581 const CryptoHandshakeMessage& message) {
583 NetLog::TYPE_QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_RECEIVED,
584 base::Bind(&NetLogQuicCryptoHandshakeMessageCallback, &message));
586 if (message.tag() == kSHLO) {
588 QuicSocketAddressCoder decoder;
589 if (message.GetStringPiece(kCADR, &address) &&
590 decoder.Decode(address.data(), address.size())) {
591 local_address_from_shlo_ = IPEndPoint(decoder.ip(), decoder.port());
592 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionTypeFromPeer",
593 local_address_from_shlo_.GetFamily(),
594 ADDRESS_FAMILY_LAST);
599 void QuicConnectionLogger::OnCryptoHandshakeMessageSent(
600 const CryptoHandshakeMessage& message) {
602 NetLog::TYPE_QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_SENT,
603 base::Bind(&NetLogQuicCryptoHandshakeMessageCallback, &message));
606 void QuicConnectionLogger::OnConnectionClosed(QuicErrorCode error,
609 NetLog::TYPE_QUIC_SESSION_CLOSED,
610 base::Bind(&NetLogQuicOnConnectionClosedCallback, error, from_peer));
613 void QuicConnectionLogger::OnSuccessfulVersionNegotiation(
614 const QuicVersion& version) {
615 string quic_version = QuicVersionToString(version);
616 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_VERSION_NEGOTIATED,
617 NetLog::StringCallback("version", &quic_version));
620 void QuicConnectionLogger::UpdateReceivedFrameCounts(
621 QuicStreamId stream_id,
622 int num_frames_received,
623 int num_duplicate_frames_received) {
624 if (stream_id != kCryptoStreamId) {
625 num_frames_received_ += num_frames_received;
626 num_duplicate_frames_received_ += num_duplicate_frames_received;
630 base::HistogramBase* QuicConnectionLogger::GetPacketSequenceNumberHistogram(
631 const char* statistic_name) const {
632 string prefix("Net.QuicSession.PacketReceived_");
633 return base::LinearHistogram::FactoryGet(
634 prefix + statistic_name + connection_description_,
635 1, received_packets_.size(), received_packets_.size() + 1,
636 base::HistogramBase::kUmaTargetedHistogramFlag);
639 base::HistogramBase* QuicConnectionLogger::Get6PacketHistogram(
640 const char* which_6) const {
641 // This histogram takes a binary encoding of the 6 consecutive packets
642 // received. As a result, there are 64 possible sample-patterns.
643 string prefix("Net.QuicSession.6PacketsPatternsReceived_");
644 return base::LinearHistogram::FactoryGet(
645 prefix + which_6 + connection_description_, 1, 64, 65,
646 base::HistogramBase::kUmaTargetedHistogramFlag);
649 base::HistogramBase* QuicConnectionLogger::Get21CumulativeHistogram(
650 const char* which_21) const {
651 // This histogram contains, for each sequence of 21 packets, the results from
652 // 21 distinct questions about that sequence. Conceptually the histogtram is
653 // broken into 21 distinct ranges, and one sample is added into each of those
654 // ranges whenever we process a set of 21 packets.
655 // There is a little rendundancy, as each "range" must have the same number
656 // of samples, all told, but the histogram is a tad easier to read this way.
657 // The questions are:
658 // Was the first packet present (bucket 0==>no; bucket 1==>yes)
659 // Of the first two packets, how many were present? (bucket 2==> none;
660 // bucket 3==> 1 of 2; bucket 4==> 2 of 2)
661 // Of the first three packets, how many were present? (bucket 5==>none;
662 // bucket 6==> 1 of 3; bucket 7==> 2 of 3; bucket 8==> 3 of 3).
664 string prefix("Net.QuicSession.21CumulativePacketsReceived_");
665 return base::LinearHistogram::FactoryGet(
666 prefix + which_21 + connection_description_,
667 1, kBoundingSampleInCumulativeHistogram,
668 kBoundingSampleInCumulativeHistogram + 1,
669 base::HistogramBase::kUmaTargetedHistogramFlag);
673 void QuicConnectionLogger::AddTo21CumulativeHistogram(
674 base::HistogramBase* histogram,
675 int bit_mask_of_packets,
676 int valid_bits_in_mask) {
677 DCHECK_LE(valid_bits_in_mask, 21);
678 DCHECK_LT(bit_mask_of_packets, 1 << 21);
679 const int blank_bits_in_mask = 21 - valid_bits_in_mask;
680 DCHECK_EQ(bit_mask_of_packets & ((1 << blank_bits_in_mask) - 1), 0);
681 bit_mask_of_packets >>= blank_bits_in_mask;
684 for (int i = 1; i <= valid_bits_in_mask; ++i) {
685 bits_so_far += bit_mask_of_packets & 1;
686 bit_mask_of_packets >>= 1;
687 DCHECK_LT(range_start + bits_so_far, kBoundingSampleInCumulativeHistogram);
688 histogram->Add(range_start + bits_so_far);
689 range_start += i + 1;
693 void QuicConnectionLogger::RecordAggregatePacketLossRate() const {
694 // For short connections under 22 packets in length, we'll rely on the
695 // Net.QuicSession.21CumulativePacketsReceived_* histogram to indicate packet
696 // loss rates. This way we avoid tremendously anomalous contributions to our
697 // histogram. (e.g., if we only got 5 packets, but lost 1, we'd otherwise
698 // record a 20% loss in this histogram!). We may still get some strange data
699 // (1 loss in 22 is still high :-/).
700 if (largest_received_packet_sequence_number_ <= 21)
703 QuicPacketSequenceNumber divisor = largest_received_packet_sequence_number_;
704 QuicPacketSequenceNumber numerator = divisor - num_packets_received_;
705 if (divisor < 100000)
709 string prefix("Net.QuicSession.PacketLossRate_");
710 base::HistogramBase* histogram = base::Histogram::FactoryGet(
711 prefix + connection_description_, 1, 1000, 75,
712 base::HistogramBase::kUmaTargetedHistogramFlag);
713 histogram->Add(numerator / divisor);
716 void QuicConnectionLogger::RecordLossHistograms() const {
717 if (largest_received_packet_sequence_number_ == 0)
718 return; // Connection was never used.
719 RecordAggregatePacketLossRate();
721 base::HistogramBase* is_not_ack_histogram =
722 GetPacketSequenceNumberHistogram("IsNotAck_");
723 base::HistogramBase* is_an_ack_histogram =
724 GetPacketSequenceNumberHistogram("IsAnAck_");
725 base::HistogramBase* packet_arrived_histogram =
726 GetPacketSequenceNumberHistogram("Ack_");
727 base::HistogramBase* packet_missing_histogram =
728 GetPacketSequenceNumberHistogram("Nack_");
729 base::HistogramBase* ongoing_cumulative_packet_histogram =
730 Get21CumulativeHistogram("Some21s_");
731 base::HistogramBase* first_cumulative_packet_histogram =
732 Get21CumulativeHistogram("First21_");
733 base::HistogramBase* six_packet_histogram = Get6PacketHistogram("Some6s_");
735 DCHECK_EQ(received_packets_.size(), received_acks_.size());
736 const QuicPacketSequenceNumber last_index =
737 std::min<QuicPacketSequenceNumber>(received_packets_.size() - 1,
738 largest_received_packet_sequence_number_);
739 const QuicPacketSequenceNumber index_of_first_21_contribution =
740 std::min<QuicPacketSequenceNumber>(21, last_index);
741 // Bit pattern of consecutively received packets that is maintained as we scan
742 // through the received_packets_ vector. Less significant bits correspond to
743 // less recent packets, and only the low order 21 bits are ever defined.
744 // Bit is 1 iff corresponding packet was received.
745 int packet_pattern_21 = 0;
746 // Zero is an invalid packet sequence number.
747 DCHECK(!received_packets_[0]);
748 for (size_t i = 1; i <= last_index; ++i) {
749 if (received_acks_[i])
750 is_an_ack_histogram->Add(i);
752 is_not_ack_histogram->Add(i);
754 packet_pattern_21 >>= 1;
755 if (received_packets_[i]) {
756 packet_arrived_histogram->Add(i);
757 packet_pattern_21 |= (1 << 20); // Turn on the 21st bit.
759 packet_missing_histogram->Add(i);
762 if (i == index_of_first_21_contribution) {
763 AddTo21CumulativeHistogram(first_cumulative_packet_histogram,
764 packet_pattern_21, i);
766 // We'll just record for non-overlapping ranges, to reduce histogramming
767 // cost for now. Each call does 21 separate histogram additions.
768 if (i > 21 || i % 21 == 0) {
769 AddTo21CumulativeHistogram(ongoing_cumulative_packet_histogram,
770 packet_pattern_21, 21);
774 continue; // Not enough packets to do any pattern recording.
775 int recent_6_mask = packet_pattern_21 >> 15;
776 DCHECK_LT(recent_6_mask, 64);
778 Get6PacketHistogram("First6_")->Add(recent_6_mask);
781 // Record some overlapping patterns, to get a better picture, since this is
782 // not very expensive.
784 six_packet_histogram->Add(recent_6_mask);