summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgagansingh@google.com <gagansingh@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-27 17:26:41 +0000
committergagansingh@google.com <gagansingh@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-27 17:26:41 +0000
commit5e6efa537dc4c06912f0bb42f16991c7ee7eafbc (patch)
treebd1336ab3629d3afd20c57c2c9d6de04603e1a10
parent0d1293040f1f79e3cddc52ba18fc6ec85f140800 (diff)
downloadchromium_src-5e6efa537dc4c06912f0bb42f16991c7ee7eafbc.zip
chromium_src-5e6efa537dc4c06912f0bb42f16991c7ee7eafbc.tar.gz
chromium_src-5e6efa537dc4c06912f0bb42f16991c7ee7eafbc.tar.bz2
Warmth of a connection (cwnd) is estimated by the amount of data written to the socket.
Choosing the warmest connection would mean faster resource load times. idle time is the time a socket has remained idle (no http requests being served on it). Probability of server resetting a connection increases with idle time duration. Using a cost function that takes into account bytes transferred and idle time to pick best connection to schedule http requests on. CODEREVIEW done in http://codereview.chromium.org/6990036/ Contributed by gagansingh@google.com Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=90373 Reverted: http://codereview.chromium.org/7255002 :( Have fixed 2 things since: 1. Removed LOG(ERROR) from http_basic_stream.cc that was causing layout tests to fail. 2. Initialized class variables in http_basic_stream.cc that was causing uninitialized memory bugs in valgrind: http://code.google.com/p/chromium/issues/detail?id=87423 Review URL: http://codereview.chromium.org/7251004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90601 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/browser_main.cc54
-rw-r--r--chrome/browser/browser_main.h7
-rw-r--r--chrome/browser/browser_main_unittest.cc68
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/chrome_switches.cc4
-rw-r--r--chrome/common/chrome_switches.h1
-rw-r--r--content/browser/renderer_host/p2p/socket_host_test_utils.h10
-rw-r--r--jingle/glue/pseudotcp_adapter.cc10
-rw-r--r--jingle/glue/pseudotcp_adapter.h2
-rw-r--r--jingle/notifier/base/fake_ssl_client_socket.cc10
-rw-r--r--jingle/notifier/base/fake_ssl_client_socket.h2
-rw-r--r--jingle/notifier/base/fake_ssl_client_socket_unittest.cc2
-rw-r--r--jingle/notifier/base/proxy_resolving_client_socket.cc14
-rw-r--r--jingle/notifier/base/proxy_resolving_client_socket.h2
-rw-r--r--net/curvecp/curvecp_client_socket.cc8
-rw-r--r--net/curvecp/curvecp_client_socket.h2
-rw-r--r--net/http/http_basic_stream.cc49
-rw-r--r--net/http/http_basic_stream.h6
-rw-r--r--net/http/http_network_transaction.cc1
-rw-r--r--net/http/http_network_transaction_unittest.cc29
-rw-r--r--net/http/http_proxy_client_socket.cc18
-rw-r--r--net/http/http_proxy_client_socket.h2
-rw-r--r--net/http/http_response_body_drainer_unittest.cc2
-rw-r--r--net/http/http_stream.h4
-rw-r--r--net/socket/client_socket_pool_base.cc44
-rw-r--r--net/socket/client_socket_pool_base.h18
-rw-r--r--net/socket/client_socket_pool_base_unittest.cc84
-rw-r--r--net/socket/socket_test_util.cc29
-rw-r--r--net/socket/socket_test_util.h7
-rw-r--r--net/socket/socks5_client_socket.cc18
-rw-r--r--net/socket/socks5_client_socket.h2
-rw-r--r--net/socket/socks_client_socket.cc16
-rw-r--r--net/socket/socks_client_socket.h2
-rw-r--r--net/socket/ssl_client_socket_mac.cc16
-rw-r--r--net/socket/ssl_client_socket_mac.h2
-rw-r--r--net/socket/ssl_client_socket_nss.cc16
-rw-r--r--net/socket/ssl_client_socket_nss.h2
-rw-r--r--net/socket/ssl_client_socket_win.cc16
-rw-r--r--net/socket/ssl_client_socket_win.h2
-rw-r--r--net/socket/ssl_server_socket_nss.cc8
-rw-r--r--net/socket/ssl_server_socket_nss.h2
-rw-r--r--net/socket/ssl_server_socket_unittest.cc8
-rw-r--r--net/socket/stream_socket.h7
-rw-r--r--net/socket/tcp_client_socket_libevent.cc15
-rw-r--r--net/socket/tcp_client_socket_libevent.h6
-rw-r--r--net/socket/tcp_client_socket_win.cc15
-rw-r--r--net/socket/tcp_client_socket_win.h6
-rw-r--r--net/socket/transport_client_socket_pool_unittest.cc12
-rw-r--r--net/socket/transport_client_socket_unittest.cc9
-rw-r--r--net/spdy/spdy_http_stream.h1
-rw-r--r--net/spdy/spdy_proxy_client_socket.cc8
-rw-r--r--net/spdy/spdy_proxy_client_socket.h2
-rw-r--r--remoting/jingle_glue/ssl_socket_adapter.cc10
-rw-r--r--remoting/jingle_glue/ssl_socket_adapter.h2
54 files changed, 681 insertions, 12 deletions
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index 6148ed5..2d1bfd1 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -101,6 +101,7 @@
#include "net/base/cookie_monster.h"
#include "net/base/net_module.h"
#include "net/base/network_change_notifier.h"
+#include "net/http/http_basic_stream.h"
#include "net/http/http_network_layer.h"
#include "net/http/http_stream_factory.h"
#include "net/socket/client_socket_pool_base.h"
@@ -208,6 +209,18 @@
#include "views/touchui/touch_factory.h"
#endif
+namespace {
+void SetSocketReusePolicy(int warmest_socket_trial_group,
+ const int socket_policy[],
+ int num_groups) {
+ const int* result = std::find(socket_policy, socket_policy + num_groups,
+ warmest_socket_trial_group);
+ DCHECK_NE(result, socket_policy + num_groups)
+ << "Not a valid socket reuse policy group";
+ net::SetSocketReusePolicy(result - socket_policy);
+}
+}
+
namespace net {
class NetLog;
} // namespace net
@@ -474,6 +487,46 @@ void BrowserMainParts::SpdyFieldTrial() {
}
}
+// If --socket-reuse-policy is not specified, run an A/B test for choosing the
+// warmest socket.
+void BrowserMainParts::WarmConnectionFieldTrial() {
+ const CommandLine& command_line = parsed_command_line();
+ if (command_line.HasSwitch(switches::kSocketReusePolicy)) {
+ std::string socket_reuse_policy_str = command_line.GetSwitchValueASCII(
+ switches::kSocketReusePolicy);
+ int policy = -1;
+ base::StringToInt(socket_reuse_policy_str, &policy);
+
+ const int policy_list[] = { 0, 1, 2 };
+ VLOG(1) << "Setting socket_reuse_policy = " << policy;
+ SetSocketReusePolicy(policy, policy_list, arraysize(policy_list));
+ return;
+ }
+
+ const base::FieldTrial::Probability kWarmSocketDivisor = 100;
+ const base::FieldTrial::Probability kWarmSocketProbability = 33;
+
+ // After January 30, 2013 builds, it will always be in default group.
+ scoped_refptr<base::FieldTrial> warmest_socket_trial(
+ new base::FieldTrial(
+ "WarmSocketImpact", kWarmSocketDivisor, "last_accessed_socket",
+ 2013, 1, 30));
+
+ // Default value is USE_LAST_ACCESSED_SOCKET.
+ const int last_accessed_socket = warmest_socket_trial->kDefaultGroupNumber;
+ const int warmest_socket = warmest_socket_trial->AppendGroup(
+ "warmest_socket", kWarmSocketProbability);
+ const int warm_socket = warmest_socket_trial->AppendGroup(
+ "warm_socket", kWarmSocketProbability);
+
+ const int warmest_socket_trial_group = warmest_socket_trial->group();
+
+ const int policy_list[] = { warmest_socket, warm_socket,
+ last_accessed_socket };
+ SetSocketReusePolicy(warmest_socket_trial_group, policy_list,
+ arraysize(policy_list));
+}
+
// If neither --enable-connect-backup-jobs or --disable-connect-backup-jobs is
// specified, run an A/B test for automatically establishing backup TCP
// connections when a certain timeout value is exceeded.
@@ -593,6 +646,7 @@ void BrowserMainParts::SetupFieldTrials(bool metrics_recording_enabled) {
prerender::ConfigurePrefetchAndPrerender(parsed_command_line());
SpdyFieldTrial();
ConnectBackupJobsFieldTrial();
+ WarmConnectionFieldTrial();
}
// -----------------------------------------------------------------------------
diff --git a/chrome/browser/browser_main.h b/chrome/browser/browser_main.h
index 417c622..e13a12d 100644
--- a/chrome/browser/browser_main.h
+++ b/chrome/browser/browser_main.h
@@ -7,6 +7,7 @@
#pragma once
#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/field_trial.h"
#include "base/tracked_objects.h"
@@ -129,6 +130,9 @@ class BrowserMainParts {
// specified timeout value is reached.
void ConnectBackupJobsFieldTrial();
+ // A/B test for warmest socket vs. most recently used socket.
+ void WarmConnectionFieldTrial();
+
// Used to initialize NSPR where appropriate.
virtual void InitializeSSL() = 0;
@@ -171,6 +175,9 @@ class BrowserMainParts {
// Initialized in SetupMetricsAndFieldTrials.
scoped_refptr<FieldTrialSynchronizer> field_trial_synchronizer_;
+ FRIEND_TEST(BrowserMainTest, WarmConnectionFieldTrial_WarmestSocket);
+ FRIEND_TEST(BrowserMainTest, WarmConnectionFieldTrial_Random);
+ FRIEND_TEST(BrowserMainTest, WarmConnectionFieldTrial_Invalid);
DISALLOW_COPY_AND_ASSIGN(BrowserMainParts);
};
diff --git a/chrome/browser/browser_main_unittest.cc b/chrome/browser/browser_main_unittest.cc
new file mode 100644
index 0000000..bc5487d
--- /dev/null
+++ b/chrome/browser/browser_main_unittest.cc
@@ -0,0 +1,68 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/browser_main.h"
+
+#include <string>
+#include <vector>
+#include "base/command_line.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/testing_pref_service.h"
+#include "content/common/main_function_params.h"
+#include "content/common/sandbox_init_wrapper.h"
+#include "net/socket/client_socket_pool_base.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class BrowserMainTest : public testing::Test {
+ public:
+ BrowserMainTest() : command_line_(CommandLine::NO_PROGRAM) {}
+ protected:
+ virtual void SetUp() {
+ sandbox_init_wrapper_.reset(new SandboxInitWrapper());
+ }
+
+ scoped_ptr<SandboxInitWrapper> sandbox_init_wrapper_;
+ TestingPrefService pref_service_;
+ CommandLine command_line_;
+};
+
+TEST_F(BrowserMainTest, WarmConnectionFieldTrial_WarmestSocket) {
+ command_line_.AppendSwitchASCII(switches::kSocketReusePolicy, "0");
+
+ scoped_ptr<MainFunctionParams> params(
+ new MainFunctionParams(command_line_, *sandbox_init_wrapper_, NULL));
+ scoped_ptr<BrowserMainParts> bw(BrowserMainParts::CreateBrowserMainParts(
+ *params));
+
+ bw->WarmConnectionFieldTrial();
+
+ EXPECT_EQ(0, net::GetSocketReusePolicy());
+}
+
+TEST_F(BrowserMainTest, WarmConnectionFieldTrial_Random) {
+ scoped_ptr<MainFunctionParams> params(
+ new MainFunctionParams(command_line_, *sandbox_init_wrapper_, NULL));
+ scoped_ptr<BrowserMainParts> bw(BrowserMainParts::CreateBrowserMainParts(
+ *params));
+
+ const int kNumRuns = 1000;
+ for (int i = 0; i < kNumRuns; i++) {
+ bw->WarmConnectionFieldTrial();
+ int val = net::GetSocketReusePolicy();
+ EXPECT_LE(val, 2);
+ EXPECT_GE(val, 0);
+ }
+}
+
+TEST_F(BrowserMainTest, WarmConnectionFieldTrial_Invalid) {
+ command_line_.AppendSwitchASCII(switches::kSocketReusePolicy, "100");
+
+ scoped_ptr<MainFunctionParams> params(
+ new MainFunctionParams(command_line_, *sandbox_init_wrapper_, NULL));
+ scoped_ptr<BrowserMainParts> bw(BrowserMainParts::CreateBrowserMainParts(
+ *params));
+
+ EXPECT_DEBUG_DEATH(bw->WarmConnectionFieldTrial(),
+ "Not a valid socket reuse policy group");
+}
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 327756a..1214adb 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1292,6 +1292,7 @@
'browser/bookmarks/bookmark_utils_unittest.cc',
'browser/browser_about_handler_unittest.cc',
'browser/browser_commands_unittest.cc',
+ 'browser/browser_main_unittest.cc',
'browser/browser_url_handler_unittest.cc',
'browser/browsing_data_appcache_helper_unittest.cc',
'browser/browsing_data_database_helper_unittest.cc',
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index d8bacf5..914ed25 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -931,6 +931,10 @@ const char kSilentDumpOnDCHECK[] = "silent-dump-on-dcheck";
// Replaces the buffered data source for <audio> and <video> with a simplified
// resource loader that downloads the entire resource into memory.
+// Choose the socket reuse policy specified. The value should be of type
+// enum ClientSocketReusePolicy.
+const char kSocketReusePolicy[] = "socket-reuse-policy";
+
// Start the browser maximized, regardless of any previous settings.
const char kStartMaximized[] = "start-maximized";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index f84cb58..aa3dcd0 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -252,6 +252,7 @@ extern const char kShowCompositedLayerTree[];
extern const char kShowFPSCounter[];
extern const char kShowIcons[];
extern const char kSilentDumpOnDCHECK[];
+extern const char kSocketReusePolicy[];
extern const char kStartMaximized[];
extern const char kSyncAllowInsecureXmppConnection[];
extern const char kSyncInvalidateXmppLogin[];
diff --git a/content/browser/renderer_host/p2p/socket_host_test_utils.h b/content/browser/renderer_host/p2p/socket_host_test_utils.h
index bc829fd..a24d094 100644
--- a/content/browser/renderer_host/p2p/socket_host_test_utils.h
+++ b/content/browser/renderer_host/p2p/socket_host_test_utils.h
@@ -73,6 +73,8 @@ class FakeSocket : public net::StreamSocket {
virtual void SetOmniboxSpeculation() OVERRIDE;
virtual bool WasEverUsed() const OVERRIDE;
virtual bool UsingTCPFastOpen() const OVERRIDE;
+ virtual int64 NumBytesRead() const OVERRIDE;
+ virtual base::TimeDelta GetConnectTimeMicros() const OVERRIDE;
private:
bool read_pending_;
@@ -209,6 +211,14 @@ bool FakeSocket::UsingTCPFastOpen() const {
return false;
}
+int64 FakeSocket::NumBytesRead() const {
+ return -1;
+}
+
+base::TimeDelta FakeSocket::GetConnectTimeMicros() const {
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
void CreateRandomPacket(std::vector<char>* packet) {
size_t size = kStunHeaderSize + rand() % 1000;
packet->resize(size);
diff --git a/jingle/glue/pseudotcp_adapter.cc b/jingle/glue/pseudotcp_adapter.cc
index 7136bbc..b86c805 100644
--- a/jingle/glue/pseudotcp_adapter.cc
+++ b/jingle/glue/pseudotcp_adapter.cc
@@ -463,4 +463,14 @@ bool PseudoTcpAdapter::UsingTCPFastOpen() const {
return false;
}
+int64 PseudoTcpAdapter::NumBytesRead() const {
+ DCHECK(CalledOnValidThread());
+ return -1;
+}
+
+base::TimeDelta PseudoTcpAdapter::GetConnectTimeMicros() const {
+ DCHECK(CalledOnValidThread());
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
} // namespace jingle_glue
diff --git a/jingle/glue/pseudotcp_adapter.h b/jingle/glue/pseudotcp_adapter.h
index 977dcf1..e53d722 100644
--- a/jingle/glue/pseudotcp_adapter.h
+++ b/jingle/glue/pseudotcp_adapter.h
@@ -49,6 +49,8 @@ class PseudoTcpAdapter : public net::StreamSocket, base::NonThreadSafe {
virtual void SetOmniboxSpeculation() OVERRIDE;
virtual bool WasEverUsed() const OVERRIDE;
virtual bool UsingTCPFastOpen() const OVERRIDE;
+ virtual int64 NumBytesRead() const OVERRIDE;
+ virtual base::TimeDelta GetConnectTimeMicros() const OVERRIDE;
private:
class Core;
diff --git a/jingle/notifier/base/fake_ssl_client_socket.cc b/jingle/notifier/base/fake_ssl_client_socket.cc
index 8838f13..20a3f39 100644
--- a/jingle/notifier/base/fake_ssl_client_socket.cc
+++ b/jingle/notifier/base/fake_ssl_client_socket.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -336,4 +336,12 @@ bool FakeSSLClientSocket::UsingTCPFastOpen() const {
return transport_socket_->UsingTCPFastOpen();
}
+int64 FakeSSLClientSocket::NumBytesRead() const {
+ return transport_socket_->NumBytesRead();
+}
+
+base::TimeDelta FakeSSLClientSocket::GetConnectTimeMicros() const {
+ return transport_socket_->GetConnectTimeMicros();
+}
+
} // namespace notifier
diff --git a/jingle/notifier/base/fake_ssl_client_socket.h b/jingle/notifier/base/fake_ssl_client_socket.h
index f2282c2..1688b70 100644
--- a/jingle/notifier/base/fake_ssl_client_socket.h
+++ b/jingle/notifier/base/fake_ssl_client_socket.h
@@ -62,6 +62,8 @@ class FakeSSLClientSocket : public net::StreamSocket {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
private:
enum HandshakeState {
diff --git a/jingle/notifier/base/fake_ssl_client_socket_unittest.cc b/jingle/notifier/base/fake_ssl_client_socket_unittest.cc
index 6f5c2da..2fe21b4 100644
--- a/jingle/notifier/base/fake_ssl_client_socket_unittest.cc
+++ b/jingle/notifier/base/fake_ssl_client_socket_unittest.cc
@@ -62,6 +62,8 @@ class MockClientSocket : public net::StreamSocket {
MOCK_METHOD0(SetOmniboxSpeculation, void());
MOCK_CONST_METHOD0(WasEverUsed, bool());
MOCK_CONST_METHOD0(UsingTCPFastOpen, bool());
+ MOCK_CONST_METHOD0(NumBytesRead, int64());
+ MOCK_CONST_METHOD0(GetConnectTimeMicros, base::TimeDelta());
};
// Break up |data| into a bunch of chunked MockReads/Writes and push
diff --git a/jingle/notifier/base/proxy_resolving_client_socket.cc b/jingle/notifier/base/proxy_resolving_client_socket.cc
index e34ca1c..4deda20 100644
--- a/jingle/notifier/base/proxy_resolving_client_socket.cc
+++ b/jingle/notifier/base/proxy_resolving_client_socket.cc
@@ -342,6 +342,20 @@ bool ProxyResolvingClientSocket::UsingTCPFastOpen() const {
return false;
}
+int64 ProxyResolvingClientSocket::NumBytesRead() const {
+ if (transport_.get() && transport_->socket())
+ return transport_->socket()->NumBytesRead();
+ NOTREACHED();
+ return -1;
+}
+
+base::TimeDelta ProxyResolvingClientSocket::GetConnectTimeMicros() const {
+ if (transport_.get() && transport_->socket())
+ return transport_->socket()->GetConnectTimeMicros();
+ NOTREACHED();
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
void ProxyResolvingClientSocket::CloseTransportSocket() {
if (transport_.get() && transport_->socket())
transport_->socket()->Disconnect();
diff --git a/jingle/notifier/base/proxy_resolving_client_socket.h b/jingle/notifier/base/proxy_resolving_client_socket.h
index 8e95f87..b97315b 100644
--- a/jingle/notifier/base/proxy_resolving_client_socket.h
+++ b/jingle/notifier/base/proxy_resolving_client_socket.h
@@ -56,6 +56,8 @@ class ProxyResolvingClientSocket : public net::StreamSocket {
virtual void SetOmniboxSpeculation() OVERRIDE;
virtual bool WasEverUsed() const OVERRIDE;
virtual bool UsingTCPFastOpen() const OVERRIDE;
+ virtual int64 NumBytesRead() const OVERRIDE;
+ virtual base::TimeDelta GetConnectTimeMicros() const OVERRIDE;
private:
// Proxy resolution and connection functions.
diff --git a/net/curvecp/curvecp_client_socket.cc b/net/curvecp/curvecp_client_socket.cc
index f28e839..95b36f6 100644
--- a/net/curvecp/curvecp_client_socket.cc
+++ b/net/curvecp/curvecp_client_socket.cc
@@ -88,6 +88,14 @@ bool CurveCPClientSocket::UsingTCPFastOpen() const {
return false;
}
+int64 CurveCPClientSocket::NumBytesRead() const {
+ return -1;
+}
+
+base::TimeDelta CurveCPClientSocket::GetConnectTimeMicros() const {
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
int CurveCPClientSocket::Read(IOBuffer* buf,
int buf_len,
CompletionCallback* callback) {
diff --git a/net/curvecp/curvecp_client_socket.h b/net/curvecp/curvecp_client_socket.h
index 213b13d..c9faa63 100644
--- a/net/curvecp/curvecp_client_socket.h
+++ b/net/curvecp/curvecp_client_socket.h
@@ -36,6 +36,8 @@ class CurveCPClientSocket : public StreamSocket {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/http/http_basic_stream.cc b/net/http/http_basic_stream.cc
index 6501a59..08785b8 100644
--- a/net/http/http_basic_stream.cc
+++ b/net/http/http_basic_stream.cc
@@ -4,6 +4,8 @@
#include "net/http/http_basic_stream.h"
+#include "base/format_macros.h"
+#include "base/metrics/histogram.h"
#include "base/stringprintf.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
@@ -12,6 +14,7 @@
#include "net/http/http_stream_parser.h"
#include "net/http/http_util.h"
#include "net/socket/client_socket_handle.h"
+#include "net/socket/client_socket_pool_base.h"
namespace net {
@@ -22,7 +25,9 @@ HttpBasicStream::HttpBasicStream(ClientSocketHandle* connection,
parser_(parser),
connection_(connection),
using_proxy_(using_proxy),
- request_info_(NULL) {
+ request_info_(NULL),
+ response_(NULL),
+ bytes_read_offset_(0) {
}
HttpBasicStream::~HttpBasicStream() {}
@@ -34,6 +39,7 @@ int HttpBasicStream::InitializeStream(const HttpRequestInfo* request_info,
request_info_ = request_info;
parser_.reset(new HttpStreamParser(connection_.get(), request_info,
read_buf_, net_log));
+ bytes_read_offset_ = connection_->socket()->NumBytesRead();
return OK;
}
@@ -50,6 +56,7 @@ int HttpBasicStream::SendRequest(const HttpRequestHeaders& headers,
request_line_ = base::StringPrintf("%s %s HTTP/1.1\r\n",
request_info_->method.c_str(),
path.c_str());
+ response_ = response;
return parser_->SendRequest(request_line_, headers, request_body, response,
callback);
}
@@ -119,4 +126,44 @@ bool HttpBasicStream::IsSpdyHttpStream() const {
return false;
}
+void HttpBasicStream::LogNumRttVsBytesMetrics() const {
+ int socket_reuse_policy = GetSocketReusePolicy();
+ if (socket_reuse_policy > 2 || socket_reuse_policy < 0) {
+ return;
+ }
+
+ int64 total_bytes_read = connection_->socket()->NumBytesRead();
+ int64 bytes_received = total_bytes_read - bytes_read_offset_;
+ int64 num_kb = bytes_received / 1024;
+ double rtt = connection_->socket()->GetConnectTimeMicros().ToInternalValue();
+ rtt /= 1000.0;
+
+ if (num_kb < 1024 && rtt > 0) { // Ignore responses > 1MB
+ base::TimeDelta duration = base::Time::Now() -
+ response_->request_time;
+ double num_rtt = static_cast<double>(duration.InMilliseconds()) / rtt;
+ int64 num_rtt_scaled = (4 * num_rtt);
+
+ static const char* const kGroups[] = {
+ "warmest_socket", "warm_socket", "last_accessed_socket"
+ };
+ int bucket = (num_kb / 5) * 5;
+ const std::string histogram(StringPrintf("Net.Num_RTT_vs_KB_%s_%dKB",
+ kGroups[socket_reuse_policy],
+ bucket));
+ base::Histogram* counter = base::Histogram::FactoryGet(
+ histogram, 0, 1000, 2, base::Histogram::kUmaTargetedHistogramFlag);
+ DCHECK_EQ(histogram, counter->histogram_name());
+ counter->Add(num_rtt_scaled);
+
+ VLOG(2) << StringPrintf("%s\nrtt = %f\tnum_rtt = %f\t"
+ "num_kb = %" PRId64 "\t"
+ "total bytes = %" PRId64 "\t"
+ "histogram = %s",
+ request_line_.data(),
+ rtt, num_rtt, num_kb, total_bytes_read,
+ histogram.data());
+ }
+}
+
} // namespace net
diff --git a/net/http/http_basic_stream.h b/net/http/http_basic_stream.h
index 267c7c1..303d68f 100644
--- a/net/http/http_basic_stream.h
+++ b/net/http/http_basic_stream.h
@@ -81,6 +81,8 @@ class HttpBasicStream : public HttpStream {
virtual bool IsSpdyHttpStream() const OVERRIDE;
+ virtual void LogNumRttVsBytesMetrics() const OVERRIDE;
+
private:
scoped_refptr<GrowableIOBuffer> read_buf_;
@@ -94,6 +96,10 @@ class HttpBasicStream : public HttpStream {
const HttpRequestInfo* request_info_;
+ const HttpResponseInfo* response_;
+
+ int64 bytes_read_offset_;
+
DISALLOW_COPY_AND_ASSIGN(HttpBasicStream);
};
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index d7a65e2..403f60f 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -920,6 +920,7 @@ int HttpNetworkTransaction::DoReadBodyComplete(int result) {
// Clean up connection if we are done.
if (done) {
LogTransactionMetrics();
+ stream_->LogNumRttVsBytesMetrics();
stream_->Close(!keep_alive);
// Note: we don't reset the stream here. We've closed it, but we still
// need it around so that callers can call methods such as
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 65d699e..a1de71f 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -12,6 +12,7 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
#include "base/utf_string_conversions.h"
#include "net/base/auth.h"
#include "net/base/capturing_net_log.h"
@@ -333,6 +334,34 @@ static const char kExpectedNPNString[] = "\x08http/1.1\x06spdy/2";
static const char kAlternateProtocolHttpHeader[] =
"Alternate-Protocol: 443:npn-spdy/2\r\n\r\n";
+TEST_F(HttpNetworkTransactionTest, LogNumRttVsBytesMetrics_WarmestSocket) {
+ MockRead data_reads[1000];
+ data_reads[0] = MockRead("HTTP/1.0 200 OK\r\n\r\n");
+ for (int i = 1; i < 999; i++) {
+ data_reads[i] = MockRead("Gagan is a good boy!");
+ }
+ data_reads[999] = MockRead(false, OK);
+
+ net::SetSocketReusePolicy(0);
+ SimpleGetHelperResult out = SimpleGetHelper(data_reads,
+ arraysize(data_reads));
+
+ base::Histogram* histogram = NULL;
+ base::StatisticsRecorder::FindHistogram(
+ "Net.Num_RTT_vs_KB_warmest_socket_15KB", &histogram);
+ CHECK(histogram);
+
+ base::Histogram::SampleSet sample_set;
+ histogram->SnapshotSample(&sample_set);
+ EXPECT_EQ(1, sample_set.TotalCount());
+
+ EXPECT_EQ(OK, out.rv);
+ EXPECT_EQ("HTTP/1.0 200 OK", out.status_line);
+}
+
+// TODO(gagansingh): Add test for LogNumRttVsBytesMetrics_LastAccessSocket once
+// it is possible to clear histograms from previous tests.
+
TEST_F(HttpNetworkTransactionTest, Basic) {
SessionDependencies session_deps;
scoped_ptr<HttpTransaction> trans(
diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc
index 0a41c1f..584cecd 100644
--- a/net/http/http_proxy_client_socket.cc
+++ b/net/http/http_proxy_client_socket.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -165,6 +165,22 @@ bool HttpProxyClientSocket::UsingTCPFastOpen() const {
return false;
}
+int64 HttpProxyClientSocket::NumBytesRead() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->NumBytesRead();
+ }
+ NOTREACHED();
+ return -1;
+}
+
+base::TimeDelta HttpProxyClientSocket::GetConnectTimeMicros() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->GetConnectTimeMicros();
+ }
+ NOTREACHED();
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(!user_callback_);
diff --git a/net/http/http_proxy_client_socket.h b/net/http/http_proxy_client_socket.h
index bd25bab..b1f32a6 100644
--- a/net/http/http_proxy_client_socket.h
+++ b/net/http/http_proxy_client_socket.h
@@ -78,6 +78,8 @@ class HttpProxyClientSocket : public ProxyClientSocket {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/http/http_response_body_drainer_unittest.cc b/net/http/http_response_body_drainer_unittest.cc
index 45c826e..47602e9 100644
--- a/net/http/http_response_body_drainer_unittest.cc
+++ b/net/http/http_response_body_drainer_unittest.cc
@@ -117,6 +117,8 @@ class MockHttpStream : public HttpStream {
virtual bool IsSpdyHttpStream() const OVERRIDE { return false; }
+ virtual void LogNumRttVsBytesMetrics() const OVERRIDE {}
+
// Methods to tweak/observer mock behavior:
void StallReadsForever() { stall_reads_forever_ = true; }
diff --git a/net/http/http_stream.h b/net/http/http_stream.h
index 7ca2203..66fd97c 100644
--- a/net/http/http_stream.h
+++ b/net/http/http_stream.h
@@ -135,6 +135,10 @@ class NET_TEST HttpStream {
// the HttpStream implementation. This is just a quick hack.
virtual bool IsSpdyHttpStream() const = 0;
+ // Record histogram of number of round trips taken to download the full
+ // response body vs bytes transferred.
+ virtual void LogNumRttVsBytesMetrics() const = 0;
+
private:
DISALLOW_COPY_AND_ASSIGN(HttpStream);
};
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index ddcbba6..d39890b 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -4,11 +4,14 @@
#include "net/socket/client_socket_pool_base.h"
+#include <math.h>
#include "base/compiler_specific.h"
#include "base/format_macros.h"
+#include "base/logging.h"
#include "base/message_loop.h"
#include "base/metrics/stats_counters.h"
#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/values.h"
@@ -32,10 +35,33 @@ const int kCleanupInterval = 10; // DO NOT INCREASE THIS TIMEOUT.
// after a certain timeout has passed without receiving an ACK.
bool g_connect_backup_jobs_enabled = true;
+double g_socket_reuse_policy_penalty_exponent = -1;
+int g_socket_reuse_policy = -1;
+
} // namespace
namespace net {
+int GetSocketReusePolicy() {
+ return g_socket_reuse_policy;
+}
+
+void SetSocketReusePolicy(int policy) {
+ DCHECK_GE(policy, 0);
+ DCHECK_LE(policy, 2);
+ if (policy > 2 || policy < 0) {
+ LOG(ERROR) << "Invalid socket reuse policy";
+ return;
+ }
+
+ double exponents[] = { 0, 0.25, -1 };
+ g_socket_reuse_policy_penalty_exponent = exponents[policy];
+ g_socket_reuse_policy = policy;
+
+ VLOG(1) << "Setting g_socket_reuse_policy_penalty_exponent = "
+ << g_socket_reuse_policy_penalty_exponent;
+}
+
ConnectJob::ConnectJob(const std::string& group_name,
base::TimeDelta timeout_duration,
Delegate* delegate,
@@ -363,6 +389,7 @@ bool ClientSocketPoolBaseHelper::AssignIdleSocketToGroup(
const Request* request, Group* group) {
std::list<IdleSocket>* idle_sockets = group->mutable_idle_sockets();
std::list<IdleSocket>::iterator idle_socket_it = idle_sockets->end();
+ double max_score = -1;
// Iterate through the idle sockets forwards (oldest to newest)
// * Delete any disconnected ones.
@@ -379,7 +406,22 @@ bool ClientSocketPoolBaseHelper::AssignIdleSocketToGroup(
if (it->socket->WasEverUsed()) {
// We found one we can reuse!
- idle_socket_it = it;
+ double score = 0;
+ int64 bytes_read = it->socket->NumBytesRead();
+ double num_kb = static_cast<double>(bytes_read) / 1024.0;
+ int idle_time_sec = (base::TimeTicks::Now() - it->start_time).InSeconds();
+ idle_time_sec = std::max(1, idle_time_sec);
+
+ if (g_socket_reuse_policy_penalty_exponent >= 0 && num_kb >= 0) {
+ score = num_kb / pow(idle_time_sec,
+ g_socket_reuse_policy_penalty_exponent);
+ }
+
+ // Equality to prefer recently used connection.
+ if (score >= max_score) {
+ idle_socket_it = it;
+ max_score = score;
+ }
}
++it;
diff --git a/net/socket/client_socket_pool_base.h b/net/socket/client_socket_pool_base.h
index a5defdf..2490c02 100644
--- a/net/socket/client_socket_pool_base.h
+++ b/net/socket/client_socket_pool_base.h
@@ -50,6 +50,13 @@ namespace net {
class ClientSocketHandle;
+// Returns the client socket reuse policy.
+int GetSocketReusePolicy();
+
+// Sets the client socket reuse policy.
+// NOTE: 'policy' should be a valid ClientSocketReusePolicy enum value.
+NET_API void SetSocketReusePolicy(int policy);
+
// ConnectJob provides an abstract interface for "connecting" a socket.
// The connection may involve host resolution, tcp connection, ssl connection,
// etc.
@@ -167,6 +174,17 @@ class NET_TEST ClientSocketPoolBaseHelper
NO_IDLE_SOCKETS = 0x1, // Do not return an idle socket. Create a new one.
};
+ enum ClientSocketReusePolicy {
+ // Socket with largest amount of bytes transferred.
+ USE_WARMEST_SOCKET = 0,
+
+ // Socket which scores highest on large bytes transferred and low idle time.
+ USE_WARM_SOCKET = 1,
+
+ // Socket which was most recently used.
+ USE_LAST_ACCESSED_SOCKET = 2,
+ };
+
class NET_TEST Request {
public:
Request(ClientSocketHandle* handle,
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 4864001..6cdbdd3 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -45,12 +45,14 @@ typedef ClientSocketPoolBase<TestSocketParams> TestClientSocketPoolBase;
class MockClientSocket : public StreamSocket {
public:
- MockClientSocket() : connected_(false), was_used_to_convey_data_(false) {}
+ MockClientSocket() : connected_(false), was_used_to_convey_data_(false),
+ num_bytes_read_(0) {}
// Socket methods:
virtual int Read(
- IOBuffer* /* buf */, int /* len */, CompletionCallback* /* callback */) {
- return ERR_UNEXPECTED;
+ IOBuffer* /* buf */, int len, CompletionCallback* /* callback */) {
+ num_bytes_read_ += len;
+ return len;
}
virtual int Write(
@@ -86,13 +88,22 @@ class MockClientSocket : public StreamSocket {
virtual void SetSubresourceSpeculation() {}
virtual void SetOmniboxSpeculation() {}
- virtual bool WasEverUsed() const { return was_used_to_convey_data_; }
+ virtual bool WasEverUsed() const {
+ return was_used_to_convey_data_ || num_bytes_read_ > 0;
+ }
virtual bool UsingTCPFastOpen() const { return false; }
+ virtual int64 NumBytesRead() const { return num_bytes_read_; }
+ virtual base::TimeDelta GetConnectTimeMicros() const {
+ static const base::TimeDelta kDummyConnectTimeMicros =
+ base::TimeDelta::FromMicroseconds(10);
+ return kDummyConnectTimeMicros; // Dummy value.
+ }
private:
bool connected_;
BoundNetLog net_log_;
bool was_used_to_convey_data_;
+ int num_bytes_read_;
DISALLOW_COPY_AND_ASSIGN(MockClientSocket);
};
@@ -604,6 +615,71 @@ class ClientSocketPoolBaseTest : public testing::Test {
ClientSocketPoolTest test_base_;
};
+TEST_F(ClientSocketPoolBaseTest, AssignIdleSocketToGroup_WarmestSocket) {
+ CreatePool(4, 4);
+ net::SetSocketReusePolicy(0);
+
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+
+ std::map<int, StreamSocket*> sockets_;
+ for (size_t i = 0; i < test_base_.requests_size(); i++) {
+ TestSocketRequest* req = test_base_.request(i);
+ StreamSocket* s = req->handle()->socket();
+ MockClientSocket* sock = static_cast<MockClientSocket*>(s);
+ CHECK(sock);
+ sockets_[i] = sock;
+ sock->Read(NULL, 1024 - i, NULL);
+ }
+
+ ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE);
+
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ TestSocketRequest* req = test_base_.request(test_base_.requests_size() - 1);
+
+ // First socket is warmest.
+ EXPECT_EQ(sockets_[0], req->handle()->socket());
+
+ // Test that NumBytes are as expected.
+ EXPECT_EQ(1024, sockets_[0]->NumBytesRead());
+ EXPECT_EQ(1023, sockets_[1]->NumBytesRead());
+ EXPECT_EQ(1022, sockets_[2]->NumBytesRead());
+ EXPECT_EQ(1021, sockets_[3]->NumBytesRead());
+
+ ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
+}
+
+TEST_F(ClientSocketPoolBaseTest, AssignIdleSocketToGroup_LastAccessedSocket) {
+ CreatePool(4, 4);
+ net::SetSocketReusePolicy(2);
+
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+
+ std::map<int, StreamSocket*> sockets_;
+ for (size_t i = 0; i < test_base_.requests_size(); i++) {
+ TestSocketRequest* req = test_base_.request(i);
+ StreamSocket* s = req->handle()->socket();
+ MockClientSocket* sock = static_cast<MockClientSocket*>(s);
+ CHECK(sock);
+ sockets_[i] = sock;
+ sock->Read(NULL, 1024 - i, NULL);
+ }
+
+ ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE);
+
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ TestSocketRequest* req = test_base_.request(test_base_.requests_size() - 1);
+
+ // Last socket is most recently accessed.
+ EXPECT_EQ(sockets_[3], req->handle()->socket());
+ ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
+}
+
// Even though a timeout is specified, it doesn't time out on a synchronous
// completion.
TEST_F(ClientSocketPoolBaseTest, ConnectJob_NoTimeoutOnSynchronousCompletion) {
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index 4e4e8fe..0573f73 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -707,6 +707,7 @@ MockTCPClientSocket::MockTCPClientSocket(const net::AddressList& addresses,
addresses_(addresses),
data_(data),
read_offset_(0),
+ num_bytes_read_(0),
read_data_(false, net::ERR_UNEXPECTED),
need_read_data_(true),
peer_closed_connection_(false),
@@ -811,6 +812,17 @@ bool MockTCPClientSocket::UsingTCPFastOpen() const {
return false;
}
+int64 MockTCPClientSocket::NumBytesRead() const {
+ return num_bytes_read_;
+}
+
+base::TimeDelta MockTCPClientSocket::GetConnectTimeMicros() const {
+ // Dummy value.
+ static const base::TimeDelta kTestingConnectTimeMicros =
+ base::TimeDelta::FromMicroseconds(20);
+ return kTestingConnectTimeMicros;
+}
+
void MockTCPClientSocket::OnReadComplete(const MockRead& data) {
// There must be a read pending.
DCHECK(pending_buf_);
@@ -853,6 +865,7 @@ int MockTCPClientSocket::CompleteRead() {
result = std::min(buf_len, read_data_.data_len - read_offset_);
memcpy(buf->data(), read_data_.data + read_offset_, result);
read_offset_ += result;
+ num_bytes_read_ += result;
if (read_offset_ == read_data_.data_len) {
need_read_data_ = true;
read_offset_ = 0;
@@ -1001,6 +1014,14 @@ bool DeterministicMockTCPClientSocket::UsingTCPFastOpen() const {
return false;
}
+int64 DeterministicMockTCPClientSocket::NumBytesRead() const {
+ return -1;
+}
+
+base::TimeDelta DeterministicMockTCPClientSocket::GetConnectTimeMicros() const {
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
void DeterministicMockTCPClientSocket::OnReadComplete(const MockRead& data) {}
class MockSSLClientSocket::ConnectCallback
@@ -1094,6 +1115,14 @@ bool MockSSLClientSocket::UsingTCPFastOpen() const {
return transport_->socket()->UsingTCPFastOpen();
}
+int64 MockSSLClientSocket::NumBytesRead() const {
+ return -1;
+}
+
+base::TimeDelta MockSSLClientSocket::GetConnectTimeMicros() const {
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
void MockSSLClientSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
ssl_info->Reset();
ssl_info->cert = data_->cert_;
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index 9a31288..d1f4816 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -631,6 +631,8 @@ class MockTCPClientSocket : public MockClientSocket {
virtual int GetPeerAddress(AddressList* address) const;
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// MockClientSocket:
virtual void OnReadComplete(const MockRead& data);
@@ -642,6 +644,7 @@ class MockTCPClientSocket : public MockClientSocket {
net::SocketDataProvider* data_;
int read_offset_;
+ int num_bytes_read_;
net::MockRead read_data_;
bool need_read_data_;
@@ -683,6 +686,8 @@ class DeterministicMockTCPClientSocket : public MockClientSocket,
virtual bool IsConnectedAndIdle() const;
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// MockClientSocket:
virtual void OnReadComplete(const MockRead& data);
@@ -724,6 +729,8 @@ class MockSSLClientSocket : public MockClientSocket {
virtual bool IsConnected() const;
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// SSLClientSocket methods:
virtual void GetSSLInfo(net::SSLInfo* ssl_info);
diff --git a/net/socket/socks5_client_socket.cc b/net/socket/socks5_client_socket.cc
index 7a1c10d..2f5cee4 100644
--- a/net/socket/socks5_client_socket.cc
+++ b/net/socket/socks5_client_socket.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -142,6 +142,22 @@ bool SOCKS5ClientSocket::UsingTCPFastOpen() const {
return false;
}
+int64 SOCKS5ClientSocket::NumBytesRead() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->NumBytesRead();
+ }
+ NOTREACHED();
+ return -1;
+}
+
+base::TimeDelta SOCKS5ClientSocket::GetConnectTimeMicros() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->GetConnectTimeMicros();
+ }
+ NOTREACHED();
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
// Read is called by the transport layer above to read. This can only be done
// if the SOCKS handshake is complete.
int SOCKS5ClientSocket::Read(IOBuffer* buf, int buf_len,
diff --git a/net/socket/socks5_client_socket.h b/net/socket/socks5_client_socket.h
index 955ad90..a9d30df 100644
--- a/net/socket/socks5_client_socket.h
+++ b/net/socket/socks5_client_socket.h
@@ -60,6 +60,8 @@ class NET_TEST SOCKS5ClientSocket : public StreamSocket {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/socks_client_socket.cc b/net/socket/socks_client_socket.cc
index d885f15..4a45b01 100644
--- a/net/socket/socks_client_socket.cc
+++ b/net/socket/socks_client_socket.cc
@@ -169,6 +169,22 @@ bool SOCKSClientSocket::UsingTCPFastOpen() const {
return false;
}
+int64 SOCKSClientSocket::NumBytesRead() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->NumBytesRead();
+ }
+ NOTREACHED();
+ return -1;
+}
+
+base::TimeDelta SOCKSClientSocket::GetConnectTimeMicros() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->GetConnectTimeMicros();
+ }
+ NOTREACHED();
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
// Read is called by the transport layer above to read. This can only be done
// if the SOCKS handshake is complete.
diff --git a/net/socket/socks_client_socket.h b/net/socket/socks_client_socket.h
index 7c4ba35..286538f 100644
--- a/net/socket/socks_client_socket.h
+++ b/net/socket/socks_client_socket.h
@@ -58,6 +58,8 @@ class NET_TEST SOCKSClientSocket : public StreamSocket {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc
index 2fc11ec..c38b78a 100644
--- a/net/socket/ssl_client_socket_mac.cc
+++ b/net/socket/ssl_client_socket_mac.cc
@@ -658,6 +658,22 @@ bool SSLClientSocketMac::UsingTCPFastOpen() const {
return false;
}
+int64 SSLClientSocketMac::NumBytesRead() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->NumBytesRead();
+ }
+ NOTREACHED();
+ return -1;
+}
+
+base::TimeDelta SSLClientSocketMac::GetConnectTimeMicros() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->GetConnectTimeMicros();
+ }
+ NOTREACHED();
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
int SSLClientSocketMac::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(completed_handshake());
diff --git a/net/socket/ssl_client_socket_mac.h b/net/socket/ssl_client_socket_mac.h
index 4dbffe6..8ef33e9 100644
--- a/net/socket/ssl_client_socket_mac.h
+++ b/net/socket/ssl_client_socket_mac.h
@@ -57,6 +57,8 @@ class SSLClientSocketMac : public SSLClientSocket {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 18b4e58..9657026 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -714,6 +714,22 @@ bool SSLClientSocketNSS::UsingTCPFastOpen() const {
return false;
}
+int64 SSLClientSocketNSS::NumBytesRead() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->NumBytesRead();
+ }
+ NOTREACHED();
+ return -1;
+}
+
+base::TimeDelta SSLClientSocketNSS::GetConnectTimeMicros() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->GetConnectTimeMicros();
+ }
+ NOTREACHED();
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
int SSLClientSocketNSS::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
EnterFunction(buf_len);
diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h
index 1c5d80e..7d2f7cf 100644
--- a/net/socket/ssl_client_socket_nss.h
+++ b/net/socket/ssl_client_socket_nss.h
@@ -75,6 +75,8 @@ class SSLClientSocketNSS : public SSLClientSocket {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/ssl_client_socket_win.cc b/net/socket/ssl_client_socket_win.cc
index 1392e1d..4cc3103 100644
--- a/net/socket/ssl_client_socket_win.cc
+++ b/net/socket/ssl_client_socket_win.cc
@@ -731,6 +731,22 @@ bool SSLClientSocketWin::UsingTCPFastOpen() const {
return false;
}
+int64 SSLClientSocketWin::NumBytesRead() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->NumBytesRead();
+ }
+ NOTREACHED();
+ return -1;
+}
+
+base::TimeDelta SSLClientSocketWin::GetConnectTimeMicros() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->GetConnectTimeMicros();
+ }
+ NOTREACHED();
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
int SSLClientSocketWin::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(completed_handshake());
diff --git a/net/socket/ssl_client_socket_win.h b/net/socket/ssl_client_socket_win.h
index fb54c43..59f403a 100644
--- a/net/socket/ssl_client_socket_win.h
+++ b/net/socket/ssl_client_socket_win.h
@@ -62,6 +62,8 @@ class SSLClientSocketWin : public SSLClientSocket {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/ssl_server_socket_nss.cc b/net/socket/ssl_server_socket_nss.cc
index 0f35ce9c..b272f8e 100644
--- a/net/socket/ssl_server_socket_nss.cc
+++ b/net/socket/ssl_server_socket_nss.cc
@@ -226,6 +226,14 @@ bool SSLServerSocketNSS::UsingTCPFastOpen() const {
return transport_socket_->UsingTCPFastOpen();
}
+int64 SSLServerSocketNSS::NumBytesRead() const {
+ return transport_socket_->NumBytesRead();
+}
+
+base::TimeDelta SSLServerSocketNSS::GetConnectTimeMicros() const {
+ return transport_socket_->GetConnectTimeMicros();
+}
+
int SSLServerSocketNSS::InitializeSSLOptions() {
// Transport connected, now hook it up to nss
// TODO(port): specify rx and tx buffer sizes separately
diff --git a/net/socket/ssl_server_socket_nss.h b/net/socket/ssl_server_socket_nss.h
index 366a915..5903c17 100644
--- a/net/socket/ssl_server_socket_nss.h
+++ b/net/socket/ssl_server_socket_nss.h
@@ -54,6 +54,8 @@ class SSLServerSocketNSS : public SSLServerSocket {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
private:
enum State {
diff --git a/net/socket/ssl_server_socket_unittest.cc b/net/socket/ssl_server_socket_unittest.cc
index 02f333b..de89c20 100644
--- a/net/socket/ssl_server_socket_unittest.cc
+++ b/net/socket/ssl_server_socket_unittest.cc
@@ -171,6 +171,14 @@ class FakeSocket : public StreamSocket {
return false;
}
+ virtual int64 NumBytesRead() const {
+ return -1;
+ }
+
+ virtual base::TimeDelta GetConnectTimeMicros() const {
+ return base::TimeDelta::FromMicroseconds(-1);
+ }
+
private:
net::BoundNetLog net_log_;
FakeDataChannel* incoming_;
diff --git a/net/socket/stream_socket.h b/net/socket/stream_socket.h
index 544fbcd..ef2f698 100644
--- a/net/socket/stream_socket.h
+++ b/net/socket/stream_socket.h
@@ -6,6 +6,7 @@
#define NET_SOCKET_STREAM_SOCKET_H_
#pragma once
+#include "base/time.h"
#include "net/base/net_log.h"
#include "net/socket/socket.h"
@@ -79,6 +80,12 @@ class NET_TEST StreamSocket : public Socket {
// TCP FastOpen is an experiment with sending data in the TCP SYN packet.
virtual bool UsingTCPFastOpen() const = 0;
+ // Returns the number of bytes successfully read from this socket.
+ virtual int64 NumBytesRead() const = 0;
+
+ // Returns the connection setup time of this socket.
+ virtual base::TimeDelta GetConnectTimeMicros() const = 0;
+
protected:
// The following class is only used to gather statistics about the history of
// a socket. It is only instantiated and used in basic sockets, such as
diff --git a/net/socket/tcp_client_socket_libevent.cc b/net/socket/tcp_client_socket_libevent.cc
index 3c5ec13..bc6270d 100644
--- a/net/socket/tcp_client_socket_libevent.cc
+++ b/net/socket/tcp_client_socket_libevent.cc
@@ -137,7 +137,8 @@ TCPClientSocketLibevent::TCPClientSocketLibevent(
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)),
previously_disconnected_(false),
use_tcp_fastopen_(false),
- tcp_fastopen_connected_(false) {
+ tcp_fastopen_connected_(false),
+ num_bytes_read_(0) {
scoped_refptr<NetLog::EventParameters> params;
if (source.is_valid())
params = new NetLogSourceParameter("source_dependency", source);
@@ -298,6 +299,7 @@ int TCPClientSocketLibevent::DoConnect() {
// Connect the socket.
if (!use_tcp_fastopen_) {
+ connect_start_time_ = base::TimeTicks::Now();
if (!HANDLE_EINTR(connect(socket_, current_ai_->ai_addr,
static_cast<int>(current_ai_->ai_addrlen)))) {
// Connected without waiting!
@@ -337,6 +339,7 @@ int TCPClientSocketLibevent::DoConnectComplete(int result) {
net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, params);
if (result == OK) {
+ connect_time_micros_ = base::TimeTicks::Now() - connect_start_time_;
write_socket_watcher_.StopWatchingFileDescriptor();
use_history_.set_was_ever_connected();
return OK; // Done!
@@ -439,6 +442,7 @@ int TCPClientSocketLibevent::Read(IOBuffer* buf,
if (nread >= 0) {
base::StatsCounter read_bytes("tcp.read_bytes");
read_bytes.Add(nread);
+ num_bytes_read_ += static_cast<int64>(nread);
if (nread > 0)
use_history_.set_was_used_to_convey_data();
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, nread,
@@ -633,6 +637,7 @@ void TCPClientSocketLibevent::DidCompleteRead() {
result = bytes_transferred;
base::StatsCounter read_bytes("tcp.read_bytes");
read_bytes.Add(bytes_transferred);
+ num_bytes_read_ += static_cast<int64>(bytes_transferred);
if (bytes_transferred > 0)
use_history_.set_was_used_to_convey_data();
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, result,
@@ -722,4 +727,12 @@ bool TCPClientSocketLibevent::UsingTCPFastOpen() const {
return use_tcp_fastopen_;
}
+int64 TCPClientSocketLibevent::NumBytesRead() const {
+ return num_bytes_read_;
+}
+
+base::TimeDelta TCPClientSocketLibevent::GetConnectTimeMicros() const {
+ return connect_time_micros_;
+}
+
} // namespace net
diff --git a/net/socket/tcp_client_socket_libevent.h b/net/socket/tcp_client_socket_libevent.h
index 607b9ee..f5e4a28 100644
--- a/net/socket/tcp_client_socket_libevent.h
+++ b/net/socket/tcp_client_socket_libevent.h
@@ -53,6 +53,8 @@ class TCPClientSocketLibevent : public StreamSocket, base::NonThreadSafe {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
// Multiple outstanding requests are not supported.
@@ -195,6 +197,10 @@ class TCPClientSocketLibevent : public StreamSocket, base::NonThreadSafe {
// True when TCP FastOpen is in use and we have done the connect.
bool tcp_fastopen_connected_;
+ base::TimeTicks connect_start_time_;
+ base::TimeDelta connect_time_micros_;
+ int64 num_bytes_read_;
+
DISALLOW_COPY_AND_ASSIGN(TCPClientSocketLibevent);
};
diff --git a/net/socket/tcp_client_socket_win.cc b/net/socket/tcp_client_socket_win.cc
index 71187a1..f4026b7 100644
--- a/net/socket/tcp_client_socket_win.cc
+++ b/net/socket/tcp_client_socket_win.cc
@@ -323,7 +323,8 @@ TCPClientSocketWin::TCPClientSocketWin(const AddressList& addresses,
next_connect_state_(CONNECT_STATE_NONE),
connect_os_error_(0),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)),
- previously_disconnected_(false) {
+ previously_disconnected_(false),
+ num_bytes_read_(0) {
scoped_refptr<NetLog::EventParameters> params;
if (source.is_valid())
params = new NetLogSourceParameter("source_dependency", source);
@@ -484,6 +485,7 @@ int TCPClientSocketWin::DoConnect() {
core_->write_overlapped_.hEvent = WSACreateEvent();
+ connect_start_time_ = base::TimeTicks::Now();
if (!connect(socket_, ai->ai_addr, static_cast<int>(ai->ai_addrlen))) {
// Connected without waiting!
//
@@ -522,6 +524,7 @@ int TCPClientSocketWin::DoConnectComplete(int result) {
net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, params);
if (result == OK) {
+ connect_time_micros_ = base::TimeTicks::Now() - connect_start_time_;
use_history_.set_was_ever_connected();
return OK; // Done!
}
@@ -658,6 +661,14 @@ bool TCPClientSocketWin::UsingTCPFastOpen() const {
return false;
}
+int64 TCPClientSocketWin::NumBytesRead() const {
+ return num_bytes_read_;
+}
+
+base::TimeDelta TCPClientSocketWin::GetConnectTimeMicros() const {
+ return connect_time_micros_;
+}
+
int TCPClientSocketWin::Read(IOBuffer* buf,
int buf_len,
CompletionCallback* callback) {
@@ -688,6 +699,7 @@ int TCPClientSocketWin::Read(IOBuffer* buf,
base::MemoryDebug::MarkAsInitialized(core_->read_buffer_.buf, num);
base::StatsCounter read_bytes("tcp.read_bytes");
read_bytes.Add(num);
+ num_bytes_read_ += num;
if (num > 0)
use_history_.set_was_used_to_convey_data();
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, num,
@@ -858,6 +870,7 @@ void TCPClientSocketWin::DidCompleteRead() {
if (ok) {
base::StatsCounter read_bytes("tcp.read_bytes");
read_bytes.Add(num_bytes);
+ num_bytes_read_ += num_bytes;
if (num_bytes > 0)
use_history_.set_was_used_to_convey_data();
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED,
diff --git a/net/socket/tcp_client_socket_win.h b/net/socket/tcp_client_socket_win.h
index 3282772..b1f9f3b 100644
--- a/net/socket/tcp_client_socket_win.h
+++ b/net/socket/tcp_client_socket_win.h
@@ -53,6 +53,8 @@ class NET_API TCPClientSocketWin : public StreamSocket,
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
// Multiple outstanding requests are not supported.
@@ -141,6 +143,10 @@ class NET_API TCPClientSocketWin : public StreamSocket,
// histograms.
UseHistory use_history_;
+ base::TimeTicks connect_start_time_;
+ base::TimeDelta connect_time_micros_;
+ int64 num_bytes_read_;
+
DISALLOW_COPY_AND_ASSIGN(TCPClientSocketWin);
};
diff --git a/net/socket/transport_client_socket_pool_unittest.cc b/net/socket/transport_client_socket_pool_unittest.cc
index 5716a4d..d12cd9d 100644
--- a/net/socket/transport_client_socket_pool_unittest.cc
+++ b/net/socket/transport_client_socket_pool_unittest.cc
@@ -85,6 +85,10 @@ class MockClientSocket : public StreamSocket {
virtual void SetOmniboxSpeculation() {}
virtual bool WasEverUsed() const { return false; }
virtual bool UsingTCPFastOpen() const { return false; }
+ virtual int64 NumBytesRead() const { return -1; }
+ virtual base::TimeDelta GetConnectTimeMicros() const {
+ return base::TimeDelta::FromMicroseconds(-1);
+ }
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len,
@@ -135,6 +139,10 @@ class MockFailingClientSocket : public StreamSocket {
virtual void SetOmniboxSpeculation() {}
virtual bool WasEverUsed() const { return false; }
virtual bool UsingTCPFastOpen() const { return false; }
+ virtual int64 NumBytesRead() const { return -1; }
+ virtual base::TimeDelta GetConnectTimeMicros() const {
+ return base::TimeDelta::FromMicroseconds(-1);
+ }
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len,
@@ -209,6 +217,10 @@ class MockPendingClientSocket : public StreamSocket {
virtual void SetOmniboxSpeculation() {}
virtual bool WasEverUsed() const { return false; }
virtual bool UsingTCPFastOpen() const { return false; }
+ virtual int64 NumBytesRead() const { return -1; }
+ virtual base::TimeDelta GetConnectTimeMicros() const {
+ return base::TimeDelta::FromMicroseconds(-1);
+ }
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len,
diff --git a/net/socket/transport_client_socket_unittest.cc b/net/socket/transport_client_socket_unittest.cc
index bb0be35..8f377e5 100644
--- a/net/socket/transport_client_socket_unittest.cc
+++ b/net/socket/transport_client_socket_unittest.cc
@@ -277,6 +277,8 @@ TEST_P(TransportClientSocketTest, Read) {
rv = sock_->Read(buf, 4096, &callback);
ASSERT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(static_cast<int64>(std::string(kServerReply).size()),
+ sock_->NumBytesRead());
CloseServerSocket();
EXPECT_EQ(0, callback.WaitForResult());
}
@@ -309,6 +311,8 @@ TEST_P(TransportClientSocketTest, Read_SmallChunks) {
// then close the server socket, and note the close.
rv = sock_->Read(buf, 1, &callback);
+ EXPECT_EQ(static_cast<int64>(std::string(kServerReply).size()),
+ sock_->NumBytesRead());
ASSERT_EQ(ERR_IO_PENDING, rv);
CloseServerSocket();
EXPECT_EQ(0, callback.WaitForResult());
@@ -329,9 +333,12 @@ TEST_P(TransportClientSocketTest, Read_Interrupted) {
scoped_refptr<IOBuffer> buf(new IOBuffer(16));
rv = sock_->Read(buf, 16, &callback);
EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
+ EXPECT_EQ(0, sock_->NumBytesRead());
- if (rv == ERR_IO_PENDING)
+ if (rv == ERR_IO_PENDING) {
rv = callback.WaitForResult();
+ EXPECT_EQ(16, sock_->NumBytesRead());
+ }
EXPECT_NE(0, rv);
}
diff --git a/net/spdy/spdy_http_stream.h b/net/spdy/spdy_http_stream.h
index 88c627d..b6727e5 100644
--- a/net/spdy/spdy_http_stream.h
+++ b/net/spdy/spdy_http_stream.h
@@ -68,6 +68,7 @@ class NET_TEST SpdyHttpStream : public SpdyStream::Delegate, public HttpStream {
virtual void GetSSLCertRequestInfo(
SSLCertRequestInfo* cert_request_info) OVERRIDE;
virtual bool IsSpdyHttpStream() const OVERRIDE;
+ virtual void LogNumRttVsBytesMetrics() const OVERRIDE {}
// SpdyStream::Delegate methods:
virtual bool OnSendHeadersComplete(int status) OVERRIDE;
diff --git a/net/spdy/spdy_proxy_client_socket.cc b/net/spdy/spdy_proxy_client_socket.cc
index 1e6e23a..c5733cf 100644
--- a/net/spdy/spdy_proxy_client_socket.cc
+++ b/net/spdy/spdy_proxy_client_socket.cc
@@ -138,6 +138,14 @@ bool SpdyProxyClientSocket::UsingTCPFastOpen() const {
return false;
}
+int64 SpdyProxyClientSocket::NumBytesRead() const {
+ return -1;
+}
+
+base::TimeDelta SpdyProxyClientSocket::GetConnectTimeMicros() const {
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
int SpdyProxyClientSocket::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(!read_callback_);
diff --git a/net/spdy/spdy_proxy_client_socket.h b/net/spdy/spdy_proxy_client_socket.h
index d7510d1..e6598ea 100644
--- a/net/spdy/spdy_proxy_client_socket.h
+++ b/net/spdy/spdy_proxy_client_socket.h
@@ -77,6 +77,8 @@ class NET_TEST SpdyProxyClientSocket : public ProxyClientSocket,
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/remoting/jingle_glue/ssl_socket_adapter.cc b/remoting/jingle_glue/ssl_socket_adapter.cc
index 101ce3d..59b42f9 100644
--- a/remoting/jingle_glue/ssl_socket_adapter.cc
+++ b/remoting/jingle_glue/ssl_socket_adapter.cc
@@ -270,6 +270,16 @@ bool TransportSocket::UsingTCPFastOpen() const {
return false;
}
+int64 TransportSocket::NumBytesRead() const {
+ NOTREACHED();
+ return -1;
+}
+
+base::TimeDelta TransportSocket::GetConnectTimeMicros() const {
+ NOTREACHED();
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
int TransportSocket::Read(net::IOBuffer* buf, int buf_len,
net::CompletionCallback* callback) {
DCHECK(buf);
diff --git a/remoting/jingle_glue/ssl_socket_adapter.h b/remoting/jingle_glue/ssl_socket_adapter.h
index 9acd3f7..388bd1c 100644
--- a/remoting/jingle_glue/ssl_socket_adapter.h
+++ b/remoting/jingle_glue/ssl_socket_adapter.h
@@ -52,6 +52,8 @@ class TransportSocket : public net::StreamSocket, public sigslot::has_slots<> {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// net::Socket implementation