Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / net / network_stats.cc
blob50e61e0997b5097f37dcaa28e80b7c304039219e
1 // Copyright 2012 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 "chrome/browser/net/network_stats.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/metrics/histogram.h"
12 #include "base/rand_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/time/time.h"
15 #include "chrome/common/chrome_version_info.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "net/base/load_flags.h"
18 #include "net/base/net_errors.h"
19 #include "net/base/network_change_notifier.h"
20 #include "net/base/test_completion_callback.h"
21 #include "net/dns/single_request_host_resolver.h"
22 #include "net/proxy/proxy_service.h"
23 #include "net/socket/client_socket_factory.h"
24 #include "net/udp/datagram_client_socket.h"
25 #include "url/gurl.h"
27 using content::BrowserThread;
29 namespace chrome_browser_net {
31 // static
32 uint32 NetworkStats::maximum_tests_ = 8;
33 // static
34 uint32 NetworkStats::maximum_sequential_packets_ = 21;
35 // static
36 uint32 NetworkStats::maximum_NAT_packets_ = 2;
37 // static
38 uint32 NetworkStats::maximum_NAT_idle_seconds_ = 300;
39 // static
40 bool NetworkStats::start_test_after_connect_ = true;
42 // Specify the possible choices of probe packet sizes.
43 const uint32 kProbePacketBytes[] = {100, 500, 1200};
44 const uint32 kPacketSizeChoices = arraysize(kProbePacketBytes);
46 // List of ports used for probing test.
47 const uint16 kPorts[] = {443, 80};
49 // Number of first few packets that are recorded in a packet-correlation
50 // histogram, which shows exactly what sequence of packets were received.
51 // We use this to deduce specific packet loss correlation.
52 const uint32 kCorrelatedLossPacketCount = 6;
54 // This specifies the maximum message (payload) size of one packet.
55 const uint32 kMaxMessageSize = 1600;
57 // This specifies the maximum udp receiver buffer size.
58 const uint32 kMaxUdpReceiveBufferSize = 63000;
60 // This specifies the maximum udp receiver buffer size.
61 const uint32 kMaxUdpSendBufferSize = 4096;
63 // This should match TestType except for the last one.
64 const char* kTestName[] = {"TokenRequest", "StartPacket", "NonPacedPacket",
65 "PacedPacket", "NATBind", "PacketSizeTest"};
67 // Perform Pacing/Non-pacing test only if at least 2 packets are received
68 // in the StartPacketTest.
69 const uint32 kMinimumReceivedPacketsForPacingTest = 2;
70 // Perform NAT binding test only if at least 10 packets are received.
71 const uint32 kMinimumReceivedPacketsForNATTest = 10;
73 // Maximum inter-packet pacing interval in microseconds.
74 const uint32 kMaximumPacingMicros = 1000000;
75 // Timeout value for getting the token.
76 const uint32 kGetTokenTimeoutSeconds = 10;
77 // Timeout value for StartPacket and NonPacedPacket if the client does not get
78 // reply. For PacedPacket test, the timeout value is this number plus the total
79 // pacing interval.
80 const uint32 kReadDataTimeoutSeconds = 30;
81 // This is the timeout for NAT without Idle periods.
82 // For NAT test with idle periods, the timeout is the Idle period + this value.
83 const uint32 kReadNATTimeoutSeconds = 10;
84 // This is the timeout for PACKET_SIZE_TEST.
85 const uint32 kReadPacketSizeTimeoutSeconds = 10;
86 // This is the maxmium number of packets we would send for PACKET_SIZE_TEST.
87 uint32 kMaximumPacketSizeTestPackets = 1;
89 // These helper functions are similar to UMA_HISTOGRAM_XXX except that they do
90 // not create a static histogram_pointer.
91 void DynamicHistogramEnumeration(const std::string& name,
92 uint32 sample,
93 uint32 boundary_value) {
94 base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet(
95 name,
97 boundary_value,
98 boundary_value + 1,
99 base::HistogramBase::kUmaTargetedHistogramFlag);
100 histogram_pointer->Add(sample);
103 void DynamicHistogramTimes(const std::string& name,
104 const base::TimeDelta& sample) {
105 base::HistogramBase* histogram_pointer = base::Histogram::FactoryTimeGet(
106 name,
107 base::TimeDelta::FromMilliseconds(1),
108 base::TimeDelta::FromSeconds(30),
110 base::HistogramBase::kUmaTargetedHistogramFlag);
111 histogram_pointer->AddTime(sample);
114 void DynamicHistogramCounts(const std::string& name,
115 uint32 sample,
116 uint32 min,
117 uint32 max,
118 uint32 bucket_count) {
119 base::HistogramBase* histogram_pointer = base::Histogram::FactoryGet(
120 name, min, max, bucket_count,
121 base::HistogramBase::kUmaTargetedHistogramFlag);
122 histogram_pointer->Add(sample);
125 NetworkStats::NetworkStats(net::ClientSocketFactory* socket_factory)
126 : socket_factory_(socket_factory),
127 histogram_port_(0),
128 has_proxy_server_(false),
129 probe_packet_bytes_(0),
130 bytes_for_packet_size_test_(0),
131 current_test_index_(0),
132 read_state_(READ_STATE_IDLE),
133 write_state_(WRITE_STATE_IDLE),
134 weak_factory_(this) {
135 ResetData();
138 NetworkStats::~NetworkStats() {}
140 bool NetworkStats::Start(net::HostResolver* host_resolver,
141 const net::HostPortPair& server_host_port_pair,
142 uint16 histogram_port,
143 bool has_proxy_server,
144 uint32 probe_bytes,
145 uint32 bytes_for_packet_size_test,
146 const net::CompletionCallback& finished_callback) {
147 DCHECK(host_resolver);
148 histogram_port_ = histogram_port;
149 has_proxy_server_ = has_proxy_server;
150 probe_packet_bytes_ = probe_bytes;
151 bytes_for_packet_size_test_ = bytes_for_packet_size_test;
152 finished_callback_ = finished_callback;
153 test_sequence_.clear();
154 test_sequence_.push_back(TOKEN_REQUEST);
156 ResetData();
158 scoped_ptr<net::SingleRequestHostResolver> resolver(
159 new net::SingleRequestHostResolver(host_resolver));
160 net::HostResolver::RequestInfo request(server_host_port_pair);
161 int rv =
162 resolver->Resolve(request,
163 net::DEFAULT_PRIORITY,
164 &addresses_,
165 base::Bind(base::IgnoreResult(&NetworkStats::DoConnect),
166 base::Unretained(this)),
167 net::BoundNetLog());
168 if (rv == net::ERR_IO_PENDING) {
169 resolver_.swap(resolver);
170 return true;
172 return DoConnect(rv);
175 void NetworkStats::StartOneTest() {
176 if (test_sequence_[current_test_index_] == TOKEN_REQUEST) {
177 DCHECK_EQ(WRITE_STATE_IDLE, write_state_);
178 write_buffer_ = NULL;
179 SendHelloRequest();
180 } else {
181 SendProbeRequest();
185 void NetworkStats::ResetData() {
186 DCHECK_EQ(WRITE_STATE_IDLE, write_state_);
187 write_buffer_ = NULL;
188 packets_received_mask_.reset();
189 first_arrival_time_ = base::TimeTicks();
190 last_arrival_time_ = base::TimeTicks();
192 packet_rtt_.clear();
193 packet_rtt_.resize(maximum_sequential_packets_);
194 probe_request_time_ = base::TimeTicks();
195 // Note: inter_arrival_time_ should not be reset here because it is used in
196 // subsequent tests.
199 bool NetworkStats::DoConnect(int result) {
200 if (result != net::OK) {
201 TestPhaseComplete(RESOLVE_FAILED, result);
202 return false;
205 scoped_ptr<net::DatagramClientSocket> udp_socket =
206 socket_factory_->CreateDatagramClientSocket(
207 net::DatagramSocket::DEFAULT_BIND,
208 net::RandIntCallback(),
209 NULL,
210 net::NetLog::Source());
211 DCHECK(udp_socket);
212 DCHECK(!socket_);
213 socket_ = udp_socket.Pass();
215 const net::IPEndPoint& endpoint = addresses_.front();
216 int rv = socket_->Connect(endpoint);
217 if (rv < 0) {
218 TestPhaseComplete(CONNECT_FAILED, rv);
219 return false;
222 socket_->SetSendBufferSize(kMaxUdpSendBufferSize);
223 socket_->SetReceiveBufferSize(kMaxUdpReceiveBufferSize);
224 return ConnectComplete(rv);
227 bool NetworkStats::ConnectComplete(int result) {
228 if (result < 0) {
229 TestPhaseComplete(CONNECT_FAILED, result);
230 return false;
233 if (start_test_after_connect_) {
234 // Reads data for all HelloReply and all subsequent probe tests.
235 if (ReadData() != net::ERR_IO_PENDING) {
236 TestPhaseComplete(READ_FAILED, result);
237 return false;
239 SendHelloRequest();
240 } else {
241 // For unittesting. Only run the callback, do not destroy it.
242 if (!finished_callback_.is_null())
243 finished_callback_.Run(result);
245 return true;
248 void NetworkStats::SendHelloRequest() {
249 StartReadDataTimer(kGetTokenTimeoutSeconds, current_test_index_);
250 ProbePacket probe_packet;
251 probe_message_.SetPacketHeader(ProbePacket_Type_HELLO_REQUEST, &probe_packet);
252 probe_packet.set_group_id(current_test_index_);
253 std::string output = probe_message_.MakeEncodedPacket(probe_packet);
255 int result = SendData(output);
256 if (result < 0 && result != net::ERR_IO_PENDING)
257 TestPhaseComplete(WRITE_FAILED, result);
260 void NetworkStats::SendProbeRequest() {
261 ResetData();
262 // Use default timeout except for the NAT bind test.
263 uint32 timeout_seconds = kReadDataTimeoutSeconds;
264 uint32 number_packets = maximum_sequential_packets_;
265 uint32 probe_bytes = probe_packet_bytes_;
266 pacing_interval_ = base::TimeDelta();
267 switch (test_sequence_[current_test_index_]) {
268 case START_PACKET_TEST:
269 case NON_PACED_PACKET_TEST:
270 break;
271 case PACED_PACKET_TEST: {
272 pacing_interval_ =
273 std::min(inter_arrival_time_,
274 base::TimeDelta::FromMicroseconds(kMaximumPacingMicros));
275 timeout_seconds += pacing_interval_.InMicroseconds() *
276 (maximum_sequential_packets_ - 1) / 1000000;
277 break;
279 case NAT_BIND_TEST: {
280 // Make sure no integer overflow.
281 DCHECK_LE(maximum_NAT_idle_seconds_, 4000U);
282 int nat_test_idle_seconds = base::RandInt(1, maximum_NAT_idle_seconds_);
283 pacing_interval_ = base::TimeDelta::FromSeconds(nat_test_idle_seconds);
284 timeout_seconds = nat_test_idle_seconds + kReadNATTimeoutSeconds;
285 number_packets = maximum_NAT_packets_;
286 break;
288 case PACKET_SIZE_TEST: {
289 number_packets = kMaximumPacketSizeTestPackets;
290 probe_bytes = bytes_for_packet_size_test_;
291 timeout_seconds = kReadPacketSizeTimeoutSeconds;
292 break;
294 default:
295 NOTREACHED();
296 return;
298 DVLOG(1) << "NetworkStat: Probe pacing " << pacing_interval_.InMicroseconds()
299 << " microseconds. Time out " << timeout_seconds << " seconds";
300 ProbePacket probe_packet;
301 probe_message_.GenerateProbeRequest(token_,
302 current_test_index_,
303 probe_bytes,
304 pacing_interval_.InMicroseconds(),
305 number_packets,
306 &probe_packet);
307 std::string output = probe_message_.MakeEncodedPacket(probe_packet);
309 StartReadDataTimer(timeout_seconds, current_test_index_);
310 probe_request_time_ = base::TimeTicks::Now();
311 int result = SendData(output);
312 if (result < 0 && result != net::ERR_IO_PENDING)
313 TestPhaseComplete(WRITE_FAILED, result);
316 int NetworkStats::ReadData() {
317 if (!socket_.get())
318 return 0;
320 if (read_state_ == READ_STATE_READ_PENDING)
321 return net::ERR_IO_PENDING;
323 int rv = 0;
324 while (true) {
325 DCHECK(!read_buffer_.get());
326 read_buffer_ = new net::IOBuffer(kMaxMessageSize);
328 rv = socket_->Read(
329 read_buffer_.get(),
330 kMaxMessageSize,
331 base::Bind(&NetworkStats::OnReadComplete, weak_factory_.GetWeakPtr()));
332 if (rv <= 0)
333 break;
334 if (ReadComplete(rv))
335 return rv;
337 if (rv == net::ERR_IO_PENDING)
338 read_state_ = READ_STATE_READ_PENDING;
339 return rv;
342 void NetworkStats::OnReadComplete(int result) {
343 DCHECK_NE(net::ERR_IO_PENDING, result);
344 DCHECK_EQ(READ_STATE_READ_PENDING, read_state_);
346 read_state_ = READ_STATE_IDLE;
347 if (!ReadComplete(result)) {
348 // Called ReadData() via PostDelayedTask() to avoid recursion. Added a delay
349 // of 1ms so that the time-out will fire before we have time to really hog
350 // the CPU too extensively (waiting for the time-out) in case of an infinite
351 // loop.
352 base::MessageLoop::current()->PostDelayedTask(
353 FROM_HERE,
354 base::Bind(base::IgnoreResult(&NetworkStats::ReadData),
355 weak_factory_.GetWeakPtr()),
356 base::TimeDelta::FromMilliseconds(1));
360 bool NetworkStats::ReadComplete(int result) {
361 DCHECK(socket_.get());
362 DCHECK_NE(net::ERR_IO_PENDING, result);
363 if (result < 0) {
364 // Something is wrong, finish the test.
365 read_buffer_ = NULL;
366 TestPhaseComplete(READ_FAILED, result);
367 return true;
370 std::string encoded_message(read_buffer_->data(),
371 read_buffer_->data() + result);
372 read_buffer_ = NULL;
373 ProbePacket probe_packet;
374 if (!probe_message_.ParseInput(encoded_message, &probe_packet))
375 return false;
376 // Discard if the packet is for a different test.
377 if (probe_packet.group_id() != current_test_index_)
378 return false;
380 // Whether all packets in the current test have been received.
381 bool current_test_complete = false;
382 switch (probe_packet.header().type()) {
383 case ProbePacket_Type_HELLO_REPLY:
384 token_ = probe_packet.token();
385 if (current_test_index_ == 0)
386 test_sequence_.push_back(START_PACKET_TEST);
387 current_test_complete = true;
388 break;
389 case ProbePacket_Type_PROBE_REPLY:
390 current_test_complete = UpdateReception(probe_packet);
391 break;
392 default:
393 DVLOG(1) << "Received unexpected packet type: "
394 << probe_packet.header().type();
397 if (!current_test_complete) {
398 // All packets have not been received for the current test.
399 return false;
401 // All packets are received for the current test.
402 // Read completes if all tests are done (if TestPhaseComplete didn't start
403 // another test).
404 return TestPhaseComplete(SUCCESS, net::OK);
407 bool NetworkStats::UpdateReception(const ProbePacket& probe_packet) {
408 uint32 packet_index = probe_packet.packet_index();
409 if (packet_index >= packet_rtt_.size())
410 return false;
411 packets_received_mask_.set(packet_index);
412 TestType test_type = test_sequence_[current_test_index_];
413 uint32 received_packets = packets_received_mask_.count();
415 // Now() has resolution ~1-15ms. HighResNow() has high resolution but it
416 // is warned not to use it unless necessary.
417 base::TimeTicks current_time = base::TimeTicks::Now();
418 last_arrival_time_ = current_time;
419 if (first_arrival_time_.is_null())
420 first_arrival_time_ = current_time;
422 // Need to do this after updating the last_arrival_time_ since NAT_BIND_TEST
423 // and PACKET_SIZE_TEST record the SendToLastRecvDelay.
424 if (test_type == NAT_BIND_TEST) {
425 return received_packets >= maximum_NAT_packets_;
427 if (test_type == PACKET_SIZE_TEST) {
428 return received_packets >= kMaximumPacketSizeTestPackets;
431 base::TimeDelta rtt =
432 current_time - probe_request_time_ -
433 base::TimeDelta::FromMicroseconds(std::max(
434 static_cast<int64>(0), probe_packet.server_processing_micros()));
435 base::TimeDelta min_rtt = base::TimeDelta::FromMicroseconds(1L);
436 packet_rtt_[packet_index] = (rtt >= min_rtt) ? rtt : min_rtt;
438 if (received_packets < maximum_sequential_packets_)
439 return false;
440 // All packets in the current test are received.
441 inter_arrival_time_ = (last_arrival_time_ - first_arrival_time_) /
442 std::max(1U, (received_packets - 1));
443 if (test_type == START_PACKET_TEST) {
444 test_sequence_.push_back(PACKET_SIZE_TEST);
445 test_sequence_.push_back(TOKEN_REQUEST);
446 // No need to add TOKEN_REQUEST here when all packets are received.
447 test_sequence_.push_back(base::RandInt(0, 1) ? PACED_PACKET_TEST
448 : NON_PACED_PACKET_TEST);
449 test_sequence_.push_back(TOKEN_REQUEST);
450 test_sequence_.push_back(NAT_BIND_TEST);
451 test_sequence_.push_back(TOKEN_REQUEST);
453 return true;
456 int NetworkStats::SendData(const std::string& output) {
457 if (write_buffer_.get() || !socket_.get() ||
458 write_state_ == WRITE_STATE_WRITE_PENDING) {
459 return net::ERR_UNEXPECTED;
461 scoped_refptr<net::StringIOBuffer> buffer(new net::StringIOBuffer(output));
462 write_buffer_ = new net::DrainableIOBuffer(buffer.get(), buffer->size());
464 int bytes_written = socket_->Write(
465 write_buffer_.get(),
466 write_buffer_->BytesRemaining(),
467 base::Bind(&NetworkStats::OnWriteComplete, weak_factory_.GetWeakPtr()));
468 if (bytes_written < 0) {
469 if (bytes_written == net::ERR_IO_PENDING)
470 write_state_ = WRITE_STATE_WRITE_PENDING;
471 return bytes_written;
473 UpdateSendBuffer(bytes_written);
474 return net::OK;
477 void NetworkStats::OnWriteComplete(int result) {
478 DCHECK_NE(net::ERR_IO_PENDING, result);
479 DCHECK_EQ(WRITE_STATE_WRITE_PENDING, write_state_);
480 write_state_ = WRITE_STATE_IDLE;
481 if (result < 0 || !socket_.get() || write_buffer_.get() == NULL) {
482 TestPhaseComplete(WRITE_FAILED, result);
483 return;
485 UpdateSendBuffer(result);
488 void NetworkStats::UpdateSendBuffer(int bytes_sent) {
489 write_buffer_->DidConsume(bytes_sent);
490 DCHECK_EQ(write_buffer_->BytesRemaining(), 0);
491 DCHECK_EQ(WRITE_STATE_IDLE, write_state_);
492 write_buffer_ = NULL;
495 void NetworkStats::StartReadDataTimer(uint32 seconds, uint32 test_index) {
496 base::MessageLoop::current()->PostDelayedTask(
497 FROM_HERE,
498 base::Bind(&NetworkStats::OnReadDataTimeout,
499 weak_factory_.GetWeakPtr(),
500 test_index),
501 base::TimeDelta::FromSeconds(seconds));
504 void NetworkStats::OnReadDataTimeout(uint32 test_index) {
505 // If the current_test_index_ has changed since we set the timeout,
506 // the current test has been completed, so do nothing.
507 if (test_index != current_test_index_)
508 return;
509 // If test_type is TOKEN_REQUEST, it will do nothing but call
510 // TestPhaseComplete().
511 TestType test_type = test_sequence_[current_test_index_];
513 uint32 received_packets = packets_received_mask_.count();
514 if (received_packets >= 2) {
515 inter_arrival_time_ =
516 (last_arrival_time_ - first_arrival_time_) / (received_packets - 1);
518 // Add other tests if this is START_PACKET_TEST.
519 if (test_type == START_PACKET_TEST) {
520 if (received_packets >= kMinimumReceivedPacketsForPacingTest) {
521 test_sequence_.push_back(TOKEN_REQUEST);
522 test_sequence_.push_back(PACKET_SIZE_TEST);
523 test_sequence_.push_back(TOKEN_REQUEST);
524 test_sequence_.push_back(base::RandInt(0, 1) ? PACED_PACKET_TEST
525 : NON_PACED_PACKET_TEST);
527 if (received_packets >= kMinimumReceivedPacketsForNATTest) {
528 test_sequence_.push_back(TOKEN_REQUEST);
529 test_sequence_.push_back(NAT_BIND_TEST);
530 test_sequence_.push_back(TOKEN_REQUEST);
533 TestPhaseComplete(READ_TIMED_OUT, net::ERR_FAILED);
536 bool NetworkStats::TestPhaseComplete(Status status, int result) {
537 // If there is no valid token, do nothing and delete self.
538 // This includes all connection error, name resolve error, etc.
539 if (write_state_ == WRITE_STATE_WRITE_PENDING) {
540 UMA_HISTOGRAM_BOOLEAN("NetConnectivity5.TestFailed.WritePending", true);
541 } else if (status == SUCCESS || status == READ_TIMED_OUT) {
542 TestType current_test = test_sequence_[current_test_index_];
543 DCHECK_LT(current_test, TEST_TYPE_MAX);
544 if (current_test != TOKEN_REQUEST) {
545 RecordHistograms(current_test);
546 } else if (current_test_index_ > 0) {
547 if (test_sequence_[current_test_index_ - 1] == NAT_BIND_TEST) {
548 // We record the NATTestReceivedHistograms after the succeeding
549 // TokenRequest.
550 RecordNATTestReceivedHistograms(status);
551 } else if (test_sequence_[current_test_index_ - 1] == PACKET_SIZE_TEST) {
552 // We record the PacketSizeTestReceivedHistograms after the succeeding
553 // TokenRequest.
554 RecordPacketSizeTestReceivedHistograms(status);
558 // Move to the next test.
559 current_test = GetNextTest();
560 if (current_test_index_ <= maximum_tests_ && current_test < TEST_TYPE_MAX) {
561 DVLOG(1) << "NetworkStat: Start Probe test: " << current_test;
562 base::MessageLoop::current()->PostTask(
563 FROM_HERE,
564 base::Bind(&NetworkStats::StartOneTest, weak_factory_.GetWeakPtr()));
565 return false;
569 // All tests are done.
570 DoFinishCallback(result);
572 // Close the socket so that there are no more IO operations.
573 if (socket_.get())
574 socket_->Close();
576 DVLOG(1) << "NetworkStat: schedule delete self at test index "
577 << current_test_index_;
578 delete this;
579 return true;
582 NetworkStats::TestType NetworkStats::GetNextTest() {
583 ++current_test_index_;
584 if (current_test_index_ >= test_sequence_.size())
585 return TEST_TYPE_MAX;
586 return test_sequence_[current_test_index_];
589 void NetworkStats::DoFinishCallback(int result) {
590 if (!finished_callback_.is_null()) {
591 net::CompletionCallback callback = finished_callback_;
592 finished_callback_.Reset();
593 callback.Run(result);
597 void NetworkStats::RecordHistograms(TestType test_type) {
598 switch (test_type) {
599 case START_PACKET_TEST:
600 case NON_PACED_PACKET_TEST:
601 case PACED_PACKET_TEST: {
602 RecordInterArrivalHistograms(test_type);
603 RecordPacketLossSeriesHistograms(test_type);
604 RecordPacketsReceivedHistograms(test_type);
605 // Only record RTT for these packet indices.
606 uint32 rtt_indices[] = {0, 1, 2, 9, 19};
607 for (uint32 i = 0; i < arraysize(rtt_indices); ++i) {
608 if (rtt_indices[i] < packet_rtt_.size())
609 RecordRTTHistograms(test_type, rtt_indices[i]);
611 RecordSendToLastRecvDelayHistograms(test_type);
612 return;
614 case NAT_BIND_TEST:
615 RecordSendToLastRecvDelayHistograms(test_type);
616 return;
617 case PACKET_SIZE_TEST:
618 // No need to record RTT for PacketSizeTest.
619 return;
620 default:
621 DVLOG(1) << "Unexpected test type " << test_type
622 << " in RecordHistograms.";
626 void NetworkStats::RecordInterArrivalHistograms(TestType test_type) {
627 DCHECK_NE(test_type, PACKET_SIZE_TEST);
628 std::string histogram_name =
629 base::StringPrintf("NetConnectivity5.%s.Sent%d.PacketDelay.%d.%dB",
630 kTestName[test_type],
631 maximum_sequential_packets_,
632 histogram_port_,
633 probe_packet_bytes_);
634 // Record the time normalized to 20 packet inter-arrivals.
635 DynamicHistogramTimes(histogram_name, inter_arrival_time_ * 20);
638 void NetworkStats::RecordPacketsReceivedHistograms(TestType test_type) {
639 DCHECK_NE(test_type, PACKET_SIZE_TEST);
640 const char* test_name = kTestName[test_type];
641 std::string histogram_prefix = base::StringPrintf(
642 "NetConnectivity5.%s.Sent%d.", test_name, maximum_sequential_packets_);
643 std::string histogram_suffix =
644 base::StringPrintf(".%d.%dB", histogram_port_, probe_packet_bytes_);
645 std::string name = histogram_prefix + "GotAPacket" + histogram_suffix;
646 base::HistogramBase* histogram_pointer = base::BooleanHistogram::FactoryGet(
647 name, base::HistogramBase::kUmaTargetedHistogramFlag);
648 histogram_pointer->Add(packets_received_mask_.any());
650 DynamicHistogramEnumeration(
651 histogram_prefix + "PacketsRecv" + histogram_suffix,
652 packets_received_mask_.count(),
653 maximum_sequential_packets_ + 1);
655 if (!packets_received_mask_.any())
656 return;
658 base::HistogramBase* received_nth_packet_histogram =
659 base::Histogram::FactoryGet(
660 histogram_prefix + "RecvNthPacket" + histogram_suffix,
662 maximum_sequential_packets_ + 1,
663 maximum_sequential_packets_ + 2,
664 base::HistogramBase::kUmaTargetedHistogramFlag);
666 int count = 0;
667 for (size_t j = 0; j < maximum_sequential_packets_; ++j) {
668 int packet_number = j + 1;
669 if (packets_received_mask_.test(j)) {
670 received_nth_packet_histogram->Add(packet_number);
671 ++count;
673 std::string histogram_name =
674 base::StringPrintf("%sNumRecvFromFirst%02dPackets%s",
675 histogram_prefix.c_str(),
676 packet_number,
677 histogram_suffix.c_str());
678 DynamicHistogramEnumeration(histogram_name, count, packet_number + 1);
682 void NetworkStats::RecordNATTestReceivedHistograms(Status status) {
683 const char* test_name = kTestName[NAT_BIND_TEST];
684 bool test_result = status == SUCCESS;
685 std::string middle_name = test_result ? "Connectivity.Success"
686 : "Connectivity.Failure";
687 // Record whether the HelloRequest got reply successfully.
688 std::string histogram_name =
689 base::StringPrintf("NetConnectivity5.%s.Sent%d.%s.%d.%dB",
690 test_name,
691 maximum_NAT_packets_,
692 middle_name.c_str(),
693 histogram_port_,
694 probe_packet_bytes_);
695 uint32 bucket_count = std::min(maximum_NAT_idle_seconds_ + 2, 50U);
696 DynamicHistogramCounts(histogram_name,
697 pacing_interval_.InSeconds(),
699 maximum_NAT_idle_seconds_ + 1,
700 bucket_count);
702 // Record the NAT bind result only if the HelloRequest successfully got the
703 // token and the first NAT test packet is received.
704 if (!test_result || !packets_received_mask_.test(0))
705 return;
707 middle_name = packets_received_mask_.test(1) ? "Bind.Success"
708 : "Bind.Failure";
709 histogram_name = base::StringPrintf("NetConnectivity5.%s.Sent%d.%s.%d.%dB",
710 test_name,
711 maximum_NAT_packets_,
712 middle_name.c_str(),
713 histogram_port_,
714 probe_packet_bytes_);
715 DynamicHistogramCounts(histogram_name,
716 pacing_interval_.InSeconds(),
718 maximum_NAT_idle_seconds_ + 1,
719 bucket_count);
722 void NetworkStats::RecordPacketSizeTestReceivedHistograms(Status status) {
723 const char* test_name = kTestName[PACKET_SIZE_TEST];
724 bool test_result = (status == SUCCESS && packets_received_mask_.test(0));
725 std::string middle_name = test_result ? "Connectivity.Success"
726 : "Connectivity.Failure";
727 // Record whether the HelloRequest got reply successfully.
728 std::string histogram_name =
729 base::StringPrintf("NetConnectivity5.%s.%s.%d",
730 test_name,
731 middle_name.c_str(),
732 histogram_port_);
733 base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet(
734 histogram_name, kProbePacketBytes[kPacketSizeChoices - 1],
735 ProbeMessage::kMaxProbePacketBytes, 60,
736 base::HistogramBase::kUmaTargetedHistogramFlag);
737 histogram_pointer->Add(bytes_for_packet_size_test_);
740 void NetworkStats::RecordPacketLossSeriesHistograms(TestType test_type) {
741 DCHECK_NE(test_type, PACKET_SIZE_TEST);
742 const char* test_name = kTestName[test_type];
743 // Build "NetConnectivity5.<TestName>.First6.SeriesRecv.<port>.<probe_size>"
744 // histogram name. Total 3(tests) x 12 histograms.
745 std::string series_acked_histogram_name =
746 base::StringPrintf("NetConnectivity5.%s.First6.SeriesRecv.%d.%dB",
747 test_name,
748 histogram_port_,
749 probe_packet_bytes_);
750 uint32 histogram_boundary = 1 << kCorrelatedLossPacketCount;
751 uint32 correlated_packet_mask =
752 (histogram_boundary - 1) & packets_received_mask_.to_ulong();
753 DynamicHistogramEnumeration(
754 series_acked_histogram_name, correlated_packet_mask, histogram_boundary);
756 // If we are running without a proxy, we'll generate an extra histogram with
757 // the ".NoProxy" suffix.
758 if (!has_proxy_server_) {
759 series_acked_histogram_name.append(".NoProxy");
760 DynamicHistogramEnumeration(series_acked_histogram_name,
761 correlated_packet_mask,
762 histogram_boundary);
766 void NetworkStats::RecordRTTHistograms(TestType test_type, uint32 index) {
767 DCHECK_NE(test_type, PACKET_SIZE_TEST);
768 DCHECK_LT(index, packet_rtt_.size());
770 if (!packets_received_mask_.test(index))
771 return; // Probe packet never received.
773 std::string rtt_histogram_name = base::StringPrintf(
774 "NetConnectivity5.%s.Sent%d.Success.RTT.Packet%02d.%d.%dB",
775 kTestName[test_type],
776 maximum_sequential_packets_,
777 index + 1,
778 histogram_port_,
779 probe_packet_bytes_);
780 DynamicHistogramTimes(rtt_histogram_name, packet_rtt_[index]);
783 void NetworkStats::RecordSendToLastRecvDelayHistograms(TestType test_type) {
784 DCHECK_NE(test_type, PACKET_SIZE_TEST);
785 if (packets_received_mask_.count() < 2)
786 return; // Too few packets are received.
787 uint32 packets_sent = test_type == NAT_BIND_TEST
788 ? maximum_NAT_packets_ : maximum_sequential_packets_;
789 std::string histogram_name = base::StringPrintf(
790 "NetConnectivity5.%s.Sent%d.SendToLastRecvDelay.%d.%dB",
791 kTestName[test_type],
792 packets_sent,
793 histogram_port_,
794 probe_packet_bytes_);
795 base::TimeDelta send_to_last_recv_time =
796 std::max(last_arrival_time_ - probe_request_time_ -
797 pacing_interval_ * (packets_sent - 1),
798 base::TimeDelta::FromMilliseconds(0));
799 DynamicHistogramTimes(histogram_name, send_to_last_recv_time);
802 // ProxyDetector methods and members.
803 ProxyDetector::ProxyDetector(net::ProxyService* proxy_service,
804 const net::HostPortPair& server_address,
805 OnResolvedCallback callback)
806 : proxy_service_(proxy_service),
807 server_address_(server_address),
808 callback_(callback),
809 has_pending_proxy_resolution_(false) {}
811 ProxyDetector::~ProxyDetector() {
812 CHECK(!has_pending_proxy_resolution_);
815 void ProxyDetector::StartResolveProxy() {
816 std::string url =
817 base::StringPrintf("https://%s", server_address_.ToString().c_str());
818 GURL gurl(url);
820 has_pending_proxy_resolution_ = true;
821 DCHECK(proxy_service_);
822 int rv = proxy_service_->ResolveProxy(
823 gurl,
824 net::LOAD_NORMAL,
825 &proxy_info_,
826 base::Bind(&ProxyDetector::OnResolveProxyComplete,
827 base::Unretained(this)),
828 NULL,
829 NULL,
830 net::BoundNetLog());
831 if (rv != net::ERR_IO_PENDING)
832 OnResolveProxyComplete(rv);
835 void ProxyDetector::OnResolveProxyComplete(int result) {
836 has_pending_proxy_resolution_ = false;
837 bool has_proxy_server =
838 (result == net::OK && proxy_info_.proxy_server().is_valid() &&
839 !proxy_info_.proxy_server().is_direct());
841 OnResolvedCallback callback = callback_;
842 BrowserThread::PostTask(
843 BrowserThread::IO, FROM_HERE, base::Bind(callback, has_proxy_server));
845 // TODO(rtenneti): Will we leak if ProxyResolve is cancelled (or proxy
846 // resolution never completes).
847 delete this;
850 void CollectNetworkStats(const std::string& network_stats_server,
851 IOThread* io_thread) {
852 if (network_stats_server.empty())
853 return;
855 // If we are not on IO Thread, then post a task to call CollectNetworkStats on
856 // IO Thread.
857 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
858 BrowserThread::PostTask(
859 BrowserThread::IO,
860 FROM_HERE,
861 base::Bind(&CollectNetworkStats, network_stats_server, io_thread));
862 return;
865 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
867 if (net::NetworkChangeNotifier::IsOffline()) {
868 return;
871 CR_DEFINE_STATIC_LOCAL(scoped_refptr<base::FieldTrial>, trial, ());
872 static bool collect_stats = false;
874 if (!trial.get()) {
875 // Set up a field trial to collect network stats for UDP.
876 const base::FieldTrial::Probability kDivisor = 1000;
878 // Enable the connectivity testing for 0.5% of the users in stable channel.
879 base::FieldTrial::Probability probability_per_group = kDivisor / 200;
881 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
882 if (channel == chrome::VersionInfo::CHANNEL_CANARY) {
883 // Enable the connectivity testing for 50% of the users in canary channel.
884 probability_per_group = kDivisor / 2;
885 } else if (channel == chrome::VersionInfo::CHANNEL_DEV) {
886 // Enable the connectivity testing for 10% of the users in dev channel.
887 probability_per_group = kDivisor / 10;
888 } else if (channel == chrome::VersionInfo::CHANNEL_BETA) {
889 // Enable the connectivity testing for 1% of the users in beta channel.
890 probability_per_group = kDivisor / 100;
893 // After July 31, 2014 builds, it will always be in default group
894 // (disable_network_stats).
895 trial = base::FieldTrialList::FactoryGetFieldTrial(
896 "NetworkConnectivity", kDivisor, "disable_network_stats",
897 2014, 7, 31, base::FieldTrial::SESSION_RANDOMIZED, NULL);
899 // Add option to collect_stats for NetworkConnectivity.
900 int collect_stats_group =
901 trial->AppendGroup("collect_stats", probability_per_group);
902 if (trial->group() == collect_stats_group)
903 collect_stats = true;
906 if (!collect_stats)
907 return;
909 // Run test kMaxNumberOfTests times.
910 const size_t kMaxNumberOfTests = INT_MAX;
911 static size_t number_of_tests_done = 0;
912 if (number_of_tests_done > kMaxNumberOfTests)
913 return;
914 ++number_of_tests_done;
916 net::HostResolver* host_resolver = io_thread->globals()->host_resolver.get();
917 DCHECK(host_resolver);
919 uint32 port_index = base::RandInt(0, arraysize(kPorts) - 1);
920 uint16 histogram_port = kPorts[port_index];
921 net::HostPortPair server_address(network_stats_server, histogram_port);
923 net::ProxyService* proxy_service =
924 io_thread->globals()->system_proxy_service.get();
925 DCHECK(proxy_service);
927 ProxyDetector::OnResolvedCallback callback = base::Bind(
928 &StartNetworkStatsTest, host_resolver, server_address, histogram_port);
930 ProxyDetector* proxy_client =
931 new ProxyDetector(proxy_service, server_address, callback);
932 proxy_client->StartResolveProxy();
935 void StartNetworkStatsTest(net::HostResolver* host_resolver,
936 const net::HostPortPair& server_address,
937 uint16 histogram_port,
938 bool has_proxy_server) {
939 int probe_choice = base::RandInt(0, kPacketSizeChoices - 1);
941 DCHECK_LE(ProbeMessage::kMaxProbePacketBytes, kMaxMessageSize);
942 // Pick a packet size between 1200 and kMaxProbePacketBytes bytes.
943 uint32 bytes_for_packet_size_test =
944 base::RandInt(kProbePacketBytes[kPacketSizeChoices - 1],
945 ProbeMessage::kMaxProbePacketBytes);
947 // |udp_stats_client| is owned and deleted in the class NetworkStats.
948 NetworkStats* udp_stats_client =
949 new NetworkStats(net::ClientSocketFactory::GetDefaultFactory());
950 udp_stats_client->Start(host_resolver,
951 server_address,
952 histogram_port,
953 has_proxy_server,
954 kProbePacketBytes[probe_choice],
955 bytes_for_packet_size_test,
956 net::CompletionCallback());
959 } // namespace chrome_browser_net