NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / net / network_stats.cc
blobc218227e454c246ee0ca75f943a770880d9a95e7
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/net_errors.h"
18 #include "net/base/network_change_notifier.h"
19 #include "net/base/test_completion_callback.h"
20 #include "net/dns/single_request_host_resolver.h"
21 #include "net/proxy/proxy_service.h"
22 #include "net/socket/client_socket_factory.h"
23 #include "net/udp/datagram_client_socket.h"
24 #include "url/gurl.h"
26 using content::BrowserThread;
28 namespace chrome_browser_net {
30 // static
31 uint32 NetworkStats::maximum_tests_ = 8;
32 // static
33 uint32 NetworkStats::maximum_sequential_packets_ = 21;
34 // static
35 uint32 NetworkStats::maximum_NAT_packets_ = 2;
36 // static
37 uint32 NetworkStats::maximum_NAT_idle_seconds_ = 300;
38 // static
39 bool NetworkStats::start_test_after_connect_ = true;
41 // Specify the possible choices of probe packet sizes.
42 const uint32 kProbePacketBytes[] = {100, 500, 1200};
43 const uint32 kPacketSizeChoices = arraysize(kProbePacketBytes);
45 // List of ports used for probing test.
46 const uint16 kPorts[] = {443, 80};
48 // Number of first few packets that are recorded in a packet-correlation
49 // histogram, which shows exactly what sequence of packets were received.
50 // We use this to deduce specific packet loss correlation.
51 const uint32 kCorrelatedLossPacketCount = 6;
53 // This specifies the maximum message (payload) size of one packet.
54 const uint32 kMaxMessageSize = 1600;
56 // This specifies the maximum udp receiver buffer size.
57 const uint32 kMaxUdpReceiveBufferSize = 63000;
59 // This specifies the maximum udp receiver buffer size.
60 const uint32 kMaxUdpSendBufferSize = 4096;
62 // This should match TestType except for the last one.
63 const char* kTestName[] = {"TokenRequest", "StartPacket", "NonPacedPacket",
64 "PacedPacket", "NATBind", "PacketSizeTest"};
66 // Perform Pacing/Non-pacing test only if at least 2 packets are received
67 // in the StartPacketTest.
68 const uint32 kMinimumReceivedPacketsForPacingTest = 2;
69 // Perform NAT binding test only if at least 10 packets are received.
70 const uint32 kMinimumReceivedPacketsForNATTest = 10;
72 // Maximum inter-packet pacing interval in microseconds.
73 const uint32 kMaximumPacingMicros = 1000000;
74 // Timeout value for getting the token.
75 const uint32 kGetTokenTimeoutSeconds = 10;
76 // Timeout value for StartPacket and NonPacedPacket if the client does not get
77 // reply. For PacedPacket test, the timeout value is this number plus the total
78 // pacing interval.
79 const uint32 kReadDataTimeoutSeconds = 30;
80 // This is the timeout for NAT without Idle periods.
81 // For NAT test with idle periods, the timeout is the Idle period + this value.
82 const uint32 kReadNATTimeoutSeconds = 10;
83 // This is the timeout for PACKET_SIZE_TEST.
84 const uint32 kReadPacketSizeTimeoutSeconds = 10;
85 // This is the maxmium number of packets we would send for PACKET_SIZE_TEST.
86 uint32 kMaximumPacketSizeTestPackets = 1;
88 // These helper functions are similar to UMA_HISTOGRAM_XXX except that they do
89 // not create a static histogram_pointer.
90 void DynamicHistogramEnumeration(const std::string& name,
91 uint32 sample,
92 uint32 boundary_value) {
93 base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet(
94 name,
96 boundary_value,
97 boundary_value + 1,
98 base::HistogramBase::kUmaTargetedHistogramFlag);
99 histogram_pointer->Add(sample);
102 void DynamicHistogramTimes(const std::string& name,
103 const base::TimeDelta& sample) {
104 base::HistogramBase* histogram_pointer = base::Histogram::FactoryTimeGet(
105 name,
106 base::TimeDelta::FromMilliseconds(1),
107 base::TimeDelta::FromSeconds(30),
109 base::HistogramBase::kUmaTargetedHistogramFlag);
110 histogram_pointer->AddTime(sample);
113 void DynamicHistogramCounts(const std::string& name,
114 uint32 sample,
115 uint32 min,
116 uint32 max,
117 uint32 bucket_count) {
118 base::HistogramBase* histogram_pointer = base::Histogram::FactoryGet(
119 name, min, max, bucket_count,
120 base::HistogramBase::kUmaTargetedHistogramFlag);
121 histogram_pointer->Add(sample);
124 NetworkStats::NetworkStats(net::ClientSocketFactory* socket_factory)
125 : socket_factory_(socket_factory),
126 histogram_port_(0),
127 has_proxy_server_(false),
128 probe_packet_bytes_(0),
129 bytes_for_packet_size_test_(0),
130 current_test_index_(0),
131 read_state_(READ_STATE_IDLE),
132 write_state_(WRITE_STATE_IDLE),
133 weak_factory_(this) {
134 ResetData();
137 NetworkStats::~NetworkStats() {}
139 bool NetworkStats::Start(net::HostResolver* host_resolver,
140 const net::HostPortPair& server_host_port_pair,
141 uint16 histogram_port,
142 bool has_proxy_server,
143 uint32 probe_bytes,
144 uint32 bytes_for_packet_size_test,
145 const net::CompletionCallback& finished_callback) {
146 DCHECK(host_resolver);
147 histogram_port_ = histogram_port;
148 has_proxy_server_ = has_proxy_server;
149 probe_packet_bytes_ = probe_bytes;
150 bytes_for_packet_size_test_ = bytes_for_packet_size_test;
151 finished_callback_ = finished_callback;
152 test_sequence_.clear();
153 test_sequence_.push_back(TOKEN_REQUEST);
155 ResetData();
157 scoped_ptr<net::SingleRequestHostResolver> resolver(
158 new net::SingleRequestHostResolver(host_resolver));
159 net::HostResolver::RequestInfo request(server_host_port_pair);
160 int rv =
161 resolver->Resolve(request,
162 net::DEFAULT_PRIORITY,
163 &addresses_,
164 base::Bind(base::IgnoreResult(&NetworkStats::DoConnect),
165 base::Unretained(this)),
166 net::BoundNetLog());
167 if (rv == net::ERR_IO_PENDING) {
168 resolver_.swap(resolver);
169 return true;
171 return DoConnect(rv);
174 void NetworkStats::StartOneTest() {
175 if (test_sequence_[current_test_index_] == TOKEN_REQUEST) {
176 DCHECK_EQ(WRITE_STATE_IDLE, write_state_);
177 write_buffer_ = NULL;
178 SendHelloRequest();
179 } else {
180 SendProbeRequest();
184 void NetworkStats::ResetData() {
185 DCHECK_EQ(WRITE_STATE_IDLE, write_state_);
186 write_buffer_ = NULL;
187 packets_received_mask_.reset();
188 first_arrival_time_ = base::TimeTicks();
189 last_arrival_time_ = base::TimeTicks();
191 packet_rtt_.clear();
192 packet_rtt_.resize(maximum_sequential_packets_);
193 probe_request_time_ = base::TimeTicks();
194 // Note: inter_arrival_time_ should not be reset here because it is used in
195 // subsequent tests.
198 bool NetworkStats::DoConnect(int result) {
199 if (result != net::OK) {
200 TestPhaseComplete(RESOLVE_FAILED, result);
201 return false;
204 scoped_ptr<net::DatagramClientSocket> udp_socket =
205 socket_factory_->CreateDatagramClientSocket(
206 net::DatagramSocket::DEFAULT_BIND,
207 net::RandIntCallback(),
208 NULL,
209 net::NetLog::Source());
210 DCHECK(udp_socket);
211 DCHECK(!socket_);
212 socket_ = udp_socket.Pass();
214 const net::IPEndPoint& endpoint = addresses_.front();
215 int rv = socket_->Connect(endpoint);
216 if (rv < 0) {
217 TestPhaseComplete(CONNECT_FAILED, rv);
218 return false;
221 socket_->SetSendBufferSize(kMaxUdpSendBufferSize);
222 socket_->SetReceiveBufferSize(kMaxUdpReceiveBufferSize);
223 return ConnectComplete(rv);
226 bool NetworkStats::ConnectComplete(int result) {
227 if (result < 0) {
228 TestPhaseComplete(CONNECT_FAILED, result);
229 return false;
232 if (start_test_after_connect_) {
233 // Reads data for all HelloReply and all subsequent probe tests.
234 if (ReadData() != net::ERR_IO_PENDING) {
235 TestPhaseComplete(READ_FAILED, result);
236 return false;
238 SendHelloRequest();
239 } else {
240 // For unittesting. Only run the callback, do not destroy it.
241 if (!finished_callback_.is_null())
242 finished_callback_.Run(result);
244 return true;
247 void NetworkStats::SendHelloRequest() {
248 StartReadDataTimer(kGetTokenTimeoutSeconds, current_test_index_);
249 ProbePacket probe_packet;
250 probe_message_.SetPacketHeader(ProbePacket_Type_HELLO_REQUEST, &probe_packet);
251 probe_packet.set_group_id(current_test_index_);
252 std::string output = probe_message_.MakeEncodedPacket(probe_packet);
254 int result = SendData(output);
255 if (result < 0 && result != net::ERR_IO_PENDING)
256 TestPhaseComplete(WRITE_FAILED, result);
259 void NetworkStats::SendProbeRequest() {
260 ResetData();
261 // Use default timeout except for the NAT bind test.
262 uint32 timeout_seconds = kReadDataTimeoutSeconds;
263 uint32 number_packets = maximum_sequential_packets_;
264 uint32 probe_bytes = probe_packet_bytes_;
265 pacing_interval_ = base::TimeDelta();
266 switch (test_sequence_[current_test_index_]) {
267 case START_PACKET_TEST:
268 case NON_PACED_PACKET_TEST:
269 break;
270 case PACED_PACKET_TEST: {
271 pacing_interval_ =
272 std::min(inter_arrival_time_,
273 base::TimeDelta::FromMicroseconds(kMaximumPacingMicros));
274 timeout_seconds += pacing_interval_.InMicroseconds() *
275 (maximum_sequential_packets_ - 1) / 1000000;
276 break;
278 case NAT_BIND_TEST: {
279 // Make sure no integer overflow.
280 DCHECK_LE(maximum_NAT_idle_seconds_, 4000U);
281 int nat_test_idle_seconds = base::RandInt(1, maximum_NAT_idle_seconds_);
282 pacing_interval_ = base::TimeDelta::FromSeconds(nat_test_idle_seconds);
283 timeout_seconds = nat_test_idle_seconds + kReadNATTimeoutSeconds;
284 number_packets = maximum_NAT_packets_;
285 break;
287 case PACKET_SIZE_TEST: {
288 number_packets = kMaximumPacketSizeTestPackets;
289 probe_bytes = bytes_for_packet_size_test_;
290 timeout_seconds = kReadPacketSizeTimeoutSeconds;
291 break;
293 default:
294 NOTREACHED();
295 return;
297 DVLOG(1) << "NetworkStat: Probe pacing " << pacing_interval_.InMicroseconds()
298 << " microseconds. Time out " << timeout_seconds << " seconds";
299 ProbePacket probe_packet;
300 probe_message_.GenerateProbeRequest(token_,
301 current_test_index_,
302 probe_bytes,
303 pacing_interval_.InMicroseconds(),
304 number_packets,
305 &probe_packet);
306 std::string output = probe_message_.MakeEncodedPacket(probe_packet);
308 StartReadDataTimer(timeout_seconds, current_test_index_);
309 probe_request_time_ = base::TimeTicks::Now();
310 int result = SendData(output);
311 if (result < 0 && result != net::ERR_IO_PENDING)
312 TestPhaseComplete(WRITE_FAILED, result);
315 int NetworkStats::ReadData() {
316 if (!socket_.get())
317 return 0;
319 if (read_state_ == READ_STATE_READ_PENDING)
320 return net::ERR_IO_PENDING;
322 int rv = 0;
323 do {
324 DCHECK(!read_buffer_.get());
325 read_buffer_ = new net::IOBuffer(kMaxMessageSize);
327 rv = socket_->Read(
328 read_buffer_.get(),
329 kMaxMessageSize,
330 base::Bind(&NetworkStats::OnReadComplete, weak_factory_.GetWeakPtr()));
331 } while (rv > 0 && !ReadComplete(rv));
332 if (rv == net::ERR_IO_PENDING)
333 read_state_ = READ_STATE_READ_PENDING;
334 return rv;
337 void NetworkStats::OnReadComplete(int result) {
338 DCHECK_NE(net::ERR_IO_PENDING, result);
339 DCHECK_EQ(READ_STATE_READ_PENDING, read_state_);
341 read_state_ = READ_STATE_IDLE;
342 if (!ReadComplete(result)) {
343 // Called ReadData() via PostDelayedTask() to avoid recursion. Added a delay
344 // of 1ms so that the time-out will fire before we have time to really hog
345 // the CPU too extensively (waiting for the time-out) in case of an infinite
346 // loop.
347 base::MessageLoop::current()->PostDelayedTask(
348 FROM_HERE,
349 base::Bind(base::IgnoreResult(&NetworkStats::ReadData),
350 weak_factory_.GetWeakPtr()),
351 base::TimeDelta::FromMilliseconds(1));
355 bool NetworkStats::ReadComplete(int result) {
356 DCHECK(socket_.get());
357 DCHECK_NE(net::ERR_IO_PENDING, result);
358 if (result < 0) {
359 // Something is wrong, finish the test.
360 read_buffer_ = NULL;
361 TestPhaseComplete(READ_FAILED, result);
362 return true;
365 std::string encoded_message(read_buffer_->data(),
366 read_buffer_->data() + result);
367 read_buffer_ = NULL;
368 ProbePacket probe_packet;
369 if (!probe_message_.ParseInput(encoded_message, &probe_packet))
370 return false;
371 // Discard if the packet is for a different test.
372 if (probe_packet.group_id() != current_test_index_)
373 return false;
375 // Whether all packets in the current test have been received.
376 bool current_test_complete = false;
377 switch (probe_packet.header().type()) {
378 case ProbePacket_Type_HELLO_REPLY:
379 token_ = probe_packet.token();
380 if (current_test_index_ == 0)
381 test_sequence_.push_back(START_PACKET_TEST);
382 current_test_complete = true;
383 break;
384 case ProbePacket_Type_PROBE_REPLY:
385 current_test_complete = UpdateReception(probe_packet);
386 break;
387 default:
388 DVLOG(1) << "Received unexpected packet type: "
389 << probe_packet.header().type();
392 if (!current_test_complete) {
393 // All packets have not been received for the current test.
394 return false;
396 // All packets are received for the current test.
397 // Read completes if all tests are done.
398 bool all_tests_done = current_test_index_ >= maximum_tests_ ||
399 current_test_index_ + 1 >= test_sequence_.size();
400 TestPhaseComplete(SUCCESS, net::OK);
401 return all_tests_done;
404 bool NetworkStats::UpdateReception(const ProbePacket& probe_packet) {
405 uint32 packet_index = probe_packet.packet_index();
406 if (packet_index >= packet_rtt_.size())
407 return false;
408 packets_received_mask_.set(packet_index);
409 TestType test_type = test_sequence_[current_test_index_];
410 uint32 received_packets = packets_received_mask_.count();
412 // Now() has resolution ~1-15ms. HighResNow() has high resolution but it
413 // is warned not to use it unless necessary.
414 base::TimeTicks current_time = base::TimeTicks::Now();
415 last_arrival_time_ = current_time;
416 if (first_arrival_time_.is_null())
417 first_arrival_time_ = current_time;
419 // Need to do this after updating the last_arrival_time_ since NAT_BIND_TEST
420 // and PACKET_SIZE_TEST record the SendToLastRecvDelay.
421 if (test_type == NAT_BIND_TEST) {
422 return received_packets >= maximum_NAT_packets_;
424 if (test_type == PACKET_SIZE_TEST) {
425 return received_packets >= kMaximumPacketSizeTestPackets;
428 base::TimeDelta rtt =
429 current_time - probe_request_time_ -
430 base::TimeDelta::FromMicroseconds(std::max(
431 static_cast<int64>(0), probe_packet.server_processing_micros()));
432 base::TimeDelta min_rtt = base::TimeDelta::FromMicroseconds(1L);
433 packet_rtt_[packet_index] = (rtt >= min_rtt) ? rtt : min_rtt;
435 if (received_packets < maximum_sequential_packets_)
436 return false;
437 // All packets in the current test are received.
438 inter_arrival_time_ = (last_arrival_time_ - first_arrival_time_) /
439 std::max(1U, (received_packets - 1));
440 if (test_type == START_PACKET_TEST) {
441 test_sequence_.push_back(PACKET_SIZE_TEST);
442 test_sequence_.push_back(TOKEN_REQUEST);
443 // No need to add TOKEN_REQUEST here when all packets are received.
444 test_sequence_.push_back(base::RandInt(0, 1) ? PACED_PACKET_TEST
445 : NON_PACED_PACKET_TEST);
446 test_sequence_.push_back(TOKEN_REQUEST);
447 test_sequence_.push_back(NAT_BIND_TEST);
448 test_sequence_.push_back(TOKEN_REQUEST);
450 return true;
453 int NetworkStats::SendData(const std::string& output) {
454 if (write_buffer_.get() || !socket_.get() ||
455 write_state_ == WRITE_STATE_WRITE_PENDING) {
456 return net::ERR_UNEXPECTED;
458 scoped_refptr<net::StringIOBuffer> buffer(new net::StringIOBuffer(output));
459 write_buffer_ = new net::DrainableIOBuffer(buffer.get(), buffer->size());
461 int bytes_written = socket_->Write(
462 write_buffer_.get(),
463 write_buffer_->BytesRemaining(),
464 base::Bind(&NetworkStats::OnWriteComplete, weak_factory_.GetWeakPtr()));
465 if (bytes_written < 0) {
466 if (bytes_written == net::ERR_IO_PENDING)
467 write_state_ = WRITE_STATE_WRITE_PENDING;
468 return bytes_written;
470 UpdateSendBuffer(bytes_written);
471 return net::OK;
474 void NetworkStats::OnWriteComplete(int result) {
475 DCHECK_NE(net::ERR_IO_PENDING, result);
476 DCHECK_EQ(WRITE_STATE_WRITE_PENDING, write_state_);
477 write_state_ = WRITE_STATE_IDLE;
478 if (result < 0 || !socket_.get() || write_buffer_ == NULL) {
479 TestPhaseComplete(WRITE_FAILED, result);
480 return;
482 UpdateSendBuffer(result);
485 void NetworkStats::UpdateSendBuffer(int bytes_sent) {
486 write_buffer_->DidConsume(bytes_sent);
487 DCHECK_EQ(write_buffer_->BytesRemaining(), 0);
488 DCHECK_EQ(WRITE_STATE_IDLE, write_state_);
489 write_buffer_ = NULL;
492 void NetworkStats::StartReadDataTimer(uint32 seconds, uint32 test_index) {
493 base::MessageLoop::current()->PostDelayedTask(
494 FROM_HERE,
495 base::Bind(&NetworkStats::OnReadDataTimeout,
496 weak_factory_.GetWeakPtr(),
497 test_index),
498 base::TimeDelta::FromSeconds(seconds));
501 void NetworkStats::OnReadDataTimeout(uint32 test_index) {
502 // If the current_test_index_ has changed since we set the timeout,
503 // the current test has been completed, so do nothing.
504 if (test_index != current_test_index_)
505 return;
506 // If test_type is TOKEN_REQUEST, it will do nothing but call
507 // TestPhaseComplete().
508 TestType test_type = test_sequence_[current_test_index_];
510 uint32 received_packets = packets_received_mask_.count();
511 if (received_packets >= 2) {
512 inter_arrival_time_ =
513 (last_arrival_time_ - first_arrival_time_) / (received_packets - 1);
515 // Add other tests if this is START_PACKET_TEST.
516 if (test_type == START_PACKET_TEST) {
517 if (received_packets >= kMinimumReceivedPacketsForPacingTest) {
518 test_sequence_.push_back(TOKEN_REQUEST);
519 test_sequence_.push_back(PACKET_SIZE_TEST);
520 test_sequence_.push_back(TOKEN_REQUEST);
521 test_sequence_.push_back(base::RandInt(0, 1) ? PACED_PACKET_TEST
522 : NON_PACED_PACKET_TEST);
524 if (received_packets >= kMinimumReceivedPacketsForNATTest) {
525 test_sequence_.push_back(TOKEN_REQUEST);
526 test_sequence_.push_back(NAT_BIND_TEST);
527 test_sequence_.push_back(TOKEN_REQUEST);
530 TestPhaseComplete(READ_TIMED_OUT, net::ERR_FAILED);
533 void NetworkStats::TestPhaseComplete(Status status, int result) {
534 // If there is no valid token, do nothing and delete self.
535 // This includes all connection error, name resolve error, etc.
536 if (write_state_ == WRITE_STATE_WRITE_PENDING) {
537 UMA_HISTOGRAM_BOOLEAN("NetConnectivity5.TestFailed.WritePending", true);
538 } else if (token_.timestamp_micros() != 0 &&
539 (status == SUCCESS || status == READ_TIMED_OUT)) {
540 TestType current_test = test_sequence_[current_test_index_];
541 DCHECK_LT(current_test, TEST_TYPE_MAX);
542 if (current_test != TOKEN_REQUEST) {
543 RecordHistograms(current_test);
544 } else if (current_test_index_ > 0) {
545 if (test_sequence_[current_test_index_ - 1] == NAT_BIND_TEST) {
546 // We record the NATTestReceivedHistograms after the succeeding
547 // TokenRequest.
548 RecordNATTestReceivedHistograms(status);
549 } else if (test_sequence_[current_test_index_ - 1] == PACKET_SIZE_TEST) {
550 // We record the PacketSizeTestReceivedHistograms after the succeeding
551 // TokenRequest.
552 RecordPacketSizeTestReceivedHistograms(status);
556 // Move to the next test.
557 current_test = GetNextTest();
558 if (current_test_index_ <= maximum_tests_ && current_test < TEST_TYPE_MAX) {
559 DVLOG(1) << "NetworkStat: Start Probe test: " << current_test;
560 base::MessageLoop::current()->PostTask(
561 FROM_HERE,
562 base::Bind(&NetworkStats::StartOneTest, weak_factory_.GetWeakPtr()));
563 return;
567 // All tests are done.
568 DoFinishCallback(result);
570 // Close the socket so that there are no more IO operations.
571 if (socket_.get())
572 socket_->Close();
574 DVLOG(1) << "NetworkStat: schedule delete self at test index "
575 << current_test_index_;
576 delete this;
579 NetworkStats::TestType NetworkStats::GetNextTest() {
580 ++current_test_index_;
581 if (current_test_index_ >= test_sequence_.size())
582 return TEST_TYPE_MAX;
583 return test_sequence_[current_test_index_];
586 void NetworkStats::DoFinishCallback(int result) {
587 if (!finished_callback_.is_null()) {
588 net::CompletionCallback callback = finished_callback_;
589 finished_callback_.Reset();
590 callback.Run(result);
594 void NetworkStats::RecordHistograms(TestType test_type) {
595 switch (test_type) {
596 case START_PACKET_TEST:
597 case NON_PACED_PACKET_TEST:
598 case PACED_PACKET_TEST: {
599 RecordInterArrivalHistograms(test_type);
600 RecordPacketLossSeriesHistograms(test_type);
601 RecordPacketsReceivedHistograms(test_type);
602 // Only record RTT for these packet indices.
603 uint32 rtt_indices[] = {0, 1, 2, 9, 19};
604 for (uint32 i = 0; i < arraysize(rtt_indices); ++i) {
605 if (rtt_indices[i] < packet_rtt_.size())
606 RecordRTTHistograms(test_type, rtt_indices[i]);
608 RecordSendToLastRecvDelayHistograms(test_type);
609 return;
611 case NAT_BIND_TEST:
612 RecordSendToLastRecvDelayHistograms(test_type);
613 return;
614 case PACKET_SIZE_TEST:
615 // No need to record RTT for PacketSizeTest.
616 return;
617 default:
618 DVLOG(1) << "Unexpected test type " << test_type
619 << " in RecordHistograms.";
623 void NetworkStats::RecordInterArrivalHistograms(TestType test_type) {
624 DCHECK_NE(test_type, PACKET_SIZE_TEST);
625 std::string histogram_name =
626 base::StringPrintf("NetConnectivity5.%s.Sent%d.PacketDelay.%d.%dB",
627 kTestName[test_type],
628 maximum_sequential_packets_,
629 histogram_port_,
630 probe_packet_bytes_);
631 // Record the time normalized to 20 packet inter-arrivals.
632 DynamicHistogramTimes(histogram_name, inter_arrival_time_ * 20);
635 void NetworkStats::RecordPacketsReceivedHistograms(TestType test_type) {
636 DCHECK_NE(test_type, PACKET_SIZE_TEST);
637 const char* test_name = kTestName[test_type];
638 std::string histogram_prefix = base::StringPrintf(
639 "NetConnectivity5.%s.Sent%d.", test_name, maximum_sequential_packets_);
640 std::string histogram_suffix =
641 base::StringPrintf(".%d.%dB", histogram_port_, probe_packet_bytes_);
642 std::string name = histogram_prefix + "GotAPacket" + histogram_suffix;
643 base::HistogramBase* histogram_pointer = base::BooleanHistogram::FactoryGet(
644 name, base::HistogramBase::kUmaTargetedHistogramFlag);
645 histogram_pointer->Add(packets_received_mask_.any());
647 DynamicHistogramEnumeration(
648 histogram_prefix + "PacketsRecv" + histogram_suffix,
649 packets_received_mask_.count(),
650 maximum_sequential_packets_ + 1);
652 if (!packets_received_mask_.any())
653 return;
655 base::HistogramBase* received_nth_packet_histogram =
656 base::Histogram::FactoryGet(
657 histogram_prefix + "RecvNthPacket" + histogram_suffix,
659 maximum_sequential_packets_ + 1,
660 maximum_sequential_packets_ + 2,
661 base::HistogramBase::kUmaTargetedHistogramFlag);
663 int count = 0;
664 for (size_t j = 0; j < maximum_sequential_packets_; ++j) {
665 int packet_number = j + 1;
666 if (packets_received_mask_.test(j)) {
667 received_nth_packet_histogram->Add(packet_number);
668 ++count;
670 std::string histogram_name =
671 base::StringPrintf("%sNumRecvFromFirst%02dPackets%s",
672 histogram_prefix.c_str(),
673 packet_number,
674 histogram_suffix.c_str());
675 DynamicHistogramEnumeration(histogram_name, count, packet_number + 1);
679 void NetworkStats::RecordNATTestReceivedHistograms(Status status) {
680 const char* test_name = kTestName[NAT_BIND_TEST];
681 bool test_result = status == SUCCESS;
682 std::string middle_name = test_result ? "Connectivity.Success"
683 : "Connectivity.Failure";
684 // Record whether the HelloRequest got reply successfully.
685 std::string histogram_name =
686 base::StringPrintf("NetConnectivity5.%s.Sent%d.%s.%d.%dB",
687 test_name,
688 maximum_NAT_packets_,
689 middle_name.c_str(),
690 histogram_port_,
691 probe_packet_bytes_);
692 uint32 bucket_count = std::min(maximum_NAT_idle_seconds_ + 2, 50U);
693 DynamicHistogramCounts(histogram_name,
694 pacing_interval_.InSeconds(),
696 maximum_NAT_idle_seconds_ + 1,
697 bucket_count);
699 // Record the NAT bind result only if the HelloRequest successfully got the
700 // token and the first NAT test packet is received.
701 if (!test_result || !packets_received_mask_.test(0))
702 return;
704 middle_name = packets_received_mask_.test(1) ? "Bind.Success"
705 : "Bind.Failure";
706 histogram_name = base::StringPrintf("NetConnectivity5.%s.Sent%d.%s.%d.%dB",
707 test_name,
708 maximum_NAT_packets_,
709 middle_name.c_str(),
710 histogram_port_,
711 probe_packet_bytes_);
712 DynamicHistogramCounts(histogram_name,
713 pacing_interval_.InSeconds(),
715 maximum_NAT_idle_seconds_ + 1,
716 bucket_count);
719 void NetworkStats::RecordPacketSizeTestReceivedHistograms(Status status) {
720 const char* test_name = kTestName[PACKET_SIZE_TEST];
721 bool test_result = (status == SUCCESS && packets_received_mask_.test(0));
722 std::string middle_name = test_result ? "Connectivity.Success"
723 : "Connectivity.Failure";
724 // Record whether the HelloRequest got reply successfully.
725 std::string histogram_name =
726 base::StringPrintf("NetConnectivity5.%s.%s.%d",
727 test_name,
728 middle_name.c_str(),
729 histogram_port_);
730 base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet(
731 histogram_name, kProbePacketBytes[kPacketSizeChoices - 1],
732 ProbeMessage::kMaxProbePacketBytes, 60,
733 base::HistogramBase::kUmaTargetedHistogramFlag);
734 histogram_pointer->Add(bytes_for_packet_size_test_);
737 void NetworkStats::RecordPacketLossSeriesHistograms(TestType test_type) {
738 DCHECK_NE(test_type, PACKET_SIZE_TEST);
739 const char* test_name = kTestName[test_type];
740 // Build "NetConnectivity5.<TestName>.First6.SeriesRecv.<port>.<probe_size>"
741 // histogram name. Total 3(tests) x 12 histograms.
742 std::string series_acked_histogram_name =
743 base::StringPrintf("NetConnectivity5.%s.First6.SeriesRecv.%d.%dB",
744 test_name,
745 histogram_port_,
746 probe_packet_bytes_);
747 uint32 histogram_boundary = 1 << kCorrelatedLossPacketCount;
748 uint32 correlated_packet_mask =
749 (histogram_boundary - 1) & packets_received_mask_.to_ulong();
750 DynamicHistogramEnumeration(
751 series_acked_histogram_name, correlated_packet_mask, histogram_boundary);
753 // If we are running without a proxy, we'll generate an extra histogram with
754 // the ".NoProxy" suffix.
755 if (!has_proxy_server_) {
756 series_acked_histogram_name.append(".NoProxy");
757 DynamicHistogramEnumeration(series_acked_histogram_name,
758 correlated_packet_mask,
759 histogram_boundary);
763 void NetworkStats::RecordRTTHistograms(TestType test_type, uint32 index) {
764 DCHECK_NE(test_type, PACKET_SIZE_TEST);
765 DCHECK_LT(index, packet_rtt_.size());
767 if (!packets_received_mask_.test(index))
768 return; // Probe packet never received.
770 std::string rtt_histogram_name = base::StringPrintf(
771 "NetConnectivity5.%s.Sent%d.Success.RTT.Packet%02d.%d.%dB",
772 kTestName[test_type],
773 maximum_sequential_packets_,
774 index + 1,
775 histogram_port_,
776 probe_packet_bytes_);
777 DynamicHistogramTimes(rtt_histogram_name, packet_rtt_[index]);
780 void NetworkStats::RecordSendToLastRecvDelayHistograms(TestType test_type) {
781 DCHECK_NE(test_type, PACKET_SIZE_TEST);
782 if (packets_received_mask_.count() < 2)
783 return; // Too few packets are received.
784 uint32 packets_sent = test_type == NAT_BIND_TEST
785 ? maximum_NAT_packets_ : maximum_sequential_packets_;
786 std::string histogram_name = base::StringPrintf(
787 "NetConnectivity5.%s.Sent%d.SendToLastRecvDelay.%d.%dB",
788 kTestName[test_type],
789 packets_sent,
790 histogram_port_,
791 probe_packet_bytes_);
792 base::TimeDelta send_to_last_recv_time =
793 std::max(last_arrival_time_ - probe_request_time_ -
794 pacing_interval_ * (packets_sent - 1),
795 base::TimeDelta::FromMilliseconds(0));
796 DynamicHistogramTimes(histogram_name, send_to_last_recv_time);
799 // ProxyDetector methods and members.
800 ProxyDetector::ProxyDetector(net::ProxyService* proxy_service,
801 const net::HostPortPair& server_address,
802 OnResolvedCallback callback)
803 : proxy_service_(proxy_service),
804 server_address_(server_address),
805 callback_(callback),
806 has_pending_proxy_resolution_(false) {}
808 ProxyDetector::~ProxyDetector() {
809 CHECK(!has_pending_proxy_resolution_);
812 void ProxyDetector::StartResolveProxy() {
813 std::string url =
814 base::StringPrintf("https://%s", server_address_.ToString().c_str());
815 GURL gurl(url);
817 has_pending_proxy_resolution_ = true;
818 DCHECK(proxy_service_);
819 int rv = proxy_service_->ResolveProxy(
820 gurl,
821 &proxy_info_,
822 base::Bind(&ProxyDetector::OnResolveProxyComplete,
823 base::Unretained(this)),
824 NULL,
825 net::BoundNetLog());
826 if (rv != net::ERR_IO_PENDING)
827 OnResolveProxyComplete(rv);
830 void ProxyDetector::OnResolveProxyComplete(int result) {
831 has_pending_proxy_resolution_ = false;
832 bool has_proxy_server =
833 (result == net::OK && proxy_info_.proxy_server().is_valid() &&
834 !proxy_info_.proxy_server().is_direct());
836 OnResolvedCallback callback = callback_;
837 BrowserThread::PostTask(
838 BrowserThread::IO, FROM_HERE, base::Bind(callback, has_proxy_server));
840 // TODO(rtenneti): Will we leak if ProxyResolve is cancelled (or proxy
841 // resolution never completes).
842 delete this;
845 void CollectNetworkStats(const std::string& network_stats_server,
846 IOThread* io_thread) {
847 if (network_stats_server.empty())
848 return;
850 // If we are not on IO Thread, then post a task to call CollectNetworkStats on
851 // IO Thread.
852 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
853 BrowserThread::PostTask(
854 BrowserThread::IO,
855 FROM_HERE,
856 base::Bind(&CollectNetworkStats, network_stats_server, io_thread));
857 return;
860 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
862 if (net::NetworkChangeNotifier::IsOffline()) {
863 return;
866 CR_DEFINE_STATIC_LOCAL(scoped_refptr<base::FieldTrial>, trial, ());
867 static bool collect_stats = false;
869 if (!trial.get()) {
870 // Set up a field trial to collect network stats for UDP.
871 const base::FieldTrial::Probability kDivisor = 1000;
873 // Enable the connectivity testing for 0.5% of the users in stable channel.
874 base::FieldTrial::Probability probability_per_group = kDivisor / 200;
876 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
877 if (channel == chrome::VersionInfo::CHANNEL_CANARY) {
878 // Enable the connectivity testing for 50% of the users in canary channel.
879 probability_per_group = kDivisor / 2;
880 } else if (channel == chrome::VersionInfo::CHANNEL_DEV) {
881 // Enable the connectivity testing for 10% of the users in dev channel.
882 probability_per_group = kDivisor / 10;
883 } else if (channel == chrome::VersionInfo::CHANNEL_BETA) {
884 // Enable the connectivity testing for 1% of the users in beta channel.
885 probability_per_group = kDivisor / 100;
888 // After July 31, 2014 builds, it will always be in default group
889 // (disable_network_stats).
890 trial = base::FieldTrialList::FactoryGetFieldTrial(
891 "NetworkConnectivity", kDivisor, "disable_network_stats",
892 2014, 7, 31, base::FieldTrial::SESSION_RANDOMIZED, NULL);
894 // Add option to collect_stats for NetworkConnectivity.
895 int collect_stats_group =
896 trial->AppendGroup("collect_stats", probability_per_group);
897 if (trial->group() == collect_stats_group)
898 collect_stats = true;
901 if (!collect_stats)
902 return;
904 // Run test kMaxNumberOfTests times.
905 const size_t kMaxNumberOfTests = INT_MAX;
906 static size_t number_of_tests_done = 0;
907 if (number_of_tests_done > kMaxNumberOfTests)
908 return;
909 ++number_of_tests_done;
911 net::HostResolver* host_resolver = io_thread->globals()->host_resolver.get();
912 DCHECK(host_resolver);
914 uint32 port_index = base::RandInt(0, arraysize(kPorts) - 1);
915 uint16 histogram_port = kPorts[port_index];
916 net::HostPortPair server_address(network_stats_server, histogram_port);
918 net::ProxyService* proxy_service =
919 io_thread->globals()->system_proxy_service.get();
920 DCHECK(proxy_service);
922 ProxyDetector::OnResolvedCallback callback = base::Bind(
923 &StartNetworkStatsTest, host_resolver, server_address, histogram_port);
925 ProxyDetector* proxy_client =
926 new ProxyDetector(proxy_service, server_address, callback);
927 proxy_client->StartResolveProxy();
930 void StartNetworkStatsTest(net::HostResolver* host_resolver,
931 const net::HostPortPair& server_address,
932 uint16 histogram_port,
933 bool has_proxy_server) {
934 int probe_choice = base::RandInt(0, kPacketSizeChoices - 1);
936 DCHECK_LE(ProbeMessage::kMaxProbePacketBytes, kMaxMessageSize);
937 // Pick a packet size between 1200 and kMaxProbePacketBytes bytes.
938 uint32 bytes_for_packet_size_test =
939 base::RandInt(kProbePacketBytes[kPacketSizeChoices - 1],
940 ProbeMessage::kMaxProbePacketBytes);
942 // |udp_stats_client| is owned and deleted in the class NetworkStats.
943 NetworkStats* udp_stats_client =
944 new NetworkStats(net::ClientSocketFactory::GetDefaultFactory());
945 udp_stats_client->Start(host_resolver,
946 server_address,
947 histogram_port,
948 has_proxy_server,
949 kProbePacketBytes[probe_choice],
950 bytes_for_packet_size_test,
951 net::CompletionCallback());
954 } // namespace chrome_browser_net